Merge "Make mapIntentToUri understand meta-data hookup"
diff --git a/api/current.txt b/api/current.txt
index 3bf3e04..c0223b7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -16276,9 +16276,7 @@
field public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.LensShadingMap> STATISTICS_LENS_SHADING_CORRECTION_MAP;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_LENS_SHADING_MAP_MODE;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_OIS_DATA_MODE;
- field public static final android.hardware.camera2.CaptureResult.Key<long[]> STATISTICS_OIS_TIMESTAMPS;
- field public static final android.hardware.camera2.CaptureResult.Key<float[]> STATISTICS_OIS_X_SHIFTS;
- field public static final android.hardware.camera2.CaptureResult.Key<float[]> STATISTICS_OIS_Y_SHIFTS;
+ field public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.OisSample[]> STATISTICS_OIS_SAMPLES;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_SCENE_FLICKER;
field public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.TonemapCurve> TONEMAP_CURVE;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> TONEMAP_GAMMA;
@@ -16374,6 +16372,13 @@
field public static final int METERING_WEIGHT_MIN = 0; // 0x0
}
+ public final class OisSample {
+ ctor public OisSample(long, float, float);
+ method public long getTimestamp();
+ method public float getXshift();
+ method public float getYshift();
+ }
+
public final class OutputConfiguration implements android.os.Parcelable {
ctor public OutputConfiguration(android.view.Surface);
ctor public OutputConfiguration(int, android.view.Surface);
@@ -24076,13 +24081,14 @@
method public static final android.media.MediaPlayer2 create();
method public abstract void deselectTrack(int);
method public abstract android.media.DataSourceDesc editPlaylistItem(int, android.media.DataSourceDesc);
+ method public abstract android.media.AudioAttributes getAudioAttributes();
method public abstract int getAudioSessionId();
method public abstract android.media.DataSourceDesc getCurrentDataSource();
method public abstract int getCurrentPlaylistItemIndex();
- method public abstract int getCurrentPosition();
+ method public abstract long getCurrentPosition();
method public abstract android.media.MediaPlayer2.DrmInfo getDrmInfo();
method public abstract java.lang.String getDrmPropertyString(java.lang.String) throws android.media.MediaPlayer2.NoDrmSchemeException;
- method public abstract int getDuration();
+ method public abstract long getDuration();
method public abstract android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer2.NoDrmSchemeException;
method public abstract int getLoopingMode();
method public abstract android.os.PersistableBundle getMetrics();
@@ -24168,8 +24174,8 @@
public static abstract class MediaPlayer2.DrmEventCallback {
ctor public MediaPlayer2.DrmEventCallback();
- method public void onDrmInfo(android.media.MediaPlayer2, android.media.MediaPlayer2.DrmInfo);
- method public void onDrmPrepared(android.media.MediaPlayer2, int);
+ method public void onDrmInfo(android.media.MediaPlayer2, long, android.media.MediaPlayer2.DrmInfo);
+ method public void onDrmPrepared(android.media.MediaPlayer2, long, int);
}
public static abstract class MediaPlayer2.DrmInfo {
@@ -24207,7 +24213,7 @@
}
public static abstract interface MediaPlayer2.OnDrmConfigHelper {
- method public abstract void onDrmConfig(android.media.MediaPlayer2);
+ method public abstract void onDrmConfig(android.media.MediaPlayer2, long);
}
public static abstract class MediaPlayer2.ProvisioningNetworkErrorException extends android.media.MediaDrmException {
@@ -38433,7 +38439,6 @@
method public boolean isRandomizedEncryptionRequired();
method public boolean isStrongBoxBacked();
method public boolean isTrustedUserPresenceRequired();
- method public boolean isUnlockedDeviceRequired();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationValidWhileOnBody();
method public boolean isUserConfirmationRequired();
@@ -38461,7 +38466,6 @@
method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
method public android.security.keystore.KeyGenParameterSpec.Builder setTrustedUserPresenceRequired(boolean);
- method public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
@@ -38553,8 +38557,6 @@
method public boolean isDigestsSpecified();
method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isRandomizedEncryptionRequired();
- method public boolean isTrustedUserPresenceRequired();
- method public boolean isUnlockedDeviceRequired();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationValidWhileOnBody();
method public boolean isUserConfirmationRequired();
@@ -38573,8 +38575,6 @@
method public android.security.keystore.KeyProtection.Builder setKeyValidityStart(java.util.Date);
method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
- method public android.security.keystore.KeyProtection.Builder setTrustedUserPresenceRequired(boolean);
- method public android.security.keystore.KeyProtection.Builder setUnlockedDeviceRequired(boolean);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int);
@@ -47622,6 +47622,7 @@
method public void setAlpha(float);
method public void setAnimation(android.view.animation.Animation);
method public void setAutofillHints(java.lang.String...);
+ method public void setAutofillId(android.view.autofill.AutofillId);
method public void setBackground(android.graphics.drawable.Drawable);
method public void setBackgroundColor(int);
method public deprecated void setBackgroundDrawable(android.graphics.drawable.Drawable);
@@ -49785,6 +49786,7 @@
method public android.content.ComponentName getAutofillServiceComponentName();
method public java.util.List<java.lang.String> getAvailableFieldClassificationAlgorithms();
method public java.lang.String getDefaultFieldClassificationAlgorithm();
+ method public android.view.autofill.AutofillId getNextAutofillId();
method public android.service.autofill.UserData getUserData();
method public java.lang.String getUserDataId();
method public boolean hasEnabledAutofillServices();
diff --git a/api/system-current.txt b/api/system-current.txt
index 1235591..d24a313 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4292,6 +4292,7 @@
}
public class RecoveryController {
+ method public android.security.keystore.recovery.RecoverySession createRecoverySession();
method public byte[] generateAndStoreKey(java.lang.String, byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
method public java.util.List<java.lang.String> getAliases(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public static android.security.keystore.recovery.RecoveryController getInstance(android.content.Context);
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index babe0fc..c40eb81 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -233,11 +233,19 @@
void AnomalyTracker::informSubscribers(const MetricDimensionKey& key) {
VLOG("informSubscribers called.");
if (mSubscriptions.empty()) {
- ALOGE("Attempt to call with no subscribers.");
+ // The config just wanted to log the anomaly. That's fine.
+ VLOG("No Subscriptions were associated with the alert.");
return;
}
for (const Subscription& subscription : mSubscriptions) {
+ if (subscription.probability_of_informing() < 1
+ && ((float)rand() / RAND_MAX) >= subscription.probability_of_informing()) {
+ // Note that due to float imprecision, 0.0 and 1.0 might not truly mean never/always.
+ // The config writer was advised to use -0.1 and 1.1 for never/always.
+ ALOGI("Fate decided that a subscriber would not be informed.");
+ continue;
+ }
switch (subscription.subscriber_information_case()) {
case Subscription::SubscriberInformationCase::kIncidentdDetails:
if (!GenerateIncidentReport(subscription.incidentd_details(), mAlert, mConfigKey)) {
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 8750275..a313854 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -307,6 +307,8 @@
PerfettoDetails perfetto_details = 5;
BroadcastSubscriberDetails broadcast_subscriber_details = 6;
}
+
+ optional float probability_of_informing = 7 [default = 1.1];
}
message StatsdConfig {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ccbf21b..3ebe89f 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1400,6 +1400,7 @@
*
* {@hide}
*/
+ @Override
public int getNextAutofillId() {
if (mLastAutofillId == Integer.MAX_VALUE - 1) {
mLastAutofillId = View.LAST_APP_AUTOFILL_ID;
@@ -1411,6 +1412,14 @@
}
/**
+ * @hide
+ */
+ @Override
+ public AutofillId autofillClientGetNextAutofillId() {
+ return new AutofillId(getNextAutofillId());
+ }
+
+ /**
* Check whether this activity is running as part of a voice interaction with the user.
* If true, it should perform its interaction with the user through the
* {@link VoiceInteractor} returned by {@link #getVoiceInteractor}.
@@ -7624,6 +7633,19 @@
/** @hide */
@Override
+ public final void autofillClientDispatchUnhandledKey(@NonNull View anchor,
+ @NonNull KeyEvent keyEvent) {
+ ViewRootImpl rootImpl = anchor.getViewRootImpl();
+ if (rootImpl != null) {
+ // dont care if anchorView is current focus, for example a custom view may only receive
+ // touchEvent, not focusable but can still trigger autofill window. The Key handling
+ // might be inside parent of the custom view.
+ rootImpl.dispatchKeyFromAutofill(keyEvent);
+ }
+ }
+
+ /** @hide */
+ @Override
public final boolean autofillClientRequestHideFillUi() {
if (mAutofillPopupWindow == null) {
return false;
@@ -7739,7 +7761,7 @@
/** @hide */
@Override
- public final boolean autofillIsCompatibilityModeEnabled() {
+ public final boolean autofillClientIsCompatibilityModeEnabled() {
return isAutofillCompatibilityEnabled();
}
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index d36a794..d1c957b 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -18,6 +18,7 @@
import android.app.IBackupAgent;
import android.app.QueuedWork;
+import android.app.backup.FullBackup.BackupScheme.PathWithRequiredFlags;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.ApplicationInfo;
@@ -343,8 +344,8 @@
return;
}
- Map<String, Set<String>> manifestIncludeMap;
- ArraySet<String> manifestExcludeSet;
+ Map<String, Set<PathWithRequiredFlags>> manifestIncludeMap;
+ ArraySet<PathWithRequiredFlags> manifestExcludeSet;
try {
manifestIncludeMap =
backupScheme.maybeParseAndGetCanonicalIncludePaths();
@@ -514,14 +515,13 @@
/**
* Check whether the xml yielded any <include/> tag for the provided <code>domainToken</code>.
* If so, perform a {@link #fullBackupFileTree} which backs up the file or recurses if the path
- * is a directory.
+ * is a directory, but only if all the required flags of the include rule are satisfied by
+ * the transport.
*/
private void applyXmlFiltersAndDoFullBackupForDomain(String packageName, String domainToken,
- Map<String, Set<String>> includeMap,
- ArraySet<String> filterSet,
- ArraySet<String> traversalExcludeSet,
- FullBackupDataOutput data)
- throws IOException {
+ Map<String, Set<PathWithRequiredFlags>> includeMap,
+ ArraySet<PathWithRequiredFlags> filterSet, ArraySet<String> traversalExcludeSet,
+ FullBackupDataOutput data) throws IOException {
if (includeMap == null || includeMap.size() == 0) {
// Do entire sub-tree for the provided token.
fullBackupFileTree(packageName, domainToken,
@@ -530,13 +530,22 @@
} else if (includeMap.get(domainToken) != null) {
// This will be null if the xml parsing didn't yield any rules for
// this domain (there may still be rules for other domains).
- for (String includeFile : includeMap.get(domainToken)) {
- fullBackupFileTree(packageName, domainToken, includeFile, filterSet,
- traversalExcludeSet, data);
+ for (PathWithRequiredFlags includeFile : includeMap.get(domainToken)) {
+ if (areIncludeRequiredTransportFlagsSatisfied(includeFile.getRequiredFlags(),
+ data.getTransportFlags())) {
+ fullBackupFileTree(packageName, domainToken, includeFile.getPath(), filterSet,
+ traversalExcludeSet, data);
+ }
}
}
}
+ private boolean areIncludeRequiredTransportFlagsSatisfied(int includeFlags,
+ int transportFlags) {
+ // all bits that are set in includeFlags must also be set in transportFlags
+ return (transportFlags & includeFlags) == includeFlags;
+ }
+
/**
* Write an entire file as part of a full-backup operation. The file's contents
* will be delivered to the backup destination along with the metadata necessary
@@ -683,7 +692,7 @@
* @hide
*/
protected final void fullBackupFileTree(String packageName, String domain, String startingPath,
- ArraySet<String> manifestExcludes,
+ ArraySet<PathWithRequiredFlags> manifestExcludes,
ArraySet<String> systemExcludes,
FullBackupDataOutput output) {
// Pull out the domain and set it aside to use when making the tarball.
@@ -714,7 +723,8 @@
filePath = file.getCanonicalPath();
// prune this subtree?
- if (manifestExcludes != null && manifestExcludes.contains(filePath)) {
+ if (manifestExcludes != null
+ && manifestExcludesContainFilePath(manifestExcludes, filePath)) {
continue;
}
if (systemExcludes != null && systemExcludes.contains(filePath)) {
@@ -750,6 +760,17 @@
}
}
+ private boolean manifestExcludesContainFilePath(
+ ArraySet<PathWithRequiredFlags> manifestExcludes, String filePath) {
+ for (PathWithRequiredFlags exclude : manifestExcludes) {
+ String excludePath = exclude.getPath();
+ if (excludePath != null && excludePath.equals(filePath)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Handle the data delivered via the given file descriptor during a full restore
* operation. The agent is given the path to the file's original location as well
@@ -796,8 +817,8 @@
return false;
}
- Map<String, Set<String>> includes = null;
- ArraySet<String> excludes = null;
+ Map<String, Set<PathWithRequiredFlags>> includes = null;
+ ArraySet<PathWithRequiredFlags> excludes = null;
final String destinationCanonicalPath = destination.getCanonicalPath();
try {
includes = bs.maybeParseAndGetCanonicalIncludePaths();
@@ -826,7 +847,7 @@
// Rather than figure out the <include/> domain based on the path (a lot of code, and
// it's a small list), we'll go through and look for it.
boolean explicitlyIncluded = false;
- for (Set<String> domainIncludes : includes.values()) {
+ for (Set<PathWithRequiredFlags> domainIncludes : includes.values()) {
explicitlyIncluded |= isFileSpecifiedInPathList(destination, domainIncludes);
if (explicitlyIncluded) {
break;
@@ -849,9 +870,10 @@
* @return True if the provided file is either directly in the provided list, or the provided
* file is within a directory in the list.
*/
- private boolean isFileSpecifiedInPathList(File file, Collection<String> canonicalPathList)
- throws IOException {
- for (String canonicalPath : canonicalPathList) {
+ private boolean isFileSpecifiedInPathList(File file,
+ Collection<PathWithRequiredFlags> canonicalPathList) throws IOException {
+ for (PathWithRequiredFlags canonical : canonicalPathList) {
+ String canonicalPath = canonical.getPath();
File fileFromList = new File(canonicalPath);
if (fileFromList.isDirectory()) {
if (file.isDirectory()) {
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index a5dd5bd..fb1c2d0 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -82,6 +82,9 @@
public static final String FULL_RESTORE_INTENT_ACTION = "fullrest";
public static final String CONF_TOKEN_INTENT_EXTRA = "conftoken";
+ public static final String FLAG_REQUIRED_CLIENT_SIDE_ENCRYPTION = "clientSideEncryption";
+ public static final String FLAG_REQUIRED_DEVICE_TO_DEVICE_TRANSFER = "deviceToDeviceTransfer";
+
/**
* @hide
*/
@@ -224,6 +227,9 @@
private final File EXTERNAL_DIR;
+ private final static String TAG_INCLUDE = "include";
+ private final static String TAG_EXCLUDE = "exclude";
+
final int mFullBackupContent;
final PackageManager mPackageManager;
final StorageManager mStorageManager;
@@ -303,15 +309,45 @@
}
/**
- * A map of domain -> list of canonical file names in that domain that are to be included.
- * We keep track of the domain so that we can go through the file system in order later on.
- */
- Map<String, Set<String>> mIncludes;
- /**e
- * List that will be populated with the canonical names of each file or directory that is
- * to be excluded.
+ * Represents a path attribute specified in an <include /> rule along with optional
+ * transport flags required from the transport to include file(s) under that path as
+ * specified by requiredFlags attribute. If optional requiredFlags attribute is not
+ * provided, default requiredFlags to 0.
+ * Note: since our parsing codepaths were the same for <include /> and <exclude /> tags,
+ * this structure is also used for <exclude /> tags to preserve that, however you can expect
+ * the getRequiredFlags() to always return 0 for exclude rules.
*/
- ArraySet<String> mExcludes;
+ public static class PathWithRequiredFlags {
+ private final String mPath;
+ private final int mRequiredFlags;
+
+ public PathWithRequiredFlags(String path, int requiredFlags) {
+ mPath = path;
+ mRequiredFlags = requiredFlags;
+ }
+
+ public String getPath() {
+ return mPath;
+ }
+
+ public int getRequiredFlags() {
+ return mRequiredFlags;
+ }
+ }
+
+ /**
+ * A map of domain -> set of pairs (canonical file; required transport flags) in that
+ * domain that are to be included if the transport has decared the required flags.
+ * We keep track of the domain so that we can go through the file system in order later on.
+ */
+ Map<String, Set<PathWithRequiredFlags>> mIncludes;
+
+ /**
+ * Set that will be populated with pairs (canonical file; requiredFlags=0) for each file or
+ * directory that is to be excluded. Note that for excludes, the requiredFlags attribute is
+ * ignored and the value should be always set to 0.
+ */
+ ArraySet<PathWithRequiredFlags> mExcludes;
BackupScheme(Context context) {
mFullBackupContent = context.getApplicationInfo().fullBackupContent;
@@ -356,13 +392,14 @@
}
/**
- * @return A mapping of domain -> canonical paths within that domain. Each of these paths
- * specifies a file that the client has explicitly included in their backup set. If this
- * map is empty we will back up the entire data directory (including managed external
- * storage).
+ * @return A mapping of domain -> set of pairs (canonical file; required transport flags)
+ * in that domain that are to be included if the transport has decared the required flags.
+ * Each of these paths specifies a file that the client has explicitly included in their
+ * backup set. If this map is empty we will back up the entire data directory (including
+ * managed external storage).
*/
- public synchronized Map<String, Set<String>> maybeParseAndGetCanonicalIncludePaths()
- throws IOException, XmlPullParserException {
+ public synchronized Map<String, Set<PathWithRequiredFlags>>
+ maybeParseAndGetCanonicalIncludePaths() throws IOException, XmlPullParserException {
if (mIncludes == null) {
maybeParseBackupSchemeLocked();
}
@@ -370,9 +407,10 @@
}
/**
- * @return A set of canonical paths that are to be excluded from the backup/restore set.
+ * @return A set of (canonical paths; requiredFlags=0) that are to be excluded from the
+ * backup/restore set.
*/
- public synchronized ArraySet<String> maybeParseAndGetCanonicalExcludePaths()
+ public synchronized ArraySet<PathWithRequiredFlags> maybeParseAndGetCanonicalExcludePaths()
throws IOException, XmlPullParserException {
if (mExcludes == null) {
maybeParseBackupSchemeLocked();
@@ -382,8 +420,8 @@
private void maybeParseBackupSchemeLocked() throws IOException, XmlPullParserException {
// This not being null is how we know that we've tried to parse the xml already.
- mIncludes = new ArrayMap<String, Set<String>>();
- mExcludes = new ArraySet<String>();
+ mIncludes = new ArrayMap<String, Set<PathWithRequiredFlags>>();
+ mExcludes = new ArraySet<PathWithRequiredFlags>();
if (mFullBackupContent == 0) {
// android:fullBackupContent="true" which means that we'll do everything.
@@ -415,8 +453,8 @@
@VisibleForTesting
public void parseBackupSchemeFromXmlLocked(XmlPullParser parser,
- Set<String> excludes,
- Map<String, Set<String>> includes)
+ Set<PathWithRequiredFlags> excludes,
+ Map<String, Set<PathWithRequiredFlags>> includes)
throws IOException, XmlPullParserException {
int event = parser.getEventType(); // START_DOCUMENT
while (event != XmlPullParser.START_TAG) {
@@ -441,8 +479,7 @@
case XmlPullParser.START_TAG:
validateInnerTagContents(parser);
final String domainFromXml = parser.getAttributeValue(null, "domain");
- final File domainDirectory =
- getDirectoryForCriteriaDomain(domainFromXml);
+ final File domainDirectory = getDirectoryForCriteriaDomain(domainFromXml);
if (domainDirectory == null) {
if (Log.isLoggable(TAG_XML_PARSER, Log.VERBOSE)) {
Log.v(TAG_XML_PARSER, "...parsing \"" + parser.getName() + "\": "
@@ -457,12 +494,23 @@
break;
}
- Set<String> activeSet = parseCurrentTagForDomain(
+ int requiredFlags = 0; // no transport flags are required by default
+ if (TAG_INCLUDE.equals(parser.getName())) {
+ // requiredFlags are only supported for <include /> tag, for <exclude />
+ // we should always leave them as the default = 0
+ requiredFlags = getRequiredFlagsFromString(
+ parser.getAttributeValue(null, "requireFlags"));
+ }
+
+ // retrieve the include/exclude set we'll be adding this rule to
+ Set<PathWithRequiredFlags> activeSet = parseCurrentTagForDomain(
parser, excludes, includes, domainFromXml);
- activeSet.add(canonicalFile.getCanonicalPath());
+ activeSet.add(new PathWithRequiredFlags(canonicalFile.getCanonicalPath(),
+ requiredFlags));
if (Log.isLoggable(TAG_XML_PARSER, Log.VERBOSE)) {
Log.v(TAG_XML_PARSER, "...parsed " + canonicalFile.getCanonicalPath()
- + " for domain \"" + domainFromXml + "\"");
+ + " for domain \"" + domainFromXml + "\", requiredFlags + \""
+ + requiredFlags + "\"");
}
// Special case journal files (not dirs) for sqlite database. frowny-face.
@@ -472,14 +520,16 @@
if ("database".equals(domainFromXml) && !canonicalFile.isDirectory()) {
final String canonicalJournalPath =
canonicalFile.getCanonicalPath() + "-journal";
- activeSet.add(canonicalJournalPath);
+ activeSet.add(new PathWithRequiredFlags(canonicalJournalPath,
+ requiredFlags));
if (Log.isLoggable(TAG_XML_PARSER, Log.VERBOSE)) {
Log.v(TAG_XML_PARSER, "...automatically generated "
+ canonicalJournalPath + ". Ignore if nonexistent.");
}
final String canonicalWalPath =
canonicalFile.getCanonicalPath() + "-wal";
- activeSet.add(canonicalWalPath);
+ activeSet.add(new PathWithRequiredFlags(canonicalWalPath,
+ requiredFlags));
if (Log.isLoggable(TAG_XML_PARSER, Log.VERBOSE)) {
Log.v(TAG_XML_PARSER, "...automatically generated "
+ canonicalWalPath + ". Ignore if nonexistent.");
@@ -491,7 +541,8 @@
!canonicalFile.getCanonicalPath().endsWith(".xml")) {
final String canonicalXmlPath =
canonicalFile.getCanonicalPath() + ".xml";
- activeSet.add(canonicalXmlPath);
+ activeSet.add(new PathWithRequiredFlags(canonicalXmlPath,
+ requiredFlags));
if (Log.isLoggable(TAG_XML_PARSER, Log.VERBOSE)) {
Log.v(TAG_XML_PARSER, "...automatically generated "
+ canonicalXmlPath + ". Ignore if nonexistent.");
@@ -508,10 +559,12 @@
Log.v(TAG_XML_PARSER, " ...nothing specified (This means the entirety of app"
+ " data minus excludes)");
} else {
- for (Map.Entry<String, Set<String>> entry : includes.entrySet()) {
+ for (Map.Entry<String, Set<PathWithRequiredFlags>> entry
+ : includes.entrySet()) {
Log.v(TAG_XML_PARSER, " domain=" + entry.getKey());
- for (String includeData : entry.getValue()) {
- Log.v(TAG_XML_PARSER, " " + includeData);
+ for (PathWithRequiredFlags includeData : entry.getValue()) {
+ Log.v(TAG_XML_PARSER, " path: " + includeData.getPath()
+ + " requiredFlags: " + includeData.getRequiredFlags());
}
}
}
@@ -520,8 +573,9 @@
if (excludes.isEmpty()) {
Log.v(TAG_XML_PARSER, " ...nothing to exclude.");
} else {
- for (String excludeData : excludes) {
- Log.v(TAG_XML_PARSER, " " + excludeData);
+ for (PathWithRequiredFlags excludeData : excludes) {
+ Log.v(TAG_XML_PARSER, " path: " + excludeData.getPath()
+ + " requiredFlags: " + excludeData.getRequiredFlags());
}
}
@@ -531,20 +585,41 @@
}
}
- private Set<String> parseCurrentTagForDomain(XmlPullParser parser,
- Set<String> excludes,
- Map<String, Set<String>> includes,
- String domain)
+ private int getRequiredFlagsFromString(String requiredFlags) {
+ int flags = 0;
+ if (requiredFlags == null || requiredFlags.length() == 0) {
+ // requiredFlags attribute was missing or empty in <include /> tag
+ return flags;
+ }
+ String[] flagsStr = requiredFlags.split("\\|");
+ for (String f : flagsStr) {
+ switch (f) {
+ case FLAG_REQUIRED_CLIENT_SIDE_ENCRYPTION:
+ flags |= BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
+ break;
+ case FLAG_REQUIRED_DEVICE_TO_DEVICE_TRANSFER:
+ flags |= BackupAgent.FLAG_DEVICE_TO_DEVICE_TRANSFER;
+ break;
+ default:
+ Log.w(TAG, "Unrecognized requiredFlag provided, value: \"" + f + "\"");
+ }
+ }
+ return flags;
+ }
+
+ private Set<PathWithRequiredFlags> parseCurrentTagForDomain(XmlPullParser parser,
+ Set<PathWithRequiredFlags> excludes,
+ Map<String, Set<PathWithRequiredFlags>> includes, String domain)
throws XmlPullParserException {
- if ("include".equals(parser.getName())) {
+ if (TAG_INCLUDE.equals(parser.getName())) {
final String domainToken = getTokenForXmlDomain(domain);
- Set<String> includeSet = includes.get(domainToken);
+ Set<PathWithRequiredFlags> includeSet = includes.get(domainToken);
if (includeSet == null) {
- includeSet = new ArraySet<String>();
+ includeSet = new ArraySet<PathWithRequiredFlags>();
includes.put(domainToken, includeSet);
}
return includeSet;
- } else if ("exclude".equals(parser.getName())) {
+ } else if (TAG_EXCLUDE.equals(parser.getName())) {
return excludes;
} else {
// Unrecognised tag => hard failure.
@@ -589,8 +664,8 @@
/**
*
* @param domain Directory where the specified file should exist. Not null.
- * @param filePathFromXml parsed from xml. Not sanitised before calling this function so may be
- * null.
+ * @param filePathFromXml parsed from xml. Not sanitised before calling this function so may
+ * be null.
* @return The canonical path of the file specified or null if no such file exists.
*/
private File extractCanonicalFile(File domain, String filePathFromXml) {
@@ -650,15 +725,27 @@
* Let's be strict about the type of xml the client can write. If we see anything untoward,
* throw an XmlPullParserException.
*/
- private void validateInnerTagContents(XmlPullParser parser)
- throws XmlPullParserException {
- if (parser.getAttributeCount() > 2) {
- throw new XmlPullParserException("At most 2 tag attributes allowed for \""
- + parser.getName() + "\" tag (\"domain\" & \"path\".");
+ private void validateInnerTagContents(XmlPullParser parser) throws XmlPullParserException {
+ if (parser == null) {
+ return;
}
- if (!"include".equals(parser.getName()) && !"exclude".equals(parser.getName())) {
- throw new XmlPullParserException("A valid tag is one of \"<include/>\" or" +
- " \"<exclude/>. You provided \"" + parser.getName() + "\"");
+ switch (parser.getName()) {
+ case TAG_INCLUDE:
+ if (parser.getAttributeCount() > 3) {
+ throw new XmlPullParserException("At most 3 tag attributes allowed for "
+ + "\"include\" tag (\"domain\" & \"path\""
+ + " & optional \"requiredFlags\").");
+ }
+ break;
+ case TAG_EXCLUDE:
+ if (parser.getAttributeCount() > 2) {
+ throw new XmlPullParserException("At most 2 tag attributes allowed for "
+ + "\"exclude\" tag (\"domain\" & \"path\".");
+ }
+ break;
+ default:
+ throw new XmlPullParserException("A valid tag is one of \"<include/>\" or" +
+ " \"<exclude/>. You provided \"" + parser.getName() + "\"");
}
}
}
diff --git a/core/java/android/app/slice/ISliceManager.aidl b/core/java/android/app/slice/ISliceManager.aidl
index 38d9025..20ec75a 100644
--- a/core/java/android/app/slice/ISliceManager.aidl
+++ b/core/java/android/app/slice/ISliceManager.aidl
@@ -16,17 +16,13 @@
package android.app.slice;
-import android.app.slice.ISliceListener;
import android.app.slice.SliceSpec;
import android.net.Uri;
/** @hide */
interface ISliceManager {
- void addSliceListener(in Uri uri, String pkg, in ISliceListener listener,
- in SliceSpec[] specs);
- void removeSliceListener(in Uri uri, String pkg, in ISliceListener listener);
- void pinSlice(String pkg, in Uri uri, in SliceSpec[] specs);
- void unpinSlice(String pkg, in Uri uri);
+ void pinSlice(String pkg, in Uri uri, in SliceSpec[] specs, in IBinder token);
+ void unpinSlice(String pkg, in Uri uri, in IBinder token);
boolean hasSliceAccess(String pkg);
SliceSpec[] getPinnedSpecs(in Uri uri, String pkg);
int checkSlicePermission(in Uri uri, String pkg, int pid, int uid);
diff --git a/core/java/android/app/slice/SliceManager.java b/core/java/android/app/slice/SliceManager.java
index 15ff03a..ae1d8d7 100644
--- a/core/java/android/app/slice/SliceManager.java
+++ b/core/java/android/app/slice/SliceManager.java
@@ -27,8 +27,10 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
@@ -74,6 +76,7 @@
private final Context mContext;
private final ArrayMap<Pair<Uri, SliceCallback>, ISliceListener> mListenerLookup =
new ArrayMap<>();
+ private final IBinder mToken = new Binder();
/**
* Permission denied.
@@ -106,7 +109,6 @@
@Deprecated
public void registerSliceCallback(@NonNull Uri uri, @NonNull SliceCallback callback,
@NonNull List<SliceSpec> specs) {
- registerSliceCallback(uri, specs, mContext.getMainExecutor(), callback);
}
/**
@@ -115,7 +117,6 @@
@Deprecated
public void registerSliceCallback(@NonNull Uri uri, @NonNull SliceCallback callback,
@NonNull List<SliceSpec> specs, Executor executor) {
- registerSliceCallback(uri, specs, executor, callback);
}
/**
@@ -133,7 +134,6 @@
*/
public void registerSliceCallback(@NonNull Uri uri, @NonNull List<SliceSpec> specs,
@NonNull SliceCallback callback) {
- registerSliceCallback(uri, specs, mContext.getMainExecutor(), callback);
}
/**
@@ -151,32 +151,7 @@
*/
public void registerSliceCallback(@NonNull Uri uri, @NonNull List<SliceSpec> specs,
@NonNull @CallbackExecutor Executor executor, @NonNull SliceCallback callback) {
- try {
- mService.addSliceListener(uri, mContext.getPackageName(),
- getListener(uri, callback, new ISliceListener.Stub() {
- @Override
- public void onSliceUpdated(Slice s) throws RemoteException {
- executor.execute(() -> callback.onSliceUpdated(s));
- }
- }), specs.toArray(new SliceSpec[specs.size()]));
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
- private ISliceListener getListener(Uri uri, SliceCallback callback,
- ISliceListener listener) {
- Pair<Uri, SliceCallback> key = new Pair<>(uri, callback);
- if (mListenerLookup.containsKey(key)) {
- try {
- mService.removeSliceListener(uri, mContext.getPackageName(),
- mListenerLookup.get(key));
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
- mListenerLookup.put(key, listener);
- return listener;
}
/**
@@ -190,12 +165,7 @@
* @see #registerSliceCallback
*/
public void unregisterSliceCallback(@NonNull Uri uri, @NonNull SliceCallback callback) {
- try {
- mService.removeSliceListener(uri, mContext.getPackageName(),
- mListenerLookup.remove(new Pair<>(uri, callback)));
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+
}
/**
@@ -216,7 +186,7 @@
public void pinSlice(@NonNull Uri uri, @NonNull List<SliceSpec> specs) {
try {
mService.pinSlice(mContext.getPackageName(), uri,
- specs.toArray(new SliceSpec[specs.size()]));
+ specs.toArray(new SliceSpec[specs.size()]), mToken);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -238,7 +208,7 @@
*/
public void unpinSlice(@NonNull Uri uri) {
try {
- mService.unpinSlice(mContext.getPackageName(), uri);
+ mService.unpinSlice(mContext.getPackageName(), uri, mToken);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/usage/AppStandbyInfo.java b/core/java/android/app/usage/AppStandbyInfo.java
new file mode 100644
index 0000000..51fe0e2
--- /dev/null
+++ b/core/java/android/app/usage/AppStandbyInfo.java
@@ -0,0 +1,64 @@
+/*
+ * 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 android.app.usage;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A pair of {package, bucket} to denote the app standby bucket for a given package.
+ * Used as a vehicle of data across the binder IPC.
+ * @hide
+ */
+public final class AppStandbyInfo implements Parcelable {
+
+ public String mPackageName;
+ public @UsageStatsManager.StandbyBuckets int mStandbyBucket;
+
+ private AppStandbyInfo(Parcel in) {
+ mPackageName = in.readString();
+ mStandbyBucket = in.readInt();
+ }
+
+ public AppStandbyInfo(String packageName, int bucket) {
+ mPackageName = packageName;
+ mStandbyBucket = bucket;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mPackageName);
+ dest.writeInt(mStandbyBucket);
+ }
+
+ public static final Creator<AppStandbyInfo> CREATOR = new Creator<AppStandbyInfo>() {
+ @Override
+ public AppStandbyInfo createFromParcel(Parcel source) {
+ return new AppStandbyInfo(source);
+ }
+
+ @Override
+ public AppStandbyInfo[] newArray(int size) {
+ return new AppStandbyInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index f089c127..e72b84d 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -40,6 +40,6 @@
in String[] annotations, String action);
int getAppStandbyBucket(String packageName, String callingPackage, int userId);
void setAppStandbyBucket(String packageName, int bucket, int userId);
- Map getAppStandbyBuckets(String callingPackage, int userId);
- void setAppStandbyBuckets(in Map appBuckets, int userId);
+ ParceledListSlice getAppStandbyBuckets(String callingPackage, int userId);
+ void setAppStandbyBuckets(in ParceledListSlice appBuckets, int userId);
}
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index cf35902..9a0bb1d 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -28,6 +28,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -388,8 +389,16 @@
@RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)
public Map<String, Integer> getAppStandbyBuckets() {
try {
- return (Map<String, Integer>) mService.getAppStandbyBuckets(
+ final ParceledListSlice<AppStandbyInfo> slice = mService.getAppStandbyBuckets(
mContext.getOpPackageName(), mContext.getUserId());
+ final List<AppStandbyInfo> bucketList = slice.getList();
+ final ArrayMap<String, Integer> bucketMap = new ArrayMap<>();
+ final int n = bucketList.size();
+ for (int i = 0; i < n; i++) {
+ final AppStandbyInfo bucketInfo = bucketList.get(i);
+ bucketMap.put(bucketInfo.mPackageName, bucketInfo.mStandbyBucket);
+ }
+ return bucketMap;
} catch (RemoteException e) {
}
return Collections.EMPTY_MAP;
@@ -404,8 +413,16 @@
@SystemApi
@RequiresPermission(android.Manifest.permission.CHANGE_APP_IDLE_STATE)
public void setAppStandbyBuckets(Map<String, Integer> appBuckets) {
+ if (appBuckets == null) {
+ return;
+ }
+ final List<AppStandbyInfo> bucketInfoList = new ArrayList<>(appBuckets.size());
+ for (Map.Entry<String, Integer> bucketEntry : appBuckets.entrySet()) {
+ bucketInfoList.add(new AppStandbyInfo(bucketEntry.getKey(), bucketEntry.getValue()));
+ }
+ final ParceledListSlice<AppStandbyInfo> slice = new ParceledListSlice<>(bucketInfoList);
try {
- mService.setAppStandbyBuckets(appBuckets, mContext.getUserId());
+ mService.setAppStandbyBuckets(slice, mContext.getUserId());
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index e558b7e..52aefcc 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -2646,6 +2646,10 @@
/**
* <p>Include OIS data in the capture result.</p>
+ * <p>{@link CaptureResult#STATISTICS_OIS_SAMPLES android.statistics.oisSamples} provides OIS sample data in the
+ * output result metadata.</p>
+ *
+ * @see CaptureResult#STATISTICS_OIS_SAMPLES
* @see CaptureRequest#STATISTICS_OIS_DATA_MODE
*/
public static final int STATISTICS_OIS_DATA_MODE_ON = 1;
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index a1a14b9..ada7ebf 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -2784,9 +2784,6 @@
/**
* <p>A control for selecting whether OIS position information is included in output
* result metadata.</p>
- * <p>When set to ON,
- * {@link CaptureResult#STATISTICS_OIS_TIMESTAMPS android.statistics.oisTimestamps}, android.statistics.oisShiftPixelX,
- * and android.statistics.oisShiftPixelY provide OIS data in the output result metadata.</p>
* <p><b>Possible values:</b>
* <ul>
* <li>{@link #STATISTICS_OIS_DATA_MODE_OFF OFF}</li>
@@ -2795,8 +2792,6 @@
* <p><b>Available values for this device:</b><br>
* android.Statistics.info.availableOisDataModes</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
- *
- * @see CaptureResult#STATISTICS_OIS_TIMESTAMPS
* @see #STATISTICS_OIS_DATA_MODE_OFF
* @see #STATISTICS_OIS_DATA_MODE_ON
*/
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index c332d30..8c2f8c1 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -3911,9 +3911,6 @@
/**
* <p>A control for selecting whether OIS position information is included in output
* result metadata.</p>
- * <p>When set to ON,
- * {@link CaptureResult#STATISTICS_OIS_TIMESTAMPS android.statistics.oisTimestamps}, android.statistics.oisShiftPixelX,
- * and android.statistics.oisShiftPixelY provide OIS data in the output result metadata.</p>
* <p><b>Possible values:</b>
* <ul>
* <li>{@link #STATISTICS_OIS_DATA_MODE_OFF OFF}</li>
@@ -3922,8 +3919,6 @@
* <p><b>Available values for this device:</b><br>
* android.Statistics.info.availableOisDataModes</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
- *
- * @see CaptureResult#STATISTICS_OIS_TIMESTAMPS
* @see #STATISTICS_OIS_DATA_MODE_OFF
* @see #STATISTICS_OIS_DATA_MODE_ON
*/
@@ -3939,8 +3934,8 @@
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
* @see CaptureResult#SENSOR_TIMESTAMP
+ * @hide
*/
- @PublicKey
public static final Key<long[]> STATISTICS_OIS_TIMESTAMPS =
new Key<long[]>("android.statistics.oisTimestamps", long[].class);
@@ -3948,16 +3943,14 @@
* <p>An array of shifts of OIS samples, in x direction.</p>
* <p>The array contains the amount of shifts in x direction, in pixels, based on OIS samples.
* A positive value is a shift from left to right in active array coordinate system. For
- * example, if the optical center is (1000, 500) in active array coordinates, an shift of
+ * example, if the optical center is (1000, 500) in active array coordinates, a shift of
* (3, 0) puts the new optical center at (1003, 500).</p>
* <p>The number of shifts must match the number of timestamps in
- * {@link CaptureResult#STATISTICS_OIS_TIMESTAMPS android.statistics.oisTimestamps}.</p>
+ * android.statistics.oisTimestamps.</p>
* <p><b>Units</b>: Pixels in active array.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
- *
- * @see CaptureResult#STATISTICS_OIS_TIMESTAMPS
+ * @hide
*/
- @PublicKey
public static final Key<float[]> STATISTICS_OIS_X_SHIFTS =
new Key<float[]>("android.statistics.oisXShifts", float[].class);
@@ -3965,20 +3958,35 @@
* <p>An array of shifts of OIS samples, in y direction.</p>
* <p>The array contains the amount of shifts in y direction, in pixels, based on OIS samples.
* A positive value is a shift from top to bottom in active array coordinate system. For
- * example, if the optical center is (1000, 500) in active array coordinates, an shift of
+ * example, if the optical center is (1000, 500) in active array coordinates, a shift of
* (0, 5) puts the new optical center at (1000, 505).</p>
* <p>The number of shifts must match the number of timestamps in
- * {@link CaptureResult#STATISTICS_OIS_TIMESTAMPS android.statistics.oisTimestamps}.</p>
+ * android.statistics.oisTimestamps.</p>
* <p><b>Units</b>: Pixels in active array.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
- *
- * @see CaptureResult#STATISTICS_OIS_TIMESTAMPS
+ * @hide
*/
- @PublicKey
public static final Key<float[]> STATISTICS_OIS_Y_SHIFTS =
new Key<float[]>("android.statistics.oisYShifts", float[].class);
/**
+ * <p>An array of OIS samples.</p>
+ * <p>Each OIS sample contains the timestamp and the amount of shifts in x and y direction,
+ * in pixels, of the OIS sample.</p>
+ * <p>A positive value for a shift in x direction is a shift from left to right in active array
+ * coordinate system. For example, if the optical center is (1000, 500) in active array
+ * coordinates, a shift of (3, 0) puts the new optical center at (1003, 500).</p>
+ * <p>A positive value for a shift in y direction is a shift from top to bottom in active array
+ * coordinate system. For example, if the optical center is (1000, 500) in active array
+ * coordinates, a shift of (0, 5) puts the new optical center at (1000, 505).</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ */
+ @PublicKey
+ @SyntheticKey
+ public static final Key<android.hardware.camera2.params.OisSample[]> STATISTICS_OIS_SAMPLES =
+ new Key<android.hardware.camera2.params.OisSample[]>("android.statistics.oisSamples", android.hardware.camera2.params.OisSample[].class);
+
+ /**
* <p>Tonemapping / contrast / gamma curve for the blue
* channel, to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} is
* CONTRAST_CURVE.</p>
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index ebe2fa1..e4b1339 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -22,12 +22,12 @@
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.marshal.Marshaler;
import android.hardware.camera2.marshal.MarshalQueryable;
import android.hardware.camera2.marshal.MarshalRegistry;
+import android.hardware.camera2.marshal.Marshaler;
import android.hardware.camera2.marshal.impl.MarshalQueryableArray;
-import android.hardware.camera2.marshal.impl.MarshalQueryableBoolean;
import android.hardware.camera2.marshal.impl.MarshalQueryableBlackLevelPattern;
+import android.hardware.camera2.marshal.impl.MarshalQueryableBoolean;
import android.hardware.camera2.marshal.impl.MarshalQueryableColorSpaceTransform;
import android.hardware.camera2.marshal.impl.MarshalQueryableEnum;
import android.hardware.camera2.marshal.impl.MarshalQueryableHighSpeedVideoConfiguration;
@@ -48,6 +48,7 @@
import android.hardware.camera2.params.Face;
import android.hardware.camera2.params.HighSpeedVideoConfiguration;
import android.hardware.camera2.params.LensShadingMap;
+import android.hardware.camera2.params.OisSample;
import android.hardware.camera2.params.ReprocessFormatsMap;
import android.hardware.camera2.params.StreamConfiguration;
import android.hardware.camera2.params.StreamConfigurationDuration;
@@ -56,8 +57,8 @@
import android.hardware.camera2.utils.TypeReference;
import android.location.Location;
import android.location.LocationManager;
-import android.os.Parcelable;
import android.os.Parcel;
+import android.os.Parcelable;
import android.os.ServiceSpecificException;
import android.util.Log;
import android.util.Size;
@@ -614,6 +615,15 @@
return (T) metadata.getLensShadingMap();
}
});
+ sGetCommandMap.put(
+ CaptureResult.STATISTICS_OIS_SAMPLES.getNativeKey(),
+ new GetCommand() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+ return (T) metadata.getOisSamples();
+ }
+ });
}
private int[] getAvailableFormats() {
@@ -962,6 +972,50 @@
return tc;
}
+ private OisSample[] getOisSamples() {
+ long[] timestamps = getBase(CaptureResult.STATISTICS_OIS_TIMESTAMPS);
+ float[] xShifts = getBase(CaptureResult.STATISTICS_OIS_X_SHIFTS);
+ float[] yShifts = getBase(CaptureResult.STATISTICS_OIS_Y_SHIFTS);
+
+ if (timestamps == null) {
+ if (xShifts != null) {
+ throw new AssertionError("timestamps is null but xShifts is not");
+ }
+
+ if (yShifts != null) {
+ throw new AssertionError("timestamps is null but yShifts is not");
+ }
+
+ return null;
+ }
+
+ if (xShifts == null) {
+ throw new AssertionError("timestamps is not null but xShifts is");
+ }
+
+ if (yShifts == null) {
+ throw new AssertionError("timestamps is not null but yShifts is");
+ }
+
+ if (xShifts.length != timestamps.length) {
+ throw new AssertionError(String.format(
+ "timestamps has %d entries but xShifts has %d", timestamps.length,
+ xShifts.length));
+ }
+
+ if (yShifts.length != timestamps.length) {
+ throw new AssertionError(String.format(
+ "timestamps has %d entries but yShifts has %d", timestamps.length,
+ yShifts.length));
+ }
+
+ OisSample[] samples = new OisSample[timestamps.length];
+ for (int i = 0; i < timestamps.length; i++) {
+ samples[i] = new OisSample(timestamps[i], xShifts[i], yShifts[i]);
+ }
+ return samples;
+ }
+
private <T> void setBase(CameraCharacteristics.Key<T> key, T value) {
setBase(key.getNativeKey(), value);
}
diff --git a/core/java/android/hardware/camera2/params/OisSample.java b/core/java/android/hardware/camera2/params/OisSample.java
new file mode 100644
index 0000000..7ebaae3
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/OisSample.java
@@ -0,0 +1,137 @@
+/*
+ * 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 android.hardware.camera2.params;
+
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.utils.HashCodeHelpers;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Immutable class to store an
+ * {@link CaptureResult#STATISTICS_OIS_SAMPLES optical image stabilization sample}.
+ */
+public final class OisSample {
+ /**
+ * Create a new {@link OisSample}.
+ *
+ * <p>{@link OisSample} contains the timestamp and the amount of shifts in x and y direction,
+ * in pixels, of the OIS sample.
+ *
+ * <p>A positive value for a shift in x direction is a shift from left to right in active array
+ * coordinate system. For example, if the optical center is {@code (1000, 500)} in active array
+ * coordinates, a shift of {@code (3, 0)} puts the new optical center at {@code (1003, 500)}.
+ * </p>
+ *
+ * <p>A positive value for a shift in y direction is a shift from top to bottom in active array
+ * coordinate system. For example, if the optical center is {@code (1000, 500)} in active array
+ * coordinates, a shift of {@code (0, 5)} puts the new optical center at {@code (1000, 505)}.
+ * </p>
+ *
+ * <p>xShift and yShift must be finite; NaN and infinity is not allowed.</p>
+ *
+ * @param timestamp timestamp of the OIS sample.
+ * @param xShift shift of the OIS sample in x direction.
+ * @param yShift shift of the OIS sample in y direction.
+ *
+ * @throws IllegalArgumentException if xShift or yShift is not finite
+ */
+ public OisSample(final long timestamp, final float xShift, final float yShift) {
+ mTimestampNs = timestamp;
+ mXShift = Preconditions.checkArgumentFinite(xShift, "xShift must be finite");
+ mYShift = Preconditions.checkArgumentFinite(yShift, "yShift must be finite");
+ }
+
+ /**
+ * Get the timestamp in nanoseconds.
+ *
+ *<p>The timestamps are in the same timebase as and comparable to
+ *{@link CaptureResult#SENSOR_TIMESTAMP android.sensor.timestamp}.</p>
+ *
+ * @return a long value (guaranteed to be finite)
+ */
+ public long getTimestamp() {
+ return mTimestampNs;
+ }
+
+ /**
+ * Get the shift in x direction.
+ *
+ * @return a floating point value (guaranteed to be finite)
+ */
+ public float getXshift() {
+ return mXShift;
+ }
+
+ /**
+ * Get the shift in y direction.
+ *
+ * @return a floating point value (guaranteed to be finite)
+ */
+ public float getYshift() {
+ return mYShift;
+ }
+
+ /**
+ * Check if this {@link OisSample} is equal to another {@link OisSample}.
+ *
+ * <p>Two samples are only equal if and only if each of the OIS information is equal.</p>
+ *
+ * @return {@code true} if the objects were equal, {@code false} otherwise
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ } else if (this == obj) {
+ return true;
+ } else if (obj instanceof OisSample) {
+ final OisSample other = (OisSample) obj;
+ return mTimestampNs == other.mTimestampNs
+ && mXShift == other.mXShift
+ && mYShift == other.mYShift;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ int timestampHash = HashCodeHelpers.hashCode(mTimestampNs);
+ return HashCodeHelpers.hashCode(mXShift, mYShift, timestampHash);
+ }
+
+ /**
+ * Return the OisSample as a string representation.
+ *
+ * <p> {@code "OisSample{timestamp:%l, shift_x:%f, shift_y:%f}"} represents the OIS sample's
+ * timestamp, shift in x direction, and shift in y direction.</p>
+ *
+ * @return string representation of {@link OisSample}
+ */
+ @Override
+ public String toString() {
+ return String.format("OisSample{timestamp:%d, shift_x:%f, shift_y:%f}", mTimestampNs,
+ mXShift, mYShift);
+ }
+
+ private final long mTimestampNs;
+ private final float mXShift;
+ private final float mYShift;
+}
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 90e3ffd..381cfb6 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -39,9 +39,6 @@
*/
INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage);
- /** Return network layer usage total for traffic that matches template. */
- long getNetworkTotalBytes(in NetworkTemplate template, long start, long end);
-
/** Return data layer snapshot of UID network usage. */
NetworkStats getDataLayerSnapshotForUid(int uid);
/** Return set of any ifaces associated with mobile networks since boot. */
@@ -50,17 +47,11 @@
/** Increment data layer count of operations performed for UID and tag. */
void incrementOperationCount(int uid, int tag, int operationCount);
- /** Mark given UID as being in foreground for stats purposes. */
- void setUidForeground(int uid, boolean uidForeground);
-
/** Force update of ifaces. */
void forceUpdateIfaces(in Network[] defaultNetworks);
/** Force update of statistics. */
void forceUpdate();
- /** Advise persistance threshold; may be overridden internally. */
- void advisePersistThreshold(long thresholdBytes);
-
/** Registers a callback on data usage. */
DataUsageRequest registerUsageCallback(String callingPackage,
in DataUsageRequest request, in Messenger messenger, in IBinder binder);
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 01b2b39..16fb858 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -234,7 +234,7 @@
public NetworkStats(long elapsedRealtime, int initialSize) {
this.elapsedRealtime = elapsedRealtime;
this.size = 0;
- if (initialSize >= 0) {
+ if (initialSize > 0) {
this.capacity = initialSize;
this.iface = new String[initialSize];
this.uid = new int[initialSize];
@@ -250,19 +250,7 @@
this.operations = new long[initialSize];
} else {
// Special case for use by NetworkStatsFactory to start out *really* empty.
- this.capacity = 0;
- this.iface = EmptyArray.STRING;
- this.uid = EmptyArray.INT;
- this.set = EmptyArray.INT;
- this.tag = EmptyArray.INT;
- this.metered = EmptyArray.INT;
- this.roaming = EmptyArray.INT;
- this.defaultNetwork = EmptyArray.INT;
- this.rxBytes = EmptyArray.LONG;
- this.rxPackets = EmptyArray.LONG;
- this.txBytes = EmptyArray.LONG;
- this.txPackets = EmptyArray.LONG;
- this.operations = EmptyArray.LONG;
+ clear();
}
}
@@ -314,6 +302,25 @@
return clone;
}
+ /**
+ * Clear all data stored in this object.
+ */
+ public void clear() {
+ this.capacity = 0;
+ this.iface = EmptyArray.STRING;
+ this.uid = EmptyArray.INT;
+ this.set = EmptyArray.INT;
+ this.tag = EmptyArray.INT;
+ this.metered = EmptyArray.INT;
+ this.roaming = EmptyArray.INT;
+ this.defaultNetwork = EmptyArray.INT;
+ this.rxBytes = EmptyArray.LONG;
+ this.rxPackets = EmptyArray.LONG;
+ this.txBytes = EmptyArray.LONG;
+ this.txPackets = EmptyArray.LONG;
+ this.operations = EmptyArray.LONG;
+ }
+
@VisibleForTesting
public NetworkStats addIfaceValues(
String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) {
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index 433f941..a13ad65 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -39,6 +39,8 @@
import com.android.internal.util.IndentingPrintWriter;
+import libcore.util.EmptyArray;
+
import java.io.CharArrayWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -459,6 +461,21 @@
}
/**
+ * Clear all data stored in this object.
+ */
+ public void clear() {
+ bucketStart = EmptyArray.LONG;
+ if (activeTime != null) activeTime = EmptyArray.LONG;
+ if (rxBytes != null) rxBytes = EmptyArray.LONG;
+ if (rxPackets != null) rxPackets = EmptyArray.LONG;
+ if (txBytes != null) txBytes = EmptyArray.LONG;
+ if (txPackets != null) txPackets = EmptyArray.LONG;
+ if (operations != null) operations = EmptyArray.LONG;
+ bucketCount = 0;
+ totalBytes = 0;
+ }
+
+ /**
* Remove buckets older than requested cutoff.
*/
@Deprecated
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 8efd39a..74233fd 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -23,7 +23,6 @@
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
import static android.net.ConnectivityManager.TYPE_WIMAX;
-import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
@@ -34,11 +33,6 @@
import static android.net.NetworkStats.ROAMING_NO;
import static android.net.NetworkStats.ROAMING_YES;
import static android.net.wifi.WifiInfo.removeDoubleQuotes;
-import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G;
-import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G;
-import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G;
-import static android.telephony.TelephonyManager.NETWORK_CLASS_UNKNOWN;
-import static android.telephony.TelephonyManager.getNetworkClass;
import android.os.Parcel;
import android.os.Parcelable;
@@ -55,8 +49,8 @@
import java.util.Objects;
/**
- * Template definition used to generically match {@link NetworkIdentity},
- * usually when collecting statistics.
+ * Predicate used to match {@link NetworkIdentity}, usually when collecting
+ * statistics. (It should probably have been named {@code NetworkPredicate}.)
*
* @hide
*/
@@ -68,13 +62,7 @@
*/
private static final int BACKUP_VERSION = 1;
- public static final int MATCH_MOBILE_ALL = 1;
- /** @deprecated don't use this any more */
- @Deprecated
- public static final int MATCH_MOBILE_3G_LOWER = 2;
- /** @deprecated don't use this any more */
- @Deprecated
- public static final int MATCH_MOBILE_4G = 3;
+ public static final int MATCH_MOBILE = 1;
public static final int MATCH_WIFI = 4;
public static final int MATCH_ETHERNET = 5;
public static final int MATCH_MOBILE_WILDCARD = 6;
@@ -84,9 +72,7 @@
private static boolean isKnownMatchRule(final int rule) {
switch (rule) {
- case MATCH_MOBILE_ALL:
- case MATCH_MOBILE_3G_LOWER:
- case MATCH_MOBILE_4G:
+ case MATCH_MOBILE:
case MATCH_WIFI:
case MATCH_ETHERNET:
case MATCH_MOBILE_WILDCARD:
@@ -111,25 +97,7 @@
* the given IMSI.
*/
public static NetworkTemplate buildTemplateMobileAll(String subscriberId) {
- return new NetworkTemplate(MATCH_MOBILE_ALL, subscriberId, null);
- }
-
- /**
- * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
- * the given IMSI that roughly meet a "3G" definition, or lower.
- */
- @Deprecated
- public static NetworkTemplate buildTemplateMobile3gLower(String subscriberId) {
- return new NetworkTemplate(MATCH_MOBILE_3G_LOWER, subscriberId, null);
- }
-
- /**
- * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
- * the given IMSI that roughly meet a "4G" definition.
- */
- @Deprecated
- public static NetworkTemplate buildTemplateMobile4g(String subscriberId) {
- return new NetworkTemplate(MATCH_MOBILE_4G, subscriberId, null);
+ return new NetworkTemplate(MATCH_MOBILE, subscriberId, null);
}
/**
@@ -307,9 +275,7 @@
public boolean isMatchRuleMobile() {
switch (mMatchRule) {
- case MATCH_MOBILE_3G_LOWER:
- case MATCH_MOBILE_4G:
- case MATCH_MOBILE_ALL:
+ case MATCH_MOBILE:
case MATCH_MOBILE_WILDCARD:
return true;
default:
@@ -348,12 +314,8 @@
if (!matchesDefaultNetwork(ident)) return false;
switch (mMatchRule) {
- case MATCH_MOBILE_ALL:
+ case MATCH_MOBILE:
return matchesMobile(ident);
- case MATCH_MOBILE_3G_LOWER:
- return matchesMobile3gLower(ident);
- case MATCH_MOBILE_4G:
- return matchesMobile4g(ident);
case MATCH_WIFI:
return matchesWifi(ident);
case MATCH_ETHERNET:
@@ -410,43 +372,6 @@
}
/**
- * Check if mobile network classified 3G or lower with matching IMSI.
- */
- @Deprecated
- private boolean matchesMobile3gLower(NetworkIdentity ident) {
- ensureSubtypeAvailable();
- if (ident.mType == TYPE_WIMAX) {
- return false;
- } else if (matchesMobile(ident)) {
- switch (getNetworkClass(ident.mSubType)) {
- case NETWORK_CLASS_UNKNOWN:
- case NETWORK_CLASS_2_G:
- case NETWORK_CLASS_3_G:
- return true;
- }
- }
- return false;
- }
-
- /**
- * Check if mobile network classified 4G with matching IMSI.
- */
- @Deprecated
- private boolean matchesMobile4g(NetworkIdentity ident) {
- ensureSubtypeAvailable();
- if (ident.mType == TYPE_WIMAX) {
- // TODO: consider matching against WiMAX subscriber identity
- return true;
- } else if (matchesMobile(ident)) {
- switch (getNetworkClass(ident.mSubType)) {
- case NETWORK_CLASS_4_G:
- return true;
- }
- }
- return false;
- }
-
- /**
* Check if matches Wi-Fi network template.
*/
private boolean matchesWifi(NetworkIdentity ident) {
@@ -506,12 +431,8 @@
private static String getMatchRuleName(int matchRule) {
switch (matchRule) {
- case MATCH_MOBILE_3G_LOWER:
- return "MOBILE_3G_LOWER";
- case MATCH_MOBILE_4G:
- return "MOBILE_4G";
- case MATCH_MOBILE_ALL:
- return "MOBILE_ALL";
+ case MATCH_MOBILE:
+ return "MOBILE";
case MATCH_WIFI:
return "WIFI";
case MATCH_ETHERNET:
@@ -529,13 +450,6 @@
}
}
- private static void ensureSubtypeAvailable() {
- if (COMBINE_SUBTYPE_ENABLED) {
- throw new IllegalArgumentException(
- "Unable to enforce 3G_LOWER template on combined data.");
- }
- }
-
/**
* Examine the given template and normalize if it refers to a "merged"
* mobile subscriber. We pick the "lowest" merged subscriber as the primary
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 68490ed..1ae0bc4 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8827,6 +8827,14 @@
*/
public static final String NETWORK_SCORER_APP = "network_scorer_app";
+ /**
+ * Whether night display forced auto mode is available.
+ * 0 = unavailable, 1 = available.
+ * @hide
+ */
+ public static final String NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE =
+ "night_display_forced_auto_mode_available";
+
/**
* If the NITZ_UPDATE_DIFF time is exceeded then an automatic adjustment
* to SystemClock will be allowed even if NITZ_UPDATE_SPACING has not been
@@ -10314,6 +10322,16 @@
public static final String SYS_VDSO = "sys_vdso";
/**
+ * UidCpuPower global setting. This links the sys.uidcpupower system property.
+ * The following values are supported:
+ * 0 -> /proc/uid_cpupower/* are disabled
+ * 1 -> /proc/uid_cpupower/* are enabled
+ * Any other value defaults to enabled.
+ * @hide
+ */
+ public static final String SYS_UIDCPUPOWER = "sys_uidcpupower";
+
+ /**
* An integer to reduce the FPS by this factor. Only for experiments. Need to reboot the
* device for this setting to take full effect.
*
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index f4dcce1..1d13335 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -75,7 +75,6 @@
public static final int KM_TAG_ALLOW_WHILE_ON_BODY = KM_BOOL | 506;
public static final int KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED = KM_BOOL | 507;
public static final int KM_TAG_TRUSTED_CONFIRMATION_REQUIRED = KM_BOOL | 508;
- public static final int KM_TAG_UNLOCKED_DEVICE_REQUIRED = KM_BOOL | 509;
public static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600;
public static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601;
@@ -217,7 +216,6 @@
public static final int KM_ERROR_MISSING_MIN_MAC_LENGTH = -58;
public static final int KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH = -59;
public static final int KM_ERROR_CANNOT_ATTEST_IDS = -66;
- public static final int KM_ERROR_DEVICE_LOCKED = -72;
public static final int KM_ERROR_UNIMPLEMENTED = -100;
public static final int KM_ERROR_VERSION_MISMATCH = -101;
public static final int KM_ERROR_UNKNOWN_ERROR = -1000;
@@ -264,7 +262,6 @@
sErrorCodeToString.put(KM_ERROR_INVALID_MAC_LENGTH,
"Invalid MAC or authentication tag length");
sErrorCodeToString.put(KM_ERROR_CANNOT_ATTEST_IDS, "Unable to attest device ids");
- sErrorCodeToString.put(KM_ERROR_DEVICE_LOCKED, "Device locked");
sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented");
sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error");
}
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index d57782c..fcca5af 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -552,6 +552,15 @@
}
}
+ /**
+ * Returns a new {@link RecoverySession}.
+ *
+ * <p>A recovery session is required to restore keys from a remote store.
+ */
+ public RecoverySession createRecoverySession() {
+ return RecoverySession.newInstance(this);
+ }
+
InternalRecoveryServiceException wrapUnexpectedServiceSpecificException(
ServiceSpecificException e) {
if (e.errorCode == ERROR_SERVICE_INTERNAL_ERROR) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3c76242..f61b652 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8144,7 +8144,12 @@
}
/**
- * Gets the unique identifier of this view in the screen, for autofill purposes.
+ * Gets the unique, logical identifier of this view in the activity, for autofill purposes.
+ *
+ * <p>The autofill id is created on demand, unless it is explicitly set by
+ * {@link #setAutofillId(AutofillId)}.
+ *
+ * <p>See {@link #setAutofillId(AutofillId)} for more info.
*
* @return The View's autofill id.
*/
@@ -8158,6 +8163,61 @@
}
/**
+ * Sets the unique, logical identifier of this view in the activity, for autofill purposes.
+ *
+ * <p>The autofill id is created on demand, and this method should only be called when a view is
+ * reused after {@link #dispatchProvideAutofillStructure(ViewStructure, int)} is called, as
+ * that method creates a snapshot of the view that is passed along to the autofill service.
+ *
+ * <p>This method is typically used when view subtrees are recycled to represent different
+ * content* —in this case, the autofill id can be saved before the view content is swapped
+ * out, and restored later when it's swapped back in. For example:
+ *
+ * <pre>
+ * EditText reusableView = ...;
+ * ViewGroup parentView = ...;
+ * AutofillManager afm = ...;
+ *
+ * // Swap out the view and change its contents
+ * AutofillId oldId = reusableView.getAutofillId();
+ * CharSequence oldText = reusableView.getText();
+ * parentView.removeView(reusableView);
+ * AutofillId newId = afm.getNextAutofillId();
+ * reusableView.setText("New I am");
+ * reusableView.setAutofillId(newId);
+ * parentView.addView(reusableView);
+ *
+ * // Later, swap the old content back in
+ * parentView.removeView(reusableView);
+ * reusableView.setAutofillId(oldId);
+ * reusableView.setText(oldText);
+ * parentView.addView(reusableView);
+ * </pre>
+ *
+ * @param id an autofill ID that is unique in the {@link android.app.Activity} hosting the view,
+ * or {@code null} to reset it. Usually it's an id previously allocated to another view (and
+ * obtained through {@link #getAutofillId()}), or a new value obtained through
+ * {@link AutofillManager#getNextAutofillId()}.
+ *
+ * @throws IllegalStateException if the view is already {@link #isAttachedToWindow() attached to
+ * a window}.
+ *
+ * @throws IllegalArgumentException if the id is an autofill id associated with a virtual view.
+ */
+ public void setAutofillId(@Nullable AutofillId id) {
+ if (android.view.autofill.Helper.sVerbose) {
+ Log.v(VIEW_LOG_TAG, "setAutofill(): from " + mAutofillId + " to " + id);
+ }
+ if (isAttachedToWindow()) {
+ throw new IllegalStateException("Cannot set autofill id when view is attached");
+ }
+ if (id.isVirtual()) {
+ throw new IllegalStateException("Cannot set autofill id assigned to virtual views");
+ }
+ mAutofillId = id;
+ }
+
+ /**
* Describes the autofill type of this view, so an
* {@link android.service.autofill.AutofillService} can create the proper {@link AutofillValue}
* when autofilling the view.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 810864e..01d9265 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3925,6 +3925,7 @@
private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
+ private final static int MSG_DISPATCH_KEY_FROM_AUTOFILL = 12;
private final static int MSG_CHECK_FOCUS = 13;
private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
private final static int MSG_DISPATCH_DRAG_EVENT = 15;
@@ -3966,6 +3967,8 @@
return "MSG_DISPATCH_GET_NEW_SURFACE";
case MSG_DISPATCH_KEY_FROM_IME:
return "MSG_DISPATCH_KEY_FROM_IME";
+ case MSG_DISPATCH_KEY_FROM_AUTOFILL:
+ return "MSG_DISPATCH_KEY_FROM_AUTOFILL";
case MSG_CHECK_FOCUS:
return "MSG_CHECK_FOCUS";
case MSG_CLOSE_SYSTEM_DIALOGS:
@@ -4143,6 +4146,15 @@
}
enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
} break;
+ case MSG_DISPATCH_KEY_FROM_AUTOFILL: {
+ if (LOCAL_LOGV) {
+ Log.v(TAG, "Dispatching key " + msg.obj + " from Autofill to " + mView);
+ }
+ KeyEvent event = (KeyEvent) msg.obj;
+ // send InputEvent to pre IME, set FLAG_FROM_AUTOFILL so the InputEvent
+ // wont be dropped as app window is not focus.
+ enqueueInputEvent(event, null, QueuedInputEvent.FLAG_FROM_AUTOFILL, true);
+ } break;
case MSG_CHECK_FOCUS: {
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) {
@@ -4433,7 +4445,8 @@
Slog.w(mTag, "Dropping event due to root view being removed: " + q.mEvent);
return true;
} else if ((!mAttachInfo.mHasWindowFocus
- && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) || mStopped
+ && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
+ && (q.mFlags & QueuedInputEvent.FLAG_FROM_AUTOFILL) == 0) || mStopped
|| (mIsAmbientMode && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON))
|| (mPausedForTransition && !isBack(q.mEvent))) {
// This is a focus event and the window doesn't currently have input focus or
@@ -6805,6 +6818,7 @@
public static final int FLAG_FINISHED_HANDLED = 1 << 3;
public static final int FLAG_RESYNTHESIZED = 1 << 4;
public static final int FLAG_UNHANDLED = 1 << 5;
+ public static final int FLAG_FROM_AUTOFILL = 1 << 6;
public QueuedInputEvent mNext;
@@ -7262,6 +7276,12 @@
mHandler.sendMessage(msg);
}
+ public void dispatchKeyFromAutofill(KeyEvent event) {
+ Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_AUTOFILL, event);
+ msg.setAsynchronous(true);
+ mHandler.sendMessage(msg);
+ }
+
/**
* Reinject unhandled {@link InputEvent}s in order to synthesize fallbacks events.
*
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 7792fa6..a4261eb 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -46,6 +46,7 @@
import android.util.Log;
import android.util.SparseArray;
import android.view.Choreographer;
+import android.view.KeyEvent;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -411,6 +412,13 @@
@Nullable Rect virtualBounds, IAutofillWindowPresenter presenter);
/**
+ * Dispatch unhandled keyevent from Autofill window
+ * @param anchor The real view the UI needs to anchor to.
+ * @param keyEvent Unhandled KeyEvent from autofill window.
+ */
+ void autofillClientDispatchUnhandledKey(@NonNull View anchor, @NonNull KeyEvent keyEvent);
+
+ /**
* Request hiding the autofill UI.
*
* @return Whether the UI was hidden.
@@ -490,7 +498,17 @@
/**
* @return Whether compatibility mode is enabled.
*/
- boolean autofillIsCompatibilityModeEnabled();
+ boolean autofillClientIsCompatibilityModeEnabled();
+
+ /**
+ * Gets the next unique autofill ID.
+ *
+ * <p>Typically used to manage views whose content is recycled - see
+ * {@link View#setAutofillId(AutofillId)} for more info.
+ *
+ * @return An ID that is unique in the activity.
+ */
+ @Nullable AutofillId autofillClientGetNextAutofillId();
}
/**
@@ -773,7 +791,7 @@
/** Returns AutofillCallback if need fire EVENT_INPUT_UNAVAILABLE */
@GuardedBy("mLock")
private AutofillCallback notifyViewEnteredLocked(@NonNull View view, int flags) {
- final AutofillId id = getAutofillId(view);
+ final AutofillId id = view.getAutofillId();
if (shouldIgnoreViewEnteredLocked(id, flags)) return null;
AutofillCallback callback = null;
@@ -823,7 +841,7 @@
if (mEnabled && isActiveLocked()) {
// dont notify exited when Activity is already in background
if (!isClientDisablingEnterExitEvent()) {
- final AutofillId id = getAutofillId(view);
+ final AutofillId id = view.getAutofillId();
// Update focus on existing session.
updateSessionLocked(id, null, null, ACTION_VIEW_EXITED, 0);
@@ -866,6 +884,7 @@
if (mEnabled && isActiveLocked()) {
final AutofillId id = virtual ? getAutofillId(view, virtualId)
: view.getAutofillId();
+ if (sVerbose) Log.v(TAG, "visibility changed for " + id + ": " + isVisible);
if (!isVisible && mFillableIds != null) {
if (mFillableIds.contains(id)) {
if (sDebug) Log.d(TAG, "Hidding UI when view " + id + " became invisible");
@@ -874,6 +893,8 @@
}
if (mTrackedViews != null) {
mTrackedViews.notifyViewVisibilityChangedLocked(id, isVisible);
+ } else if (sVerbose) {
+ Log.v(TAG, "Ignoring visibility change on " + id + ": no tracked views");
}
}
}
@@ -1004,7 +1025,7 @@
if (mLastAutofilledData == null) {
view.setAutofilled(false);
} else {
- id = getAutofillId(view);
+ id = view.getAutofillId();
if (mLastAutofilledData.containsKey(id)) {
value = view.getAutofillValue();
valueWasRead = true;
@@ -1029,7 +1050,7 @@
}
if (id == null) {
- id = getAutofillId(view);
+ id = view.getAutofillId();
}
if (!valueWasRead) {
@@ -1429,8 +1450,27 @@
}
}
- private static AutofillId getAutofillId(View view) {
- return new AutofillId(view.getAutofillViewId());
+ /**
+ * Gets the next unique autofill ID for the activity context.
+ *
+ * <p>Typically used to manage views whose content is recycled - see
+ * {@link View#setAutofillId(AutofillId)} for more info.
+ *
+ * @return An ID that is unique in the activity, or {@code null} if autofill is not supported in
+ * the {@link Context} associated with this {@link AutofillManager}.
+ */
+ @Nullable
+ public AutofillId getNextAutofillId() {
+ final AutofillClient client = getClient();
+ if (client == null) return null;
+
+ final AutofillId id = client.autofillClientGetNextAutofillId();
+
+ if (id == null && sDebug) {
+ Log.d(TAG, "getNextAutofillId(): client " + client + " returned null");
+ }
+
+ return id;
}
private static AutofillId getAutofillId(View parent, int virtualId) {
@@ -1668,6 +1708,24 @@
}
}
+ private void dispatchUnhandledKey(int sessionId, AutofillId id, KeyEvent keyEvent) {
+ final View anchor = findView(id);
+ if (anchor == null) {
+ return;
+ }
+
+ AutofillCallback callback = null;
+ synchronized (mLock) {
+ if (mSessionId == sessionId) {
+ AutofillClient client = getClient();
+
+ if (client != null) {
+ client.autofillClientDispatchUnhandledKey(anchor, keyEvent);
+ }
+ }
+ }
+ }
+
/** @hide */
public static final int SET_STATE_FLAG_ENABLED = 0x01;
/** @hide */
@@ -1713,7 +1771,7 @@
if (mLastAutofilledData == null) {
mLastAutofilledData = new ParcelableMap(1);
}
- mLastAutofilledData.put(getAutofillId(view), targetValue);
+ mLastAutofilledData.put(view.getAutofillId(), targetValue);
}
view.setAutofilled(true);
}
@@ -2610,6 +2668,14 @@
}
@Override
+ public void dispatchUnhandledKey(int sessionId, AutofillId id, KeyEvent fullScreen) {
+ final AutofillManager afm = mAfm.get();
+ if (afm != null) {
+ afm.post(() -> afm.dispatchUnhandledKey(sessionId, id, fullScreen));
+ }
+ }
+
+ @Override
public void startIntentSender(IntentSender intentSender, Intent intent) {
final AutofillManager afm = mAfm.get();
if (afm != null) {
diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
index 254c8a5..0ff7a0b 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -25,6 +25,7 @@
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
import android.view.autofill.IAutofillWindowPresenter;
+import android.view.KeyEvent;
/**
* Object running in the application process and responsible for autofilling it.
@@ -74,6 +75,13 @@
void notifyNoFillUi(int sessionId, in AutofillId id, int sessionFinishedState);
/**
+ * Dispatches unhandled keyevent from autofill ui. Autofill ui handles DPAD and ENTER events,
+ * other unhandled keyevents are dispatched to app's window to filter autofill result.
+ * Note this method is not called when autofill ui is in fullscreen mode (TV only).
+ */
+ void dispatchUnhandledKey(int sessionId, in AutofillId id, in KeyEvent keyEvent);
+
+ /**
* Starts the provided intent sender.
*/
void startIntentSender(in IntentSender intentSender, in Intent intent);
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 6427965..eb2af60 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -89,6 +89,9 @@
NONEXISTENT_PREVIOUS_CONFIG_VALUE, NONEXISTENT_PREVIOUS_CONFIG_VALUE);
// Rectangle defining the view surface area we pixel copy content from.
private final Rect mPixelCopyRequestRect = new Rect();
+ // Lock to synchronize between the UI thread and the thread that handles pixel copy results.
+ // Only sync mWindow writes from UI thread with mWindow reads from sPixelCopyHandlerThread.
+ private final Object mLock = new Object();
/**
* Initializes a magnifier.
@@ -170,9 +173,12 @@
if (xPosInView != mPrevPosInView.x || yPosInView != mPrevPosInView.y) {
if (mWindow == null) {
- mWindow = new InternalPopupWindow(mView.getContext(), mView.getDisplay(),
- getValidViewSurface(), mWindowWidth, mWindowHeight, mWindowElevation,
- Handler.getMain() /* draw the magnifier on the UI thread */, mCallback);
+ synchronized (mLock) {
+ mWindow = new InternalPopupWindow(mView.getContext(), mView.getDisplay(),
+ getValidViewSurface(), mWindowWidth, mWindowHeight, mWindowElevation,
+ Handler.getMain() /* draw the magnifier on the UI thread */, mLock,
+ mCallback);
+ }
}
performPixelCopy(startX, startY, true /* update window position */);
mPrevPosInView.x = xPosInView;
@@ -200,8 +206,10 @@
*/
public void dismiss() {
if (mWindow != null) {
- mWindow.destroy();
- mWindow = null;
+ synchronized (mLock) {
+ mWindow.destroy();
+ mWindow = null;
+ }
}
}
@@ -281,19 +289,22 @@
clampedStartYInSurface + mBitmapHeight);
final int windowCoordsX = mWindowCoords.x;
final int windowCoordsY = mWindowCoords.y;
+ final InternalPopupWindow currentWindowInstance = mWindow;
final Bitmap bitmap =
Bitmap.createBitmap(mBitmapWidth, mBitmapHeight, Bitmap.Config.ARGB_8888);
PixelCopy.request(surface, mPixelCopyRequestRect, bitmap,
result -> {
- synchronized (mWindow.mLock) {
- if (mWindow != null) {
- if (updateWindowPosition) {
- // TODO: pull the position update outside #performPixelCopy
- mWindow.setContentPositionForNextDraw(windowCoordsX, windowCoordsY);
- }
- mWindow.updateContent(bitmap);
+ synchronized (mLock) {
+ if (mWindow != currentWindowInstance) {
+ // The magnifier was dismissed (and maybe shown again) in the meantime.
+ return;
}
+ if (updateWindowPosition) {
+ // TODO: pull the position update outside #performPixelCopy
+ mWindow.setContentPositionForNextDraw(windowCoordsX, windowCoordsY);
+ }
+ mWindow.updateContent(bitmap);
}
},
sPixelCopyHandlerThread.getThreadHandler());
@@ -337,7 +348,7 @@
// Members below describe the state of the magnifier. Reads/writes to them
// have to be synchronized between the UI thread and the thread that handles
// the pixel copy results. This is the purpose of mLock.
- private final Object mLock = new Object();
+ private final Object mLock;
// Whether a magnifier frame draw is currently pending in the UI thread queue.
private boolean mFrameDrawScheduled;
// The content bitmap.
@@ -353,8 +364,9 @@
InternalPopupWindow(final Context context, final Display display,
final Surface parentSurface,
final int width, final int height, final float elevation,
- final Handler handler, final Callback callback) {
+ final Handler handler, final Object lock, final Callback callback) {
mDisplay = display;
+ mLock = lock;
mCallback = callback;
mContentWidth = width;
diff --git a/core/java/android/widget/VideoView2.java b/core/java/android/widget/VideoView2.java
index 69c1fb6..340be46 100644
--- a/core/java/android/widget/VideoView2.java
+++ b/core/java/android/widget/VideoView2.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioManager;
+import android.media.MediaMetadata2;
import android.media.MediaPlayerInterface;
import android.media.session.MediaController;
import android.media.session.MediaSession;
@@ -168,6 +169,27 @@
return mProvider.getMediaControlView2_impl();
}
+ /**
+ * Sets MediaMetadata2 instance. It will replace the previously assigned MediaMetadata2 instance
+ * if any.
+ *
+ * @param metadata a MediaMetadata2 instance.
+ * @hide
+ */
+ public void setMediaMetadata(MediaMetadata2 metadata) {
+ mProvider.setMediaMetadata_impl(metadata);
+ }
+
+ /**
+ * Returns MediaMetadata2 instance which is retrieved from MediaPlayer2 inside VideoView2 by
+ * default or by {@link #setMediaMetadata} method.
+ * @hide
+ */
+ public MediaMetadata2 getMediaMetadata() {
+ // TODO: add to Javadoc whether this value can be null or not when integrating with
+ // MediaSession2.
+ return mProvider.getMediaMetadata_impl();
+ }
/**
* Returns MediaController instance which is connected with MediaSession that VideoView2 is
diff --git a/core/java/com/android/internal/app/ColorDisplayController.java b/core/java/com/android/internal/app/ColorDisplayController.java
index b8682a8..278d31a 100644
--- a/core/java/com/android/internal/app/ColorDisplayController.java
+++ b/core/java/com/android/internal/app/ColorDisplayController.java
@@ -22,6 +22,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
+import android.metrics.LogMaker;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
@@ -31,6 +32,8 @@
import android.util.Slog;
import com.android.internal.R;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -109,10 +112,10 @@
private final Context mContext;
private final int mUserId;
-
private final ContentObserver mContentObserver;
private Callback mCallback;
+ private MetricsLogger mMetricsLogger;
public ColorDisplayController(@NonNull Context context) {
this(context, ActivityManager.getCurrentUser());
@@ -209,6 +212,15 @@
}
/**
+ * Returns the current auto mode value, without validation, or {@code 1} if the auto mode has
+ * never been set.
+ */
+ public int getAutoModeRaw() {
+ return Secure.getIntForUser(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_AUTO_MODE,
+ -1, mUserId);
+ }
+
+ /**
* Sets the current auto mode value controlling when Night display will be automatically
* activated. One of {@link #AUTO_MODE_DISABLED}, {@link #AUTO_MODE_CUSTOM}, or
* {@link #AUTO_MODE_TWILIGHT}.
@@ -228,7 +240,12 @@
Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
null,
mUserId);
+ getMetricsLogger().write(new LogMaker(
+ MetricsEvent.ACTION_NIGHT_DISPLAY_AUTO_MODE_CHANGED)
+ .setType(MetricsEvent.TYPE_ACTION)
+ .setSubtype(autoMode));
}
+
return Secure.putIntForUser(mContext.getContentResolver(),
Secure.NIGHT_DISPLAY_AUTO_MODE, autoMode, mUserId);
}
@@ -263,6 +280,10 @@
if (startTime == null) {
throw new IllegalArgumentException("startTime cannot be null");
}
+ getMetricsLogger().write(new LogMaker(
+ MetricsEvent.ACTION_NIGHT_DISPLAY_AUTO_MODE_CUSTOM_TIME_CHANGED)
+ .setType(MetricsEvent.TYPE_ACTION)
+ .setSubtype(0));
return Secure.putIntForUser(mContext.getContentResolver(),
Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, startTime.toSecondOfDay() * 1000, mUserId);
}
@@ -297,6 +318,10 @@
if (endTime == null) {
throw new IllegalArgumentException("endTime cannot be null");
}
+ getMetricsLogger().write(new LogMaker(
+ MetricsEvent.ACTION_NIGHT_DISPLAY_AUTO_MODE_CUSTOM_TIME_CHANGED)
+ .setType(MetricsEvent.TYPE_ACTION)
+ .setSubtype(1));
return Secure.putIntForUser(mContext.getContentResolver(),
Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, endTime.toSecondOfDay() * 1000, mUserId);
}
@@ -450,6 +475,13 @@
}
}
+ private MetricsLogger getMetricsLogger() {
+ if (mMetricsLogger == null) {
+ mMetricsLogger = new MetricsLogger();
+ }
+ return mMetricsLogger;
+ }
+
/**
* Returns {@code true} if Night display is supported by the device.
*/
diff --git a/core/java/com/android/internal/util/IndentingPrintWriter.java b/core/java/com/android/internal/util/IndentingPrintWriter.java
index 696667c..e453866 100644
--- a/core/java/com/android/internal/util/IndentingPrintWriter.java
+++ b/core/java/com/android/internal/util/IndentingPrintWriter.java
@@ -57,26 +57,46 @@
mWrapLength = wrapLength;
}
- public void increaseIndent() {
+ public IndentingPrintWriter setIndent(String indent) {
+ mIndentBuilder.setLength(0);
+ mIndentBuilder.append(indent);
+ mCurrentIndent = null;
+ return this;
+ }
+
+ public IndentingPrintWriter setIndent(int indent) {
+ mIndentBuilder.setLength(0);
+ for (int i = 0; i < indent; i++) {
+ increaseIndent();
+ }
+ return this;
+ }
+
+ public IndentingPrintWriter increaseIndent() {
mIndentBuilder.append(mSingleIndent);
mCurrentIndent = null;
+ return this;
}
- public void decreaseIndent() {
+ public IndentingPrintWriter decreaseIndent() {
mIndentBuilder.delete(0, mSingleIndent.length());
mCurrentIndent = null;
+ return this;
}
- public void printPair(String key, Object value) {
+ public IndentingPrintWriter printPair(String key, Object value) {
print(key + "=" + String.valueOf(value) + " ");
+ return this;
}
- public void printPair(String key, Object[] value) {
+ public IndentingPrintWriter printPair(String key, Object[] value) {
print(key + "=" + Arrays.toString(value) + " ");
+ return this;
}
- public void printHexPair(String key, int value) {
+ public IndentingPrintWriter printHexPair(String key, int value) {
print(key + "=0x" + Integer.toHexString(value) + " ");
+ return this;
}
@Override
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 304e63f..2d31c5a 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -201,6 +201,12 @@
// be indices into this array, rather than the raw constants used by
// AppIdleHistory.
repeated int32 standby_beats = 20;
+ // The fraction of a job's running window that must pass before we
+ // consider running it when the network is congested.
+ optional double conn_congestion_delay_frac = 21;
+ // The fraction of a prefetch job's running window that must pass before
+ // we consider matching it against a metered network.
+ optional double conn_prefetch_relax_frac = 22;
}
message StateControllerProto {
diff --git a/core/res/res/drawable-watch/sym_def_app_icon.xml b/core/res/res/drawable-watch/sym_def_app_icon.xml
new file mode 100644
index 0000000..2720bfa
--- /dev/null
+++ b/core/res/res/drawable-watch/sym_def_app_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@color/accent_device_default_dark" />
+ <foreground android:drawable="@mipmap/sym_def_app_icon_foreground" />
+</adaptive-icon>
diff --git a/core/res/res/layout/autofill_dataset_picker.xml b/core/res/res/layout/autofill_dataset_picker.xml
index a88836e..ef19f87 100644
--- a/core/res/res/layout/autofill_dataset_picker.xml
+++ b/core/res/res/layout/autofill_dataset_picker.xml
@@ -14,7 +14,8 @@
limitations under the License.
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<view xmlns:android="http://schemas.android.com/apk/res/android"
+ class="com.android.server.autofill.ui.FillUi$AutofillFrameLayout"
android:id="@+id/autofill_dataset_picker"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
@@ -30,4 +31,4 @@
android:visibility="gone">
</ListView>
-</FrameLayout>
+</view>
diff --git a/core/res/res/mipmap-watch-anydpi/sym_def_app_icon_foreground.xml b/core/res/res/mipmap-watch-anydpi/sym_def_app_icon_foreground.xml
new file mode 100644
index 0000000..69c241c
--- /dev/null
+++ b/core/res/res/mipmap-watch-anydpi/sym_def_app_icon_foreground.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<inset
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:insetLeft="24dp"
+ android:insetRight="24dp"
+ android:insetTop="24dp"
+ android:insetBottom="24dp">
+ <vector
+ android:width="60dp"
+ android:height="60dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M20,12c0,-2.6 -1.2,-4.8 -3.1,-6.3l-0.5,-2.8c-1.4,-0.7 -2.9,-1.1 -4.5,-1.1c-1.6,0 -3.1,0.4 -4.5,1.1L7,5.7C5.1,7.2 3.9,9.4 3.9,12c0,2.6 1.2,4.8 3.1,6.3l0.5,2.8c1.4,0.7 2.9,1.1 4.5,1.1c1.6,0 3.2,-0.4 4.5,-1.1l0.5,-2.8C18.8,16.8 20,14.6 20,12zM12,18c-3.3,0 -6,-2.7 -6,-6c0,-3.3 2.7,-6 6,-6s6,2.7 6,6C18,15.3 15.3,18 12,18z"/>
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M11.2,15.6h1.4v-4.3h-1.4V15.6zM11.2,9.8h1.4V8.4h-1.4V9.8z"/>
+ </vector>
+</inset>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 9d7432e..0b33211 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5905,6 +5905,9 @@
<!-- Identifier of the image file. This attribute is mandatory.
It must be an image file with multiple frames, e.g. gif or webp -->
<attr name="src" />
+ <!-- Indicates if the drawable needs to be mirrored when its layout direction is
+ RTL (right-to-left). -->
+ <attr name="autoMirrored" />
</declare-styleable>
<!-- Drawable used to draw bitmaps. -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f4be888..cadc3ff 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3772,31 +3772,23 @@
<string name="extract_edit_menu_button">Edit</string>
<!-- Notification title when data usage has exceeded warning threshold. [CHAR LIMIT=50] -->
- <string name="data_usage_warning_title">Data usage alert</string>
+ <string name="data_usage_warning_title">Data warning</string>
<!-- Notification body when data usage has exceeded warning threshold. [CHAR LIMIT=32] -->
- <string name="data_usage_warning_body">Tap to view usage and settings.</string>
+ <string name="data_usage_warning_body">You've used <xliff:g id="app" example="3.8GB">%s</xliff:g> of data</string>
- <!-- Notification title when 2G-3G data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
- <string name="data_usage_3g_limit_title">2G-3G data limit reached</string>
- <!-- Notification title when 4G data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
- <string name="data_usage_4g_limit_title">4G data limit reached</string>
<!-- Notification title when mobile data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=50] -->
<string name="data_usage_mobile_limit_title">Mobile data limit reached</string>
<!-- Notification title when Wi-Fi data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
<string name="data_usage_wifi_limit_title">Wi-Fi data limit reached</string>
<!-- Notification body when data usage has exceeded limit threshold, and has been disabled. -->
- <string name="data_usage_limit_body">Data paused for rest of cycle</string>
+ <string name="data_usage_limit_body">Data paused for the rest of your cycle</string>
- <!-- Notification title when 2G-3G data usage has exceeded limit threshold. [CHAR LIMIT=32] -->
- <string name="data_usage_3g_limit_snoozed_title">2G-3G data limit exceeded</string>
- <!-- Notification title when 4G data usage has exceeded limit threshold. [CHAR LIMIT=32] -->
- <string name="data_usage_4g_limit_snoozed_title">4G data limit exceeded</string>
<!-- Notification title when mobile data usage has exceeded limit threshold. [CHAR LIMIT=32] -->
- <string name="data_usage_mobile_limit_snoozed_title">Mobile data limit exceeded</string>
+ <string name="data_usage_mobile_limit_snoozed_title">Over your mobile data limit</string>
<!-- Notification title when Wi-Fi data usage has exceeded limit threshold. [CHAR LIMIT=32] -->
- <string name="data_usage_wifi_limit_snoozed_title">Wi-Fi data limit exceeded</string>
+ <string name="data_usage_wifi_limit_snoozed_title">Over your Wi-Fi data limit</string>
<!-- Notification body when data usage has exceeded limit threshold. -->
- <string name="data_usage_limit_snoozed_body"><xliff:g id="size" example="3.8GB">%s</xliff:g> over specified limit.</string>
+ <string name="data_usage_limit_snoozed_body">You've gone <xliff:g id="size" example="3.8GB">%s</xliff:g> over your set limit</string>
<!-- Notification title when background data usage is limited. [CHAR LIMIT=32] -->
<string name="data_usage_restricted_title">Background data restricted</string>
@@ -3804,9 +3796,11 @@
<string name="data_usage_restricted_body">Tap to remove restriction.</string>
<!-- Notification title when there has been recent excessive data usage. [CHAR LIMIT=32] -->
- <string name="data_usage_rapid_title">Large data usage</string>
+ <string name="data_usage_rapid_title">High mobile data usage</string>
<!-- Notification body when there has been recent excessive data usage. [CHAR LIMIT=128] -->
- <string name="data_usage_rapid_body">Your data usage over the last few days is larger than normal. Tap to view usage and settings.</string>
+ <string name="data_usage_rapid_body">Your apps have used more data than usual</string>
+ <!-- Notification body when there has been recent excessive data usage by a specific app. [CHAR LIMIT=128] -->
+ <string name="data_usage_rapid_app_body"><xliff:g id="app" example="Calculator">%s</xliff:g> has used more data than usual</string>
<!-- SSL Certificate dialogs -->
<!-- Title for an SSL Certificate dialog -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index fc4d4e7..a2af57e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1971,10 +1971,6 @@
<java-symbol type="string" name="config_wimaxServiceClassname" />
<java-symbol type="string" name="config_wimaxServiceJarLocation" />
<java-symbol type="string" name="config_wimaxStateTrackerClassname" />
- <java-symbol type="string" name="data_usage_3g_limit_snoozed_title" />
- <java-symbol type="string" name="data_usage_3g_limit_title" />
- <java-symbol type="string" name="data_usage_4g_limit_snoozed_title" />
- <java-symbol type="string" name="data_usage_4g_limit_title" />
<java-symbol type="string" name="data_usage_limit_body" />
<java-symbol type="string" name="data_usage_limit_snoozed_body" />
<java-symbol type="string" name="data_usage_mobile_limit_snoozed_title" />
@@ -1987,6 +1983,7 @@
<java-symbol type="string" name="data_usage_wifi_limit_title" />
<java-symbol type="string" name="data_usage_rapid_title" />
<java-symbol type="string" name="data_usage_rapid_body" />
+ <java-symbol type="string" name="data_usage_rapid_app_body" />
<java-symbol type="string" name="default_wallpaper_component" />
<java-symbol type="string" name="device_storage_monitor_notification_channel" />
<java-symbol type="string" name="dlg_ok" />
diff --git a/core/tests/coretests/src/android/app/backup/FullBackupTest.java b/core/tests/coretests/src/android/app/backup/FullBackupTest.java
index bc6fc15..58ee7a7 100644
--- a/core/tests/coretests/src/android/app/backup/FullBackupTest.java
+++ b/core/tests/coretests/src/android/app/backup/FullBackupTest.java
@@ -19,6 +19,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import android.app.backup.FullBackup.BackupScheme.PathWithRequiredFlags;
import android.content.Context;
import android.support.test.filters.LargeTest;
import android.test.AndroidTestCase;
@@ -43,8 +44,8 @@
private XmlPullParser mXpp;
private Context mContext;
- Map<String, Set<String>> includeMap;
- Set<String> excludesSet;
+ Map<String, Set<PathWithRequiredFlags>> includeMap;
+ Set<PathWithRequiredFlags> excludesSet;
@Override
public void setUp() throws Exception {
@@ -52,8 +53,8 @@
mXpp = mFactory.newPullParser();
mContext = getContext();
- includeMap = new ArrayMap();
- excludesSet = new ArraySet();
+ includeMap = new ArrayMap<>();
+ excludesSet = new ArraySet<>();
}
public void testparseBackupSchemeFromXml_onlyInclude() throws Exception {
@@ -68,11 +69,127 @@
assertEquals("Excluding files when there was no <exclude/> tag.", 0, excludesSet.size());
assertEquals("Unexpected number of <include/>s", 1, includeMap.size());
- Set<String> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
+ Set<PathWithRequiredFlags> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
assertEquals("Didn't find expected file domain include.", 1, fileDomainIncludes.size());
+ PathWithRequiredFlags include = fileDomainIncludes.iterator().next();
assertEquals("Invalid path parsed for <include/>",
new File(mContext.getFilesDir(), "onlyInclude.txt").getCanonicalPath(),
- fileDomainIncludes.iterator().next());
+ include.getPath());
+ assertEquals("Invalid requireFlags parsed for <include/>", 0, include.getRequiredFlags());
+ }
+
+ public void testparseBackupSchemeFromXml_onlyIncludeRequireEncryptionFlag() throws Exception {
+ mXpp.setInput(new StringReader(
+ "<full-backup-content>" +
+ "<include path=\"onlyInclude.txt\" domain=\"file\""
+ + " requireFlags=\"clientSideEncryption\"/>" +
+ "</full-backup-content>"));
+
+ FullBackup.BackupScheme bs = FullBackup.getBackupSchemeForTest(mContext);
+ bs.parseBackupSchemeFromXmlLocked(mXpp, excludesSet, includeMap);
+
+ assertEquals("Excluding files when there was no <exclude/> tag.", 0, excludesSet.size());
+ assertEquals("Unexpected number of <include/>s", 1, includeMap.size());
+
+ Set<PathWithRequiredFlags> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
+ assertEquals("Didn't find expected file domain include.", 1, fileDomainIncludes.size());
+ PathWithRequiredFlags include = fileDomainIncludes.iterator().next();
+ assertEquals("Invalid path parsed for <include/>",
+ new File(mContext.getFilesDir(), "onlyInclude.txt").getCanonicalPath(),
+ include.getPath());
+ assertEquals("Invalid requireFlags parsed for <include/>",
+ BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED,
+ include.getRequiredFlags());
+ }
+
+ public void testparseBackupSchemeFromXml_onlyIncludeRequireD2DFlag() throws Exception {
+ mXpp.setInput(new StringReader(
+ "<full-backup-content>" +
+ "<include path=\"onlyInclude.txt\" domain=\"file\""
+ + " requireFlags=\"deviceToDeviceTransfer\"/>" +
+ "</full-backup-content>"));
+
+ FullBackup.BackupScheme bs = FullBackup.getBackupSchemeForTest(mContext);
+ bs.parseBackupSchemeFromXmlLocked(mXpp, excludesSet, includeMap);
+
+ assertEquals("Excluding files when there was no <exclude/> tag.", 0, excludesSet.size());
+ assertEquals("Unexpected number of <include/>s", 1, includeMap.size());
+
+ Set<PathWithRequiredFlags> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
+ assertEquals("Didn't find expected file domain include.", 1, fileDomainIncludes.size());
+ PathWithRequiredFlags include = fileDomainIncludes.iterator().next();
+ assertEquals("Invalid path parsed for <include/>",
+ new File(mContext.getFilesDir(), "onlyInclude.txt").getCanonicalPath(),
+ include.getPath());
+ assertEquals("Invalid requireFlags parsed for <include/>",
+ BackupAgent.FLAG_DEVICE_TO_DEVICE_TRANSFER,
+ include.getRequiredFlags());
+ }
+
+ public void testparseBackupSchemeFromXml_onlyIncludeRequireEncryptionAndD2DFlags()
+ throws Exception {
+ mXpp.setInput(new StringReader(
+ "<full-backup-content>" +
+ "<include path=\"onlyInclude.txt\" domain=\"file\""
+ + " requireFlags=\"clientSideEncryption|deviceToDeviceTransfer\"/>" +
+ "</full-backup-content>"));
+
+ FullBackup.BackupScheme bs = FullBackup.getBackupSchemeForTest(mContext);
+ bs.parseBackupSchemeFromXmlLocked(mXpp, excludesSet, includeMap);
+
+ assertEquals("Excluding files when there was no <exclude/> tag.", 0, excludesSet.size());
+ assertEquals("Unexpected number of <include/>s", 1, includeMap.size());
+
+ Set<PathWithRequiredFlags> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
+ assertEquals("Didn't find expected file domain include.", 1, fileDomainIncludes.size());
+ PathWithRequiredFlags include = fileDomainIncludes.iterator().next();
+ assertEquals("Invalid path parsed for <include/>",
+ new File(mContext.getFilesDir(), "onlyInclude.txt").getCanonicalPath(),
+ include.getPath());
+ assertEquals("Invalid requireFlags parsed for <include/>",
+ BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED
+ | BackupAgent.FLAG_DEVICE_TO_DEVICE_TRANSFER,
+ include.getRequiredFlags());
+ }
+
+ public void testparseBackupSchemeFromXml_onlyIncludeRequireD2DFlagAndIngoreGarbage()
+ throws Exception {
+ mXpp.setInput(new StringReader(
+ "<full-backup-content>" +
+ "<include path=\"onlyInclude.txt\" domain=\"file\""
+ + " requireFlags=\"deviceToDeviceTransfer|garbageFlag\"/>" +
+ "</full-backup-content>"));
+
+ FullBackup.BackupScheme bs = FullBackup.getBackupSchemeForTest(mContext);
+ bs.parseBackupSchemeFromXmlLocked(mXpp, excludesSet, includeMap);
+
+ assertEquals("Excluding files when there was no <exclude/> tag.", 0, excludesSet.size());
+ assertEquals("Unexpected number of <include/>s", 1, includeMap.size());
+
+ Set<PathWithRequiredFlags> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
+ assertEquals("Didn't find expected file domain include.", 1, fileDomainIncludes.size());
+ PathWithRequiredFlags include = fileDomainIncludes.iterator().next();
+ assertEquals("Invalid path parsed for <include/>",
+ new File(mContext.getFilesDir(), "onlyInclude.txt").getCanonicalPath(),
+ include.getPath());
+ assertEquals("Invalid requireFlags parsed for <include/>",
+ BackupAgent.FLAG_DEVICE_TO_DEVICE_TRANSFER,
+ include.getRequiredFlags());
+ }
+
+ public void testparseBackupSchemeFromXml_onlyExcludeRequireFlagsNotSupported()
+ throws Exception {
+ mXpp.setInput(new StringReader(
+ "<full-backup-content>" +
+ "<exclude path=\"onlyExclude.txt\" domain=\"file\""
+ + " requireFlags=\"deviceToDeviceTransfer\"/>" +
+ "</full-backup-content>"));
+
+ try {
+ FullBackup.BackupScheme bs = FullBackup.getBackupSchemeForTest(mContext);
+ bs.parseBackupSchemeFromXmlLocked(mXpp, excludesSet, includeMap);
+ fail("Having more than 3 attributes in exclude should throw an XmlPullParserException");
+ } catch (XmlPullParserException expected) {}
}
public void testparseBackupSchemeFromXml_onlyExclude() throws Exception {
@@ -88,7 +205,7 @@
assertEquals("Unexpected number of <exclude/>s", 1, excludesSet.size());
assertEquals("Invalid path parsed for <exclude/>",
new File(mContext.getFilesDir(), "onlyExclude.txt").getCanonicalPath(),
- excludesSet.iterator().next());
+ excludesSet.iterator().next().getPath());
}
public void testparseBackupSchemeFromXml_includeAndExclude() throws Exception {
@@ -101,16 +218,16 @@
FullBackup.BackupScheme bs = FullBackup.getBackupSchemeForTest(mContext);
bs.parseBackupSchemeFromXmlLocked(mXpp, excludesSet, includeMap);
- Set<String> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
+ Set<PathWithRequiredFlags> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
assertEquals("Didn't find expected file domain include.", 1, fileDomainIncludes.size());
assertEquals("Invalid path parsed for <include/>",
new File(mContext.getFilesDir(), "include.txt").getCanonicalPath(),
- fileDomainIncludes.iterator().next());
+ fileDomainIncludes.iterator().next().getPath());
assertEquals("Unexpected number of <exclude/>s", 1, excludesSet.size());
assertEquals("Invalid path parsed for <exclude/>",
new File(mContext.getFilesDir(), "exclude.txt").getCanonicalPath(),
- excludesSet.iterator().next());
+ excludesSet.iterator().next().getPath());
}
public void testparseBackupSchemeFromXml_lotsOfIncludesAndExcludes() throws Exception {
@@ -126,61 +243,74 @@
"<include path=\"include4.xml\" domain=\"sharedpref\"/>" +
"</full-backup-content>"));
-
FullBackup.BackupScheme bs = FullBackup.getBackupSchemeForTest(mContext);
bs.parseBackupSchemeFromXmlLocked(mXpp, excludesSet, includeMap);
- Set<String> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
+ Set<PathWithRequiredFlags> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
assertEquals("Didn't find expected file domain include.", 1, fileDomainIncludes.size());
assertEquals("Invalid path parsed for <include/>",
new File(mContext.getFilesDir(), "include1.txt").getCanonicalPath(),
- fileDomainIncludes.iterator().next());
+ fileDomainIncludes.iterator().next().getPath());
- Set<String> databaseDomainIncludes = includeMap.get(FullBackup.DATABASE_TREE_TOKEN);
+ Set<PathWithRequiredFlags> databaseDomainIncludes =
+ includeMap.get(FullBackup.DATABASE_TREE_TOKEN);
+ Set<String> databaseDomainIncludesPaths = new ArraySet<>();
+ for (PathWithRequiredFlags databaseInclude : databaseDomainIncludes) {
+ databaseDomainIncludesPaths.add(databaseInclude.getPath());
+ }
// Three expected here because of "-journal" and "-wal" files
assertEquals("Didn't find expected database domain include.",
3, databaseDomainIncludes.size());
assertTrue("Invalid path parsed for <include/>",
- databaseDomainIncludes.contains(
+ databaseDomainIncludesPaths.contains(
new File(mContext.getDatabasePath("foo").getParentFile(), "include2.txt")
.getCanonicalPath()));
assertTrue("Invalid path parsed for <include/>",
- databaseDomainIncludes.contains(
+ databaseDomainIncludesPaths.contains(
new File(
mContext.getDatabasePath("foo").getParentFile(),
"include2.txt-journal")
.getCanonicalPath()));
assertTrue("Invalid path parsed for <include/>",
- databaseDomainIncludes.contains(
+ databaseDomainIncludesPaths.contains(
new File(
mContext.getDatabasePath("foo").getParentFile(),
"include2.txt-wal")
.getCanonicalPath()));
- List<String> sharedPrefDomainIncludes = new ArrayList<String>(
+ List<PathWithRequiredFlags> sharedPrefDomainIncludes = new ArrayList<PathWithRequiredFlags>(
includeMap.get(FullBackup.SHAREDPREFS_TREE_TOKEN));
- Collections.sort(sharedPrefDomainIncludes);
+ ArrayList<String> sharedPrefDomainIncludesPaths = new ArrayList<>();
+ for (PathWithRequiredFlags sharedPrefInclude : sharedPrefDomainIncludes) {
+ sharedPrefDomainIncludesPaths.add(sharedPrefInclude.getPath());
+ }
+ // Sets are annoying to iterate over b/c order isn't enforced - convert to an array and
+ // sort lexicographically.
+ Collections.sort(sharedPrefDomainIncludesPaths);
assertEquals("Didn't find expected sharedpref domain include.",
3, sharedPrefDomainIncludes.size());
assertEquals("Invalid path parsed for <include/>",
new File(mContext.getSharedPrefsFile("foo").getParentFile(), "include3")
.getCanonicalPath(),
- sharedPrefDomainIncludes.get(0));
+ sharedPrefDomainIncludesPaths.get(0));
assertEquals("Invalid path parsed for <include/>",
new File(mContext.getSharedPrefsFile("foo").getParentFile(), "include3.xml")
.getCanonicalPath(),
- sharedPrefDomainIncludes.get(1));
+ sharedPrefDomainIncludesPaths.get(1));
assertEquals("Invalid path parsed for <include/>",
new File(mContext.getSharedPrefsFile("foo").getParentFile(), "include4.xml")
.getCanonicalPath(),
- sharedPrefDomainIncludes.get(2));
+ sharedPrefDomainIncludesPaths.get(2));
assertEquals("Unexpected number of <exclude/>s", 7, excludesSet.size());
// Sets are annoying to iterate over b/c order isn't enforced - convert to an array and
// sort lexicographically.
- List<String> arrayedSet = new ArrayList<String>(excludesSet);
+ ArrayList<String> arrayedSet = new ArrayList<>();
+ for (PathWithRequiredFlags exclude : excludesSet) {
+ arrayedSet.add(exclude.getPath());
+ }
Collections.sort(arrayedSet);
assertEquals("Invalid path parsed for <exclude/>",
@@ -260,9 +390,10 @@
assertEquals("Didn't throw away invalid \"..\" path.", 0, includeMap.size());
- Set<String> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
+ Set<PathWithRequiredFlags> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
assertNull("Didn't throw away invalid \"..\" path.", fileDomainIncludes);
}
+
public void testDoubleDotInPath_isIgnored() throws Exception {
mXpp.setInput(new StringReader(
"<full-backup-content>" +
@@ -274,7 +405,7 @@
assertEquals("Didn't throw away invalid \"..\" path.", 0, includeMap.size());
- Set<String> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
+ Set<PathWithRequiredFlags> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
assertNull("Didn't throw away invalid \"..\" path.", fileDomainIncludes);
}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 38e20a1..bba8c1a 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -305,6 +305,7 @@
Settings.Global.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS,
Settings.Global.NETWORK_WATCHLIST_ENABLED,
Settings.Global.NEW_CONTACT_AGGREGATOR,
+ Settings.Global.NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE,
Settings.Global.NITZ_UPDATE_DIFF,
Settings.Global.NITZ_UPDATE_SPACING,
Settings.Global.NOTIFICATION_SNOOZE_OPTIONS,
@@ -376,6 +377,7 @@
Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES,
Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE,
Settings.Global.SYS_VDSO,
+ Settings.Global.SYS_UIDCPUPOWER,
Settings.Global.FPS_DEVISOR,
Settings.Global.TCP_DEFAULT_INIT_RWND,
Settings.Global.TETHER_DUN_APN,
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
index bd6d73d..d26425b 100644
--- a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
@@ -56,7 +56,7 @@
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1
LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/v1/res
-LOCAL_MANIFEST_FILE := app/AndroidManifest.xml
+LOCAL_MANIFEST_FILE := app/v1/AndroidManifest.xml
include $(BUILD_PACKAGE)
include $(CLEAR_VARS)
@@ -67,7 +67,7 @@
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2
LOCAL_AAPT_FLAGS += --version-code 2 --version-name v2
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/v2/res
-LOCAL_MANIFEST_FILE := app/AndroidManifest.xml
+LOCAL_MANIFEST_FILE := app/v2/AndroidManifest.xml
include $(BUILD_PACKAGE)
my_package_prefix :=
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v1/AndroidManifest.xml
similarity index 100%
rename from core/tests/overlaytests/host/test-apps/UpdateOverlay/app/AndroidManifest.xml
rename to core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v1/AndroidManifest.xml
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/AndroidManifest.xml
new file mode 100644
index 0000000..9ec7d06
--- /dev/null
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/AndroidManifest.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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.om.hosttest.app_overlay">
+ <overlay android:targetPackage="com.android.server.om.hosttest.update_overlay_test"
+ android:category="android.theme" />
+</manifest>
diff --git a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
index 598807d..796d008 100644
--- a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
@@ -72,11 +72,14 @@
mAssetFd = afd;
}
- public final long mNativePtr;
+ final long mNativePtr;
// These just keep references so the native code can continue using them.
private final InputStream mInputStream;
private final AssetFileDescriptor mAssetFd;
+
+ int[] mThemeAttrs = null;
+ boolean mAutoMirrored = false;
}
private State mState;
@@ -99,7 +102,7 @@
* <p>By default, the loop count in the encoded data is respected.</p>
*/
public void setLoopCount(int loopCount) {
- if (mState == null) {
+ if (mState.mNativePtr == 0) {
throw new IllegalStateException("called setLoopCount on empty AnimatedImageDrawable");
}
nSetLoopCount(mState.mNativePtr, loopCount);
@@ -109,7 +112,7 @@
* Create an empty AnimatedImageDrawable.
*/
public AnimatedImageDrawable() {
- mState = null;
+ mState = new State(0, null, null);
}
@Override
@@ -123,6 +126,7 @@
private void updateStateFromTypedArray(TypedArray a, int srcDensityOverride)
throws XmlPullParserException {
+ State oldState = mState;
final Resources r = a.getResources();
final int srcResId = a.getResourceId(R.styleable.AnimatedImageDrawable_src, 0);
if (srcResId != 0) {
@@ -172,6 +176,16 @@
mIntrinsicWidth = other.mIntrinsicWidth;
mIntrinsicHeight = other.mIntrinsicHeight;
}
+
+ mState.mThemeAttrs = a.extractThemeAttrs();
+ if (mState.mNativePtr == 0 && (mState.mThemeAttrs == null
+ || mState.mThemeAttrs[R.styleable.AnimatedImageDrawable_src] == 0)) {
+ throw new XmlPullParserException(a.getPositionDescription() +
+ ": <animated-image> requires a valid 'src' attribute");
+ }
+
+ mState.mAutoMirrored = a.getBoolean(
+ R.styleable.AnimatedImageDrawable_autoMirrored, oldState.mAutoMirrored);
}
/**
@@ -225,7 +239,7 @@
@Override
public void draw(@NonNull Canvas canvas) {
- if (mState == null) {
+ if (mState.mNativePtr == 0) {
throw new IllegalStateException("called draw on empty AnimatedImageDrawable");
}
@@ -256,7 +270,7 @@
+ " 255! provided " + alpha);
}
- if (mState == null) {
+ if (mState.mNativePtr == 0) {
throw new IllegalStateException("called setAlpha on empty AnimatedImageDrawable");
}
@@ -266,7 +280,7 @@
@Override
public int getAlpha() {
- if (mState == null) {
+ if (mState.mNativePtr == 0) {
throw new IllegalStateException("called getAlpha on empty AnimatedImageDrawable");
}
return nGetAlpha(mState.mNativePtr);
@@ -274,7 +288,7 @@
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
- if (mState == null) {
+ if (mState.mNativePtr == 0) {
throw new IllegalStateException("called setColorFilter on empty AnimatedImageDrawable");
}
@@ -298,11 +312,28 @@
}
@Override
+ public void setAutoMirrored(boolean mirrored) {
+ if (mState.mAutoMirrored != mirrored) {
+ mState.mAutoMirrored = mirrored;
+ invalidateSelf();
+ }
+ }
+
+ @Override
+ public final boolean isAutoMirrored() {
+ return mState.mAutoMirrored;
+ }
+
+ @Override
public boolean setVisible(boolean visible, boolean restart) {
if (!super.setVisible(visible, restart)) {
return false;
}
+ if (mState.mNativePtr == 0) {
+ throw new IllegalStateException("called setVisible on empty AnimatedImageDrawable");
+ }
+
if (!visible) {
nMarkInvisible(mState.mNativePtr);
}
@@ -319,7 +350,7 @@
*/
@Override
public boolean isRunning() {
- if (mState == null) {
+ if (mState.mNativePtr == 0) {
throw new IllegalStateException("called isRunning on empty AnimatedImageDrawable");
}
return nIsRunning(mState.mNativePtr);
@@ -336,7 +367,7 @@
*/
@Override
public void start() {
- if (mState == null) {
+ if (mState.mNativePtr == 0) {
throw new IllegalStateException("called start on empty AnimatedImageDrawable");
}
@@ -354,7 +385,7 @@
*/
@Override
public void stop() {
- if (mState == null) {
+ if (mState.mNativePtr == 0) {
throw new IllegalStateException("called stop on empty AnimatedImageDrawable");
}
if (nStop(mState.mNativePtr)) {
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index e2aba04..ded427e 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -545,9 +545,7 @@
try {
args = args != null ? args : new KeymasterArguments();
entropy = entropy != null ? entropy : new byte[0];
- OperationResult res = mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid);
- // This result is -26 (KEY_USER_NOT_AUTHENTICATED) but why??
- return res;
+ return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return null;
@@ -565,8 +563,7 @@
try {
arguments = arguments != null ? arguments : new KeymasterArguments();
input = input != null ? input : new byte[0];
- OperationResult res = mBinder.update(token, arguments, input);
- return res;
+ return mBinder.update(token, arguments, input);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return null;
@@ -621,9 +618,9 @@
* @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to
* a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
*/
- public int addAuthToken(byte[] authToken, int userId) {
+ public int addAuthToken(byte[] authToken) {
try {
- return mBinder.addAuthToken(authToken, userId);
+ return mBinder.addAuthToken(authToken);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
@@ -835,14 +832,14 @@
public InvalidKeyException getInvalidKeyException(
String keystoreKeyAlias, int uid, KeyStoreException e) {
switch (e.getErrorCode()) {
- case LOCKED: // 2
+ case LOCKED:
return new UserNotAuthenticatedException();
- case KeymasterDefs.KM_ERROR_KEY_EXPIRED: // -25
+ case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
return new KeyExpiredException();
- case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID: // -2
+ case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
return new KeyNotYetValidException();
- case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED: // -26
- case OP_AUTH_NEEDED: // 15
+ case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
+ case OP_AUTH_NEEDED:
{
// We now need to determine whether the key/operation can become usable if user
// authentication is performed, or whether it can never become usable again.
@@ -882,7 +879,7 @@
// None of the key's SIDs can ever be authenticated
return new KeyPermanentlyInvalidatedException();
}
- case UNINITIALIZED: // 3
+ case UNINITIALIZED:
return new KeyPermanentlyInvalidatedException();
default:
return new InvalidKeyException("Keystore operation failed", e);
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index 419eb24..09b3b9b 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -243,7 +243,13 @@
// Check that user authentication related parameters are acceptable. This method
// will throw an IllegalStateException if there are issues (e.g., secure lock screen
// not set up).
- KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), spec);
+ KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
+ spec.isUserAuthenticationRequired(),
+ spec.getUserAuthenticationValidityDurationSeconds(),
+ spec.isUserAuthenticationValidWhileOnBody(),
+ spec.isInvalidatedByBiometricEnrollment(),
+ GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
+ spec.isUserConfirmationRequired());
} catch (IllegalStateException | IllegalArgumentException e) {
throw new InvalidAlgorithmParameterException(e);
}
@@ -279,7 +285,16 @@
args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes);
args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterPaddings);
args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
- KeymasterUtils.addUserAuthArgs(args, spec);
+ KeymasterUtils.addUserAuthArgs(args,
+ spec.isUserAuthenticationRequired(),
+ spec.getUserAuthenticationValidityDurationSeconds(),
+ spec.isUserAuthenticationValidWhileOnBody(),
+ spec.isInvalidatedByBiometricEnrollment(),
+ GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
+ spec.isUserConfirmationRequired());
+ if (spec.isTrustedUserPresenceRequired()) {
+ args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
+ }
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
args,
mKeymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index d68a33d..e33e3cd 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -344,7 +344,13 @@
// Check that user authentication related parameters are acceptable. This method
// will throw an IllegalStateException if there are issues (e.g., secure lock screen
// not set up).
- KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), mSpec);
+ KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
+ mSpec.isUserAuthenticationRequired(),
+ mSpec.getUserAuthenticationValidityDurationSeconds(),
+ mSpec.isUserAuthenticationValidWhileOnBody(),
+ mSpec.isInvalidatedByBiometricEnrollment(),
+ GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
+ mSpec.isUserConfirmationRequired());
} catch (IllegalArgumentException | IllegalStateException e) {
throw new InvalidAlgorithmParameterException(e);
}
@@ -535,7 +541,13 @@
args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterSignaturePaddings);
args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
- KeymasterUtils.addUserAuthArgs(args, mSpec);
+ KeymasterUtils.addUserAuthArgs(args,
+ mSpec.isUserAuthenticationRequired(),
+ mSpec.getUserAuthenticationValidityDurationSeconds(),
+ mSpec.isUserAuthenticationValidWhileOnBody(),
+ mSpec.isInvalidatedByBiometricEnrollment(),
+ GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
+ mSpec.isUserConfirmationRequired());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
mSpec.getKeyValidityForOriginationEnd());
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index fc86ca0..05cc74a 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -497,7 +497,13 @@
importArgs.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterEncryptionPaddings);
importArgs.addEnums(KeymasterDefs.KM_TAG_PADDING,
KeyProperties.SignaturePadding.allToKeymaster(spec.getSignaturePaddings()));
- KeymasterUtils.addUserAuthArgs(importArgs, spec);
+ KeymasterUtils.addUserAuthArgs(importArgs,
+ spec.isUserAuthenticationRequired(),
+ spec.getUserAuthenticationValidityDurationSeconds(),
+ spec.isUserAuthenticationValidWhileOnBody(),
+ spec.isInvalidatedByBiometricEnrollment(),
+ spec.getBoundToSpecificSecureUserId(),
+ spec.isUserConfirmationRequired());
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
spec.getKeyValidityStart());
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
@@ -694,7 +700,13 @@
int[] keymasterPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
params.getEncryptionPaddings());
args.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
- KeymasterUtils.addUserAuthArgs(args, params);
+ KeymasterUtils.addUserAuthArgs(args,
+ params.isUserAuthenticationRequired(),
+ params.getUserAuthenticationValidityDurationSeconds(),
+ params.isUserAuthenticationValidWhileOnBody(),
+ params.isInvalidatedByBiometricEnrollment(),
+ params.getBoundToSpecificSecureUserId(),
+ params.isUserConfirmationRequired());
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
args,
keymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index d0814c6..da23c70 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -21,7 +21,6 @@
import android.annotation.Nullable;
import android.app.KeyguardManager;
import android.hardware.fingerprint.FingerprintManager;
-import android.security.GateKeeper;
import android.security.KeyStore;
import android.text.TextUtils;
@@ -233,7 +232,7 @@
* key = (SecretKey) keyStore.getKey("key2", null);
* }</pre>
*/
-public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAuthArgs {
+public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
private static final X500Principal DEFAULT_CERT_SUBJECT = new X500Principal("CN=fake");
private static final BigInteger DEFAULT_CERT_SERIAL_NUMBER = new BigInteger("1");
@@ -266,7 +265,6 @@
private final boolean mInvalidatedByBiometricEnrollment;
private final boolean mIsStrongBoxBacked;
private final boolean mUserConfirmationRequired;
- private final boolean mUnlockedDeviceRequired;
/**
* @hide should be built with Builder
@@ -297,8 +295,7 @@
boolean userAuthenticationValidWhileOnBody,
boolean invalidatedByBiometricEnrollment,
boolean isStrongBoxBacked,
- boolean userConfirmationRequired,
- boolean unlockedDeviceRequired) {
+ boolean userConfirmationRequired) {
if (TextUtils.isEmpty(keyStoreAlias)) {
throw new IllegalArgumentException("keyStoreAlias must not be empty");
}
@@ -347,7 +344,6 @@
mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
mIsStrongBoxBacked = isStrongBoxBacked;
mUserConfirmationRequired = userConfirmationRequired;
- mUnlockedDeviceRequired = unlockedDeviceRequired;
}
/**
@@ -673,22 +669,6 @@
}
/**
- * Returns {@code true} if the key cannot be used unless the device screen is unlocked.
- *
- * @see Builder#SetUnlockedDeviceRequired(boolean)
- */
- public boolean isUnlockedDeviceRequired() {
- return mUnlockedDeviceRequired;
- }
-
- /**
- * @hide
- */
- public long getBoundToSpecificSecureUserId() {
- return GateKeeper.INVALID_SECURE_USER_ID;
- }
-
- /**
* Builder of {@link KeyGenParameterSpec} instances.
*/
public final static class Builder {
@@ -719,7 +699,6 @@
private boolean mInvalidatedByBiometricEnrollment = true;
private boolean mIsStrongBoxBacked = false;
private boolean mUserConfirmationRequired;
- private boolean mUnlockedDeviceRequired = false;
/**
* Creates a new instance of the {@code Builder}.
@@ -1288,18 +1267,6 @@
}
/**
- * Sets whether the keystore requires the screen to be unlocked before allowing decryption
- * using this key. If this is set to {@code true}, any attempt to decrypt using this key
- * while the screen is locked will fail. A locked device requires a PIN, password,
- * fingerprint, or other trusted factor to access.
- */
- @NonNull
- public Builder setUnlockedDeviceRequired(boolean unlockedDeviceRequired) {
- mUnlockedDeviceRequired = unlockedDeviceRequired;
- return this;
- }
-
- /**
* Builds an instance of {@code KeyGenParameterSpec}.
*/
@NonNull
@@ -1330,8 +1297,7 @@
mUserAuthenticationValidWhileOnBody,
mInvalidatedByBiometricEnrollment,
mIsStrongBoxBacked,
- mUserConfirmationRequired,
- mUnlockedDeviceRequired);
+ mUserConfirmationRequired);
}
}
}
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 7f8259b..b5b3281 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -212,7 +212,7 @@
* ...
* }</pre>
*/
-public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
+public final class KeyProtection implements ProtectionParameter {
private final Date mKeyValidityStart;
private final Date mKeyValidityForOriginationEnd;
private final Date mKeyValidityForConsumptionEnd;
@@ -229,8 +229,6 @@
private final long mBoundToSecureUserId;
private final boolean mCriticalToDeviceEncryption;
private final boolean mUserConfirmationRequired;
- private final boolean mTrustedUserPresenceRequired;
- private final boolean mUnlockedDeviceRequired;
private KeyProtection(
Date keyValidityStart,
@@ -244,13 +242,11 @@
boolean randomizedEncryptionRequired,
boolean userAuthenticationRequired,
int userAuthenticationValidityDurationSeconds,
- boolean trustedUserPresenceRequired,
boolean userAuthenticationValidWhileOnBody,
boolean invalidatedByBiometricEnrollment,
long boundToSecureUserId,
boolean criticalToDeviceEncryption,
- boolean userConfirmationRequired,
- boolean unlockedDeviceRequired) {
+ boolean userConfirmationRequired) {
mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
@@ -269,8 +265,6 @@
mBoundToSecureUserId = boundToSecureUserId;
mCriticalToDeviceEncryption = criticalToDeviceEncryption;
mUserConfirmationRequired = userConfirmationRequired;
- mTrustedUserPresenceRequired = trustedUserPresenceRequired;
- mUnlockedDeviceRequired = unlockedDeviceRequired;
}
/**
@@ -443,14 +437,6 @@
}
/**
- * Returns {@code true} if the key is authorized to be used only if a test of user presence has
- * been performed between the {@code Signature.initSign()} and {@code Signature.sign()} calls.
- */
- public boolean isTrustedUserPresenceRequired() {
- return mTrustedUserPresenceRequired;
- }
-
- /**
* Returns {@code true} if the key will be de-authorized when the device is removed from the
* user's body. This option has no effect on keys that don't have an authentication validity
* duration, and has no effect if the device lacks an on-body sensor.
@@ -508,15 +494,6 @@
}
/**
- * Returns {@code true} if the key cannot be used unless the device screen is unlocked.
- *
- * @see Builder#SetRequireDeviceUnlocked(boolean)
- */
- public boolean isUnlockedDeviceRequired() {
- return mUnlockedDeviceRequired;
- }
-
- /**
* Builder of {@link KeyProtection} instances.
*/
public final static class Builder {
@@ -535,9 +512,6 @@
private boolean mUserAuthenticationValidWhileOnBody;
private boolean mInvalidatedByBiometricEnrollment = true;
private boolean mUserConfirmationRequired;
- private boolean mTrustedUserPresenceRequired = false;
- private boolean mUnlockedDeviceRequired = false;
-
private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID;
private boolean mCriticalToDeviceEncryption = false;
@@ -837,16 +811,6 @@
}
/**
- * Sets whether a test of user presence is required to be performed between the
- * {@code Signature.initSign()} and {@code Signature.sign()} method calls.
- */
- @NonNull
- public Builder setTrustedUserPresenceRequired(boolean required) {
- mTrustedUserPresenceRequired = required;
- return this;
- }
-
- /**
* Sets whether the key will remain authorized only until the device is removed from the
* user's body up to the limit of the authentication validity period (see
* {@link #setUserAuthenticationValidityDurationSeconds} and
@@ -928,18 +892,6 @@
}
/**
- * Sets whether the keystore requires the screen to be unlocked before allowing decryption
- * using this key. If this is set to {@code true}, any attempt to decrypt using this key
- * while the screen is locked will fail. A locked device requires a PIN, password,
- * fingerprint, or other trusted factor to access.
- */
- @NonNull
- public Builder setUnlockedDeviceRequired(boolean unlockedDeviceRequired) {
- mUnlockedDeviceRequired = unlockedDeviceRequired;
- return this;
- }
-
- /**
* Builds an instance of {@link KeyProtection}.
*
* @throws IllegalArgumentException if a required field is missing
@@ -958,13 +910,11 @@
mRandomizedEncryptionRequired,
mUserAuthenticationRequired,
mUserAuthenticationValidityDurationSeconds,
- mTrustedUserPresenceRequired,
mUserAuthenticationValidWhileOnBody,
mInvalidatedByBiometricEnrollment,
mBoundToSecureUserId,
mCriticalToDeviceEncryption,
- mUserConfirmationRequired,
- mUnlockedDeviceRequired);
+ mUserConfirmationRequired);
}
}
}
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
index 5bd0e74..4e28601 100644
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore/KeymasterUtils.java
@@ -18,7 +18,6 @@
import android.util.Log;
import android.hardware.fingerprint.FingerprintManager;
-import android.os.UserHandle;
import android.security.GateKeeper;
import android.security.KeyStore;
import android.security.keymaster.KeymasterArguments;
@@ -102,27 +101,22 @@
* require user authentication.
*/
public static void addUserAuthArgs(KeymasterArguments args,
- UserAuthArgs spec) {
- if (spec.isTrustedUserPresenceRequired()) {
- args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
- }
-
- if (spec.isUserConfirmationRequired()) {
+ boolean userAuthenticationRequired,
+ int userAuthenticationValidityDurationSeconds,
+ boolean userAuthenticationValidWhileOnBody,
+ boolean invalidatedByBiometricEnrollment,
+ long boundToSpecificSecureUserId,
+ boolean userConfirmationRequired) {
+ if (userConfirmationRequired) {
args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED);
}
- if (spec.isUnlockedDeviceRequired()) {
- args.addBoolean(KeymasterDefs.KM_TAG_UNLOCKED_DEVICE_REQUIRED);
- // Once keymaster is properly ignoring this tag, it should be added to every auth list
- args.addUnsignedInt(KeymasterDefs.KM_TAG_USER_ID, UserHandle.getCallingUserId());
- }
-
- if (!spec.isUserAuthenticationRequired()) {
+ if (!userAuthenticationRequired) {
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
return;
}
- if (spec.getUserAuthenticationValidityDurationSeconds() == -1) {
+ if (userAuthenticationValidityDurationSeconds == -1) {
// Every use of this key needs to be authorized by the user. This currently means
// fingerprint-only auth.
FingerprintManager fingerprintManager =
@@ -138,9 +132,9 @@
}
long sid;
- if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
- sid = spec.getBoundToSpecificSecureUserId();
- } else if (spec.isInvalidatedByBiometricEnrollment()) {
+ if (boundToSpecificSecureUserId != GateKeeper.INVALID_SECURE_USER_ID) {
+ sid = boundToSpecificSecureUserId;
+ } else if (invalidatedByBiometricEnrollment) {
// The fingerprint-only SID will change on fingerprint enrollment or removal of all,
// enrolled fingerprints, invalidating the key.
sid = fingerprintOnlySid;
@@ -153,14 +147,14 @@
args.addUnsignedLong(
KeymasterDefs.KM_TAG_USER_SECURE_ID, KeymasterArguments.toUint64(sid));
args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, KeymasterDefs.HW_AUTH_FINGERPRINT);
- if (spec.isUserAuthenticationValidWhileOnBody()) {
+ if (userAuthenticationValidWhileOnBody) {
throw new ProviderException("Key validity extension while device is on-body is not "
+ "supported for keys requiring fingerprint authentication");
}
} else {
long sid;
- if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
- sid = spec.getBoundToSpecificSecureUserId();
+ if (boundToSpecificSecureUserId != GateKeeper.INVALID_SECURE_USER_ID) {
+ sid = boundToSpecificSecureUserId;
} else {
// The key is authorized for use for the specified amount of time after the user has
// authenticated. Whatever unlocks the secure lock screen should authorize this key.
@@ -171,8 +165,8 @@
args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
KeymasterDefs.HW_AUTH_PASSWORD | KeymasterDefs.HW_AUTH_FINGERPRINT);
args.addUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
- spec.getUserAuthenticationValidityDurationSeconds());
- if (spec.isUserAuthenticationValidWhileOnBody()) {
+ userAuthenticationValidityDurationSeconds);
+ if (userAuthenticationValidWhileOnBody) {
args.addBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
}
}
diff --git a/keystore/java/android/security/keystore/UserAuthArgs.java b/keystore/java/android/security/keystore/UserAuthArgs.java
deleted file mode 100644
index 3a7017e..0000000
--- a/keystore/java/android/security/keystore/UserAuthArgs.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.security.keystore;
-
-/**
- * @hide
- *
- * This is an interface to encapsulate the user authentication arguments that
- * are passed to KeymasterUtils.addUserAuthArgs. Classes that represent
- * authorization characteristics for new or imported keys can implement this
- * interface to be passed to that method.
- */
-public interface UserAuthArgs {
-
- boolean isUserAuthenticationRequired();
- int getUserAuthenticationValidityDurationSeconds();
- boolean isUserAuthenticationValidWhileOnBody();
- boolean isInvalidatedByBiometricEnrollment();
- boolean isTrustedUserPresenceRequired();
- boolean isUnlockedDeviceRequired();
- boolean isUserConfirmationRequired();
- long getBoundToSpecificSecureUserId();
-
-}
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 9d246ff..21c91a2 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -310,7 +310,7 @@
for (uint32_t i = 0; i < surface->mImageCount; ++i) {
GrVkImageInfo info;
info.fImage = surface->mImages[i];
- info.fAlloc = {VK_NULL_HANDLE, 0, 0, 0};
+ info.fAlloc = GrVkAlloc();
info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
info.fFormat = format;
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index 2f3d972..1446660 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -1223,7 +1223,7 @@
*
* @return the current position in milliseconds
*/
- public abstract int getCurrentPosition();
+ public abstract long getCurrentPosition();
/**
* Gets the duration of the file.
@@ -1231,7 +1231,7 @@
* @return the duration in milliseconds, if no duration is available
* (for example, if streaming live content), -1 is returned.
*/
- public abstract int getDuration();
+ public abstract long getDuration();
/**
* Gets the media metadata.
@@ -1278,27 +1278,6 @@
}
/**
- * Set the MediaPlayer2 to start when this MediaPlayer2 finishes playback
- * (i.e. reaches the end of the stream).
- * The media framework will attempt to transition from this player to
- * the next as seamlessly as possible. The next player can be set at
- * any time before completion, but shall be after setDataSource has been
- * called successfully. The next player must be prepared by the
- * app, and the application should not call play() on it.
- * The next MediaPlayer2 must be different from 'this'. An exception
- * will be thrown if next == this.
- * The application may call setNextMediaPlayer(null) to indicate no
- * next player should be started at the end of playback.
- * If the current player is looping, it will keep looping and the next
- * player will not be started.
- *
- * @param next the player to start after this one completes playback.
- *
- * @hide
- */
- public void setNextMediaPlayer(MediaPlayer2 next) { }
-
- /**
* Resets the MediaPlayer2 to its uninitialized state. After calling
* this method, you will have to initialize it again by setting the
* data source and calling prepareAsync().
@@ -1326,6 +1305,13 @@
public abstract void setAudioAttributes(AudioAttributes attributes);
/**
+ * Gets the audio attributes for this MediaPlayer2.
+ * @return attributes a set of audio attributes
+ * @throws IllegalArgumentException if the attributes are null or invalid.
+ */
+ public abstract AudioAttributes getAudioAttributes();
+
+ /**
* Sets the player to be looping or non-looping.
*
* @param looping whether to loop or not
@@ -2029,8 +2015,9 @@
* Called to give the app the opportunity to configure DRM before the session is created
*
* @param mp the {@code MediaPlayer2} associated with this callback
+ * @param srcId the Id of this data source
*/
- public void onDrmConfig(MediaPlayer2 mp);
+ public void onDrmConfig(MediaPlayer2 mp, long srcId);
}
/**
@@ -2051,24 +2038,25 @@
/**
* Called to indicate DRM info is available
*
- * @param mp the {@code MediaPlayer2} associated with this callback
- * @param drmInfo DRM info of the source including PSSH, and subset
- * of crypto schemes supported by this device
+ * @param mp the {@code MediaPlayer2} associated with this callback
+ * @param srcId the Id of this data source
+ * @param drmInfo DRM info of the source including PSSH, and subset
+ * of crypto schemes supported by this device
*/
- public void onDrmInfo(MediaPlayer2 mp, DrmInfo drmInfo) { }
+ public void onDrmInfo(MediaPlayer2 mp, long srcId, DrmInfo drmInfo) { }
/**
* Called to notify the client that {@code prepareDrm} is finished and ready for key request/response.
*
- * @param mp the {@code MediaPlayer2} associated with this callback
- * @param status the result of DRM preparation which can be
+ * @param mp the {@code MediaPlayer2} associated with this callback
+ * @param srcId the Id of this data source
+ * @param status the result of DRM preparation which can be
* {@link #PREPARE_DRM_STATUS_SUCCESS},
* {@link #PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR},
* {@link #PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR}, or
* {@link #PREPARE_DRM_STATUS_PREPARATION_ERROR}.
*/
- public void onDrmPrepared(MediaPlayer2 mp, @PrepareDrmStatusCode int status) { }
-
+ public void onDrmPrepared(MediaPlayer2 mp, long srcId, @PrepareDrmStatusCode int status) { }
}
/**
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 1b21b5b..7794e08 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -1889,7 +1889,7 @@
* @return the current position in milliseconds
*/
@Override
- public native int getCurrentPosition();
+ public native long getCurrentPosition();
/**
* Gets the duration of the file.
@@ -1898,7 +1898,7 @@
* (for example, if streaming live content), -1 is returned.
*/
@Override
- public native int getDuration();
+ public native long getDuration();
/**
* Gets the media metadata.
@@ -1986,28 +1986,6 @@
}
/**
- * Set the MediaPlayer2 to start when this MediaPlayer2 finishes playback
- * (i.e. reaches the end of the stream).
- * The media framework will attempt to transition from this player to
- * the next as seamlessly as possible. The next player can be set at
- * any time before completion, but shall be after setDataSource has been
- * called successfully. The next player must be prepared by the
- * app, and the application should not call play() on it.
- * The next MediaPlayer2 must be different from 'this'. An exception
- * will be thrown if next == this.
- * The application may call setNextMediaPlayer(null) to indicate no
- * next player should be started at the end of playback.
- * If the current player is looping, it will keep looping and the next
- * player will not be started.
- *
- * @param next the player to start after this one completes playback.
- *
- * @hide
- */
- @Override
- public native void setNextMediaPlayer(MediaPlayer2 next);
-
- /**
* Resets the MediaPlayer2 to its uninitialized state. After calling
* this method, you will have to initialize it again by setting the
* data source and calling prepareAsync().
@@ -2078,10 +2056,11 @@
* @param key key indicates the parameter to be set.
* @param value value of the parameter to be set.
* @return true if the parameter is set successfully, false otherwise
- * {@hide}
*/
private native boolean setParameter(int key, Parcel value);
+ private native Parcel getParameter(int key);
+
/**
* Sets the audio attributes for this MediaPlayer2.
* See {@link AudioAttributes} for how to build and configure an instance of this class.
@@ -2105,6 +2084,14 @@
pattributes.recycle();
}
+ @Override
+ public AudioAttributes getAudioAttributes() {
+ Parcel pattributes = getParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES);
+ AudioAttributes attributes = AudioAttributes.CREATOR.createFromParcel(pattributes);
+ pattributes.recycle();
+ return attributes;
+ }
+
/**
* Sets the player to be looping or non-looping.
*
@@ -3211,11 +3198,12 @@
}
// notifying the client outside the lock
+ // TODO: get srcId
if (drmInfo != null) {
synchronized (mEventCbLock) {
for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
cb.first.execute(() -> cb.second.onDrmInfo(
- mMediaPlayer, drmInfo));
+ mMediaPlayer, 0, drmInfo));
}
}
}
@@ -3747,8 +3735,9 @@
// call the callback outside the lock
+ // TODO: get srcId
if (mOnDrmConfigHelper != null) {
- mOnDrmConfigHelper.onDrmConfig(this);
+ mOnDrmConfigHelper.onDrmConfig(this, 0);
}
synchronized (mDrmLock) {
@@ -3818,11 +3807,12 @@
// if finished successfully without provisioning, call the callback outside the lock
+ // TODO: get srcId
if (allDoneWithoutProvisioning) {
synchronized (mDrmEventCbLock) {
for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
cb.first.execute(() -> cb.second.onDrmPrepared(
- this, PREPARE_DRM_STATUS_SUCCESS));
+ this, 0, PREPARE_DRM_STATUS_SUCCESS));
}
}
}
@@ -4488,9 +4478,10 @@
} // synchronized
// calling the callback outside the lock
+ // TODO: get srcId
synchronized (mDrmEventCbLock) {
for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
- cb.first.execute(() -> cb.second.onDrmPrepared(mediaPlayer, status));
+ cb.first.execute(() -> cb.second.onDrmPrepared(mediaPlayer, 0, status));
}
}
} else { // blocking mode already has the lock
diff --git a/media/java/android/media/update/VideoView2Provider.java b/media/java/android/media/update/VideoView2Provider.java
index 21cc61f..4333c96 100644
--- a/media/java/android/media/update/VideoView2Provider.java
+++ b/media/java/android/media/update/VideoView2Provider.java
@@ -18,6 +18,7 @@
import android.annotation.SystemApi;
import android.media.AudioAttributes;
+import android.media.MediaMetadata2;
import android.media.MediaPlayerInterface;
import android.media.session.MediaController;
import android.media.session.PlaybackState;
@@ -51,8 +52,10 @@
void initialize(AttributeSet attrs, int defStyleAttr, int defStyleRes);
void setMediaControlView2_impl(MediaControlView2 mediaControlView, long intervalMs);
+ void setMediaMetadata_impl(MediaMetadata2 metadata);
MediaController getMediaController_impl();
MediaControlView2 getMediaControlView2_impl();
+ MediaMetadata2 getMediaMetadata_impl();
void setSubtitleEnabled_impl(boolean enable);
boolean isSubtitleEnabled_impl();
// TODO: remove setSpeed_impl once MediaController2 is ready.
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index fe2f64f..3c8af8a 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -51,6 +51,7 @@
"libexif",
"libpiex",
"libandroidfw",
+ "libhidlallocatorutils",
"libhidlbase",
"libhidltransport",
"android.hardware.cas@1.0",
@@ -106,6 +107,7 @@
"liblog", // NDK
"libdrmframework", // for FileSource, MediaHTTP
"libgui", // for VideoFrameScheduler
+ "libhidlallocatorutils",
"libhidlbase", // VNDK???
"libmediandk", // NDK
"libpowermanager", // for JWakeLock. to be removed
diff --git a/media/jni/android_media_MediaDescrambler.cpp b/media/jni/android_media_MediaDescrambler.cpp
index e77e855..add47463 100644
--- a/media/jni/android_media_MediaDescrambler.cpp
+++ b/media/jni/android_media_MediaDescrambler.cpp
@@ -27,12 +27,13 @@
#include <android/hardware/cas/native/1.0/BnHwDescrambler.h>
#include <binder/MemoryDealer.h>
#include <hidl/HidlSupport.h>
+#include <hidlmemory/FrameworkUtils.h>
#include <media/stagefright/foundation/ADebug.h>
#include <nativehelper/ScopedLocalRef.h>
namespace android {
-using hardware::hidl_handle;
+using hardware::fromHeap;
struct fields_t {
jfieldID context;
@@ -146,14 +147,8 @@
return false;
}
- native_handle_t* nativeHandle = native_handle_create(1, 0);
- if (!nativeHandle) {
- ALOGE("ensureBufferCapacity: failed to create native handle");
- return false;
- }
- nativeHandle->data[0] = heap->getHeapID();
- mDescramblerSrcBuffer.heapBase = hidl_memory("ashmem",
- hidl_handle(nativeHandle), heap->getSize());
+ mHidlMemory = fromHeap(heap);
+ mDescramblerSrcBuffer.heapBase = *mHidlMemory;
mDescramblerSrcBuffer.offset = (uint64_t) offset;
mDescramblerSrcBuffer.size = (uint64_t) size;
return true;
diff --git a/media/jni/android_media_MediaDescrambler.h b/media/jni/android_media_MediaDescrambler.h
index 015fad2..2354dc2 100644
--- a/media/jni/android_media_MediaDescrambler.h
+++ b/media/jni/android_media_MediaDescrambler.h
@@ -28,7 +28,10 @@
class IMemory;
class MemoryDealer;
-using hardware::hidl_memory;
+namespace hardware {
+class HidlMemory;
+};
+using hardware::HidlMemory;
using hardware::hidl_string;
using hardware::hidl_vec;
using namespace hardware::cas::V1_0;
@@ -58,6 +61,7 @@
sp<IDescrambler> mDescrambler;
sp<IMemory> mMem;
sp<MemoryDealer> mDealer;
+ sp<HidlMemory> mHidlMemory;
SharedBuffer mDescramblerSrcBuffer;
Mutex mSharedMemLock;
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index cf115a4..2258c78 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -760,7 +760,8 @@
return;
}
ALOGV("seekTo: %lld(msec), mode=%d", (long long)msec, mode);
- process_media_player_call( env, thiz, mp->seekTo((int)msec, (MediaPlayer2SeekMode)mode), NULL, NULL );
+ process_media_player_call(env, thiz, mp->seekTo((int64_t)msec, (MediaPlayer2SeekMode)mode),
+ NULL, NULL);
}
static void
@@ -838,7 +839,7 @@
return mybundle;
}
-static jint
+static jlong
android_media_MediaPlayer2_getCurrentPosition(JNIEnv *env, jobject thiz)
{
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
@@ -846,13 +847,13 @@
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return 0;
}
- int msec;
+ int64_t msec;
process_media_player_call( env, thiz, mp->getCurrentPosition(&msec), NULL, NULL );
- ALOGV("getCurrentPosition: %d (msec)", msec);
- return (jint) msec;
+ ALOGV("getCurrentPosition: %lld (msec)", (long long)msec);
+ return (jlong) msec;
}
-static jint
+static jlong
android_media_MediaPlayer2_getDuration(JNIEnv *env, jobject thiz)
{
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
@@ -860,10 +861,10 @@
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return 0;
}
- int msec;
+ int64_t msec;
process_media_player_call( env, thiz, mp->getDuration(&msec), NULL, NULL );
- ALOGV("getDuration: %d (msec)", msec);
- return (jint) msec;
+ ALOGV("getDuration: %lld (msec)", (long long)msec);
+ return (jlong) msec;
}
static void
@@ -911,6 +912,28 @@
}
}
+static jobject
+android_media_MediaPlayer2_getParameter(JNIEnv *env, jobject thiz, jint key)
+{
+ ALOGV("getParameter: key %d", key);
+ sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return NULL;
+ }
+
+ jobject jParcel = createJavaParcelObject(env);
+ if (jParcel != NULL) {
+ Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
+ status_t err = mp->getParameter(key, nativeParcel);
+ if (err != OK) {
+ env->DeleteLocalRef(jParcel);
+ return NULL;
+ }
+ }
+ return jParcel;
+}
+
static void
android_media_MediaPlayer2_setLooping(JNIEnv *env, jobject thiz, jboolean looping)
{
@@ -1171,33 +1194,6 @@
process_media_player_call( env, thiz, mp->attachAuxEffect(effectId), NULL, NULL );
}
-static void
-android_media_MediaPlayer2_setNextMediaPlayer(JNIEnv *env, jobject thiz, jobject java_player)
-{
- ALOGV("setNextMediaPlayer");
- sp<MediaPlayer2> thisplayer = getMediaPlayer(env, thiz);
- if (thisplayer == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", "This player not initialized");
- return;
- }
- sp<MediaPlayer2> nextplayer = (java_player == NULL) ? NULL : getMediaPlayer(env, java_player);
- if (nextplayer == NULL && java_player != NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", "That player not initialized");
- return;
- }
-
- if (nextplayer == thisplayer) {
- jniThrowException(env, "java/lang/IllegalArgumentException", "Next player can't be self");
- return;
- }
- // tie the two players together
- process_media_player_call(
- env, thiz, thisplayer->setNextMediaPlayer(nextplayer),
- "java/lang/IllegalArgumentException",
- "setNextMediaPlayer failed." );
- ;
-}
-
/////////////////////////////////////////////////////////////////////////////////////
// Modular DRM begin
@@ -1498,12 +1494,13 @@
{"_notifyAt", "(J)V", (void *)android_media_MediaPlayer2_notifyAt},
{"_pause", "()V", (void *)android_media_MediaPlayer2_pause},
{"isPlaying", "()Z", (void *)android_media_MediaPlayer2_isPlaying},
- {"getCurrentPosition", "()I", (void *)android_media_MediaPlayer2_getCurrentPosition},
- {"getDuration", "()I", (void *)android_media_MediaPlayer2_getDuration},
+ {"getCurrentPosition", "()J", (void *)android_media_MediaPlayer2_getCurrentPosition},
+ {"getDuration", "()J", (void *)android_media_MediaPlayer2_getDuration},
{"_release", "()V", (void *)android_media_MediaPlayer2_release},
{"_reset", "()V", (void *)android_media_MediaPlayer2_reset},
{"_getAudioStreamType", "()I", (void *)android_media_MediaPlayer2_getAudioStreamType},
{"setParameter", "(ILandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer2_setParameter},
+ {"getParameter", "(I)Landroid/os/Parcel;", (void *)android_media_MediaPlayer2_getParameter},
{"setLooping", "(Z)V", (void *)android_media_MediaPlayer2_setLooping},
{"isLooping", "()Z", (void *)android_media_MediaPlayer2_isLooping},
{"_setVolume", "(FF)V", (void *)android_media_MediaPlayer2_setVolume},
@@ -1517,7 +1514,6 @@
{"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer2_set_audio_session_id},
{"_setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer2_setAuxEffectSendLevel},
{"attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer2_attachAuxEffect},
- {"setNextMediaPlayer", "(Landroid/media/MediaPlayer2;)V", (void *)android_media_MediaPlayer2_setNextMediaPlayer},
// Modular DRM
{ "_prepareDrm", "([B[B)V", (void *)android_media_MediaPlayer2_prepareDrm },
{ "_releaseDrm", "()V", (void *)android_media_MediaPlayer2_releaseDrm },
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerProvider.java b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerProvider.java
index 06723c3..24449fd 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerProvider.java
@@ -16,6 +16,8 @@
package com.android.printspooler.model;
+import static android.content.Context.BIND_AUTO_CREATE;
+
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -32,7 +34,7 @@
mContext = context;
mCallback = callback;
Intent intent = new Intent(mContext, PrintSpoolerService.class);
- mContext.bindService(intent, this, 0);
+ mContext.bindService(intent, this, BIND_AUTO_CREATE);
}
public PrintSpoolerService getSpooler() {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index d73a5d7..83d7e16 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -306,19 +306,22 @@
// This will take just a few milliseconds, so just wait to
// bind to the local service before showing the UI.
mSpoolerProvider = new PrintSpoolerProvider(this,
- new Runnable() {
- @Override
- public void run() {
- if (isFinishing() || isDestroyed()) {
- // onPause might have not been able to cancel the job, see PrintActivity#onPause
- // To be sure, cancel the job again. Double canceling does no harm.
- mSpoolerProvider.getSpooler().setPrintJobState(mPrintJob.getId(),
- PrintJobInfo.STATE_CANCELED, null);
- } else {
- onConnectedToPrintSpooler(adapter);
- }
- }
- });
+ () -> {
+ if (isFinishing() || isDestroyed()) {
+ if (savedInstanceState != null) {
+ // onPause might have not been able to cancel the job, see
+ // PrintActivity#onPause
+ // To be sure, cancel the job again. Double canceling does no harm.
+ mSpoolerProvider.getSpooler().setPrintJobState(mPrintJob.getId(),
+ PrintJobInfo.STATE_CANCELED, null);
+ }
+ } else {
+ if (savedInstanceState == null) {
+ mSpoolerProvider.getSpooler().createPrintJob(mPrintJob);
+ }
+ onConnectedToPrintSpooler(adapter);
+ }
+ });
getLoaderManager().initLoader(LOADER_ID_ENABLED_PRINT_SERVICES, null, this);
}
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index f2c05bf..6c8c69a 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"የሲም መዳረሻ"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"ኤችዲ ኦዲዮ፦ <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"ኤችዲ ኦዲዮ"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"መስሚያ አጋዥ መሣሪያ"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ለስልክ ድምፅ ተጠቀም"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ለፋይል ዝውውር ተጠቀም"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ለውፅአት ተጠቀም"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"ለመስሚያ አጋዥ መሣሪያ ተጠቀም"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"አጣምር"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"አጣምር"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"ይቅር"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 6acc8e9..40c16b9 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"الوصول إلى شريحة SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"صوت عالي الدقة: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"صوت عالي الدقة"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"سماعة الأذن الطبية"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"الاستخدام لإعدادات الهاتف الصوتية"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"استخدامه لنقل الملفات"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"استخدام للإدخال"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"استخدام سماعة الأذن الطبية"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"اقتران"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"إقران"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"إلغاء"</string>
diff --git a/packages/SettingsLib/res/values-as/arrays.xml b/packages/SettingsLib/res/values-as/arrays.xml
new file mode 100644
index 0000000..0eff708
--- /dev/null
+++ b/packages/SettingsLib/res/values-as/arrays.xml
@@ -0,0 +1,253 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** Copyright 2015 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="wifi_status">
+ <item msgid="1922181315419294640"></item>
+ <item msgid="8934131797783724664">"স্কেন কৰি থকা হৈছে…"</item>
+ <item msgid="8513729475867537913">"সংযোগ কৰি থকা হৈছে…"</item>
+ <item msgid="515055375277271756">"বিস্বাশযোগ্যতা প্ৰমাণ কৰি থকা হৈছে …"</item>
+ <item msgid="1943354004029184381">"আইপি ঠিকনা সংগ্ৰহ কৰি থকা হৈছে…"</item>
+ <item msgid="4221763391123233270">"সংযোগ কৰা হ’ল"</item>
+ <item msgid="624838831631122137">"স্থগিত"</item>
+ <item msgid="7979680559596111948">"সংযোগ বিচ্ছিন্ন কৰি থকা হৈছে"</item>
+ <item msgid="1634960474403853625">"সংযোগ বিচ্ছিন্ন"</item>
+ <item msgid="746097431216080650">"অসফল"</item>
+ <item msgid="6367044185730295334">"অৱৰোধিত"</item>
+ <item msgid="503942654197908005">"কিছুসময়ৰ বাবে দুৰ্বল সংযোগ দেখুওৱা হোৱা নাই"</item>
+ </string-array>
+ <string-array name="wifi_status_with_ssid">
+ <item msgid="7714855332363650812"></item>
+ <item msgid="8878186979715711006">"স্কেন কৰি থকা হৈছে…"</item>
+ <item msgid="355508996603873860">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ৰ সৈতে সংযোগ কৰি থকা হৈছে…"</item>
+ <item msgid="554971459996405634">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ৰ জৰিয়তে সত্যাপন কৰি থকা হৈছে…"</item>
+ <item msgid="7928343808033020343">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ৰ আইপি ঠিকনা পৰা সংগ্ৰহ কৰি থকা হৈছে…"</item>
+ <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ৰ সৈতে সংযোগ কৰা হ\'ল"</item>
+ <item msgid="1330262655415760617">"স্থগিত"</item>
+ <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ৰ পৰা সংযোগ বিচ্ছিন্ন কৰি থকা হৈছে…"</item>
+ <item msgid="197508606402264311">"সংযোগ বিচ্ছিন্ন"</item>
+ <item msgid="8578370891960825148">"বিফল হৈছে"</item>
+ <item msgid="5660739516542454527">"অৱৰোধিত"</item>
+ <item msgid="1805837518286731242">"কিছুসময়ৰ বাবে দুৰ্বল সংযোগ দেখুওৱা হোৱা নাই"</item>
+ </string-array>
+ <string-array name="hdcp_checking_titles">
+ <item msgid="441827799230089869">"কেতিয়াও পৰীক্ষা নকৰিব"</item>
+ <item msgid="6042769699089883931">"কেৱল DRM সমলৰ বাবে পৰীক্ষা কৰক"</item>
+ <item msgid="9174900380056846820">"সদায় পৰীক্ষা কৰক"</item>
+ </string-array>
+ <string-array name="hdcp_checking_summaries">
+ <item msgid="505558545611516707">"কেতিয়াও HDCP পৰীক্ষণ ব্যৱহাৰ নকৰিব"</item>
+ <item msgid="3878793616631049349">"কেৱল DRM সমলৰ বাবে HDCP পৰীক্ষণ ব্যৱহাৰ কৰক"</item>
+ <item msgid="45075631231212732">"সদায় HDCP পৰীক্ষণ ব্যৱহাৰ কৰক"</item>
+ </string-array>
+ <string-array name="bluetooth_avrcp_versions">
+ <item msgid="5347678900838034763">"AVRCP ১.৪ (ডিফ’ল্ট)"</item>
+ <item msgid="2809759619990248160">"AVRCP ১.৩"</item>
+ <item msgid="6199178154704729352">"AVRCP ১.৫"</item>
+ <item msgid="5172170854953034852">"AVRCP ১.৬"</item>
+ </string-array>
+ <string-array name="bluetooth_avrcp_version_values">
+ <item msgid="2838624067805073303">"avrcp14"</item>
+ <item msgid="3011533352527449572">"avrcp১৩"</item>
+ <item msgid="8837606198371920819">"avrcp১৫"</item>
+ <item msgid="3422726142222090896">"avrcp১৬"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"ছিষ্টেমৰ বাছনি ব্যৱহাৰ কৰক (ডিফ\'ল্ট)"</item>
+ <item msgid="7539690996561263909">"এছবিচি"</item>
+ <item msgid="686685526567131661">"এএচি"</item>
+ <item msgid="5254942598247222737">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> অডিঅ\'"</item>
+ <item msgid="2091430979086738145">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> অডিঅ’"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ <item msgid="723675059572222462">"বিকল্প ক\'ডেকসমূহ সক্ষম কৰক"</item>
+ <item msgid="3304843301758635896">"বিকল্প ক\'ডেকসমূহ অসক্ষম কৰক"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"ছিষ্টেমৰ বাছনি ব্যৱহাৰ কৰক (ডিফল্ট)"</item>
+ <item msgid="6898329690939802290">"এছবিচি"</item>
+ <item msgid="6839647709301342559">"এএচি"</item>
+ <item msgid="7848030269621918608">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> অডিঅ’"</item>
+ <item msgid="298198075927343893">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> অডিঅ’"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ <item msgid="2209680154067241740">"বিকল্প ক\'ডেকসমূহ সক্ষম কৰক"</item>
+ <item msgid="741805482892725657">"ঐচ্ছিক ক’ডেকসমূহ অক্ষম কৰক"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"ছিষ্টেমৰ বাছনি ব্যৱহাৰ কৰক (ডিফ\'ল্ট)"</item>
+ <item msgid="8895532488906185219">"৪৪.১ কিল\'হাৰ্টজ"</item>
+ <item msgid="2909915718994807056">"৪৮.০ কিল’হাৰ্টজ"</item>
+ <item msgid="3347287377354164611">"৮৮.২ কিল\'হাৰ্টজ"</item>
+ <item msgid="1234212100239985373">"৯৬.০ কিল’হাৰ্টজ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"ছিষ্টেমৰ বাছনি ব্যৱহাৰ কৰক (ডিফ’ল্ট)"</item>
+ <item msgid="4482862757811638365">"৪৪.১ কিল’হাৰ্টজ"</item>
+ <item msgid="354495328188724404">"৪৮.০ কিল’হাৰ্টজ"</item>
+ <item msgid="7329816882213695083">"৮৮.২ কিল\'হাৰ্টজ"</item>
+ <item msgid="6967397666254430476">"৯৬.০ কিল’হাৰ্টজ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"ছিষ্টেমৰ বাছনি ব্যৱহাৰ কৰক (ডিফ\'ল্ট)"</item>
+ <item msgid="5618929009984956469">"১৬ বিট/নমুনা"</item>
+ <item msgid="3412640499234627248">"২৪ বিট/নমুনা"</item>
+ <item msgid="121583001492929387">"৩২ বিট/নমুনা"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"ছিষ্টেমৰ বাছনি ব্যৱহাৰ কৰক (ডিফ’ল্ট)"</item>
+ <item msgid="4726688794884191540">"১৬ বিট/নমুনা"</item>
+ <item msgid="305344756485516870">"২৪ বিট/নমুনা"</item>
+ <item msgid="244568657919675099">"৩২ বিট/নমুনা"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"ছিষ্টেমৰ বাছনি ব্যৱহাৰ কৰক (ডিফ\'ল্ট)"</item>
+ <item msgid="4106832974775067314">"ম\'ন\'"</item>
+ <item msgid="5571632958424639155">"ষ্টেৰিঅ\'"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"ছিষ্টেমৰ বাছনি ব্যৱহাৰ কৰক (ডিফ\'ল্ট)"</item>
+ <item msgid="8900559293912978337">"ম\'ন\'"</item>
+ <item msgid="8883739882299884241">"ষ্টেৰিঅ\'"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"ধ্বনিৰ মানৰ বাবে অপ্টিমাইজ কৰা হৈছে (৯৯০কি.বা.প্ৰ.ছে./৯০৯কি.বা.প্ৰ.ছে.)"</item>
+ <item msgid="2921767058740704969">"ধ্বনি আৰু সংযোগৰ সন্তুলিত গুণগত মান (৬৬০কে.বি.প্ৰ.ছে./৬০৬কে.বি.প্ৰ.ছে."</item>
+ <item msgid="8860982705384396512">"সংযোগৰ ক্ষমতা অনুযায়ী সৰ্বোত্তম (৩৩০কে.বি.প্ৰ.ছে/৩০৩কে.বি.প্ৰ.ছে)"</item>
+ <item msgid="4414060457677684127">"সৰ্বশ্ৰেষ্ঠ প্ৰচেষ্টা (খাপ খাব পৰা ৰেইট)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"অডিঅ\' গুণমানৰ বাবে অপ্টিমাইজ কৰা হৈছে"</item>
+ <item msgid="4327143584633311908">"ধ্বনি আৰু সংযোগৰ সন্তুলিত গুণগত মান"</item>
+ <item msgid="4681409244565426925">"সংযোগৰ ক্ষমতা অনুযায়ী সৰ্বোত্তম"</item>
+ <item msgid="364670732877872677">"উত্তম প্ৰচেষ্টা (খাপ খাব পৰা বিট ৰেইট)"</item>
+ </string-array>
+ <string-array name="select_logd_size_titles">
+ <item msgid="8665206199209698501">"অফ কৰক"</item>
+ <item msgid="1593289376502312923">"৬৪কে."</item>
+ <item msgid="487545340236145324">"২৫৬কে."</item>
+ <item msgid="2423528675294333831">"১মি."</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"১৬মি."</item>
+ </string-array>
+ <string-array name="select_logd_size_lowram_titles">
+ <item msgid="6089470720451068364">"অফ কৰক"</item>
+ <item msgid="4622460333038586791">"৬৪কে."</item>
+ <item msgid="2212125625169582330">"২৫৬কে."</item>
+ <item msgid="1704946766699242653">"১মি."</item>
+ </string-array>
+ <string-array name="select_logd_size_summaries">
+ <item msgid="6921048829791179331">"অফ কৰক"</item>
+ <item msgid="2969458029344750262">"প্ৰতিটো লগ বাফাৰত ৬৪কে."</item>
+ <item msgid="1342285115665698168">"প্ৰতি লগ বাফাৰত 256K"</item>
+ <item msgid="1314234299552254621">"প্ৰতিটো লগ বাফাৰত ১মি."</item>
+ <item msgid="3606047780792894151">"প্ৰতিটো লগ বাফাৰত ৪মি."</item>
+ <item msgid="5431354956856655120">"প্ৰতিটো লগ বাফাৰত ১৬মি."</item>
+ </string-array>
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"অফ অৱস্থাত আছে"</item>
+ <item msgid="3054662377365844197">"সকলো"</item>
+ <item msgid="688870735111627832">"ৰেডিঅ\'ৰ বাহিৰে সকলো"</item>
+ <item msgid="2850427388488887328">"কেৱল কাৰ্ণেল"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"অফ কৰক"</item>
+ <item msgid="172978079776521897">"সকলো লগ বাফাৰ"</item>
+ <item msgid="3873873912383879240">"ৰেডিঅ\' লগ বাফাৰৰ বাহিৰে সকলো"</item>
+ <item msgid="8489661142527693381">"কেৱল কাৰ্ণেল লগ বাফাৰ"</item>
+ </string-array>
+ <string-array name="window_animation_scale_entries">
+ <item msgid="8134156599370824081">"এনিমেশ্বন অফ"</item>
+ <item msgid="6624864048416710414">"এনিমেশ্বন স্কেল .৫গুণ"</item>
+ <item msgid="2219332261255416635">"এনিমেশ্বন স্কেল ১গুণ"</item>
+ <item msgid="3544428804137048509">"এনিমেশ্বন স্কেল ১.৫গুণ"</item>
+ <item msgid="3110710404225974514">"এনিমেশ্বন স্কেল ২গুণ"</item>
+ <item msgid="4402738611528318731">"এনিমেশ্বন স্কেল ৫গুণ"</item>
+ <item msgid="6189539267968330656">"এনিমেশ্বন স্কেল ১০গু"</item>
+ </string-array>
+ <string-array name="transition_animation_scale_entries">
+ <item msgid="8464255836173039442">"এনিমেশ্বন অফ"</item>
+ <item msgid="3375781541913316411">"এনিমেশ্বন স্কেল .৫গুণ"</item>
+ <item msgid="1991041427801869945">"এনিমেশ্বন স্কেল 1গু"</item>
+ <item msgid="4012689927622382874">"এনিমেশ্বন স্কেল .৫গুণ"</item>
+ <item msgid="3289156759925947169">"এনিমেশ্বন স্কেল ২গুণ"</item>
+ <item msgid="7705857441213621835">"এনিমেশ্বন স্কেল ৫গুণ"</item>
+ <item msgid="6660750935954853365">"এনিমেশ্বন স্কেল ১০গুণ"</item>
+ </string-array>
+ <string-array name="animator_duration_scale_entries">
+ <item msgid="6039901060648228241">"এনিমেশ্বন অফ অৱস্থাত আছে"</item>
+ <item msgid="1138649021950863198">"এনিমেশ্বন স্কেল .৫গুণ"</item>
+ <item msgid="4394388961370833040">"এনিমেশ্বন স্কেল ১গুণ"</item>
+ <item msgid="8125427921655194973">"এনিমেশ্বন স্কেল ১.৫গুণ"</item>
+ <item msgid="3334024790739189573">"এনিমেশ্বন স্কেল ২গুণ"</item>
+ <item msgid="3170120558236848008">"এনিমেশ্বন স্কেল ৫গুণ"</item>
+ <item msgid="1069584980746680398">"এনিমেশ্বন স্কেল ১০গুণ"</item>
+ </string-array>
+ <string-array name="overlay_display_devices_entries">
+ <item msgid="1606809880904982133">"নাই"</item>
+ <item msgid="9033194758688161545">"৪৮০পি."</item>
+ <item msgid="1025306206556583600">"৪৮০পি. (সুৰক্ষিত)"</item>
+ <item msgid="1853913333042744661">"৭২০পি."</item>
+ <item msgid="3414540279805870511">"৭২০পি. (সুৰক্ষিত)"</item>
+ <item msgid="9039818062847141551">"১০৮০পি."</item>
+ <item msgid="4939496949750174834">"১০৮০পি. (সুৰক্ষিত)"</item>
+ <item msgid="1833612718524903568">"4K"</item>
+ <item msgid="238303513127879234">"৪কে. (সুৰক্ষিত)"</item>
+ <item msgid="3547211260846843098">"৪কে. (বৰ্ধিত)"</item>
+ <item msgid="5411365648951414254">"৪কে. (বৰ্ধিত, সুৰক্ষিত)"</item>
+ <item msgid="1311305077526792901">"৭২০পি., ১০৮০পি. (দ্বৈত স্ক্ৰীণ)"</item>
+ </string-array>
+ <string-array name="enable_opengl_traces_entries">
+ <item msgid="3191973083884253830">"নাই"</item>
+ <item msgid="9089630089455370183">"লগকেট"</item>
+ <item msgid="5397807424362304288">"ছিছট্ৰেইচ (গ্ৰাফিক্স)"</item>
+ <item msgid="1340692776955662664">"glGetErrorত কলৰ খাপ"</item>
+ </string-array>
+ <string-array name="show_non_rect_clip_entries">
+ <item msgid="993742912147090253">"অফ কৰক"</item>
+ <item msgid="675719912558941285">"আয়তাকাৰ নোহোৱা ক্লিপ অঞ্চল নীলাৰে আঁকক"</item>
+ <item msgid="1064373276095698656">"পৰীক্ষণ কৰা চিত্ৰাংকণ কমাণ্ডবোৰ সেউজীয়া ৰঙত হাইলাইট কৰক"</item>
+ </string-array>
+ <string-array name="track_frame_time_entries">
+ <item msgid="2193584639058893150">"অফ"</item>
+ <item msgid="2751513398307949636">"স্ক্ৰীণত দণ্ড হিচাপে"</item>
+ <item msgid="2355151170975410323">"<xliff:g id="AS_TYPED_COMMAND">adb shell dumpsys gfxinfo</xliff:g>ত"</item>
+ </string-array>
+ <string-array name="debug_hw_overdraw_entries">
+ <item msgid="8190572633763871652">"বন্ধ কৰক"</item>
+ <item msgid="7688197031296835369">"পিক্সেল একাধিকবাৰ ব্যৱহৃত অংশসমূহ দেখুৱাওক"</item>
+ <item msgid="2290859360633824369">"ডিউটাৰএন\'মেলীৰ অংশসমূহ দেখুৱাওক"</item>
+ </string-array>
+ <string-array name="app_process_limit_entries">
+ <item msgid="3401625457385943795">"মান্য সীমা"</item>
+ <item msgid="4071574792028999443">"নেপথ্যত কোনো প্ৰক্ৰিয়া চলি থকা নাই"</item>
+ <item msgid="4810006996171705398">"সৰ্বাধিক ১টা প্ৰক্ৰিয়া"</item>
+ <item msgid="8586370216857360863">"সৰ্বাধিক ২টা প্ৰক্ৰিয়া"</item>
+ <item msgid="836593137872605381">"সৰ্বাধিক ৩টা প্ৰক্ৰিয়া"</item>
+ <item msgid="7899496259191969307">"সৰ্বাধিক ৪টা প্ৰক্ৰিয়া"</item>
+ </string-array>
+ <string-array name="usb_configuration_titles">
+ <item msgid="488237561639712799">"চ্চাৰ্জ কৰি থকা হৈছে"</item>
+ <item msgid="5220695614993094977">"এমটিপি (মিডিয়া ট্ৰান্সফাৰ প্ৰ’ট’কল)"</item>
+ <item msgid="2086000968159047375">"পিটিপি (পিকচাৰ ট্ৰান্সফাৰ প্ৰ’ট’কল)"</item>
+ <item msgid="7398830860950841822">"RNDIS (USB ইথাৰনেট)"</item>
+ <item msgid="1718924214939774352">"ধ্বনিৰ উৎস"</item>
+ <item msgid="8126315616613006284">"এমআইডিআই"</item>
+ </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
new file mode 100644
index 0000000..b4d1af8
--- /dev/null
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -0,0 +1,466 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** Copyright 2015 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_fail_to_scan" msgid="1265540342578081461">"নেটৱৰ্ক বিচাৰি স্কেন কৰিব পৰা নাই"</string>
+ <string name="wifi_security_none" msgid="7985461072596594400">"নাই"</string>
+ <string name="wifi_remembered" msgid="4955746899347821096">"ছেভ কৰি থোৱা নেটৱৰ্কসমূহ"</string>
+ <string name="wifi_disabled_generic" msgid="4259794910584943386">"নিষ্ক্ৰিয় হৈ আছে"</string>
+ <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP কনফিগাৰেশ্বন বিফল হৈছে"</string>
+ <string name="wifi_disabled_by_recommendation_provider" msgid="5168315140978066096">"নিম্নমানৰ নেটৱৰ্কৰ বাবে সংযোগ কৰা হোৱা নাই"</string>
+ <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"ৱাই-ফাই সংযোগ বিফল হৈছে"</string>
+ <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"সত্য়াপন কৰাত সমস্যা হৈছে"</string>
+ <string name="wifi_cant_connect" msgid="5410016875644565884">"সংযোগ কৰিব নোৱাৰে"</string>
+ <string name="wifi_cant_connect_to_ap" msgid="1222553274052685331">"\'<xliff:g id="AP_NAME">%1$s</xliff:g>\'ৰ সৈতে সংযোগ কৰিব পৰা নাই"</string>
+ <string name="wifi_check_password_try_again" msgid="516958988102584767">"পাছৱৰ্ড পৰীক্ষা কৰি আকৌ চেষ্টা কৰক"</string>
+ <string name="wifi_not_in_range" msgid="1136191511238508967">"পৰিসৰৰ ভিতৰত নাই"</string>
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"স্বয়ংক্ৰিয়ভাৱে সংযোগ নহ\'ব"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"ইণ্টাৰনেট সংযোগ নাই"</string>
+ <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g>এ ছেভ কৰিছে"</string>
+ <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s মাধ্যমেদি স্বয়ংক্ৰিয়ভাৱে সংযোগ কৰা হৈছে"</string>
+ <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"নেটৱৰ্ক ৰেটিং প্ৰদানকাৰীৰ জৰিয়তে স্বয়ং সংয়োগ কৰা হ\'ল"</string>
+ <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s-ৰ মাধ্যমেদি সংযোগ কৰা হৈছে"</string>
+ <string name="available_via_passpoint" msgid="1617440946846329613">"%1$sৰ মাধ্যমেৰে উপলব্ধ"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"সংযোজিত, ইণ্টাৰনেট নাই"</string>
+ <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"একচেছ পইণ্ট কিছু সময়ৰ বাবে পূৰ্ণ হৈ আছে"</string>
+ <string name="connected_via_carrier" msgid="7583780074526041912">"%1$sৰ যোগেৰে সংযোজিত"</string>
+ <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_medium" msgid="3175763313268941953">"মধ্যমীয়া"</string>
+ <string name="speed_label_fast" msgid="7715732164050975057">"দ্ৰুত"</string>
+ <string name="speed_label_very_fast" msgid="2265363430784523409">"অতি দ্ৰুত"</string>
+ <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="bluetooth_disconnected" msgid="6557104142667339895">"সংযোগ বিচ্ছিন্ন কৰা হ’ল"</string>
+ <string name="bluetooth_disconnecting" msgid="8913264760027764974">"সংযোগ বিচ্ছিন্ন কৰি থকা হৈছে…"</string>
+ <string name="bluetooth_connecting" msgid="8555009514614320497">"সংযোগ কৰি থকা হৈছে…"</string>
+ <!-- no translation found for bluetooth_connected (5427152882755735944) -->
+ <skip />
+ <string name="bluetooth_pairing" msgid="1426882272690346242">"যোৰা লগোৱা হৈছে…"</string>
+ <!-- no translation found for bluetooth_connected_no_headset (616068069034994802) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp (3736431800395923868) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_map (3200033913678466453) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp (2047403011284187056) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_battery_level (5162924691231307748) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (1610296229139400266) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (3908466636369853652) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1163440823807659316) -->
+ <skip />
+ <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"মিডিয়াৰ অডিঅ’"</string>
+ <string name="bluetooth_profile_headset" msgid="7815495680863246034">"ফ\'ন কলসমূহ"</string>
+ <string name="bluetooth_profile_opp" msgid="9168139293654233697">"ফাইল স্থানান্তৰণ"</string>
+ <string name="bluetooth_profile_hid" msgid="3680729023366986480">"ইনপুট ডিভাইচ"</string>
+ <string name="bluetooth_profile_pan" msgid="3391606497945147673">"ইণ্টাৰনেট সংযোগ"</string>
+ <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"শ্বেয়াৰিঙৰ সৈতে যোগাযোগ কৰক"</string>
+ <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"সম্পৰ্ক শ্বেয়াৰ কৰিবলৈ ব্যৱহাৰ কৰক"</string>
+ <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"ইণ্টাৰনেট সংযোগ শ্বেয়াৰ"</string>
+ <string name="bluetooth_profile_map" msgid="1019763341565580450">"পাঠ বাৰ্তা"</string>
+ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"ছিম প্ৰৱেশ"</string>
+ <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"এইচ্ছডি অডি\'অ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
+ <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"এইচ্ছডি অডিঅ’"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
+ <skip />
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
+ <skip />
+ <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>
+ <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"মেপৰ সৈতে সংযোগ কৰক"</string>
+ <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAPৰ সৈতে সংযোজিত হৈ আছে"</string>
+ <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ফাইল স্থানান্তৰণ ছাৰ্ভাৰৰ সৈতে সংযোজিত হৈ থকা নাই"</string>
+ <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ইনপুট ডিভাইচৰ সৈতে সংযোজিত হৈ আছে"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"ইণ্টাৰনেটৰ বাবে ডিভাইচৰ সৈতে সংযোজিত"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"ডিভাইচৰ সৈতে স্থানীয় ইণ্টাৰনেট সংযোগ শ্বেয়াৰ কৰা হৈছে"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"ইণ্টাৰনেট চলাবলৈ ব্যৱহাৰ কৰক"</string>
+ <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"মেপৰ বাবে ব্যৱহাৰ কৰক"</string>
+ <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"ছিমত প্ৰৱেশৰ বাবে ব্যৱহাৰ কৰক"</string>
+ <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"মিডিয়া অডিঅ\'ৰ বাবে ব্যৱহাৰ কৰক"</string>
+ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ফ\'ন অডিঅ\'ৰ বাবে ব্যৱহাৰ কৰক"</string>
+ <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ফাইল স্থানান্তৰ কৰিবলৈ ব্যৱহাৰ কৰক"</string>
+ <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ইনপুটৰ বাবে ব্যৱহাৰ কৰক"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
+ <skip />
+ <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"যোৰা লগাওক"</string>
+ <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"যোৰা লগাওক"</string>
+ <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"বাতিল কৰক"</string>
+ <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"যোৰা লগালে ইয়ে সংযোজিত কৰাৰ সময়ত আপোনাৰ সম্পৰ্কসমূহ আৰু কলৰ ইতিহাস চাবলৈ অনুমতি দিব।"</string>
+ <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>ৰ সৈতে যোৰা লগাব পৰা নগ\'ল৷"</string>
+ <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"এটা ভুল পিন বা পাছকীৰ কাৰণে <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ৰ সৈতে যোৰা লগাব পৰা নাই৷"</string>
+ <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>ৰ সৈতে যোগাযোগ কৰিব পৰা নগ\'ল"</string>
+ <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>এ যোৰা লগাব বিচৰা নাই"</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"কম্পিউটাৰ"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"হেডছেট"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"ফ\'ন"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"ইমেজিং"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"হেডফ\'ন"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"ইনপুট সম্পৰ্কীয় বাহ্য় ডিভাইচ"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"ব্লুটুথ"</string>
+ <string name="accessibility_wifi_off" msgid="1166761729660614716">"ৱাই-ফাই অফহৈ আছে।"</string>
+ <string name="accessibility_no_wifi" msgid="8834610636137374508">"ৱাইফাই সংযোগ বিচ্ছিন্ন হৈ আছে।"</string>
+ <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"ৱাই-ফাই এদাল দণ্ড।"</string>
+ <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"ৱাই-ফাইৰ দুডাল দণ্ড।"</string>
+ <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"ৱাই-ফাইৰ তিনিডাল দণ্ড।"</string>
+ <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"ৱাই-ফাই সংকেত সৰ্বোচ্চ।"</string>
+ <string name="accessibility_wifi_security_type_none" msgid="1223747559986205423">"মুক্ত নেটৱৰ্ক"</string>
+ <string name="accessibility_wifi_security_type_secured" msgid="862921720418885331">"সুৰক্ষিত নেটৱৰ্ক"</string>
+ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+ <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"আঁতৰোৱা এপ্সমূহ"</string>
+ <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"আঁতৰোৱা এপ্ আৰু ব্যৱহাৰকাৰীসমূহ"</string>
+ <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB টেডাৰিং"</string>
+ <string name="tether_settings_title_wifi" msgid="3277144155960302049">"প\'ৰ্টেবল হটস্পট"</string>
+ <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ব্লুটুথ টেডাৰিং"</string>
+ <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"টেডাৰ কৰি থকা হৈছে"</string>
+ <string name="tether_settings_title_all" msgid="8356136101061143841">"টেদৰিং আৰু প\'ৰ্টেবল হ\'টস্পট"</string>
+ <string name="managed_user_title" msgid="8109605045406748842">"কৰ্মস্থানৰ সকলো এপ"</string>
+ <string name="user_guest" msgid="8475274842845401871">"অতিথি"</string>
+ <string name="unknown" msgid="1592123443519355854">"অজ্ঞাত"</string>
+ <string name="running_process_item_user_label" msgid="3129887865552025943">"ব্যৱহাৰকাৰী: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+ <string name="launch_defaults_some" msgid="313159469856372621">"কিছুমান ডিফ\'ল্ট ছেট কৰা হৈছে"</string>
+ <string name="launch_defaults_none" msgid="4241129108140034876">"কোনো ডিফ\'ল্ট ছেট কৰা হোৱা নাই"</string>
+ <string name="tts_settings" msgid="8186971894801348327">"পাঠৰ পৰা কথনৰ ছেটিংসমূহ"</string>
+ <string name="tts_settings_title" msgid="1237820681016639683">"পাঠৰ পৰা কথনৰ আউটপুট"</string>
+ <string name="tts_default_rate_title" msgid="6030550998379310088">"কথা কোৱাৰ হাৰ"</string>
+ <string name="tts_default_rate_summary" msgid="4061815292287182801">"পাঠ কথনৰ বেগ"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"পিচ্চ"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"সংশ্লেষিত কথনৰ সুৰক প্ৰভাৱিত কৰে"</string>
+ <string name="tts_default_lang_title" msgid="8018087612299820556">"ভাষা"</string>
+ <string name="tts_lang_use_system" msgid="2679252467416513208">"ছিষ্টেমৰ ভাষা ব্যৱহাৰ কৰক"</string>
+ <string name="tts_lang_not_selected" msgid="7395787019276734765">"ভাষা বাছনি কৰা হোৱা নাই"</string>
+ <string name="tts_default_lang_summary" msgid="5219362163902707785">"কথিত পাঠৰ বাবে ভাষা-নিৰ্দিষ্ট কণ্ঠস্বৰ ছেট কৰে"</string>
+ <string name="tts_play_example_title" msgid="7094780383253097230">"এটা উদাহৰণ মাতি শুনোৱা শুনক"</string>
+ <string name="tts_play_example_summary" msgid="8029071615047894486">"কণ্ঠস্বৰ সংশ্লেষণৰ এটা চুটি উদাহৰণ দেখুৱাওক"</string>
+ <string name="tts_install_data_title" msgid="4264378440508149986">"ভইচ ডেটা ইনষ্টল কৰক"</string>
+ <string name="tts_install_data_summary" msgid="5742135732511822589">"কণ্ঠস্বৰ সংশ্লেষণৰ বাবে দৰকাৰী ভইচ ডেটা ইনষ্টল কৰক"</string>
+ <string name="tts_engine_security_warning" msgid="8786238102020223650">"এই কণ্ঠধ্বনি সংশ্লেষক ইঞ্জিনটোৱে কথিত ব্যক্তিগত ডেটা যেনে পাছৱৰ্ড আৰু ক্ৰেডিট কাৰ্ডৰ নম্বৰ আদিকে ধৰি সকলো পাঠ সংগ্ৰহ কৰবলৈ সক্ষম হ\'ব পাৰে। ই <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g> ইঞ্জিনটোৰ লগত আহিছে। এই কণ্ঠধ্বনি সংশ্লেষক ইঞ্জিনটো সক্ষম কৰিবনে?"</string>
+ <string name="tts_engine_network_required" msgid="1190837151485314743">"পাঠৰ পৰা কথন আউটপুটৰ বাবে এই ভাষাটোক এক কৰ্মক্ষম নেটৱৰ্ক সংযোগৰ দৰকাৰ।"</string>
+ <string name="tts_default_sample_string" msgid="4040835213373086322">"কথনভংগী সংশ্লেষণৰ ই এটা উদাহৰণ"</string>
+ <string name="tts_status_title" msgid="7268566550242584413">"ভাষাৰ ডিফ\'ল্ট স্থিতি"</string>
+ <string name="tts_status_ok" msgid="1309762510278029765">"<xliff:g id="LOCALE">%1$s</xliff:g> সম্পূৰ্ণৰূপে সমৰ্থিত"</string>
+ <string name="tts_status_requires_network" msgid="6042500821503226892">"<xliff:g id="LOCALE">%1$s</xliff:g>ক নেটৱৰ্ক সংযোগৰ দৰকাৰ"</string>
+ <string name="tts_status_not_supported" msgid="4491154212762472495">"<xliff:g id="LOCALE">%1$s</xliff:g> সমৰ্থিত নহয়"</string>
+ <string name="tts_status_checking" msgid="5339150797940483592">"পৰীক্ষা কৰি থকা হৈছে…"</string>
+ <string name="tts_engine_settings_title" msgid="3499112142425680334">"<xliff:g id="TTS_ENGINE_NAME">%s</xliff:g>ৰ বাবে ছেটিংসমূহ"</string>
+ <string name="tts_engine_settings_button" msgid="1030512042040722285">"ইঞ্জিনৰ ছেটিংসমূহ লঞ্চ কৰক"</string>
+ <string name="tts_engine_preference_section_title" msgid="448294500990971413">"অগ্ৰাধিকাৰপ্ৰাপ্ত ইঞ্জিন"</string>
+ <string name="tts_general_section_title" msgid="4402572014604490502">"সাধাৰণ"</string>
+ <string name="tts_reset_speech_pitch_title" msgid="5789394019544785915">"কথনভংগী তীব্ৰতা ৰিছেট কৰক"</string>
+ <string name="tts_reset_speech_pitch_summary" msgid="8700539616245004418">"পাঠ উচ্চাৰণৰ স্বৰ-তীব্ৰতা ৰিছেট কৰক যিটো ডিফল্ট হিচাপে ব্যৱহাৰ কৰা হ\'ব।"</string>
+ <string-array name="tts_rate_entries">
+ <item msgid="6695494874362656215">"অতি লেহেম"</item>
+ <item msgid="4795095314303559268">"লেহেমীয়া"</item>
+ <item msgid="8903157781070679765">"সাধাৰণ"</item>
+ <item msgid="164347302621392996">"দ্ৰুত"</item>
+ <item msgid="5794028588101562009">"দ্ৰুত"</item>
+ <item msgid="7163942783888652942">"অতি দ্ৰুত"</item>
+ <item msgid="7831712693748700507">"দ্ৰুত"</item>
+ <item msgid="5194774745031751806">"অতি দ্ৰুত"</item>
+ <item msgid="9085102246155045744">"দ্ৰুততম"</item>
+ </string-array>
+ <string name="choose_profile" msgid="6921016979430278661">"প্ৰ’ফাইল বাছনি কৰক"</string>
+ <string name="category_personal" msgid="1299663247844969448">"ব্যক্তিগত"</string>
+ <string name="category_work" msgid="8699184680584175622">"কৰ্মস্থান-সম্পৰ্কীয়"</string>
+ <string name="development_settings_title" msgid="215179176067683667">"বিকাশকৰ্তাৰ বিকল্পসমূহ"</string>
+ <string name="development_settings_enable" msgid="542530994778109538">"বিকাশকৰ্তা বিষয়ক বিকল্পসমূহ সক্ষম কৰক"</string>
+ <string name="development_settings_summary" msgid="1815795401632854041">"এপৰ বিকাশৰ বাবে বিকল্পসমূহ ছেট কৰক"</string>
+ <string name="development_settings_not_available" msgid="4308569041701535607">"এইজন ব্যৱহাৰকাৰীৰ বাবে বিকাশকৰ্তাৰ বিকল্পসমূহ উপলব্ধ নহয়"</string>
+ <string name="vpn_settings_not_available" msgid="956841430176985598">"ভিপিএন ছেটিংসমূহ এই ব্যৱহাৰকাৰীজনৰ বাবে উপলব্ধ নহয়"</string>
+ <string name="tethering_settings_not_available" msgid="6765770438438291012">"এই ব্যৱহাৰকাৰীৰ বাবে টেডাৰিং ছেটিংসমূহ উপলব্ধ নহয়"</string>
+ <string name="apn_settings_not_available" msgid="7873729032165324000">"এই ব্যৱহাৰকাৰীৰ বাবে একচেছ পইণ্টৰ নাম ছেটিংসমূহ উপলব্ধ নহয়"</string>
+ <string name="enable_adb" msgid="7982306934419797485">"ইউএছবি ডিবাগিং"</string>
+ <string name="enable_adb_summary" msgid="4881186971746056635">"USB সংযোগ হৈ থকাৰ অৱস্থাত ডিবাগ ম\'ড"</string>
+ <string name="clear_adb_keys" msgid="4038889221503122743">"ইউএছবি ডিবাগিং অনুমতিসমূহ প্ৰত্যাহাৰ কৰক"</string>
+ <string name="bugreport_in_power" msgid="7923901846375587241">"বাগ ৰিপৰ্টৰ শ্ৱৰ্টকাট"</string>
+ <string name="bugreport_in_power_summary" msgid="1778455732762984579">"পাৱাৰ মেনুত বাগ প্ৰতিবেদন গ্ৰহণ কৰিবলৈ এটা বুটাম দেখুৱাওক"</string>
+ <string name="keep_screen_on" msgid="1146389631208760344">"জাগ্ৰত কৰি ৰাখক"</string>
+ <string name="keep_screen_on_summary" msgid="2173114350754293009">"চ্চাৰ্জ হৈ থকাৰ সময়ত স্ক্ৰীণ কেতিয়াও সুপ্ত অৱস্থালৈ নাযায়"</string>
+ <string name="bt_hci_snoop_log" msgid="3340699311158865670">"ব্লুটুথ HCI স্নুপ ল’গ সক্ষম কৰক"</string>
+ <string name="bt_hci_snoop_log_summary" msgid="730247028210113851">"ব্লুটুথ HCI পেকেটসমূহ এটা ফাইলত ৰাখক"</string>
+ <string name="oem_unlock_enable" msgid="6040763321967327691">"ঔইএম আনলক"</string>
+ <string name="oem_unlock_enable_summary" msgid="4720281828891618376">"বুটল\'ডাৰটো আনলক কৰিবলৈ অনুমতি দিয়ক"</string>
+ <string name="confirm_enable_oem_unlock_title" msgid="4802157344812385674">"ঔইএম আনলক কৰাৰ অনুমতি দিবনে?"</string>
+ <string name="confirm_enable_oem_unlock_text" msgid="5517144575601647022">"সাৱধান: এই ছেটিংটো সক্ষম কৰি থাকোতে ডিভাইচৰ সুৰক্ষা সুবিধাসমূহে কাম নকৰিব।"</string>
+ <string name="mock_location_app" msgid="7966220972812881854">"নকল অৱস্থানৰ এপ্ বাছনি কৰক"</string>
+ <string name="mock_location_app_not_set" msgid="809543285495344223">"কোনো নকল অৱস্থান এপ্ নিৰ্ধাৰণ কৰা হোৱা নাই"</string>
+ <string name="mock_location_app_set" msgid="8966420655295102685">"নকল অৱস্থানৰ এপ্: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="debug_networking_category" msgid="7044075693643009662">"নেটৱৰ্কিং"</string>
+ <string name="wifi_display_certification" msgid="8611569543791307533">"বেতাঁৰ ডিছপ্লে প্ৰমাণীকৰণ"</string>
+ <string name="wifi_verbose_logging" msgid="4203729756047242344">"ৱাই-ফাই ভাৰ্ব\'ছ লগিং সক্ষম কৰক"</string>
+ <!-- no translation found for wifi_connected_mac_randomization (3168165236877957767) -->
+ <skip />
+ <string name="mobile_data_always_on" msgid="8774857027458200434">"ম\'বাইল ডেটা সদা-সক্ৰিয়"</string>
+ <string name="tethering_hardware_offload" msgid="7470077827090325814">"টেডাৰিং হাৰ্ডৱেৰ ত্বৰণ"</string>
+ <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"নামবিহীন ব্লুটুথ ডিভাইচসমূহ দেখুৱাওক"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"পূৰ্ণ মাত্ৰাৰ ভলিউম অক্ষম কৰক"</string>
+ <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"ব্লুটুথ AVRCP সংস্কৰণ"</string>
+ <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"ব্লুটুথ AVRCP সংস্কৰণ বাছনি কৰক"</string>
+ <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ব্লুটুথ অডিঅ’ ক’ডেক"</string>
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"ব্লুটুথ অডিঅ’ ক’ডেক বাছনি কৰক"</string>
+ <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"ব্লুটুথ অডিঅ\' ছেম্পল ৰেইট"</string>
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"ব্লুটুথ অডিঅ\' ক\'ডেক বাছনি কৰক:\nনমুনাৰ হাৰ"</string>
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"প্ৰতি ছেম্পলত ব্লুটুথ অডিঅ\' বিটসমূহ"</string>
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"ব্লুটুথ অডিঅ\' ক\'ডেক বাছনি কৰক:\nবিট প্ৰতি নমুনা"</string>
+ <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"ব্লুটুথ অডিঅ\' চেনেল ম\'ড"</string>
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"ব্লুটুথ অডিঅ\' ক\'ডেক বাছনি কৰক:\nচ্চেনেল ম\'ড"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"ব্লুটুথ অডিঅ’ LDAC ক’ডেক: পৰিৱেশনৰ মান"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"ব্লুটুথ LDAC ক\'ডেক বাছনি কৰক:\nপৰিৱেশনৰ মান"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"ষ্ট্ৰীম কৰি থকা হৈছে: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
+ <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>
+ <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>
+ <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"ৱাই-ফাই লগিঙৰ মাত্ৰা বঢ়াওক, Wi‑Fi পিকাৰত প্ৰতি SSID RSSI দেখুৱাওক"</string>
+ <!-- no translation found for wifi_connected_mac_randomization_summary (1743059848752201485) -->
+ <skip />
+ <string name="select_logd_size_title" msgid="7433137108348553508">"লগাৰৰ বাফাৰৰ আকাৰ"</string>
+ <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"প্ৰতিটো লগ বাফাৰত ল\'গাৰৰ আকাৰ বাছনি কৰক"</string>
+ <string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"লগাৰৰ স্থায়ী সঞ্চয়াগাৰৰ বস্তুবোৰ মচিবনে?"</string>
+ <string name="dev_logpersist_clear_warning_message" msgid="2256582531342994562">"পাৰ্ছিছটেণ্ট লগাৰ ব্যৱহাৰ কৰ নিৰীক্ষণ নকৰাৰ সময়ত, আমি আপোনাৰ ডিভাইচত থকা লগাৰ ডেটা নিৱাসীক মচা দৰকাৰ।"</string>
+ <string name="select_logpersist_title" msgid="7530031344550073166">"ডিভাইচটোত লগাৰৰ ডেটা নিৰবচ্ছিন্নভাৱে সঞ্চয় কৰক"</string>
+ <string name="select_logpersist_dialog_title" msgid="4003400579973269060">"ডিভাইচত স্থায়ীভাৱে সঞ্চয় কৰিবলৈ লগ বাফাৰবোৰ বাছনি কৰক"</string>
+ <string name="select_usb_configuration_title" msgid="2649938511506971843">"ইউএছবি কনফিগাৰেশ্বন বাছনি কৰক"</string>
+ <string name="select_usb_configuration_dialog_title" msgid="6385564442851599963">"ইউএছবি কনফিগাৰেশ্বন বাছনি কৰক"</string>
+ <string name="allow_mock_location" msgid="2787962564578664888">"নকল অৱস্থানৰ অনুমতি দিয়ক"</string>
+ <string name="allow_mock_location_summary" msgid="317615105156345626">"নকল অৱস্থানৰ অনুমতি দিয়ক"</string>
+ <string name="debug_view_attributes" msgid="6485448367803310384">"দৃশ্যৰ গুণাগুণ নিৰীক্ষণ সক্ষম কৰক"</string>
+ <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"ৱাই-ফাই থকা সময়তো সদায় ম\'বাইল ডেটা সক্ৰিয় ৰাখক (খৰতকীয়াকৈ নেটৱৰ্ক সলনি কৰিবৰ বাবে)।"</string>
+ <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"যদিহে উপলব্ধ হয় তেন্তে টেডাৰিং হাৰ্ডৱেৰ ত্বৰণ ব্যৱহাৰ কৰক"</string>
+ <string name="adb_warning_title" msgid="6234463310896563253">"ইউএছবি ডিবাগিঙৰ অনুমতি দিয়েনে?"</string>
+ <string name="adb_warning_message" msgid="7316799925425402244">"ইউএছবি ডিবাগ কৰা কাৰ্য কেৱল বিকাশৰ উদ্দেশ্যৰেহে কৰা হৈছে৷ আপোনাৰ কম্পিউটাৰ আৰু আপোনাৰ ডিভাইচৰ মাজত ডেটা প্ৰতিলিপি কৰিবলৈ এইটো ব্যৱহাৰ কৰক, কোনো জাননী নিদিয়াকৈয়ে আপোনাৰ ডিভাইচত এপ্সমূহ ইনষ্টল কৰক আৰু লগ ডেটা পঢ়ক৷"</string>
+ <string name="adb_keys_warning_message" msgid="5659849457135841625">"আপুনি আগতে ইউএছবি ডিবাগিঙৰ বাবে প্ৰৱেশৰ অনুমতি দিয়া সকলো কম্পিউটাৰৰ পৰা সেই অনুমতি প্ৰত্যাহাৰ কৰেনে?"</string>
+ <string name="dev_settings_warning_title" msgid="7244607768088540165">"বিকাশৰ কামৰ বাবে থকা ছেটিংবিলাকক অনুমতি দিবনে?"</string>
+ <string name="dev_settings_warning_message" msgid="2298337781139097964">"এই ছেটিংসমূহ বিকাশৰ কামত ব্যৱহাৰ কৰিবলৈ তৈয়াৰ কৰা হৈছে। সেইবিলাকে আপোনাৰ ডিভাইচ আৰু তাত থকা এপ্লিকেশ্বনসমূহক অকামিলা কৰি পেলাব পাৰে আৰু সেইবিলাকৰ কাৰণে এপ্লিকেশ্বনসমূহে অদ্ভুত আচৰণ কৰিব পাৰে।"</string>
+ <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"ইউএছবিৰ যোগেৰে এপৰ সত্যাপন কৰক"</string>
+ <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADTৰ যোগেৰে ইনষ্টল কৰা এপসমূহে কিবা ক্ষতিকাৰক আচৰণ কৰিছে নেকি পৰীক্ষা কৰক।"</string>
+ <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"নামহীন ব্লুটুথ ডিভাইচসমূহ (মাত্ৰ MAC ঠিকনাযুক্ত) দেখুওৱা হ\'ব"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ৰিম\'ট ডিভাইচবিলাকৰ সৈতে ভলিউম সম্পৰ্কীয় সমস্যা, যেনেকৈ অতি উচ্চ ভলিউম বা নিয়ন্ত্ৰণ কৰিবই নোৱাৰা অৱস্থাত ব্লুটুথৰ পূৰ্ণ ভলিউম সুবিধা অক্ষম কৰে।"</string>
+ <string name="enable_terminal_title" msgid="95572094356054120">"স্থানীয় টাৰ্মিনেল"</string>
+ <string name="enable_terminal_summary" msgid="67667852659359206">"স্থানীয় শ্বেল প্ৰৱেশাধিকাৰ দিয়া টাৰ্মিনেল এপ্ সক্ষম কৰক"</string>
+ <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP পৰীক্ষণ"</string>
+ <string name="hdcp_checking_dialog_title" msgid="5141305530923283">"HDCP পৰীক্ষণ আচৰণ ছেট কৰক"</string>
+ <string name="debug_debugging_category" msgid="6781250159513471316">"ডিবাগিং"</string>
+ <string name="debug_app" msgid="8349591734751384446">"ডিবাগ এপ্ বাছনি কৰক"</string>
+ <string name="debug_app_not_set" msgid="718752499586403499">"কোনো ডিবাগ এপ্লিকেশ্বন ছেট কৰা হোৱা নাই"</string>
+ <string name="debug_app_set" msgid="2063077997870280017">"ডিবাগিং এপ্লিকেশ্বন: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="select_application" msgid="5156029161289091703">"এপ্লিকেশ্বন বাছনি কৰক"</string>
+ <string name="no_application" msgid="2813387563129153880">"একোৱেই নাই"</string>
+ <string name="wait_for_debugger" msgid="1202370874528893091">"ডিবাগাৰৰ বাবে অপেক্ষা কৰক"</string>
+ <string name="wait_for_debugger_summary" msgid="1766918303462746804">"ডিবাগ কৰা এপ্লিকেশ্বনবোৰে কাৰ্য ৰূপায়ণ কৰাৰ আগতে ডিবাগাৰ সংলগ্ন হোৱা কাৰ্যলৈ অপেক্ষা কৰে"</string>
+ <string name="debug_input_category" msgid="1811069939601180246">"ইনপুট"</string>
+ <string name="debug_drawing_category" msgid="6755716469267367852">"অংকন"</string>
+ <string name="debug_hw_drawing_category" msgid="6220174216912308658">"হাৰ্ডৱেৰৰদ্বাৰা ত্বৰিত ৰেণ্ডাৰিং"</string>
+ <string name="media_category" msgid="4388305075496848353">"মিডিয়া"</string>
+ <string name="debug_monitoring_category" msgid="7640508148375798343">"নিৰীক্ষণ কৰি থকা হৈছে"</string>
+ <string name="strict_mode" msgid="1938795874357830695">"কঠোৰ ম’ড সক্ষম কৰা হৈছে"</string>
+ <string name="strict_mode_summary" msgid="142834318897332338">"যেতিয়া এপসমূহে মুখ্য থ্ৰেডত দীঘলীয়া কাৰ্যকলাপ চলাই, তেতিয়া স্ক্ৰীণ ফ্লাশ্ব কৰক"</string>
+ <string name="pointer_location" msgid="6084434787496938001">"পইণ্টাৰৰ অৱস্থান"</string>
+ <string name="pointer_location_summary" msgid="840819275172753713">"চলিত স্পৰ্শ-বিষয়ক তথ্যসহ স্ক্ৰীণ অভাৰলে\'"</string>
+ <string name="show_touches" msgid="2642976305235070316">"টেপসমূহ দেখুৱাওক"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"টিপিলে দৃশ্যায়িত ফীডবেক দিয়ক"</string>
+ <string name="show_screen_updates" msgid="5470814345876056420">"পৃষ্ঠভাগৰ আপডেইট দেখুৱাওক"</string>
+ <string name="show_screen_updates_summary" msgid="2569622766672785529">"আপডেইট হওতে গোটেই ৱিণ্ড পৃষ্ঠসমূহ ফ্লাশ্ব কৰক"</string>
+ <string name="show_hw_screen_updates" msgid="5036904558145941590">"জিপিইউৰ দৰ্শন আপডেইটসমূহ দেখুৱাওক"</string>
+ <string name="show_hw_screen_updates_summary" msgid="1115593565980196197">"জিপিইউৰ জৰিয়তে অঁকাৰ সময়ত ৱিণ্ড’ৰ ভিতৰত ফ্লাশ্ব দৰ্শন"</string>
+ <string name="show_hw_layers_updates" msgid="5645728765605699821">"হাৰ্ডৱেৰৰ তৰপৰ আপডেইট দেখুৱাওক"</string>
+ <string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"হাৰ্ডৱেৰ লেয়াৰ আপডেইট হওতে সিঁহতক সেউজীয়া ৰঙেৰে ফ্লাশ্ব কৰক"</string>
+ <string name="debug_hw_overdraw" msgid="2968692419951565417">"GPU অভাৰড্ৰ ডিবাগ কৰক"</string>
+ <string name="disable_overlays" msgid="2074488440505934665">"HW অ’ভাৰলে অক্ষম কৰক"</string>
+ <string name="disable_overlays_summary" msgid="3578941133710758592">"স্ক্ৰীণ কম্প’জিট কৰাৰ বাবে সদায় জিপিইউ ব্যৱহাৰ কৰক"</string>
+ <string name="simulate_color_space" msgid="6745847141353345872">"ৰঙৰ ঠাই ছিমিউলেইট কৰক"</string>
+ <string name="enable_opengl_traces_title" msgid="6790444011053219871">"OpenGL ট্ৰেছ সক্ষম কৰক"</string>
+ <string name="usb_audio_disable_routing" msgid="8114498436003102671">"ইউএছবি অডিঅ\' ৰাউটিং অক্ষম কৰক"</string>
+ <string name="usb_audio_disable_routing_summary" msgid="980282760277312264">"স্বয়ংক্ৰিয়ভাৱে ইউএছবি ধ্বনিৰ আনুষংগিক আহিলাবিলাকলৈ ৰাউটিং কৰাটো অক্ষম কৰক"</string>
+ <string name="debug_layout" msgid="5981361776594526155">"লেআউটৰ সময় দেখুৱাওক"</string>
+ <string name="debug_layout_summary" msgid="2001775315258637682">"ক্লিপ বাউণ্ড, মাৰ্জিন আদিসমূহ দেখুৱাওক"</string>
+ <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"আৰটিএল চানেকিৰ দিশ বলেৰে সলনি কৰক"</string>
+ <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"সকলো ভাষাৰ বাবে স্ক্ৰীণৰ চানেকিৰ দিশ RTLলৈ বলেৰে সলনি কৰক"</string>
+ <string name="force_hw_ui" msgid="6426383462520888732">"জিপিইউ ৰেণ্ডাৰিং বলেৰে ব্যৱহাৰ কৰক"</string>
+ <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d চিত্ৰাংকনৰ বাবে GPUক বলেৰে ব্যৱহাৰ কৰক"</string>
+ <string name="force_msaa" msgid="7920323238677284387">"বল ৪গুণ MSAA"</string>
+ <string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0 এপত ৪গুণ MSAA সক্ষম কৰক"</string>
+ <string name="show_non_rect_clip" msgid="505954950474595172">"আয়তাকৃতিৰ নোহোৱা ক্লিপ প্ৰক্ৰিয়াসমূহ ডিবাগ কৰক"</string>
+ <string name="track_frame_time" msgid="6146354853663863443">"প্ৰ\'ফাইল জিপিইউ ৰেণ্ডাৰিং"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"জিপিইউ ডিবাগ স্তৰবোৰ সক্ষম কৰক"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"ডিবাগ এপসমূহৰ বাবে জিপিইউ ডিবাগ তৰপ ল\'ড কৰিবলৈ অনুমতি দিয়ক"</string>
+ <string name="window_animation_scale_title" msgid="6162587588166114700">"ৱিণ্ড\' এনিমেশ্বন স্কেল"</string>
+ <string name="transition_animation_scale_title" msgid="387527540523595875">"ট্ৰাঞ্জিশ্বন এনিমেশ্বন স্কেল"</string>
+ <string name="animator_duration_scale_title" msgid="3406722410819934083">"এনিমেটৰ কালদৈৰ্ঘ্য স্কেল"</string>
+ <string name="overlay_display_devices_title" msgid="5364176287998398539">"গৌণ প্ৰদৰ্শনৰ নকল বনাওক"</string>
+ <string name="debug_applications_category" msgid="4206913653849771549">"এপসমূহ"</string>
+ <string name="immediately_destroy_activities" msgid="1579659389568133959">"কাৰ্যকলাপসমূহ নাৰাখিব"</string>
+ <string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"ব্যৱহাৰকাৰী ওলোৱাৰ লগে লগে সকলো কাৰ্যকলাপ মচক"</string>
+ <string name="app_process_limit_title" msgid="4280600650253107163">"নেপথ্যত চলা প্ৰক্ৰিয়াৰ সীমা"</string>
+ <string name="show_all_anrs" msgid="28462979638729082">"সকলো এএনআৰ দেখুৱাওক"</string>
+ <string name="show_all_anrs_summary" msgid="641908614413544127">"নেপথ্য এপসমূহৰ বাবে এপে সঁহাৰি দিয়া নাই মন্তব্য দেখুৱাওক"</string>
+ <string name="show_notification_channel_warnings" msgid="1399948193466922683">"জাননী চ্চেনেলৰ সকীয়নিসমূহ দেখুৱাওক"</string>
+ <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"কোনো এপে বৈধ চ্চেনেল নোহোৱাকৈ কোনো জাননী প\'ষ্ট কৰিলে স্ক্ৰীণত সকীয়নি প্ৰদৰ্শন হয়"</string>
+ <string name="force_allow_on_external" msgid="3215759785081916381">"বাহ্যিক সঞ্চয়াগাৰত এপক বলেৰে অনুমতি দিয়ক"</string>
+ <string name="force_allow_on_external_summary" msgid="3640752408258034689">"মেনিফেষ্টৰ মান যিয়েই নহওক, বাহ্যিক সঞ্চয়াগাৰত লিখিবলৈ যিকোনো এপক উপযুক্ত কৰি তোলে"</string>
+ <string name="force_resizable_activities" msgid="8615764378147824985">"বলেৰে কাৰ্যকলাপসমূহৰ আকাৰ সলনি কৰিব পৰা কৰক"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"মেনিফেষ্টৰ মান যিয়েই নহওক, মাল্টি-ৱিণ্ডৰ বাবে সকলো কাৰ্যকলাপৰ আকাৰ সলনি কৰিব পৰা কৰক।"</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"ফ্ৰিফৰ্ম ৱিণ্ড\'জ সক্ষম কৰক"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"পৰীক্ষামূলক ফ্ৰী-ফৰ্ম ৱিণ্ড’বোৰৰ বাবে সহায়তা সক্ষম কৰক৷"</string>
+ <string name="local_backup_password_title" msgid="3860471654439418822">"ডেস্কটপ বেকআপ পাছৱৰ্ড"</string>
+ <string name="local_backup_password_summary_none" msgid="6951095485537767956">"ডেস্কটপৰ পূৰ্ণ বেকআপ এতিয়ালৈকে সংৰক্ষিত অৱস্থাত নাই"</string>
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"ডেস্কটপ সম্পূৰ্ণ বেকআপৰ বাবে পাছৱৰ্ডটো সলনি কৰিবলৈ বা আঁতৰাবলৈ টিপক"</string>
+ <string name="local_backup_password_toast_success" msgid="582016086228434290">"নতুন বেকআপ পাছৱৰ্ড ছেট কৰা হ\'ল"</string>
+ <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"নতুন পাছৱৰ্ডটোৰ লগত নিশ্চিত কৰা পাছৱৰ্ডটো মিলা নাই"</string>
+ <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"বেকআপ পাছৱৰ্ড নিৰ্ধাৰণ কৰিব পৰা নহ\'ল"</string>
+ <string-array name="color_mode_names">
+ <item msgid="2425514299220523812">"জীৱন্ত (ডিফল্ট)"</item>
+ <item msgid="8446070607501413455">"প্ৰাকৃতিক"</item>
+ <item msgid="6553408765810699025">"মানক"</item>
+ </string-array>
+ <string-array name="color_mode_descriptions">
+ <item msgid="4979629397075120893">"বৰ্ধিত ৰং"</item>
+ <item msgid="8280754435979370728">"চকুৱে দেখা পোৱা ধৰণৰ প্ৰাকৃতিক ৰং"</item>
+ <item msgid="5363960654009010371">"ডিজিটেল সমলৰ বাবে ৰং অপ্টিমাইজ কৰা হৈছে"</item>
+ </string-array>
+ <!-- no translation found for inactive_apps_title (9042996804461901648) -->
+ <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"নিষ্ক্ৰিয়। ট\'গল কৰিবলৈ টিপক।"</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"সক্ৰিয়। ট\'গল কৰিবলৈ টিপক।"</string>
+ <!-- no translation found for standby_bucket_summary (6567835350910684727) -->
+ <skip />
+ <string name="runningservices_settings_title" msgid="8097287939865165213">"চলিত সেৱা"</string>
+ <string name="runningservices_settings_summary" msgid="854608995821032748">"বৰ্তমান চলি থকা সেৱাসমূহ চাওক আৰু নিয়ন্ত্ৰণ কৰক"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"ৱেবভিউ প্ৰয়োগ"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"ৱেবভিউ প্ৰয়োগ ছেট কৰক"</string>
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"বাছনিটো এতিয়া আৰু মান্য় নহয়। আকৌ চেষ্টা কৰক।"</string>
+ <string name="convert_to_file_encryption" msgid="3060156730651061223">"ফাইল এনক্ৰিপশ্বন কৰিবলৈ ৰূপান্তৰ কৰক"</string>
+ <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ৰূপান্তৰ কৰক…"</string>
+ <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ফাইল ইতিমধ্যে এনক্ৰিপ্ট কৰা হৈছে"</string>
+ <string name="title_convert_fbe" msgid="1263622876196444453">"ফাইল-ভিত্তিক এনক্ৰিপশ্বনলৈ ৰূপান্তৰ কৰা হৈছে"</string>
+ <string name="convert_to_fbe_warning" msgid="6139067817148865527">"ডেটা বিভাজনক ফাইল ভিত্তিক এনক্ৰিপশ্বনলৈ সলনি কৰক।\n !!সাৱধান!! ই আপোনাৰ সকলো ডেটা মচিব।\n এই সুবিধাটো আলফা পৰীক্ষণ অৱস্থাত আছে গতিকে ই সঠিকভাৱে কাম নকৰিব পাৰে।\n অব্যাহত ৰাখিবলৈ \'মচক আৰু ৰূপান্তৰ কৰক…\' দবাওক।"</string>
+ <string name="button_convert_fbe" msgid="5152671181309826405">"মচক আৰু ৰূপান্তৰ কৰক…"</string>
+ <string name="picture_color_mode" msgid="4560755008730283695">"চিত্ৰৰ ৰং ম’ড"</string>
+ <string name="picture_color_mode_desc" msgid="1141891467675548590">"এছআৰজিবি ব্যৱহাৰ কৰক"</string>
+ <string name="daltonizer_mode_disabled" msgid="7482661936053801862">"নিষ্ক্ৰিয় হৈ আছে"</string>
+ <string name="daltonizer_mode_monochromacy" msgid="8485709880666106721">"ম\'ন\'ক্ৰ\'মেচী"</string>
+ <string name="daltonizer_mode_deuteranomaly" msgid="5475532989673586329">"ডিউটাৰএন\'মেলী (ৰঙা-সেউজীয়া)"</string>
+ <string name="daltonizer_mode_protanomaly" msgid="8424148009038666065">"প্ৰ’টানোমালি (ৰঙা-সেউজীয়া)"</string>
+ <string name="daltonizer_mode_tritanomaly" msgid="481725854987912389">"ট্ৰাইটান\'মেলী (নীলা-হালধীয়া)"</string>
+ <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"ৰং শুধৰণী"</string>
+ <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>
+ <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>
+ <string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> বাকী"</string>
+ <!-- no translation found for power_remaining_less_than_duration_only (5996752448813295329) -->
+ <skip />
+ <!-- no translation found for power_remaining_less_than_duration (7967078125657859046) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (6846716609975752316) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8884488700395194194) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (8168317165722752881) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (5957064378548718872) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (9055596817716471373) -->
+ <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) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (261050880878965621) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (2020049829798578618) -->
+ <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_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>
+ <string name="battery_info_status_charging_lower" msgid="8689770213898117994">"চ্চাৰ্জ হৈ আছে"</string>
+ <string name="battery_info_status_discharging" msgid="310932812698268588">"চ্চাৰ্জ কৰা নাই"</string>
+ <string name="battery_info_status_not_charging" msgid="8523453668342598579">"প্লাগ কৰি থোৱা হৈছে, এই মুহূৰ্তত চ্চাৰ্জ কৰিব নোৱাৰি"</string>
+ <string name="battery_info_status_full" msgid="2824614753861462808">"পূৰ্ণ"</string>
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"এডমিনৰ দ্বাৰা নিয়ন্ত্ৰিত"</string>
+ <string name="enabled_by_admin" msgid="5302986023578399263">"প্ৰশাসকে সক্ষম কৰিছে"</string>
+ <string name="disabled_by_admin" msgid="8505398946020816620">"এডমিনে অক্ষম কৰিছে ৰাখিছে"</string>
+ <string name="disabled" msgid="9206776641295849915">"নিষ্ক্ৰিয়"</string>
+ <string name="external_source_trusted" msgid="2707996266575928037">"অনুমতি দিয়া হৈছে"</string>
+ <string name="external_source_untrusted" msgid="2677442511837596726">"অনুমতি দিয়া হোৱা নাই"</string>
+ <string name="install_other_apps" msgid="6986686991775883017">"অজ্ঞাত এপ্ ইনষ্টল কৰক"</string>
+ <string name="home" msgid="3256884684164448244">"ছেটিংসমূহৰ গৃহপৃষ্ঠা"</string>
+ <string-array name="battery_labels">
+ <item msgid="8494684293649631252">"০%"</item>
+ <item msgid="8934126114226089439">"৫০%"</item>
+ <item msgid="1286113608943010849">"১০০%"</item>
+ </string-array>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> আগত"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> বাকী আছে"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"সৰু"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ডিফ’ল্ট"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"ডাঙৰ"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"বৃহত্তৰ"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"সকলোতকৈ ডাঙৰ"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"নিজৰ উপযোগিতা অনুযায়ী (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
+ <string name="help_feedback_label" msgid="6815040660801785649">"সহায় আৰু ফীডবেক"</string>
+ <string name="content_description_menu_button" msgid="8182594799812351266">"মেনু"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"ডেম’ ম\'ডত ফেক্টৰী ৰিছেট কৰিবলৈ পাছৱৰ্ড দিয়ক"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"পৰৱৰ্তী"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"পাছৱৰ্ড দৰকাৰী"</string>
+ <string name="active_input_method_subtypes" msgid="3596398805424733238">"সক্ৰিয়হৈ থকা ইনপুট পদ্ধতিসমূহ"</string>
+ <string name="use_system_language_to_select_input_method_subtypes" msgid="5747329075020379587">"ছিষ্টেমৰ ভাষা ব্যৱহাৰ কৰক"</string>
+ <string name="failed_to_open_app_settings_toast" msgid="1251067459298072462">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g>ৰ ছেটিংবিলাক খুলিব পৰা নগ\'ল"</string>
+ <string name="ime_security_warning" msgid="4135828934735934248">"এই ইনপুট পদ্ধতিটোৱে আপুনি টাইপ কৰা আপোনাৰ ব্যক্তিগত ডেটা যেনে পাছৱৰ্ডসমূহ আৰু ক্ৰেডিট কাৰ্ডৰ নম্বৰসমূহকে ধৰি সকলো পাঠ সংগ্ৰহ কৰিবলৈ সক্ষম হ\'ব পাৰে। <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> এপটোৰ লগত ই সংলগ্ন। এই ইনপুট পদ্ধতিটো ব্যৱহাৰ কৰেনে?"</string>
+ <string name="direct_boot_unaware_dialog_message" msgid="7870273558547549125">"টোকা: ৰিবুট কৰাৰ পিছত আপুনি ফ\'নটো আনলক নকৰালৈকে এই এপটো ষ্টাৰ্ট নহ\'ব"</string>
+ <string name="ims_reg_title" msgid="7609782759207241443">"আইএমএছ পঞ্জীয়ন স্থিতি"</string>
+ <string name="ims_reg_status_registered" msgid="933003316932739188">"পঞ্জীকৃত"</string>
+ <string name="ims_reg_status_not_registered" msgid="6529783773485229486">"পঞ্জীকৃত নহয়"</string>
+ <string name="status_unavailable" msgid="7862009036663793314">"উপলব্ধ নহয়"</string>
+ <!-- no translation found for wifi_tether_connected_summary (3871603864314407780) -->
+ <!-- no translation found for accessibility_manual_zen_more_time (1636187409258564291) -->
+ <skip />
+ <!-- no translation found for accessibility_manual_zen_less_time (6590887204171164991) -->
+ <skip />
+ <!-- no translation found for zen_mode_enable_dialog_turn_on (8287824809739581837) -->
+ <skip />
+ <string name="cancel" msgid="6859253417269739139">"বাতিল কৰক"</string>
+ <!-- no translation found for zen_mode_settings_turn_on_dialog_title (2297134204747331078) -->
+ <skip />
+ <string name="zen_mode_settings_summary_off" msgid="6119891445378113334">"কেতিয়াও নহয়"</string>
+ <!-- no translation found for zen_interruption_level_priority (2078370238113347720) -->
+ <skip />
+ <!-- no translation found for zen_mode_and_condition (4927230238450354412) -->
+ <skip />
+ <!-- no translation found for zen_alarm_warning_indef (3007988140196673193) -->
+ <skip />
+ <!-- no translation found for zen_alarm_warning (6236690803924413088) -->
+ <skip />
+ <!-- no translation found for alarm_template (4996153414057676512) -->
+ <skip />
+ <!-- no translation found for alarm_template_far (3779172822607461675) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 97ccf91..1a0a251 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"Доступ да SIM-карты"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Слыхавы апарат"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Выкарыстоўваць для аўдыё тэлефона"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Выкарыстоўваць для перадачы файлаў"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Выкарыстоўваць для ўводу"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Выкарыстоўваць для слыхавога апарата"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Падлучыць"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"СПАЛУЧЫЦЬ"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Скасаваць"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 9bde546..d071c64 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"Достъп до SIM картата"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Висококачествено аудио: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Висококачествено аудио"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Слухов апарат"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Използване на телефон за аудио"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Използване на за пренос на файлове"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Да се използва за въвеждане"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Използване за слухов апарат"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Сдвояване"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"СДВОЯВАНЕ"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Отказ"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 28b879bd..baa31e6 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"সিম -এর অ্যাক্সেস"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"হিয়ারিং এড"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ফোন অডিওয়ের জন্য ব্যবহার করুন"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ফাইল স্থানান্তরের জন্য ব্যবহার করুন"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ইনপুটের জন্য ব্যবহার করুন"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"শ্রবণ যন্ত্রের জন্য ব্যবহার করুন"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"যুক্ত করুন"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"যুক্ত করুন"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"বাতিল করুন"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 998ef58..fe1c6bc 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"Πρόσβαση SIM"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Βοήθημα ακοής"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Χρήση για ήχο τηλεφώνου"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Χρήση για τη μεταφορά αρχείων"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Χρήση για είσοδο"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Χρήση για βοήθημα ακοής"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Σύζευξη"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ΣΥΖΕΥΞΗ"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Ακύρωση"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index f38643f..bf62e59 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"Acceso SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Audio en HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Audio en HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Audífonos"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Conectado a un audífono"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Conectado al audio multimedia"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Conectado al audio del dispositivo"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Conectado al servidor de transferencia de archivo"</string>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Utilizar para el audio del dispositivo"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Utilizar para la transferencia de archivos"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Utilizar para entrada"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Usar con audífonos"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Vincular"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SINCRONIZAR"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancelar"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 382a514..77d55ff 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM-kaardi juurdepääs"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD-heli: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD-heli"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Kuuldeaparaat"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Kuuldeaparaadiga ühendatud"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Ühendatud meediumiheliga"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Ühendatud telefoniheliga"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Ühendatud failiedastuse serveriga"</string>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Kasuta telefoniheli jaoks"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Kasutage failide edastamiseks"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Kasutage sisendi jaoks"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Kuuldeaparaadiga kasutamiseks"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Seo"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SEO"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Tühista"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 15fe55b..effcd47 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"Acceso á SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Audio en HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Audio en HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Audiófonos"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Conectouse aos audiófonos"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Conectado ao audio multimedia"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Conectado ao audio do teléfono"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Conectado ao servidor de transferencia de ficheiros"</string>
@@ -95,8 +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>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Usar para o audiófono"</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>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 617230e..c517b8b 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"સિમ ઍક્સેસ"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"સાંભળવામાં સહાય આપતું યંત્ર"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ફોન ઑડિઓ માટે ઉપયોગ કરો"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ફાઇલ સ્થાનાંતર માટે ઉપયોગ કરો"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ઇનપુટ માટે ઉપયોગ કરો"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"સાંભળવામાં સહાય આપતા યંત્ર માટે ઉપયોગ કરો"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"જોડી"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"જોડાણ બનાવો"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"રદ કરો"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 4a12196..2726c46 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"सिम ऐक्सेस"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"सुनने में मददगार डिवाइस"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"फ़ोन ऑडियो के लिए उपयोग करें"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"फ़ाइल स्थानांतरण के लिए उपयोग करें"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"इनपुट के लिए उपयोग करें"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"सुनने में मददगार डिवाइस के लिए इस्तेमाल करें"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"युग्म बनाएं"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"दूसरे डिवाइस से जोड़ें"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"रद्द करें"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 8e5cf7d..35a5560 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM-elérés"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD audio"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Hallókészülék"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Csatlakoztatva a hallókészülékhez"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Csatlakoztatva az eszköz hangjához"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Csatlakoztatva a telefon hangjához"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Csatlakozva a fájlküldő szerverhez"</string>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Felhasználás a telefon hangjához"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Felhasználás fájlátvitelre"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Használat beviteli eszközként"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Használat hallókészülékhez"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Párosítás"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PÁROSÍTÁS"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Mégse"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index e5e5beb..44a1714 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM քարտի հասանելիություն"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Լսողական ապարատ"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Օգտագործել հեռախոսի աուդիոյի համար"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Օգտագործել ֆայլի փոխանցման համար"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Օգտագործել ներմուծման համար"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Օգտագործել լսողական ապարատի համար"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Զուգավորել"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"Զուգավորել"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Չեղարկել"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index b957898..81307f7 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"גישה ל-SIM"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"מכשיר שמיעה"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"השתמש עבור האודיו של הטלפון"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"השתמש להעברת קבצים"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"השתמש לקלט"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"יש להשתמש עבור מכשיר שמיעה"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"התאם"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"התאם"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"ביטול"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 953b2e3..346a96d 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIMアクセス"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"補聴器"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"携帯電話の音声に使用"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ファイル転送に使用"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"入力に使用"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"補聴器に使用"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"ペア設定する"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ペア設定する"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"キャンセル"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index a5fd213..db03069 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM წვდომა"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"სმენის აპარატი"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"გამოიყენეთ ტელეფონის აუდიომოწყობილობაში"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ფაილების ტრანსფერისათვის გამოყენება"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"შეტანისთვის გამოყენება"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"სმენის აპარატის გამოყენება"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"დაწყვილება"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"დაწყვილება"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"გაუქმება"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 4e2dacb..acd7d87 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM картасына кіру"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Есту аппараты"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Телефон аудиосы үшін қолдану"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Файлды жіберу үшін қолдану"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Кіріс үшін қолдану"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Есту аппаратына пайдалану"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Жұптау"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ЖҰПТАУ"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Бас тарту"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 400be09..9f55983 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"ಸಿಮ್ ಪ್ರವೇಶ"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"ಶ್ರವಣ ಸಾಧನ"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ಫೋನ್ ಆಡಿಯೋಗಾಗಿ ಬಳಕೆ"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ಫೈಲ್ ವರ್ಗಾವಣೆಗಾಗಿ ಬಳಸು"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ಇನ್ಪುಟ್ಗಾಗಿ ಬಳಸು"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"ಶ್ರವಣ ಸಾಧನಕ್ಕಾಗಿ ಬಳಸಿ"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"ಜೋಡಿ"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ಜೋಡಿ ಮಾಡು"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"ರದ್ದುಮಾಡಿ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index ab02029..35a2867 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM 액세스"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"보청기"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"휴대전화 오디오에 사용"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"파일 전송에 사용"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"입력에 사용"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"보청기에 사용"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"페어링"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"페어링"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"취소"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 993fc33..c1f73cc 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM картаны пайдалануу мүмкүнчүлүгү"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Угуу аппараты"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Телефон аудиосу үчүн колдонулсун"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Файл өткөрүү үчүн колдонулсун"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Киргизүү үчүн колдонулсун"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Угуу аппараты үчүн колдонуу"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Жупташтыруу"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ЖУПТАШТЫРУУ"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Жок"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index dc771f8..24cc69e 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"Piekļuve SIM kartei"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD audio"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Dzirdes aparāts"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Izveidots savienojums ar dzirdes aparātu"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Savienots ar multivides audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Savienots ar tālruņa audio"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Savienots ar failu pārsūtīšanas serveri"</string>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Izmantot tālruņa skaņai"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Izmantot faila pārsūtīšanai"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Izmantot ievadei"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Izmantot dzirdes aparātam"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Izveidot pāri"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SAVIENOT PĀRĪ"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Atcelt"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 4ef3e86..4798a6f 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"Пристап до SIM"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Слушно помагало"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Користи за аудио на телефон"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Користи за пренос на датотеки"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Користи за внес"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Користете како слушно помагало"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Спари"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"СПАРИ"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Откажи"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index c242701..04b08f4 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM ആക്സസ്"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"ശ്രവണ സഹായി"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ഫോൺ ഓഡിയോയ്ക്കായി ഉപയോഗിക്കുക"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ഫയൽ കൈമാറ്റത്തിനായി ഉപയോഗിക്കുന്നു"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ഇൻപുട്ടിനായി ഉപയോഗിക്കുക"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"ശ്രവണ സഹായത്തിനായി ഉപയോഗിക്കുക"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"ജോടിയാക്കുക"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ജോടിയാക്കുക"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"റദ്ദാക്കുക"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 7934e8d..26f4344 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"सिम प्रवेश"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"ऐकण्याची सुविधा"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"फोन ऑडिओसाठी वापरा"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"फाईल स्थानांतरणासाठी वापरा"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"इनपुट साठी वापरा"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"ऐकण्याच्या सुविधेसाठी वापरा"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"पेअर करा"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"पेअर करा"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"रद्द करा"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index e1aa376..8e24cee 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"Akses SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Audio HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Alat Bantu Pendengaran"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Disambungkan ke Alat Bantu Pendengaran"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Disambungkan ke audio media"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Disambungkan ke audio telefon"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Bersambung ke pelayan pemindahan fail"</string>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Gunakan untuk audio telefon"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Gunakan untuk pemindahan fail"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Gunakan untuk input"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Gunakan untuk Alat Bantu Pendengaran"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Jadikan pasangan"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"JADIKAN PASANGAN"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Batal"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index f962316..0b54624 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"Tilgang til SIM-kortet"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD-lyd: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD-lyd"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Høreapparat"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Koblet til høreapparat"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Koblet til medielyd"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Koblet til telefonlyd"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Koblet til tjener for filoverføring"</string>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Bruk for telefonlyd"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Bruk til filoverføring"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Bruk for inndata"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Bruk for høreapparat"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Sammenkoble"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"KOBLE TIL"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Avbryt"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 0cac05e..7b78009 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM पहुँच"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"सुन्नमा मद्दत गर्ने यन्त्र"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"फोन अडियोको लागि प्रयोग गर्नुहोस्"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"फाइल ट्रान्सफरका लागि प्रयोग गर्नुहोस्"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"इनपुटको लागि प्रयोग गर्नुहोस्"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"सुन्नमा मद्दत गर्ने यन्त्रका लागि प्रयोग गर्नुहोस्"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"जोडी"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"जोडी"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"रद्द गर्नुहोस्"</string>
diff --git a/packages/SettingsLib/res/values-or/arrays.xml b/packages/SettingsLib/res/values-or/arrays.xml
new file mode 100644
index 0000000..22f6eda
--- /dev/null
+++ b/packages/SettingsLib/res/values-or/arrays.xml
@@ -0,0 +1,253 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** Copyright 2015 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="wifi_status">
+ <item msgid="1922181315419294640"></item>
+ <item msgid="8934131797783724664">"ସ୍କାନ୍ କରୁଛି…"</item>
+ <item msgid="8513729475867537913">"ସଂଯୋଗ କରୁଛି…"</item>
+ <item msgid="515055375277271756">"ପ୍ରାମାଣିକୀକରଣ କରାଯାଉଛି…"</item>
+ <item msgid="1943354004029184381">"IP ଠିକଣା ପ୍ରାପ୍ତ କରୁଛି…"</item>
+ <item msgid="4221763391123233270">"ସଂଯୋଜିତ"</item>
+ <item msgid="624838831631122137">"ନିଲମ୍ବିତ"</item>
+ <item msgid="7979680559596111948">"ବିଚ୍ଛିନ୍ନ ହେଉଛି…"</item>
+ <item msgid="1634960474403853625">"ବିଚ୍ଛିନ୍ନ"</item>
+ <item msgid="746097431216080650">"ଅସଫଳ"</item>
+ <item msgid="6367044185730295334">"ଅବରୋଧିତ"</item>
+ <item msgid="503942654197908005">"ସାମୟିକ ଭାବେ ଖରାପ ସଂଯୋଜନାକୁ ଏଡାଉଛି"</item>
+ </string-array>
+ <string-array name="wifi_status_with_ssid">
+ <item msgid="7714855332363650812"></item>
+ <item msgid="8878186979715711006">"ସ୍କାନ୍ କରୁଛି…"</item>
+ <item msgid="355508996603873860">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>କୁ ସଂଯୋଗ କରାଯାଉଛି…"</item>
+ <item msgid="554971459996405634">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ସହ ପ୍ରମାଣିତ ହେଉଛି…"</item>
+ <item msgid="7928343808033020343">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ରୁ IP ଠିକଣା ହାସଲ କରୁଛି…"</item>
+ <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ସହ ସଂଯୁକ୍ତ"</item>
+ <item msgid="1330262655415760617">"କଟିଯାଇଛି"</item>
+ <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ରୁ ବିଚ୍ଛିନ୍ନ ହେଉଛି…"</item>
+ <item msgid="197508606402264311">"ସଂଯୁକ୍ତ ନାହିଁ"</item>
+ <item msgid="8578370891960825148">"ଅସଫଳ"</item>
+ <item msgid="5660739516542454527">"ଅବରୋଧିତ"</item>
+ <item msgid="1805837518286731242">"ଦୁର୍ବଳ ସଂଯୋଗକୂ ସାମୟିକ ଭାବେ ଏଡ଼ାଉଛି"</item>
+ </string-array>
+ <string-array name="hdcp_checking_titles">
+ <item msgid="441827799230089869">"ଆଦୌ ଯାଞ୍ଚ କରନାହିଁ"</item>
+ <item msgid="6042769699089883931">"କେବଳ DRM କଣ୍ଟେଣ୍ଟ ଠାବ କର"</item>
+ <item msgid="9174900380056846820">"ସର୍ବଦା ଠାବ କର"</item>
+ </string-array>
+ <string-array name="hdcp_checking_summaries">
+ <item msgid="505558545611516707">"କଦାପି HDCP ଯାଞ୍ଚ କରିବା ବ୍ୟବହାର କରନ୍ତୁ ନାହିଁ"</item>
+ <item msgid="3878793616631049349">"କେବଳ DRM ବିଷୟବସ୍ତୁ ପାଇଁ HDCP ଯାଞ୍ଚ ବ୍ୟବହାର କରନ୍ତୁ"</item>
+ <item msgid="45075631231212732">"ସର୍ବଦା HDCP ଯାଞ୍ଚ ବ୍ୟବହାର କରନ୍ତୁ"</item>
+ </string-array>
+ <string-array name="bluetooth_avrcp_versions">
+ <item msgid="5347678900838034763">"AVRCP 1.4 (ଡିଫଲ୍ଟ)"</item>
+ <item msgid="2809759619990248160">"AVRCP 1.3"</item>
+ <item msgid="6199178154704729352">"AVRCP 1.5"</item>
+ <item msgid="5172170854953034852">"AVRCP 1.6"</item>
+ </string-array>
+ <string-array name="bluetooth_avrcp_version_values">
+ <item msgid="2838624067805073303">"avrcp14"</item>
+ <item msgid="3011533352527449572">"avrcp13"</item>
+ <item msgid="8837606198371920819">"avrcp15"</item>
+ <item msgid="3422726142222090896">"avrcp16"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"ସିଷ୍ଟମ୍ ଚୟନ ବ୍ୟବହାର କରନ୍ତୁ (ଡିଫଲ୍ଟ)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="5254942598247222737">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ଅଡିଓ"</item>
+ <item msgid="2091430979086738145">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ଅଡିଓ"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ <item msgid="723675059572222462">"ବିକଳ୍ପ କୋଡେକ୍ସକୁ ସକ୍ଷମ କରନ୍ତୁ"</item>
+ <item msgid="3304843301758635896">"ବିକଳ୍ପ କୋଡେକ୍ଗୁଡ଼ିକୁ ଅକ୍ଷମ କରନ୍ତୁ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"ସିଷ୍ଟମ୍ର ଚୟନ (ପୂର୍ବ-ନିର୍ଦ୍ଧାରିତ) ବ୍ୟବହାର କରନ୍ତୁ"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="7848030269621918608">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ଅଡିଓ"</item>
+ <item msgid="298198075927343893">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ଅଡିଓ"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ <item msgid="2209680154067241740">"ବିକଳ୍ପ କୋଡେକ୍ସ ସକ୍ଷମ କରନ୍ତୁ"</item>
+ <item msgid="741805482892725657">"ବିକଳ୍ପ କୋଡେକ୍ସ ଅକ୍ଷମ କରନ୍ତୁ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"ସିଷ୍ଟମ୍ର ଚୟନ (ପୂର୍ବ-ନିର୍ଦ୍ଧାରିତ) ବ୍ୟବହାର କରନ୍ତୁ"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"ସିଷ୍ଟମ୍ ଚୟନ ବ୍ୟବହାର କରନ୍ତୁ (ପୂର୍ବ-ନିର୍ଦ୍ଧାରିତ)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"ସିଷ୍ଟମ୍ର ଚୟନ (ପୂର୍ବ-ନିର୍ଦ୍ଧାରିତ) ବ୍ୟବହାର କରନ୍ତୁ"</item>
+ <item msgid="5618929009984956469">"16 ବିଟ୍ସ/ସାମ୍ପଲ୍"</item>
+ <item msgid="3412640499234627248">"24 ବିଟ୍ସ/ନମୁନା"</item>
+ <item msgid="121583001492929387">"32 ବିଟସ୍/ନମୂନା"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"ସିଷ୍ଟମ୍ ମନୋନୟନ (ଡିଫଲ୍ଟ) ବ୍ୟବହାର କରନ୍ତୁ"</item>
+ <item msgid="4726688794884191540">"୧୬ ବିଟସ୍/ନମୁନା"</item>
+ <item msgid="305344756485516870">"24 ବିଟସ୍/ନମୂନା"</item>
+ <item msgid="244568657919675099">"32 ବିଟସ୍/ନମୁନା"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"ସିଷ୍ଟମ୍ ଚୟନ ବ୍ୟବହାର କରନ୍ତୁ (ଡିଫଲ୍ଟ)"</item>
+ <item msgid="4106832974775067314">"ମୋନୋ"</item>
+ <item msgid="5571632958424639155">"ଷ୍ଟେରିଓ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"ସିଷ୍ଟମ୍ ଚୟନ ବ୍ୟବହାର କରନ୍ତୁ(ପୂର୍ବ-ନିର୍ଦ୍ଧାରିତ)"</item>
+ <item msgid="8900559293912978337">"ମୋନୋ"</item>
+ <item msgid="8883739882299884241">"ଷ୍ଟେରିଓ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"ଅଡିଓ ଗୁଣବତ୍ତା ପାଇଁ ଅନୁକୂଳିତ(990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"ସନ୍ତୁଳିତ ଅଡିଓ ଓ ସଂଯୋଗ ଗୁଣବତ୍ତା (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"ସଂଯୋଗର ଗୁଣବତ୍ତା (330kbps/303kbps) ପାଇଁ ଉପଯୁକ୍ତ କରାଯାଇଛି"</item>
+ <item msgid="4414060457677684127">"ସର୍ବୋତ୍ତମ ପ୍ରୟାସ (ଅନୁକୁଳ ବିଟ୍ ରେଟ୍)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"ଅଡିଓର ଗୁଣବତ୍ତା ପାଇଁ ଅନୁକୂଳିତ"</item>
+ <item msgid="4327143584633311908">"ସନ୍ତୁଳିତ ଅଡିଓ ଓ ସଂଯୋଗ କ୍ୱାଲିଟୀ"</item>
+ <item msgid="4681409244565426925">"ସଂଯୋଗର ଗୁଣବତ୍ତା ପାଇଁ ଅନୁକୂଳିତ"</item>
+ <item msgid="364670732877872677">"ସର୍ବୋତ୍ତମ ପ୍ରୟାସ (ଅନୁକୂଳ ବିଟ୍ ରେଟ୍)"</item>
+ </string-array>
+ <string-array name="select_logd_size_titles">
+ <item msgid="8665206199209698501">"ଅଫ୍"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
+ </string-array>
+ <string-array name="select_logd_size_lowram_titles">
+ <item msgid="6089470720451068364">"ବନ୍ଦ"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
+ </string-array>
+ <string-array name="select_logd_size_summaries">
+ <item msgid="6921048829791179331">"ବନ୍ଦ"</item>
+ <item msgid="2969458029344750262">"64K ପିଛା ଲଗ୍ ବଫର୍"</item>
+ <item msgid="1342285115665698168">"256K ଲଗ୍ ପ୍ରତି ବଫର୍"</item>
+ <item msgid="1314234299552254621">"ଲଗ୍ ବଫର୍ ପ୍ରତି 1M"</item>
+ <item msgid="3606047780792894151">"ଲଗ୍ ବଫର୍ ପ୍ରତି 4M"</item>
+ <item msgid="5431354956856655120">"16M ଲଗ ପିଛା ବଫର୍"</item>
+ </string-array>
+ <string-array name="select_logpersist_titles">
+ <item msgid="1744840221860799971">"ବନ୍ଦ"</item>
+ <item msgid="3054662377365844197">"ସମସ୍ତ"</item>
+ <item msgid="688870735111627832">"ରେଡିଓ ଛଡ଼ା ଅନ୍ୟ ସବୁ"</item>
+ <item msgid="2850427388488887328">"କେବଳ କର୍ନେଲ୍"</item>
+ </string-array>
+ <string-array name="select_logpersist_summaries">
+ <item msgid="2216470072500521830">"ଅଫ"</item>
+ <item msgid="172978079776521897">"ସମସ୍ତ ଲଗ୍ ବଫର୍"</item>
+ <item msgid="3873873912383879240">"ରେଡିଓ ଲଗ୍ ବଫର୍ଗୁଡିକ ଛଡ଼ା ଅନ୍ୟ ସବୁ"</item>
+ <item msgid="8489661142527693381">"କେବଳ କର୍ନେଲ୍ ଲଗ୍ ବଫର୍"</item>
+ </string-array>
+ <string-array name="window_animation_scale_entries">
+ <item msgid="8134156599370824081">"ଆନିମେଶନ୍ ବନ୍ଦ କରନ୍ତୁ"</item>
+ <item msgid="6624864048416710414">"ଆନିମେଶନ ସ୍କେଲ .5x"</item>
+ <item msgid="2219332261255416635">"ଆନିମେଶନ୍ ସ୍କେଲ୍ 1x"</item>
+ <item msgid="3544428804137048509">"ଆନିମେଶନ୍ ସ୍କେଲ୍ 1.5x"</item>
+ <item msgid="3110710404225974514">"ଆନିମେଶନ ସ୍କେଲ 2x"</item>
+ <item msgid="4402738611528318731">"ଆନିମେଶନ୍ ସ୍କେଲ୍ 5x"</item>
+ <item msgid="6189539267968330656">"ଆନିମେଶନ୍ ସ୍କେଲ୍ 10x"</item>
+ </string-array>
+ <string-array name="transition_animation_scale_entries">
+ <item msgid="8464255836173039442">"ଆନିମେଶନ୍ ବନ୍ଦ କରନ୍ତୁ"</item>
+ <item msgid="3375781541913316411">"ଆନିମେଶନ୍ ସ୍କେଲ୍ .5x"</item>
+ <item msgid="1991041427801869945">"ଆନିମେଶନ୍ ସ୍କେଲ୍ 1x"</item>
+ <item msgid="4012689927622382874">"ଆନିମେସନ୍ ସ୍କେଲ 1.5x"</item>
+ <item msgid="3289156759925947169">"ଆନିମେଶନ୍ ସ୍କେଲ୍ 2x"</item>
+ <item msgid="7705857441213621835">"ଆନିମେଶନ୍ ସ୍କେଲ୍ 5x"</item>
+ <item msgid="6660750935954853365">"ଆନିମେସନ୍ ସ୍କେଲ୍ 10x"</item>
+ </string-array>
+ <string-array name="animator_duration_scale_entries">
+ <item msgid="6039901060648228241">"ଆନିମେଶନ୍ ବନ୍ଦ"</item>
+ <item msgid="1138649021950863198">"ଆନିମେଶନ୍ ସ୍କେଲ୍ .5x"</item>
+ <item msgid="4394388961370833040">"ଆନିମେଶନ୍ ସ୍କେଲ୍ 1x"</item>
+ <item msgid="8125427921655194973">"ଆନିମେଶନ୍ ସ୍କେଲ୍ 1.5x"</item>
+ <item msgid="3334024790739189573">"ଆନିମେଶନ୍ ସ୍କେଲ୍ 2x"</item>
+ <item msgid="3170120558236848008">"ଆନିମେଶନ୍ ସ୍କେଲ୍ 5x"</item>
+ <item msgid="1069584980746680398">"ଆନିମେଶନ୍ ସ୍କେଲ୍ 10x"</item>
+ </string-array>
+ <string-array name="overlay_display_devices_entries">
+ <item msgid="1606809880904982133">"କିଛି ନାହିଁ"</item>
+ <item msgid="9033194758688161545">"480p"</item>
+ <item msgid="1025306206556583600">"480p (ସୁରକ୍ଷିତ)"</item>
+ <item msgid="1853913333042744661">"p"</item>
+ <item msgid="3414540279805870511">"720p (ସୁରକ୍ଷିତ)"</item>
+ <item msgid="9039818062847141551">"1080p"</item>
+ <item msgid="4939496949750174834">"1080p (ସୁରକ୍ଷିତ)"</item>
+ <item msgid="1833612718524903568">"4K"</item>
+ <item msgid="238303513127879234">"4K (ସୁରକ୍ଷିତ)"</item>
+ <item msgid="3547211260846843098">"4K (ଅପ୍ସ୍କେଲ୍ କରାଯାଇଛି)"</item>
+ <item msgid="5411365648951414254">"4K (ଉତ୍ତମ, ସୁରକ୍ଷିତ)"</item>
+ <item msgid="1311305077526792901">"720p, 1080p (ଡୁଆଲ୍ ସ୍କ୍ରୀନ୍)"</item>
+ </string-array>
+ <string-array name="enable_opengl_traces_entries">
+ <item msgid="3191973083884253830">"କିଛିନାହିଁ"</item>
+ <item msgid="9089630089455370183">"Logcat"</item>
+ <item msgid="5397807424362304288">"Systrace (ଗ୍ରାଫିକ୍ସ)"</item>
+ <item msgid="1340692776955662664">"glGetError ରେ କଲ୍ ଷ୍ଟାକ୍"</item>
+ </string-array>
+ <string-array name="show_non_rect_clip_entries">
+ <item msgid="993742912147090253">"ଅଫ୍"</item>
+ <item msgid="675719912558941285">"ଅଣ-ଆୟତାକାର କ୍ଲିପ୍ କ୍ଷେତ୍ର ନୀଳ ରଙ୍ଗରେ ଆଙ୍କନ୍ତୁ"</item>
+ <item msgid="1064373276095698656">"ଟେଷ୍ଟ ହୋଇଥିବା ଅଙ୍କନ କମାଣ୍ଡଗୁଡ଼ିକୁ ସବୁଜରେ ଚିହ୍ନିତ କରନ୍ତୁ"</item>
+ </string-array>
+ <string-array name="track_frame_time_entries">
+ <item msgid="2193584639058893150">"ବନ୍ଦ"</item>
+ <item msgid="2751513398307949636">"ସ୍କ୍ରୀନ୍ରେ ବାର୍ ପରି"</item>
+ <item msgid="2355151170975410323">"ରେ <xliff:g id="AS_TYPED_COMMAND">adb shell dumpsys gfxinfo</xliff:g>"</item>
+ </string-array>
+ <string-array name="debug_hw_overdraw_entries">
+ <item msgid="8190572633763871652">"ଅଫ୍"</item>
+ <item msgid="7688197031296835369">"ଓଭର୍ ଡ୍ର କ୍ଷେତ୍ରଗୁଡ଼ିକୁ ଦେଖାଅ"</item>
+ <item msgid="2290859360633824369">"ଡିଉଟେରାନୋମାଲୀ ପାଇଁ କ୍ଷେତ୍ର ଦେଖନ୍ତୁ"</item>
+ </string-array>
+ <string-array name="app_process_limit_entries">
+ <item msgid="3401625457385943795">"ମାନକ ସୀମା"</item>
+ <item msgid="4071574792028999443">"କୌଣସି ବ୍ୟାକ୍ଗ୍ରାଉଣ୍ଡ ପ୍ରୋସେସ୍ ଚାଲୁନାହିଁ"</item>
+ <item msgid="4810006996171705398">"ସର୍ବାଧିକ 1ଟି ପ୍ରକ୍ରିୟା"</item>
+ <item msgid="8586370216857360863">"ସର୍ବାଧିକ 2 ଟି ପ୍ରକ୍ରିୟା"</item>
+ <item msgid="836593137872605381">"ଅତିବେଶୀରେ 3ଟି ପ୍ରକ୍ରିୟା"</item>
+ <item msgid="7899496259191969307">"ସର୍ବାଧିକ 4 ଟି ପ୍ରକ୍ରିୟା"</item>
+ </string-array>
+ <string-array name="usb_configuration_titles">
+ <item msgid="488237561639712799">"ଚାର୍ଜ ହେଉଛି"</item>
+ <item msgid="5220695614993094977">"MTP (ମିଡିଆ ସ୍ଥାନାନ୍ତର ପ୍ରୋଟୋକଲ୍)"</item>
+ <item msgid="2086000968159047375">"PTP (ପିକଚର୍ ଟ୍ରାନ୍ସଫର୍ ପ୍ରୋଟୋକଲ୍)"</item>
+ <item msgid="7398830860950841822">"RNDIS (USB ଏଥରନେଟ)"</item>
+ <item msgid="1718924214939774352">"ଅଡିଓ ଉତ୍ସ"</item>
+ <item msgid="8126315616613006284">"MIDI"</item>
+ </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
new file mode 100644
index 0000000..0c2cbda
--- /dev/null
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -0,0 +1,466 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** Copyright 2015 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_fail_to_scan" msgid="1265540342578081461">"ନେଟ୍ୱର୍କଗୁଡ଼ିକୁ ଖୋଜିପାରୁନାହିଁ"</string>
+ <string name="wifi_security_none" msgid="7985461072596594400">"କିଛି ନାହିଁ"</string>
+ <string name="wifi_remembered" msgid="4955746899347821096">"ସେଭ୍ ହୋଇଗଲା"</string>
+ <string name="wifi_disabled_generic" msgid="4259794910584943386">"ଅକ୍ଷମ ହୋଇଛି"</string>
+ <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP କନଫିଗରେଶନ ବିଫଳ ହୋଇଛି"</string>
+ <string name="wifi_disabled_by_recommendation_provider" msgid="5168315140978066096">"ନିମ୍ନ ମାନର ନେଟ୍ୱର୍କ କାରଣରୁ ସଂଯୁକ୍ତ ହୋଇନାହିଁ"</string>
+ <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"ୱାଇଫାଇ ସଂଯୋଗ ବିଫଳ ହୋଇଛି"</string>
+ <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ସତ୍ୟାପନରେ ସମସ୍ୟା"</string>
+ <string name="wifi_cant_connect" msgid="5410016875644565884">"ସଂଯୋଗ କରିପାରିବ ନାହିଁ"</string>
+ <string name="wifi_cant_connect_to_ap" msgid="1222553274052685331">"\'<xliff:g id="AP_NAME">%1$s</xliff:g>\' ସହିତ ସଂଯୁକ୍ତ ହୋଇପାରୁନାହିଁ"</string>
+ <string name="wifi_check_password_try_again" msgid="516958988102584767">"ପାସ୍ୱର୍ଡ ଯାଞ୍ଚ କରନ୍ତୁ ଏବଂ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string>
+ <string name="wifi_not_in_range" msgid="1136191511238508967">"ପରିସୀମାରେ ନାହିଁ"</string>
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"ସ୍ୱଚାଳିତ ଭାବେ ସଂଯୁକ୍ତ ହେବନାହିଁ"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"ଇଣ୍ଟରନେଟ୍ର କୌଣସି ଆକ୍ସେସ୍ ନାହିଁ"</string>
+ <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> ଦ୍ୱାରା ସେଭ କରାଯାଇଛି"</string>
+ <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s ମାଧ୍ୟମରେ ଅଟୋମେଟିକାଲୀ ସଂଯୁକ୍ତ"</string>
+ <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"ନେଟୱର୍କ ମୂଲ୍ୟାୟନ ପ୍ରଦାତାଙ୍କ ମାଧ୍ୟମରେ ଅଟୋମେଟିକାଲ୍ୟ ସଂଯୁକ୍ତ"</string>
+ <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ମାଧ୍ୟମରେ ସଂଯୁକ୍ତ"</string>
+ <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s ମାଧ୍ୟମରେ ଉପଲବ୍ଧ"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"ସଂଯୁକ୍ତ, ଇଣ୍ଟର୍ନେଟ୍ ନାହିଁ"</string>
+ <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ଆକ୍ସେସ୍ ପଏଣ୍ଟ ସାମୟିକ ଭାବେ ପୂର୍ଣ୍ଣ"</string>
+ <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s ମାଧ୍ୟମରେ ସଂଯୁକ୍ତ"</string>
+ <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_medium" msgid="3175763313268941953">"ମଧ୍ୟମ"</string>
+ <string name="speed_label_fast" msgid="7715732164050975057">"ଦ୍ରୁତ"</string>
+ <string name="speed_label_very_fast" msgid="2265363430784523409">"ଅତି ଦ୍ରୁତ"</string>
+ <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="bluetooth_disconnected" msgid="6557104142667339895">"ବିଛିନ୍ନ ହେଲା"</string>
+ <string name="bluetooth_disconnecting" msgid="8913264760027764974">"ବିଚ୍ଛିନ୍ନ କରୁଛି…"</string>
+ <string name="bluetooth_connecting" msgid="8555009514614320497">"ସଂଯୋଗ କରାଯାଉଛି…"</string>
+ <!-- no translation found for bluetooth_connected (5427152882755735944) -->
+ <skip />
+ <string name="bluetooth_pairing" msgid="1426882272690346242">"ପେୟାର୍ କରୁଛି…"</string>
+ <!-- no translation found for bluetooth_connected_no_headset (616068069034994802) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp (3736431800395923868) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_map (3200033913678466453) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp (2047403011284187056) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_battery_level (5162924691231307748) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (1610296229139400266) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (3908466636369853652) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1163440823807659316) -->
+ <skip />
+ <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"ମିଡିଆ ଅଡିଓ"</string>
+ <string name="bluetooth_profile_headset" msgid="7815495680863246034">"ଫୋନ୍ କଲ୍ଗୁଡ଼ିକ"</string>
+ <string name="bluetooth_profile_opp" msgid="9168139293654233697">"ଫାଇଲ୍ ଟ୍ରାନ୍ସଫର୍"</string>
+ <string name="bluetooth_profile_hid" msgid="3680729023366986480">"ଇନ୍ପୁଟ୍ ଡିଭାଇସ୍"</string>
+ <string name="bluetooth_profile_pan" msgid="3391606497945147673">"ଇଣ୍ଟର୍ନେଟ୍ ଆକ୍ସେସ୍"</string>
+ <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"ଯୋଗାଯୋଗ ଶେୟାରିଙ୍ଗ"</string>
+ <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"ଯୋଗାଯୋଗ ଶେୟାର୍ କରିବା ପାଇଁ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ଶେୟାରିଙ୍ଗ"</string>
+ <string name="bluetooth_profile_map" msgid="1019763341565580450">"ଟେକ୍ସଟ୍ ମେସେଜ୍"</string>
+ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"ସିମ୍ ଆକ୍ସେସ୍"</string>
+ <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>
+ <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
+ <skip />
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
+ <skip />
+ <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>
+ <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"ମାନଚିତ୍ର ସହିତ ସଂଯୁକ୍ତ"</string>
+ <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP ସହିତ ସଂଯୁକ୍ତ"</string>
+ <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ଫାଇଲ୍ ଟ୍ରାନ୍ସଫର୍ ସର୍ଭର୍ ସହ ସଂଯୁକ୍ତ ହୋଇନାହିଁ"</string>
+ <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ଇନ୍ପୁଟ୍ ଡିଇଭାସ୍ ସହ ସଂଯୁକ୍ତ"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"ଆଭ୍ୟନ୍ତରୀଣ ଆକ୍ସେସ୍ ପାଇଁ ଡିଭାଇସ୍ ସହିତ ସଂଯୁକ୍ତ"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"ଡିଭାଇସ୍ ସହ ସ୍ଥାନୀୟ ଇଣ୍ଟରନେଟ୍ ସଂଯୋଗ ଶେୟାର୍ କରାଯାଉଛି"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"ଇଣ୍ଟର୍ନେଟ୍ ଆକ୍ସେସ୍ ପାଇଁ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"ମାନଚିତ୍ର ପାଇଁ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM ଆକସେସ୍ ପାଇଁ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"ମିଡିଆ ଅଡିଓ ପାଇଁ ବ୍ୟବହାର କର"</string>
+ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ଫୋନ୍ ଅଡିଓ ପାଇଁ ବ୍ୟବହାର କର"</string>
+ <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ଫାଇଲ୍ ଟ୍ରାନ୍ସଫର୍ ପାଇଁ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ଇନ୍ପୁଟ୍ ପାଇଁ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
+ <skip />
+ <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"ପେୟାର୍"</string>
+ <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ପେୟାର୍"</string>
+ <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"କ୍ୟାନ୍ସଲ୍ କରନ୍ତୁ"</string>
+ <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"ପେୟାରିଂ ଫଳରେ ସଂଯୁକ୍ତ ଥିବା ବେଳେ ଆପଣଙ୍କ ସମ୍ପର୍କଗୁଡ଼ିକୁ ଏବଂ କଲ୍ର ଇତିବୃତିକୁ ଆକସେସ୍ ମଞ୍ଜୁର ହୁଏ।"</string>
+ <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ସହ ପେୟାର୍ କରିହେଲା ନାହିଁ।"</string>
+ <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"ଏକ ଭୁଲ୍ PIN କିମ୍ବା ପାସକୀ କାରଣରୁ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ସହ ପେୟାର୍ କରିପାରିଲା ନାହିଁ।"</string>
+ <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ସହ ଯୋଗାଯୋଗ ସ୍ଥାପନା କରିପାରୁନାହିଁ।"</string>
+ <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ଦ୍ୱାରା ପେୟାରିଙ୍ଗ ପାଇଁ ପ୍ରତ୍ୟାଖ୍ୟାନ କରିଦିଆଗଲା।"</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"କମ୍ପ୍ୟୁଟର୍"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"ହେଡ୍ସେଟ୍"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"ଫୋନ୍"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"ଇମେଜିଙ୍ଗ"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"ହେଡ୍ଫୋନ୍"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"ଇନ୍ପୁଟ୍ ଉପକରଣ"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"ବ୍ଲୁଟୂଥ୍"</string>
+ <string name="accessibility_wifi_off" msgid="1166761729660614716">"ୱାଇ-ଫାଇ ବନ୍ଦ।"</string>
+ <string name="accessibility_no_wifi" msgid="8834610636137374508">"ୱାଇଫାଇ ବିଚ୍ଛିନ୍ନ କରାଗଲା।"</string>
+ <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wifiର 1 ବାର"</string>
+ <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"ୱାଇ-ଫାଇର ଦୁଇଟି ବାର୍ ଅଛି।"</string>
+ <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"ୱାଇ-ଫାଇର ତିନୋଟି ବାର୍।"</string>
+ <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"ୱାଇ-ଫାଇର ସଙ୍କେତ ସର୍ବୋଚ୍ଚ।"</string>
+ <string name="accessibility_wifi_security_type_none" msgid="1223747559986205423">"ଖୋଲା ନେଟୱର୍କ"</string>
+ <string name="accessibility_wifi_security_type_secured" msgid="862921720418885331">"ସୁରକ୍ଷିତ ନେଟ୍ୱର୍କ"</string>
+ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+ <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"କଢ଼ାଯାଇଥିବା ଆପ୍ଗୁଡ଼ିକ"</string>
+ <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"ଆପ୍ ଏବଂ ଉପଯୋଗକର୍ତ୍ତା ବାହାର କରାଗଲା"</string>
+ <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ଟିଥରିଙ୍ଗ"</string>
+ <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ପୋର୍ଟବଲ୍ ହଟସ୍ପଟ୍"</string>
+ <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ବ୍ଲୁଟୂଥ ଟିଥରିଙ୍ଗ"</string>
+ <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"ଟିଥର୍ କରୁଛି"</string>
+ <string name="tether_settings_title_all" msgid="8356136101061143841">"ଟିଥରିଙ୍ଗ ଓ ପୋର୍ଟବଲ୍ ହଟ୍ସ୍ପଟ୍"</string>
+ <string name="managed_user_title" msgid="8109605045406748842">"ସମସ୍ତ କାର୍ଯ୍ୟ ଆପ୍"</string>
+ <string name="user_guest" msgid="8475274842845401871">"ଅତିଥି"</string>
+ <string name="unknown" msgid="1592123443519355854">"ଅଜଣା"</string>
+ <string name="running_process_item_user_label" msgid="3129887865552025943">"ଉପଯୋଗକର୍ତ୍ତା: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+ <string name="launch_defaults_some" msgid="313159469856372621">"କିଛି ପୂର୍ବ-ନିର୍ଦ୍ଧାରିତ ମାନ ସେଟ୍ ହୋଇଛି"</string>
+ <string name="launch_defaults_none" msgid="4241129108140034876">"କୌଣସି ପୂର୍ବ-ନିର୍ଦ୍ଧାରଣ ସେଟ୍ ହୋଇନାହିଁ"</string>
+ <string name="tts_settings" msgid="8186971894801348327">"ଲେଖା-ରୁ-କଥା ସେଟିଙ୍ଗ୍"</string>
+ <string name="tts_settings_title" msgid="1237820681016639683">"ଲେଖା-ରୁ-କଥା ଆଉଟ୍ପୁଟ୍"</string>
+ <string name="tts_default_rate_title" msgid="6030550998379310088">"ସ୍ପୀଚ୍ ଦର"</string>
+ <string name="tts_default_rate_summary" msgid="4061815292287182801">"ଲେଖା ପଢ଼ିବାର ବେଗ"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"ପିଚ୍"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"ସଂଶ୍ଳେଷିତ ସ୍ପିଚ୍ର ଟୋନ୍ରେ ପ୍ରଭାବ ପକାଏ"</string>
+ <string name="tts_default_lang_title" msgid="8018087612299820556">"ଭାଷା"</string>
+ <string name="tts_lang_use_system" msgid="2679252467416513208">"ସିଷ୍ଟମ୍ ଭାଷା ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <string name="tts_lang_not_selected" msgid="7395787019276734765">"ଭାଷା ମନୋନୀତ ନୁହେଁ"</string>
+ <string name="tts_default_lang_summary" msgid="5219362163902707785">"ପଢ଼ାଯାଇଥିବା ଲେଖା ପାଇଁ ଭାଷା-ନିର୍ଦ୍ଦିଷ୍ଟ ସ୍ୱର ସେଟ୍ କରେ"</string>
+ <string name="tts_play_example_title" msgid="7094780383253097230">"ଗୋଟିଏ ଉଦାହରଣକୁ ଶୁଣନ୍ତୁ"</string>
+ <string name="tts_play_example_summary" msgid="8029071615047894486">"ସ୍ପୀଚ୍ ସିନ୍ଥେସିସ୍ର ଏକ ଛୋଟ ନମୁନା ଶୁଣନ୍ତୁ"</string>
+ <string name="tts_install_data_title" msgid="4264378440508149986">"ଭଏସ୍ ଡାଟା ଇନ୍ଷ୍ଟଲ୍ କରନ୍ତୁ"</string>
+ <string name="tts_install_data_summary" msgid="5742135732511822589">"ସ୍ପୀଚ୍ ସିନ୍ଥେସିସ୍ ପାଇଁ ଆବଶ୍ୟକ ଭଏସ୍ ଡାଟା ଇନ୍ଷ୍ଟଲ୍ କରନ୍ତୁ"</string>
+ <string name="tts_engine_security_warning" msgid="8786238102020223650">"ପାସ୍ୱର୍ଡ ଓ କ୍ରେଡିଟ୍ କାର୍ଡ ନମ୍ୱର୍ଗୁଡ଼ିକ ଭଳି ବ୍ୟକ୍ତିଗତ ତଥ୍ୟ ସମେତ କୁହାଯିବାକୁ ଥିବା ସମସ୍ତ ଲେଖାକୁ, ସ୍ପୀଚ୍ ସିନ୍ଥେସିସ୍ ଇଞ୍ଜିନ୍ ସଂଗ୍ରହ କରିପାରେ। ଏହା, <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g> ଇଞ୍ଜିନ୍ରୁ ଆସିଛି। ଏହି ସ୍ପୀଚ୍ ସିନ୍ଥେସିସ୍ ଇଞ୍ଜିନ୍ର ବ୍ୟବହାରକୁ ସକ୍ଷମ କରିବେ?"</string>
+ <string name="tts_engine_network_required" msgid="1190837151485314743">"ଟେକ୍ସଟ୍-ରୁ-କଥା ଆଉଟପୁଟ୍ ପାଇଁ ଏହି ଭାଷା ଏକ କାମକରୁଥିବା ନେଟୱାର୍କ ସଂଯୋଗ ଆବଶ୍ୟକ କରେ।"</string>
+ <string name="tts_default_sample_string" msgid="4040835213373086322">"ଏହା ହେଉଛି ସ୍ପୀଚ୍ ସିନ୍ଥେସିସ୍ର ଏକ ଉଦାହରଣ"</string>
+ <string name="tts_status_title" msgid="7268566550242584413">"ଡିଫଲ୍ଟ ଭାଷା ଷ୍ଟାଟସ୍"</string>
+ <string name="tts_status_ok" msgid="1309762510278029765">"<xliff:g id="LOCALE">%1$s</xliff:g> ପୂର୍ଣ୍ଣରୂପେ ସମର୍ଥିତ"</string>
+ <string name="tts_status_requires_network" msgid="6042500821503226892">"<xliff:g id="LOCALE">%1$s</xliff:g> ନେଟ୍ୱର୍କ ସଂଯୋଜନା ଆବଶ୍ୟକ କରେ"</string>
+ <string name="tts_status_not_supported" msgid="4491154212762472495">"<xliff:g id="LOCALE">%1$s</xliff:g> ସପୋର୍ଟ କରୁ ନାହିଁ"</string>
+ <string name="tts_status_checking" msgid="5339150797940483592">"ଯାଞ୍ଚ କରାଯାଉଛି…"</string>
+ <string name="tts_engine_settings_title" msgid="3499112142425680334">"<xliff:g id="TTS_ENGINE_NAME">%s</xliff:g> ପାଇଁ ସେଟିଙ୍ଗ"</string>
+ <string name="tts_engine_settings_button" msgid="1030512042040722285">"ଇଞ୍ଜିନ୍ ସେଟିଙ୍ଗ ଆରମ୍ଭ କରନ୍ତୁ"</string>
+ <string name="tts_engine_preference_section_title" msgid="448294500990971413">"ନିଜ ପସନ୍ଦର ଇଞ୍ଜିନ୍"</string>
+ <string name="tts_general_section_title" msgid="4402572014604490502">"ସାଧାରଣ"</string>
+ <string name="tts_reset_speech_pitch_title" msgid="5789394019544785915">"ସ୍ପୀଚ୍ର ପିଚ୍ ରିସେଟ୍ କରନ୍ତୁ"</string>
+ <string name="tts_reset_speech_pitch_summary" msgid="8700539616245004418">"ପିଚକୁ ରିସେଟ କରନ୍ତୁ, ଯେଉଁଠାରେ ଲେଖା, ଡିଫଲ୍ଟ ଭାବେ କୁହାଯାଏ।"</string>
+ <string-array name="tts_rate_entries">
+ <item msgid="6695494874362656215">"ବହୁତ ମନ୍ଥର"</item>
+ <item msgid="4795095314303559268">"ମନ୍ଥର"</item>
+ <item msgid="8903157781070679765">"ସାମାନ୍ୟ"</item>
+ <item msgid="164347302621392996">"ଦ୍ରୁତ"</item>
+ <item msgid="5794028588101562009">"ଦ୍ରୁତତର"</item>
+ <item msgid="7163942783888652942">"ଅତି ଦ୍ରୁତ"</item>
+ <item msgid="7831712693748700507">"ଦ୍ରୁତ"</item>
+ <item msgid="5194774745031751806">"ଅତି ତୀବ୍ର"</item>
+ <item msgid="9085102246155045744">"ଦ୍ରୁତତ୍ତମ"</item>
+ </string-array>
+ <string name="choose_profile" msgid="6921016979430278661">"ପ୍ରୋଫାଇଲ୍ ବାଛନ୍ତୁ"</string>
+ <string name="category_personal" msgid="1299663247844969448">"ବ୍ୟକ୍ତିଗତ"</string>
+ <string name="category_work" msgid="8699184680584175622">"କାମ"</string>
+ <string name="development_settings_title" msgid="215179176067683667">"ଡେଭଲପର୍ଙ୍କ ପାଇଁ ବିକଳ୍ପମାନ"</string>
+ <string name="development_settings_enable" msgid="542530994778109538">"ଡେଭଲପର୍ ବିକଳ୍ପଗୁଡ଼ିକ ସକ୍ଷମ କରନ୍ତୁ"</string>
+ <string name="development_settings_summary" msgid="1815795401632854041">"ଆପ୍ର ବିକାଶ ପାଇଁ ବିକଳ୍ପମାନ ସେଟ୍ କରନ୍ତୁ"</string>
+ <string name="development_settings_not_available" msgid="4308569041701535607">"ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଡେଭଲପରଙ୍କ ବିକଳ୍ପସମୂହ ଉପଲବ୍ଧ ନୁହେଁ"</string>
+ <string name="vpn_settings_not_available" msgid="956841430176985598">"VPN ସେଟିଙ୍ଗ ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଉପଲବ୍ଧ ନୁହେଁ"</string>
+ <string name="tethering_settings_not_available" msgid="6765770438438291012">"ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଟିଥରିଙ୍ଗ ସେଟିଙ୍ଗ ଉପଲବ୍ଧ ନାହିଁ"</string>
+ <string name="apn_settings_not_available" msgid="7873729032165324000">"ଆକ୍ସେସ୍ ପଏଣ୍ଟ ନାମର ସେଟିଙ୍ଗ ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଉପଲବ୍ଧ ନାହିଁ"</string>
+ <string name="enable_adb" msgid="7982306934419797485">"USB ଡିବଗ୍ ହେଉଛି"</string>
+ <string name="enable_adb_summary" msgid="4881186971746056635">"USB ସଂଯୁକ୍ତ ହେବାବେଳେ ଡିବଗ୍ ମୋଡ୍"</string>
+ <string name="clear_adb_keys" msgid="4038889221503122743">"USB ଡିବଗିଙ୍ଗ ଅଧିକାରକୁ କାଢ଼ିଦିଅନ୍ତୁ"</string>
+ <string name="bugreport_in_power" msgid="7923901846375587241">"ବଗ୍ ରିପୋର୍ଟ ଶର୍ଟକଟ୍"</string>
+ <string name="bugreport_in_power_summary" msgid="1778455732762984579">"ତ୍ରୁଟି ରିପୋର୍ଟ ଦେବାପାଇଁ ପାୱର୍ ମେନୁରେ ଏକ ବଟନ୍ ଦେଖନ୍ତୁ"</string>
+ <string name="keep_screen_on" msgid="1146389631208760344">"ଜାଗ୍ରତ ରଖନ୍ତୁ"</string>
+ <string name="keep_screen_on_summary" msgid="2173114350754293009">"ଚାର୍ଜ ହେବାବେଳେ ସ୍କ୍ରୀନ୍ ଆଦୌ ବନ୍ଦ ହେବନାହିଁ"</string>
+ <string name="bt_hci_snoop_log" msgid="3340699311158865670">"ବ୍ଲୁଟୁଥ୍ HCI ସ୍ନୁପ୍ ଲଗ୍ ସକ୍ଷମ କରନ୍ତୁ"</string>
+ <string name="bt_hci_snoop_log_summary" msgid="730247028210113851">"ଗୋଟିଏ ଫାଇଲ୍ରେ ସମସ୍ତ ବ୍ଲୁଟୂଥ୍ HCI ପ୍ୟାକେଟ୍ଗୁଡିକୁ କ୍ୟାପଚର୍ କରନ୍ତୁ"</string>
+ <string name="oem_unlock_enable" msgid="6040763321967327691">"OEM ଅନଲକ୍ କରିବା"</string>
+ <string name="oem_unlock_enable_summary" msgid="4720281828891618376">"bootloaderକୁ ଅନ୍ଲକ୍ ହେବାର ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+ <string name="confirm_enable_oem_unlock_title" msgid="4802157344812385674">"OEM ଅନଲକ୍ କରିବା ଅନୁମତି ଦେବେ?"</string>
+ <string name="confirm_enable_oem_unlock_text" msgid="5517144575601647022">"ଚେତାବନୀ: ଏହି ସେଟିଙ୍ଗ ଚାଲୁ ଥିବାବେଳେ ଡିଭାଇସ୍ର ସୁରକ୍ଷା ବୈଶିଷ୍ଟ୍ୟ କାମ କରିବ ନାହିଁ"</string>
+ <string name="mock_location_app" msgid="7966220972812881854">"ନକଲି ଲୋକେଶନ୍ ଆପ୍ର ଚୟନ କରନ୍ତୁ"</string>
+ <string name="mock_location_app_not_set" msgid="809543285495344223">"କୌଣସି ନକଲି ଲୋକେଶନ ଏପ ସେଟ କରାଯାଇନାହିଁ"</string>
+ <string name="mock_location_app_set" msgid="8966420655295102685">"ନକଲି ଲୋକେଶନ୍ ଆପ୍: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="debug_networking_category" msgid="7044075693643009662">"ନେଟ୍ୱର୍କିଙ୍ଗ"</string>
+ <string name="wifi_display_certification" msgid="8611569543791307533">"ୱାୟର୍ଲେସ୍ ଡିସ୍ପ୍ଲେ ସର୍ଟିଫିକେଶନ୍"</string>
+ <string name="wifi_verbose_logging" msgid="4203729756047242344">"Wi‑Fi ଭରବୋସ୍ ଲଗିଙ୍ଗ ସକ୍ଷମ କରନ୍ତୁ"</string>
+ <!-- no translation found for wifi_connected_mac_randomization (3168165236877957767) -->
+ <skip />
+ <string name="mobile_data_always_on" msgid="8774857027458200434">"ମୋବାଇଲ୍ ଡାଟା ସର୍ବଦା ସକ୍ରିୟ"</string>
+ <string name="tethering_hardware_offload" msgid="7470077827090325814">"ଟିଥରିଙ୍ଗ ହାର୍ଡୱେର ବେଗ"</string>
+ <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"ବ୍ଲୁଟୂଥ୍ ଡିଭାଇସ୍ଗୁଡ଼ିକୁ ନାମ ବିନା ଦେଖନ୍ତୁ"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ପୂର୍ଣ୍ଣ ଭଲ୍ୟୁମ୍ ଅକ୍ଷମ କରନ୍ତୁ"</string>
+ <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"ବ୍ଲୁଟୂଥ୍ AVRCP ଭର୍ସନ୍"</string>
+ <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"ବ୍ଲୁଟୂଥ୍ AVRCP ଭର୍ସନ୍"</string>
+ <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ବ୍ଲୁଟୁଥ୍ ଅଡିଓ କୋଡେକ୍"</string>
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"ବ୍ଲୁଟୁଥ୍ ଅଡିଓ କୋଡେକ୍ ଚୟନ କରନ୍ତୁ"</string>
+ <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"ବ୍ଲୁଟୂଥ୍ ଅଡିଓ ସାମ୍ପଲ୍ ରେଟ୍"</string>
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"ବ୍ଲୁଟୁଥ୍ ଅଡିଓ କୋଡେକ୍ ଚୟନ କରନ୍ତୁ: \n ନମୁନା ଦର"</string>
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"ନମୁନା ପିଛା ବ୍ଲୁଟୁଥ୍ ଅଡିଓ ବିଟ୍ସ"</string>
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"ବ୍ଲୁଟୂଥ ଅଡିଓ କୋଡେକ୍ ବାଛନ୍ତୁ:\nନମୂନା ପ୍ରତି ବିଟସ୍"</string>
+ <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"ବ୍ଲୁଟୂଥ୍ ଅଡିଓ ଚ୍ୟାନେଲ୍ ମୋଡ୍"</string>
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"ବ୍ଲୁଟୂଥ୍ ଅଡ଼ିଓ କୋଡେକ୍:\nଚାନେଲ୍ ମୋଡ୍ ବାଛନ୍ତୁ"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"ବ୍ଲୁଟୁଥ୍ ଅଡିଓ LDAC କୋଡେକ୍: ପ୍ଲେବ୍ୟାକ୍ ଗୁଣବତ୍ତା"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"ବ୍ଲୁଟୂଥ୍ ଅଡିଓ LDAC କୋଡେକ୍ ବାଛନ୍ତୁ:\nପ୍ଲେବ୍ୟାକ୍ କ୍ୱାଲିଟୀ"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"ଷ୍ଟ୍ରିମ୍ କରୁଛି: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
+ <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>
+ <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>
+ <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"ୱାଇ-ଫାଇ ଲଗିଙ୍ଗ ସ୍ତର ବଢ଼ାନ୍ତୁ, ୱାଇ-ଫାଇ ପିକର୍ରେ ପ୍ରତି SSID RSSI ଦେଖାନ୍ତୁ"</string>
+ <!-- no translation found for wifi_connected_mac_randomization_summary (1743059848752201485) -->
+ <skip />
+ <string name="select_logd_size_title" msgid="7433137108348553508">"ଲଗର୍ ବଫର୍ ଆକାରଗୁଡ଼ିକ"</string>
+ <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"ଲଗ୍ ବଫର୍ ପିଛା ଲଗର୍ ଆକାରଗୁଡିକର ଚୟନ କରନ୍ତୁ"</string>
+ <string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"ଲଗର୍ ରୋଧି ଷ୍ଟୋରେଜ୍ ଖାଲି କରିବେ?"</string>
+ <string name="dev_logpersist_clear_warning_message" msgid="2256582531342994562">"ଯଦି ଆମେ ଦୃଢ ଲଗର୍ ସହିତ ଆଉ ତଦାରଖ କରୁନଥିବୁ, ତେବେ ଆମକୁ ଆପଣଙ୍କ ଡିଭାଇସ୍ରେ ଥିବା ଲଗର୍ ଡାଟାକୁ ଲିଭାଇବାକୁ ପଡ଼ିବ।"</string>
+ <string name="select_logpersist_title" msgid="7530031344550073166">"ଡିଭାଇସ୍ରେ ଲଗାତର ଲଗର୍ ଡାଟା ଷ୍ଟୋର୍ କରନ୍ତୁ"</string>
+ <string name="select_logpersist_dialog_title" msgid="4003400579973269060">"ଡିଭାଇସ୍ରେ ଲଗାତର ଷ୍ଟୋର୍ କରିବାକୁ ଲଗ୍ ବଫର୍ ଚୟନ କରନ୍ତୁ"</string>
+ <string name="select_usb_configuration_title" msgid="2649938511506971843">"USB କନଫିଗ୍ୟୁରେସନ୍ ଚୟନ କରନ୍ତୁ"</string>
+ <string name="select_usb_configuration_dialog_title" msgid="6385564442851599963">"USB କନଫିଗ୍ୟୁରେସନ୍ ଚୟନ କରନ୍ତୁ"</string>
+ <string name="allow_mock_location" msgid="2787962564578664888">"ନକଲି ଲୋକେଶନ୍ର ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+ <string name="allow_mock_location_summary" msgid="317615105156345626">"ନକଲି ଲୋକେଶନ୍ର ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+ <string name="debug_view_attributes" msgid="6485448367803310384">"ବିଶେଷତା ଯାଞ୍ଚ ଦର୍ଶନ ସକ୍ଷମ କରନ୍ତୁ"</string>
+ <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"ୱାଇ-ଫାଇ ସକ୍ରିୟ ଥିଲେ ମଧ୍ୟ ସର୍ବଦା ମୋବାଇଲ୍ ଡାଟାକୁ ସକ୍ରିୟ ରଖନ୍ତୁ (ଦ୍ରୁତ ନେଟ୍ୱର୍କ ସ୍ୱିଚିଙ୍ଗ ପାଇଁ)।"</string>
+ <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"ଯଦି ଉପଲବ୍ଧ ଥାଏ, ଟିଥରିଙ୍ଗ ହାର୍ଡୱେର୍ ଆକ୍ସଲରେଶନ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <string name="adb_warning_title" msgid="6234463310896563253">"USB ଡିବଗିଙ୍ଗ କରିବେ?"</string>
+ <string name="adb_warning_message" msgid="7316799925425402244">"USB ଡିବଗିଂ କେବଳ ଡେଭଲପମେଣ୍ଟ ଉଦ୍ଦେଶ୍ୟ ପାଇଁ ଉଦ୍ଦିଷ୍ଟ ଅଟେ। ଆପଣଙ୍କ କମ୍ପ୍ୟୁଟର ଏବଂ ଡିଭାଇସ୍ ମଧ୍ୟରେ ଡାଟା କପି କରିବାକୁ, ବିନା ବିଜ୍ଞପ୍ତିରେ ଆପଣଙ୍କ ଡିଭାଇସରେ ଆପସ୍ ସଂସ୍ଥାପନ କରିବାକୁ, ଏବଂ ଲଗ୍ ଡାଟା ପଢିବାକୁ ଏହା ବ୍ୟବହାର କରନ୍ତୁ।"</string>
+ <string name="adb_keys_warning_message" msgid="5659849457135841625">"ଅଧିକୃତ ସମସ୍ତ କମ୍ପ୍ୟୁଟରରୁ USB ଡିବଗ୍ କରିବା ଆକ୍ସେସ୍ ପ୍ରତ୍ୟାହାର କରିବେ କି?"</string>
+ <string name="dev_settings_warning_title" msgid="7244607768088540165">"ଡେଭଲପମେଣ୍ଟ ସେଟିଙ୍ଗ ଅନୁମତି ଦେବେ?"</string>
+ <string name="dev_settings_warning_message" msgid="2298337781139097964">"ଏହି ସେଟିଙ୍ଗଗୁଡ଼ିକ କେବଳ ବିକାଶ ବ୍ୟବହାର ପାଇଁ ଉଦ୍ଦିଷ୍ଟ। ସେଗୁଡ଼ିକ କାରଣରୁ ଆପଣଙ୍କ ଡିଭାଇସ୍ ଓ ଆପ୍ଲିକେଶନ୍ଗୁଡ଼ିକ ଠିକ୍ ଭାବେ କାମ ନକରିପାରେ।"</string>
+ <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB ଜରିଆରେ ଆପ୍ଗୁଡ଼ିକୁ ଯାଞ୍ଚ କରନ୍ତୁ"</string>
+ <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT ମାଧ୍ୟମରେ ଇନଷ୍ଟଲ ହୋଇଥିବା ଆପ୍ଗୁଡ଼ିକ ହାନିକାରକ କାର୍ଯ୍ୟକଳାପ କରୁଛି କି ନାହିଁ ଯାଞ୍ଚ କରନ୍ତୁ।"</string>
+ <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"(କେବଳ MAC ଠିକଣା ଥାଇ) ନାମ ବିନା ବ୍ଲୁଟୂଥ ଡିଭାଇସଗୁଡ଼ିକ ପ୍ରଦର୍ଶିତ ହେବ"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ରିମୋଟ୍ ଡିଭାଇସ୍ଗୁଡ଼ିକରେ ଯଦି ଅସ୍ୱୀକାର୍ଯ୍ୟ ଭାବେ ଉଚ୍ଚ ଭଲ୍ୟୁମ କିମ୍ବା ନିୟନ୍ତ୍ରଣର ଅଭାବ ପରି ଭଲ୍ୟୁମ ସମସ୍ୟା ଥାଏ ବ୍ଲୁଟୁଥ୍ ଆବସଲ୍ୟୁଟ୍ ଭଲ୍ୟୁମ ବୈଶିଷ୍ଟ୍ୟ ଅକ୍ଷମ କରେ।"</string>
+ <string name="enable_terminal_title" msgid="95572094356054120">"ସ୍ଥାନୀୟ ଟର୍ମିନାଲ୍"</string>
+ <string name="enable_terminal_summary" msgid="67667852659359206">"ସ୍ଥାନୀୟ ଶେଲ୍କୁ ଆକସେସ୍ ଦେଉଥିବା ଟର୍ମିନଲ୍ ଆପ୍କୁ ସକ୍ଷମ କରନ୍ତୁ"</string>
+ <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP ଯାଞ୍ଚ କରୁଛି"</string>
+ <string name="hdcp_checking_dialog_title" msgid="5141305530923283">"HDCPର ଯାଞ୍ଚ ଗତିବିଧି ସେଟ୍ କରନ୍ତୁ"</string>
+ <string name="debug_debugging_category" msgid="6781250159513471316">"ଡିବଗ୍ କରୁଛି"</string>
+ <string name="debug_app" msgid="8349591734751384446">"ଡିବଗ୍ ଆପ୍ ବାଛି ନିଅନ୍ତୁ"</string>
+ <string name="debug_app_not_set" msgid="718752499586403499">"କୌଣସି ଡିବଗ୍ ଆପ୍ଲିକେଶନ୍ ସେଟ୍ ହୋଇନାହିଁ"</string>
+ <string name="debug_app_set" msgid="2063077997870280017">"ଆପ୍ଲିକେଶନ୍ ଡିବଗ୍ କରୁଛି: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="select_application" msgid="5156029161289091703">"ଆପ୍ଲିକେଶନ୍ ବାଛନ୍ତୁ"</string>
+ <string name="no_application" msgid="2813387563129153880">"କିଛି ନୁହେଁ"</string>
+ <string name="wait_for_debugger" msgid="1202370874528893091">"ଡିବଗର୍ ପାଇଁ ଅପେକ୍ଷା କରନ୍ତୁ"</string>
+ <string name="wait_for_debugger_summary" msgid="1766918303462746804">"ଡିବଗ୍ ହୋଇଥିବା ଆପ୍ଲିକେଶନ୍, ନିଷ୍ପାଦନ ପୂର୍ବରୁ ଆଟାଚ୍ କରିବା ପାଇଁ ଡିବଗର୍କୁ ଅପେକ୍ଷା କରେ"</string>
+ <string name="debug_input_category" msgid="1811069939601180246">"ଇନପୁଟ୍"</string>
+ <string name="debug_drawing_category" msgid="6755716469267367852">"ଅଙ୍କନ"</string>
+ <string name="debug_hw_drawing_category" msgid="6220174216912308658">"ହାର୍ଡୱେର୍ ଆକ୍ସଲରେଟେଡ୍ ରେଣ୍ଡରିଙ୍ଗ"</string>
+ <string name="media_category" msgid="4388305075496848353">"ମିଡିଆ"</string>
+ <string name="debug_monitoring_category" msgid="7640508148375798343">"ତଦାରାଖ କରିବା"</string>
+ <string name="strict_mode" msgid="1938795874357830695">"କଡ଼ା ମୋଡ୍ ସକ୍ଷମ କରାଯାଇଛି"</string>
+ <string name="strict_mode_summary" msgid="142834318897332338">"ମୁଖ୍ୟ ଥ୍ରେଡ୍ରେ ଆପ୍ ଦୀର୍ଘ ସମୟ କାର୍ଯ୍ୟ କରିବା ବେଳେ ସ୍କ୍ରିନ୍ ଫ୍ଲାସ୍ କରନ୍ତୁ"</string>
+ <string name="pointer_location" msgid="6084434787496938001">"ପଏଣ୍ଟର୍ ଲୋକେଶନ୍"</string>
+ <string name="pointer_location_summary" msgid="840819275172753713">"ଏବେର ଟଚ୍ ଡାଟା ଦେଖାଉଥିବା ସ୍କ୍ରୀନ୍ ଓଭର୍ଲେ"</string>
+ <string name="show_touches" msgid="2642976305235070316">"ଟାପ୍ଗୁଡ଼ିକୁ ଦେଖାଅ"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"ଟାପ୍ସ ପାଇଁ ଦୃଶ୍ୟ ମତାମତ ଦେଖାଅ"</string>
+ <string name="show_screen_updates" msgid="5470814345876056420">"ସର୍ଫେସ୍ ଅପ୍ଡେଟ୍ ଦେଖାଅ"</string>
+ <string name="show_screen_updates_summary" msgid="2569622766672785529">"ସମଗ୍ର ୱିଣ୍ଡୋ ପୃଷ୍ଠ ଅପଡେଟ୍ ହେବା ବେଳେ ସେଗୁଡ଼ିକ ଫ୍ଲାସ୍ କରନ୍ତୁ"</string>
+ <string name="show_hw_screen_updates" msgid="5036904558145941590">"GPU ଭ୍ୟୁ ଅପଡେଟ୍ ଦେଖନ୍ତୁ"</string>
+ <string name="show_hw_screen_updates_summary" msgid="1115593565980196197">"GPU ସହ ଅଙ୍କାଯାଇଥିବା ବେଳେ ୱିଣ୍ଡୋ ଭିତରେ ଦୃଶ୍ୟଗୁଡ଼ିକ ଫ୍ଲାଶ କରନ୍ତୁ"</string>
+ <string name="show_hw_layers_updates" msgid="5645728765605699821">"ହାର୍ଡୱେର୍ ଲେୟର୍ର ଅପଡେଟଗୁଡ଼ିକ ଦେଖାନ୍ତୁ"</string>
+ <string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"ହାର୍ଡୱେୟାର ଲେୟାରଗୁଡିକ ଅପଡେଟ୍ ହେବା ବେଳେ ସେଗୁଡିକ ସବୁଜ ଫ୍ଲାସ୍ କରନ୍ତୁ"</string>
+ <string name="debug_hw_overdraw" msgid="2968692419951565417">"GPU ଓଭର୍ଡ୍ର ଡିବଗ୍ କର"</string>
+ <string name="disable_overlays" msgid="2074488440505934665">"HW ଓଭରଲେସ ଅକ୍ଷମ କରନ୍ତୁ"</string>
+ <string name="disable_overlays_summary" msgid="3578941133710758592">"ସ୍କ୍ରୀନ୍ କମ୍ପୋଜିଟିଙ୍ଗ ପାଇଁ ସର୍ବଦା GPU ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <string name="simulate_color_space" msgid="6745847141353345872">"ରଙ୍ଗ ସ୍ଥାନ ଅନୁକରଣ କରନ୍ତୁ"</string>
+ <string name="enable_opengl_traces_title" msgid="6790444011053219871">"OpenGL ଟ୍ରେସ୍ ସକ୍ଷମ କରନ୍ତୁ"</string>
+ <string name="usb_audio_disable_routing" msgid="8114498436003102671">"USB ଅଡିଓ ରାଉଟିଙ୍ଗ ଅକ୍ଷମ କରନ୍ତୁ"</string>
+ <string name="usb_audio_disable_routing_summary" msgid="980282760277312264">"USB ଅଡିଓ ଉପକରଣଗୁଡ଼ିକୁ ଅଟୋମେଟିକ୍ ରୂଟିଙ୍ଗ ଅକ୍ଷମ କରନ୍ତୁ"</string>
+ <string name="debug_layout" msgid="5981361776594526155">"ଲେଆଉଟ୍ ବାଉଣ୍ଡ ଦେଖାଅ"</string>
+ <string name="debug_layout_summary" msgid="2001775315258637682">"କ୍ଲିପ୍ ବାଉଣ୍ଡ, ମାର୍ଜିନ୍ ଆଦି ଦେଖନ୍ତୁ"</string>
+ <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL ଲେଆଉଟ୍ ଦିଗ ବାଧ୍ୟ କରନ୍ତୁ"</string>
+ <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"ସମସ୍ତ ଲୋକେଲ୍ ପାଇଁ ସ୍କ୍ରିନ୍ ଲେଆଉଟ୍ ଦିଗ ଡାହାଣରୁ ବାମକୁ ବାଧ୍ୟ କରନ୍ତୁ"</string>
+ <string name="force_hw_ui" msgid="6426383462520888732">"GPU ରେଣ୍ଡରିଂ ବାଧ୍ୟ କରନ୍ତୁ"</string>
+ <string name="force_hw_ui_summary" msgid="5535991166074861515">"2D ଅଙ୍କନ ପାଇଁ ଜିପିୟୁର ବ୍ୟବହାର ଉପରେ ଜୋର ଦେବା"</string>
+ <string name="force_msaa" msgid="7920323238677284387">"4x MSAA ବାଧ୍ୟ କରନ୍ତୁ"</string>
+ <string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0 ଆପ୍ରେ 4x MSAA ସକ୍ଷମ କରନ୍ତୁ"</string>
+ <string name="show_non_rect_clip" msgid="505954950474595172">"ଅଣ-ଆୟତାକାର କ୍ଲିପ୍ କାର୍ଯ୍ୟକୁ ଡିବଗ୍ କରନ୍ତୁ"</string>
+ <string name="track_frame_time" msgid="6146354853663863443">"ପ୍ରୋଫାଇଲ୍ GPU ରେଣ୍ଡରିଂ"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU ଡିବଗ୍ ଲେୟର୍ ସକ୍ଷମ କରନ୍ତୁ"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"ଡିବଗ୍ ଆପ୍ଗୁଡ଼ିକ ପାଇଁ GPU ଡିବଗ୍ ଲେୟର୍ ଲୋଡ୍ କରିବାର ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+ <string name="window_animation_scale_title" msgid="6162587588166114700">"ୱିଣ୍ଡୋ ଆନିମେଶନ୍ ସ୍କେଲ୍"</string>
+ <string name="transition_animation_scale_title" msgid="387527540523595875">"ଟ୍ରାଞ୍ଜିସନ୍ ଆନିମେସନ୍ ସ୍କେଲ୍"</string>
+ <string name="animator_duration_scale_title" msgid="3406722410819934083">"ଆନିମେଟର୍ ଅବଧି ସ୍କେଲ୍"</string>
+ <string name="overlay_display_devices_title" msgid="5364176287998398539">"ମଧ୍ୟମ ଡିସ୍ପ୍ଲେର ଛଳନା କରନ୍ତୁ"</string>
+ <string name="debug_applications_category" msgid="4206913653849771549">"ଆପ୍ଗୁଡ଼ିକ"</string>
+ <string name="immediately_destroy_activities" msgid="1579659389568133959">"କାର୍ଯ୍ୟକଳାପଗୁଡ଼ିକୁ ରଖନ୍ତୁ ନାହିଁ"</string>
+ <string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"ଉପଯୋଗକର୍ତ୍ତା ଏହାକୁ ଛାଡ଼ିବା କ୍ଷଣି ସମସ୍ତ କାର୍ଯ୍ୟକଳାପକୁ ନଷ୍ଟ କରିଦିଅନ୍ତୁ"</string>
+ <string name="app_process_limit_title" msgid="4280600650253107163">"ପୃଷ୍ଠପଟ ପ୍ରକ୍ରିୟା ସୀମା"</string>
+ <string name="show_all_anrs" msgid="28462979638729082">"ସମସ୍ତ ANRs ଦେଖାଦେଉ"</string>
+ <string name="show_all_anrs_summary" msgid="641908614413544127">"ବ୍ୟାକ୍ଗ୍ରାଉଣ୍ଡ ଆପ୍ଗୁଡ଼ିକ ପାଇଁ \"ଆପ୍ ଉତ୍ତର ଦେଉନାହିଁ\" ଡାୟଲଗ୍ ଦେଖାଅ"</string>
+ <string name="show_notification_channel_warnings" msgid="1399948193466922683">"ବିଜ୍ଞପ୍ତି ଚାନେଲ୍ ଚେତାବନୀ ଦେଖାଦେଉ"</string>
+ <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"ଏକ ବୈଧ ଚ୍ୟାନେଲ୍ ବିନା ଏକ ଆପ୍ ଗୋଟିଏ ବିଜ୍ଞପ୍ତି ପୋଷ୍ଠ କରିବା ବେଳେ ଅନ୍-ସ୍କ୍ରୀନ୍ ସତର୍କତା ଦେଖାଏ"</string>
+ <string name="force_allow_on_external" msgid="3215759785081916381">"ଏକ୍ସଟର୍ନଲ୍ ଆପ୍ଗୁଡ଼ିକୁ ଜବରଦସ୍ତି ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+ <string name="force_allow_on_external_summary" msgid="3640752408258034689">"ଯେକୌଣସି ଆପ୍କୁ ଏକ୍ସଟର୍ନଲ୍ ଷ୍ଟୋରେଜ୍ରେ ଲେଖାଯୋଗ୍ୟ କରନ୍ତୁ, ମେନିଫେଷ୍ଟ ମୂଲ୍ୟ ଯାହା ହୋଇଥାଉ ନା କାହିଁକି"</string>
+ <string name="force_resizable_activities" msgid="8615764378147824985">"ଆକାର ବଦଳାଇବା ପାଇଁ କାର୍ଯ୍ୟକଳାପକୁ ବାଧ୍ୟ କରନ୍ତୁ"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"ସ୍ପଷ୍ଟ ଭାଲ୍ୟୁର ଚିନ୍ତା ନକରି ମଲ୍ଟୀ-ୱିଣ୍ଡୋ ପାଇଁ ସମସ୍ତ କାର୍ଯ୍ୟ ବଦଳାଇବାଯୋଗ୍ୟ କରନ୍ତୁ"</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"ଫ୍ରୀଫର୍ମ ୱିଣ୍ଡୋ ସକ୍ଷମ କର"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"ପରୀକ୍ଷାମୂଳକ ଫ୍ରୀଫର୍ମ ୱିଣ୍ଡୋସ୍ ପାଇଁ ସପୋର୍ଟ ସକ୍ଷମ କରନ୍ତୁ।"</string>
+ <string name="local_backup_password_title" msgid="3860471654439418822">"ଡେସ୍କଟପ୍ ବ୍ୟାକ୍ଅପ୍ର ପାସ୍ୱର୍ଡ"</string>
+ <string name="local_backup_password_summary_none" msgid="6951095485537767956">"ଡେସ୍କଟପ୍ ପୂର୍ଣ୍ଣ ବ୍ୟାକ୍ଅପ୍ଗୁଡ଼ିକ ବର୍ତ୍ତମାନ ସୁରକ୍ଷିତ ନୁହେଁ"</string>
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"ଡେସ୍କଟପ୍ର ସମ୍ପୂର୍ଣ୍ଣ ବ୍ୟାକ୍ଅପ୍ ପାଇଁ ପାସ୍ୱର୍ଡ ବଦଳାଇବା କିମ୍ୱା କାଢ଼ିଦେବା ନିମନ୍ତେ ଟାପ୍ କରନ୍ତୁ"</string>
+ <string name="local_backup_password_toast_success" msgid="582016086228434290">"ନୂଆ ବ୍ୟାକ୍ଅପ୍ ପାସ୍ୱର୍ଡ ସେଟ୍ କରିଦିଆଗଲା"</string>
+ <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"ନୂଆ ପାସ୍ୱର୍ଡ ଓ ସୁନିଶ୍ଚିତତା ମେଳ ହେଉନାହିଁ"</string>
+ <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"ବ୍ୟାକ୍ଅପ୍ ପାସ୍ୱର୍ଡ ସେଟିଙ୍ଗ ବିଫଳ ହୋଇଛି"</string>
+ <string-array name="color_mode_names">
+ <item msgid="2425514299220523812">"ଜୀବନ୍ତ (ପୂର୍ବ-ନିର୍ଦ୍ଧାରିତ)"</item>
+ <item msgid="8446070607501413455">"ପ୍ରାକୃତିକ"</item>
+ <item msgid="6553408765810699025">"ମାନକ"</item>
+ </string-array>
+ <string-array name="color_mode_descriptions">
+ <item msgid="4979629397075120893">"ବର୍ଦ୍ଧିତ ରଙ୍ଗ"</item>
+ <item msgid="8280754435979370728">"ଆଖି ଦ୍ୱାରା ଦେଖାଯାଇଥିବା ପରି ପ୍ରାକୃତିକ ରଙ୍ଗ"</item>
+ <item msgid="5363960654009010371">"ଡିଜିଟାଲ୍ କଣ୍ଟେଣ୍ଟ ପାଇଁ ରଙ୍ଗଗୁଡ଼ିକ ଅନୁକୂଳିତ ହୋଇଛି"</item>
+ </string-array>
+ <!-- no translation found for inactive_apps_title (9042996804461901648) -->
+ <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"ନିଷ୍କ୍ରିୟ। ଟୋଗଲ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"ସକ୍ରିୟ। ବଦଳାଇବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for standby_bucket_summary (6567835350910684727) -->
+ <skip />
+ <string name="runningservices_settings_title" msgid="8097287939865165213">"ଚାଲୁଥିବା ସେବାଗୁଡ଼ିକ"</string>
+ <string name="runningservices_settings_summary" msgid="854608995821032748">"ଏବେ ଚାଲୁଥିବା ସେବାଗୁଡ଼ିକୁ ଦେଖନ୍ତୁ ଓ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"ୱେବ୍ଦୃଶ୍ୟ ପ୍ରୟୋଗ"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView କାର୍ଯ୍ୟକାରିତାକୁ ସେଟ୍ କରନ୍ତୁ"</string>
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ଏହି ପସନ୍ଦ ଆଉ ମାନ୍ୟ ନାହିଁ। ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="convert_to_file_encryption" msgid="3060156730651061223">"ଫାଇଲ ଏନକ୍ରିପ୍ସନକୁ ବଦଳାଅ"</string>
+ <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ବଦଳାନ୍ତୁ…"</string>
+ <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ଫାଇଲ୍ ଏନ୍କ୍ରିପ୍ଟ ହୋଇସାରିଲାଣି"</string>
+ <string name="title_convert_fbe" msgid="1263622876196444453">"ଫାଇଲ୍ ଭିତ୍ତିକ ଏନ୍କ୍ରିପ୍ସନ୍ ପାଇଁ ବଦଳାଉଛି"</string>
+ <string name="convert_to_fbe_warning" msgid="6139067817148865527">"ଫାଇଲ୍ ଭିତ୍ତିକ ଏନ୍କ୍ରିପ୍ସନ୍ରେ ଡାଟା ପାର୍ଟିଶନ୍ ବଦଳାନ୍ତୁ।\n !!ଚେତାବନୀ!! ଏହା ଆପଣଙ୍କର ସମସ୍ତ ଡାଟା ଉଡ଼ାଇଦେବ।\n ଏହି ବୈଶିଷ୍ଟ୍ୟ ହେଉଛି ଆଲ୍ଫା ଏବଂ ଠିକ ଭାବେ କାମ କରିନପାରେ।\n ଜାରି ରଖିବା ପାଇଁ \"ୱାଇପ୍ ଓ କନ୍ଭର୍ଟ…\" ଦାବନ୍ତୁ"</string>
+ <string name="button_convert_fbe" msgid="5152671181309826405">"ଲିଭାନ୍ତୁ ଏବଂ ବଦଳାନ୍ତୁ…"</string>
+ <string name="picture_color_mode" msgid="4560755008730283695">"ପିକ୍ଚର୍ ରଙ୍ଗ ମୋଡ୍"</string>
+ <string name="picture_color_mode_desc" msgid="1141891467675548590">"sRGB ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <string name="daltonizer_mode_disabled" msgid="7482661936053801862">"ଅକ୍ଷମ ହୋଇଛି"</string>
+ <string name="daltonizer_mode_monochromacy" msgid="8485709880666106721">"ସମ୍ପୂର୍ଣ୍ଣ ବର୍ଣ୍ଣାନ୍ଧତା"</string>
+ <string name="daltonizer_mode_deuteranomaly" msgid="5475532989673586329">"ବର୍ଣ୍ଣାନ୍ଧତା (ନାଲି-ସବୁଜ)"</string>
+ <string name="daltonizer_mode_protanomaly" msgid="8424148009038666065">"ପ୍ରୋଟାନୋମାଲି (ଲାଲ୍-ସବୁଜ)"</string>
+ <string name="daltonizer_mode_tritanomaly" msgid="481725854987912389">"Tritanomaly (ନୀଳ-ହଳଦିଆ)"</string>
+ <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"ରଙ୍ଗ ସଠିକତା"</string>
+ <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>
+ <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>
+ <string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> ଅବଶିଷ୍ଟ"</string>
+ <!-- no translation found for power_remaining_less_than_duration_only (5996752448813295329) -->
+ <skip />
+ <!-- no translation found for power_remaining_less_than_duration (7967078125657859046) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (6846716609975752316) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8884488700395194194) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (8168317165722752881) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (5957064378548718872) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (9055596817716471373) -->
+ <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) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (261050880878965621) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (2020049829798578618) -->
+ <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_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>
+ <string name="battery_info_status_charging_lower" msgid="8689770213898117994">"ଚାର୍ଜ ହେଉଛି"</string>
+ <string name="battery_info_status_discharging" msgid="310932812698268588">"ଚାର୍ଜ ହେଉନାହିଁ"</string>
+ <string name="battery_info_status_not_charging" msgid="8523453668342598579">"ପ୍ଲଗ୍ରେ ଲାଗିଛି, ହେଲେ ଏବେ ଚାର୍ଜ କରିପାରିବ ନାହିଁ"</string>
+ <string name="battery_info_status_full" msgid="2824614753861462808">"ସମ୍ପୂର୍ଣ୍ଣ"</string>
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ଆଡ୍ମିନ୍ ଦ୍ୱାରା ନିୟନ୍ତ୍ରିତ"</string>
+ <string name="enabled_by_admin" msgid="5302986023578399263">"ଆଡମିନ୍ଙ୍କ ଦ୍ୱାରା ସକ୍ଷମ କରାଯାଇଛି"</string>
+ <string name="disabled_by_admin" msgid="8505398946020816620">"ଆଡ୍ମିନ୍ ଦ୍ଵାରା ଅକ୍ଷମ କରାଯାଇଛି"</string>
+ <string name="disabled" msgid="9206776641295849915">"ଅକ୍ଷମ ହୋଇଛି"</string>
+ <string name="external_source_trusted" msgid="2707996266575928037">"ଅନୁମୋଦିତ"</string>
+ <string name="external_source_untrusted" msgid="2677442511837596726">"ଅନୁମତି ନାହିଁ"</string>
+ <string name="install_other_apps" msgid="6986686991775883017">"ଅଜଣା ଆପ୍ଗୁଡଡ଼ିକ ଇନ୍ଷ୍ଟଲ୍ କର"</string>
+ <string name="home" msgid="3256884684164448244">"ସେଟିଙ୍ଗ ହୋମ୍"</string>
+ <string-array name="battery_labels">
+ <item msgid="8494684293649631252">"0%"</item>
+ <item msgid="8934126114226089439">"୫୦%"</item>
+ <item msgid="1286113608943010849">"୧୦୦%"</item>
+ </string-array>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ପୂର୍ବେ"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ଅବଶିଷ୍ଟ"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"ଛୋଟ"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ଡିଫଲ୍ଟ"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"ବଡ"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ବୃହତ୍ତମ"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ବୃହତ୍ତମ"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"କଷ୍ଟମ୍ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
+ <string name="help_feedback_label" msgid="6815040660801785649">"ସହାୟତା ଓ ମତାମତ"</string>
+ <string name="content_description_menu_button" msgid="8182594799812351266">"ମେନୁ"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"ଡେମୋ ମୋଡ୍ରେ ଫ୍ୟାକ୍ଟୋରୀ ରିସେଟ୍ କରିବାକୁ ପାସ୍ୱାର୍ଡ ଲେଖନ୍ତୁ"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"ପରବର୍ତ୍ତୀ"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"ପାସ୍ୱର୍ଡ ଆବଶ୍ୟକ"</string>
+ <string name="active_input_method_subtypes" msgid="3596398805424733238">"ସକ୍ରିୟ ଇନପୁଟ୍-ପଦ୍ଧତିଗୁଡ଼ିକ"</string>
+ <string name="use_system_language_to_select_input_method_subtypes" msgid="5747329075020379587">"ସିଷ୍ଟମ୍ ଭାଷା ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <string name="failed_to_open_app_settings_toast" msgid="1251067459298072462">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> ପାଇଁ ସେଟିଙ୍ଗ ଖୋଲିବାରେ ବିଫଳ"</string>
+ <string name="ime_security_warning" msgid="4135828934735934248">"ଏହି ଇନ୍ପୁଟ୍ ପଦ୍ଧତି, ପାସ୍ୱର୍ଡ ଓ କ୍ରେଡିଟ୍ କାର୍ଡ ନମ୍ୱର୍ ଭଳି ବ୍ୟକ୍ତିଗତ ଡାଟା ସମେତ ଆପଣ ଟାଇପ୍ କରିଥିବା ସମସ୍ତ ଅକ୍ଷର ସଂଗହ କରିପାରେ।ଏହା, <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> ଆପ୍ରୁ ଆସିଛି| ଏହି ଇନ୍ପୁଟ୍ ପଦ୍ଧତି ବ୍ୟବହାର କରିବେ?"</string>
+ <string name="direct_boot_unaware_dialog_message" msgid="7870273558547549125">"ଧ୍ୟାନଦିଅନ୍ତୁ: ରିବୁଟ୍ କରିବା ପରେ, ଆପଣଙ୍କ ଫୋନ୍ ଅନଲକ୍ ନହେବା ପର୍ଯ୍ୟନ୍ତ ଏହି ଆପ୍ ଆରମ୍ଭ ହୋଇପାରିବ ନାହିଁ"</string>
+ <string name="ims_reg_title" msgid="7609782759207241443">"IMS ପଞ୍ଜିକରଣ ସ୍ଥିତି"</string>
+ <string name="ims_reg_status_registered" msgid="933003316932739188">"ପଞ୍ଜିକୃତ"</string>
+ <string name="ims_reg_status_not_registered" msgid="6529783773485229486">"ପଞ୍ଜିକୃତ ହୋଇନାହିଁ"</string>
+ <string name="status_unavailable" msgid="7862009036663793314">"ଉପଲବ୍ଧ ନାହିଁ"</string>
+ <!-- no translation found for wifi_tether_connected_summary (3871603864314407780) -->
+ <!-- no translation found for accessibility_manual_zen_more_time (1636187409258564291) -->
+ <skip />
+ <!-- no translation found for accessibility_manual_zen_less_time (6590887204171164991) -->
+ <skip />
+ <!-- no translation found for zen_mode_enable_dialog_turn_on (8287824809739581837) -->
+ <skip />
+ <string name="cancel" msgid="6859253417269739139">"କ୍ୟାନ୍ସଲ୍"</string>
+ <!-- no translation found for zen_mode_settings_turn_on_dialog_title (2297134204747331078) -->
+ <skip />
+ <string name="zen_mode_settings_summary_off" msgid="6119891445378113334">"କଦାପି ନୁହେଁ"</string>
+ <!-- no translation found for zen_interruption_level_priority (2078370238113347720) -->
+ <skip />
+ <!-- no translation found for zen_mode_and_condition (4927230238450354412) -->
+ <skip />
+ <!-- no translation found for zen_alarm_warning_indef (3007988140196673193) -->
+ <skip />
+ <!-- no translation found for zen_alarm_warning (6236690803924413088) -->
+ <skip />
+ <!-- no translation found for alarm_template (4996153414057676512) -->
+ <skip />
+ <!-- no translation found for alarm_template_far (3779172822607461675) -->
+ <skip />
+</resources>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index bfea9a8..6549861 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"ਸਿਮ ਪਹੁੰਚ"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"ਸੁਣਨ ਦਾ ਸਾਧਨ"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ਫ਼ੋਨ ਔਡੀਓ ਲਈ ਵਰਤੋ"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ਫਾਈਲ ਟ੍ਰਾਂਸਫਰ ਲਈ ਵਰਤੋ"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ਇਨਪੁਟ ਲਈ ਵਰਤੋ"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"ਸੁਣਨ ਦੇ ਸਾਧਨ ਲਈ ਵਰਤੋ"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"ਪੇਅਰ ਕਰੋ"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ਪੇਅਰ ਕਰੋ"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"ਰੱਦ ਕਰੋ"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index fd177e5..55e43089 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"Dostop do kartice SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Zvok visoke kakovosti: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Zvok visoke kakovosti"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Slušni pripomoček"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Povezava s slušnim pripomočkom je vzpostavljena"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Povezan s profilom za predstavnostni zvok"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Povezava s profilom za zvok telefona vzpostavljena"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Povezava s strežnikom za prenos datotek je vzpostavljena"</string>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Uporabi za zvok telefona"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Uporabi za prenos datotek"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Uporabi za vnos"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Uporaba za slušni pripomoček"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Seznani"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SEZNANI"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Prekliči"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index cf0fe12..5524e2c 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"Qasje në kartën SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Audio HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Aparati i dëgjimit"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Lidhur me aparatin e dëgjimit"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"U lidh me audion e medias"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"U lidh me audion e telefonit"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"U lidh me serverin e transferimit të skedarëve"</string>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Përdor për audion e telefonit"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Përdor për transferimin e skedarëve"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Përdore për hyrjen"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Përdore për aparatin e dëgjimit"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Çifto"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ÇIFTO"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Anulo"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 4509470..d8c6e4d 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM-åtkomst"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD-ljud: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD-ljud"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Hörapparat"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Ansluten till hörapparat"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Ansluten till medialjud"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Ansluten till telefonens ljud"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Ansluten till filöverföringsserver"</string>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Använd för telefonens ljud"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Använd för filöverföring"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Använd för inmatning"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Använd med hörapparat"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Parkoppling"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PARKOPPLA"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Avbryt"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 274222b..b417cfb 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"சிம் அணுகல்"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"செவித்துணைக் கருவி"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"மொபைல் ஆடியோவைப் பயன்படுத்து"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"கோப்பு பரிமாற்றத்திற்காகப் பயன்படுத்து"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"உள்ளீட்டுக்குப் பயன்படுத்து"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"செவித்துணைக் கருவிக்காகப் பயன்படுத்து"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"இணை"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"இணை"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"ரத்துசெய்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 31f0cdf..99a35a3 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM యాక్సెస్"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"వినికిడి పరికరం"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ఫోన్ ఆడియో కోసం ఉపయోగించు"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ఫైల్ బదిలీ కోసం ఉపయోగించు"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ఇన్పుట్ కోసం ఉపయోగించు"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"వినికిడి పరికరం కోసం ఉపయోగించు"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"జత చేయి"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"జత చేయి"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"రద్దు చేయి"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 1985bda..9fdeb4a 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM Erişimi"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD ses: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD ses"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"İşitme Cihazı"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"İşitme Cihazına bağlandı"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Medya sesine bağlanıldı"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Telefon sesine bağlandı"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Dosya aktarım sunucusuna bağlandı"</string>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Telefon sesi için kullan"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Dosya aktarımı için kullan"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Giriş için kullan"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"İşitme Cihazı için kullan"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Eşle"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"EŞLE"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"İptal"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 90c77741..7c221d7 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM رسائی"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"سماعتی آلہ"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"فون آڈیو کیلئے استعمال کریں"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"فائل منتقل کرنے کیلئے استعمال کریں"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ان پٹ کیلئے استعمال"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"سماعتی آلے کیلئے استعمال کریں"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"جوڑا بنائیں"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"جوڑا بنائیں"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"منسوخ کریں"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index e37ab74..74bac0a 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"Quyền truy cập SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Âm thanh HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Âm thanh HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Trợ thính"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Đã kết nối với thiết bị trợ thính"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Đã kết nối với âm thanh phương tiện"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Đã kết nối với âm thanh điện thoại"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Đã kết nối với máy chủ chuyển tệp"</string>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Sử dụng cho âm thanh điện thoại"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Sử dụng để chuyển tệp"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Sử dụng để nhập"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Sử dụng cho thiết bị trợ thính"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Ghép nối"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"GHÉP NỐI"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Hủy"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 89edf54..3590ace 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM 卡存取权限"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"助听器"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"用于手机音频"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"用于文件传输"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"用于输入"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"用于助听器"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"配对"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"配对"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"取消"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 9b0ec86..f2162f4 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM 卡存取"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"高清音訊:<xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"高清音訊"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"助聽器"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"用於手機音效"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"用於傳輸檔案"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"用於輸入"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"用於助聽器"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"配對"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"配對"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"取消"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 1d6b4b9..fa3001a 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -75,10 +75,8 @@
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM 卡存取權"</string>
<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>
- <!-- no translation found for bluetooth_profile_hearing_aid (7999237886427812595) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (7188282786730266159) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"助聽器"</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>
@@ -95,8 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"用於電話音訊"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"用於傳輸檔案"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"用於輸入"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (908775281788309484) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"用於助聽器"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"配對"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"配對"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"取消"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
old mode 100755
new mode 100644
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
old mode 100755
new mode 100644
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
old mode 100755
new mode 100644
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
old mode 100755
new mode 100644
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
old mode 100755
new mode 100644
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
old mode 100755
new mode 100644
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
old mode 100755
new mode 100644
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
old mode 100755
new mode 100644
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
old mode 100755
new mode 100644
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
old mode 100755
new mode 100644
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
old mode 100755
new mode 100644
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
old mode 100755
new mode 100644
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
old mode 100755
new mode 100644
diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionController.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionController.java
index f740f7c..b0451b7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionController.java
@@ -107,7 +107,7 @@
} catch (NullPointerException e) {
Log.w(TAG, "mRemote service detached before able to query", e);
return null;
- } catch (RemoteException e) {
+ } catch (RemoteException | RuntimeException e) {
Log.w(TAG, "Error when calling getSuggestion()", e);
return null;
}
@@ -120,7 +120,7 @@
}
try {
mRemoteService.dismissSuggestion(suggestion);
- } catch (RemoteException e) {
+ } catch (RemoteException | RuntimeException e) {
Log.w(TAG, "Error when calling dismissSuggestion()", e);
}
}
@@ -133,7 +133,7 @@
try {
mRemoteService.launchSuggestion(suggestion);
- } catch (RemoteException e) {
+ } catch (RemoteException | RuntimeException e) {
Log.w(TAG, "Error when calling launchSuggestion()", e);
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java
index f50c0a4..9d7f59a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java
@@ -26,7 +26,6 @@
import android.widget.EditText;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -35,7 +34,6 @@
import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Ignore
public class CustomEditTextPreferenceTest {
@Mock
@@ -50,7 +48,6 @@
}
@Test
- @Ignore
public void bindDialogView_shouldRequestFocus() {
final String testText = "";
final EditText editText = spy(new EditText(RuntimeEnvironment.application));
@@ -63,7 +60,6 @@
}
@Test
- @Ignore
public void getEditText_noDialog_shouldNotCrash() {
ReflectionHelpers.setField(mPreference, "mFragment",
mock(CustomEditTextPreference.CustomPreferenceDialogFragment.class));
diff --git a/packages/SystemUI/README.md b/packages/SystemUI/README.md
index ae0a362..b441bbd 100644
--- a/packages/SystemUI/README.md
+++ b/packages/SystemUI/README.md
@@ -1,4 +1,170 @@
-# SystemUI Documentation
+# SystemUI
+
+“Everything you see in Android that's not an app”
+
+SystemUI is a persistent process that provides UI for the system but outside
+of the system_server process.
+
+The starting point for most of sysui code is a list of services that extend
+SystemUI that are started up by SystemUIApplication. These services then depend
+on some custom dependency injection provided by Dependency.
+
+Inputs directed at sysui (as opposed to general listeners) generally come in
+through IStatusBar. Outputs from sysui are through a variety of private APIs to
+the android platform all over.
+
+## SystemUIApplication
+
+When SystemUIApplication starts up, it will start up the services listed in
+config_systemUIServiceComponents or config_systemUIServiceComponentsPerUser.
+
+Each of these services extend SystemUI. SystemUI provides them with a Context
+and gives them callbacks for onConfigurationChanged (this historically was
+the main path for onConfigurationChanged, now also happens through
+ConfigurationController). They also receive a callback for onBootCompleted
+since these objects may be started before the device has finished booting.
+
+SystemUI and SystemUIApplication also have methods for putComponent and
+getComponent which were existing systems to get a hold of other parts of
+sysui before Dependency existed. Generally new things should not be added
+to putComponent, instead Dependency and other refactoring is preferred to
+make sysui structure cleaner.
+
+Each SystemUI service is expected to be a major part of system ui and the
+goal is to minimize communication between them. So in general they should be
+relatively silo'd.
+
+## Dependencies
+
+The first SystemUI service that is started should always be Dependency.
+Dependency provides a static method for getting a hold of dependencies that
+have a lifecycle that spans sysui. Dependency has code for how to create all
+dependencies manually added. SystemUIFactory is also capable of
+adding/replacing these dependencies.
+
+Dependencies are lazily initialized, so if a Dependency is never referenced at
+runtime, it will never be created.
+
+If an instantiated dependency implements Dumpable it will be included in dumps
+of sysui (and bug reports), allowing it to include current state information.
+This is how \*Controllers dump state to bug reports.
+
+If an instantiated dependency implements ConfigurationChangeReceiver it will
+receive onConfigurationChange callbacks when the configuration changes.
+
+## IStatusBar
+
+CommandQueue is the object that receives all of the incoming events from the
+system_server. It extends IStatusBar and dispatches those callbacks back any
+number of listeners. The system_server gets a hold of the IStatusBar when
+StatusBar calls IStatusBarService#registerStatusBar, so if StatusBar is not
+included in the XML service list, it will not be registered with the OS.
+
+CommandQueue posts all incoming callbacks to a handler and then dispatches
+those messages to each callback that is currently registered. CommandQueue
+also tracks the current value of disable flags and will call #disable
+immediately for any callbacks added.
+
+There are a few places where CommandQueue is used as a bus to communicate
+across sysui. Such as when StatusBar calls CommandQueue#recomputeDisableFlags.
+This is generally used a shortcut to directly trigger CommandQueue rather than
+calling StatusManager and waiting for the call to come back to IStatusBar.
+
+## Default SystemUI services list
+
+### [com.android.systemui.Dependency](/packages/SystemUI/src/com/android/systemui/Dependency.java)
+
+Provides custom dependency injection.
+
+### [com.android.systemui.util.NotificationChannels](/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java)
+
+Creates/initializes the channels sysui uses when posting notifications.
+
+### [com.android.systemui.statusbar.CommandQueue$CommandQueueStart](/packages/SystemUI/src/com/android/systemui/sstatusbar/CommandQueue.java)
+
+Creates CommandQueue and calls putComponent because its always been there
+and sysui expects it to be there :/
+
+### [com.android.systemui.keyguard.KeyguardViewMediator](/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java)
+
+Manages keyguard view state.
+
+### [com.android.systemui.recents.Recents](/packages/SystemUI/src/com/android/systemui/recents/Recents.java)
+
+Recents tracks all the data needed for recents and starts/stops the recents
+activity. It provides this cached data to RecentsActivity when it is started.
+
+### [com.android.systemui.volume.VolumeUI](/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java)
+
+Registers all the callbacks/listeners required to show the Volume dialog when
+it should be shown.
+
+### [com.android.systemui.stackdivider.Divider](/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java)
+
+Shows the drag handle for the divider between two apps when in split screen
+mode.
+
+### [com.android.systemui.SystemBars](/packages/SystemUI/src/com/android/systemui/SystemBars.java)
+
+This is a proxy to the actual SystemUI for the status bar. This loads from
+config_statusBarComponent which defaults to StatusBar. (maybe this should be
+removed and copy how config_systemUiVendorServiceComponent works)
+
+### [com.android.systemui.status.phone.StatusBar](/packages/SystemUI/src/com/android/systemui/status/phone/StatusBar.java)
+
+This shows the UI for the status bar and the notification shade it contains.
+It also contains a significant amount of other UI that interacts with these
+surfaces (keyguard, AOD, etc.). StatusBar also contains a notification listener
+to receive notification callbacks.
+
+### [com.android.systemui.usb.StorageNotification](/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java)
+
+Tracks USB status and sends notifications for it.
+
+### [com.android.systemui.power.PowerUI](/packages/SystemUI/src/com/android/systemui/power/PowerUI.java)
+
+Tracks power status and sends notifications for low battery/power saver.
+
+### [com.android.systemui.media.RingtonePlayer](/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java)
+
+Plays ringtones.
+
+### [com.android.systemui.keyboard.KeyboardUI](/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java)
+
+Shows UI for keyboard shortcuts (triggered by keyboard shortcut).
+
+### [com.android.systemui.pip.PipUI](/packages/SystemUI/src/com/android/systemui/pip/PipUI.java)
+
+Shows the overlay controls when Pip is showing.
+
+### [com.android.systemui.shortcut.ShortcutKeyDispatcher](/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java)
+
+Dispatches shortcut to System UI components.
+
+### @string/config_systemUIVendorServiceComponent
+
+Component allowing the vendor/OEM to inject a custom component.
+
+### [com.android.systemui.util.leak.GarbageMonitor$Service](/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java)
+
+Tracks large objects in sysui to see if there are leaks.
+
+### [com.android.systemui.LatencyTester](/packages/SystemUI/src/com/android/systemui/LatencyTester.java)
+
+Class that only runs on debuggable builds that listens to broadcasts that
+simulate actions in the system that are used for testing the latency.
+
+### [com.android.systemui.globalactions.GlobalActionsComponent](/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java)
+
+Shows the global actions dialog (long-press power).
+
+### [com.android.systemui.ScreenDecorations](/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java)
+
+Draws decorations about the screen in software (e.g. rounded corners, cutouts).
+
+### [com.android.systemui.fingerprint.FingerprintDialogImpl](/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java)
+
+Fingerprint UI.
---
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
index d0389eb..828c9df 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
@@ -34,6 +34,7 @@
android:layout_marginBottom="7dp"
android:paddingStart="64dp"
android:paddingEnd="64dp"
+ android:textColor="?attr/wallpaperTextColor"
android:theme="@style/TextAppearance.Keyguard"
/>
<LinearLayout android:id="@+id/row"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
index 31635a5..713c573 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
@@ -76,6 +76,7 @@
android:layout_marginTop="22dp"
android:layout_below="@id/clock_view"
android:background="#f00"
+ android:backgroundTint="?attr/wallpaperTextColor"
android:layout_centerHorizontal="true" />
<include layout="@layout/keyguard_status_area"
diff --git a/packages/SystemUI/res/color/white_disabled.xml b/packages/SystemUI/res/color/white_disabled.xml
new file mode 100644
index 0000000..617e232
--- /dev/null
+++ b/packages/SystemUI/res/color/white_disabled.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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@android:color/white"
+ android:alpha="?android:attr/disabledAlpha" />
+</selector>
diff --git a/packages/SystemUI/res/drawable/brightness_mirror_background.xml b/packages/SystemUI/res/drawable/brightness_mirror_background.xml
index b3a0484..43c9b73 100644
--- a/packages/SystemUI/res/drawable/brightness_mirror_background.xml
+++ b/packages/SystemUI/res/drawable/brightness_mirror_background.xml
@@ -16,4 +16,5 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/qs_background_dark" />
+ <corners android:radius="8dp" />
</shape>
diff --git a/packages/SystemUI/res/drawable/brightness_progress_drawable.xml b/packages/SystemUI/res/drawable/brightness_progress_drawable.xml
new file mode 100644
index 0000000..45d8dc1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/brightness_progress_drawable.xml
@@ -0,0 +1,37 @@
+<?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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@android:id/background"
+ android:gravity="center_vertical|fill_horizontal">
+ <shape android:shape="rectangle"
+ android:tint="?android:attr/colorControlActivated">
+ <size android:height="@dimen/seek_bar_height" />
+ <solid android:color="@color/white_disabled" />
+ <corners android:radius="@dimen/seek_bar_corner_radius" />
+ </shape>
+ </item>
+ <item android:id="@android:id/progress"
+ android:gravity="center_vertical|fill_horizontal">
+ <scale android:scaleWidth="100%">
+ <shape android:shape="rectangle"
+ android:tint="?android:attr/colorControlActivated">
+ <size android:height="@dimen/seek_bar_height" />
+ <solid android:color="@android:color/white" />
+ <corners android:radius="@dimen/seek_bar_corner_radius" />
+ </shape>
+ </scale>
+ </item>
+</layer-list>
diff --git a/packages/SystemUI/res/drawable/ic_brightness_thumb.xml b/packages/SystemUI/res/drawable/ic_brightness_thumb.xml
index beedcbb..8281836 100644
--- a/packages/SystemUI/res/drawable/ic_brightness_thumb.xml
+++ b/packages/SystemUI/res/drawable/ic_brightness_thumb.xml
@@ -14,14 +14,14 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="28.0dp"
- android:height="28.0dp"
+ android:width="24dp"
+ android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:pathData="m18.250000,12.000000a6.250000,6.250000 0.000000,1.000000 1.000000,-12.500000 0.000000,6.250000 6.250000,0.000000 1.000000,1.000000 12.500000,0.000000z"
- android:fillColor="?android:attr/colorPrimary" />
+ android:fillColor="@android:color/transparent" />
<path
android:pathData="M20,8.69L20,5c0,-0.55 -0.45,-1 -1,-1h-3.69l-2.6,-2.6a0.996,0.996 0,0 0,-1.41 0L8.69,4L5,4c-0.55,0 -1,0.45 -1,1v3.69l-2.6,2.6a0.996,0.996 0,0 0,0 1.41L4,15.3L4,19c0,0.55 0.45,1 1,1h3.69l2.6,2.6c0.39,0.39 1.02,0.39 1.41,0l2.6,-2.6L19,20c0.55,0 1,-0.45 1,-1v-3.69l2.6,-2.6a0.996,0.996 0,0 0,0 -1.41L20,8.69zM12,18.08c-3.36,0 -6.08,-2.73 -6.08,-6.08S8.64,5.92 12,5.92s6.08,2.73 6.08,6.08 -2.72,6.08 -6.08,6.08zM12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4z"
- android:fillColor="?android:attr/colorControlNormal" />
+ android:fillColor="?android:attr/colorControlActivated" />
</vector>
diff --git a/packages/SystemUI/res/layout/brightness_mirror.xml b/packages/SystemUI/res/layout/brightness_mirror.xml
index d6e7507..e3440b5 100644
--- a/packages/SystemUI/res/layout/brightness_mirror.xml
+++ b/packages/SystemUI/res/layout/brightness_mirror.xml
@@ -14,19 +14,19 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/brightness_mirror"
android:layout_width="@dimen/qs_panel_width"
- android:layout_height="wrap_content"
+ android:layout_height="@dimen/brightness_mirror_height"
android:layout_gravity="@integer/notification_panel_layout_gravity"
android:visibility="invisible">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@drawable/brightness_mirror_background"
- android:elevation="2dp">
- <include layout="@layout/quick_settings_brightness_dialog"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
+ android:layout_marginLeft="@dimen/notification_side_paddings"
+ android:layout_marginRight="@dimen/notification_side_paddings"
+ android:background="@drawable/brightness_mirror_background">
+ <include layout="@layout/quick_settings_brightness_dialog" />
</FrameLayout>
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
index 080f553..2efae71 100644
--- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
@@ -15,8 +15,9 @@
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:layout_height="48dp"
+ android:layout_height="wrap_content"
android:layout_width="match_parent"
+ android:layout_gravity="center_vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp"
style="@style/BrightnessDialogContainer">
@@ -34,7 +35,7 @@
<com.android.systemui.settings.ToggleSliderView
android:id="@+id/brightness_slider"
android:layout_width="0dp"
- android:layout_height="wrap_content"
+ android:layout_height="48dp"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:contentDescription="@string/accessibility_brightness"
diff --git a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml b/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
index 062e6cb..942f3dd 100644
--- a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
+++ b/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
@@ -16,10 +16,7 @@
-->
<!-- android:background="@drawable/status_bar_closed_default_background" -->
-<merge
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
- >
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBox
android:id="@+id/toggle"
android:layout_width="48dp"
@@ -44,6 +41,7 @@
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:thumb="@drawable/ic_brightness_thumb"
+ android:progressDrawable="@drawable/brightness_progress_drawable"
android:splitTrack="false"
/>
<TextView
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index ca05240..e37ca1c 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -22,8 +22,10 @@
<dimen name="docked_divider_handle_width">2dp</dimen>
<dimen name="docked_divider_handle_height">16dp</dimen>
+ <dimen name="brightness_mirror_height">96dp</dimen>
+
<dimen name="qs_tile_margin_top">2dp</dimen>
- <dimen name="qs_brightness_padding_top">0dp</dimen>
+ <dimen name="qs_header_tooltip_height">24dp</dimen>
<dimen name="battery_detail_graph_space_top">9dp</dimen>
<dimen name="battery_detail_graph_space_bottom">9dp</dimen>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 59c009f..1ec59bf 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -259,6 +259,8 @@
<dimen name="notification_panel_width">@dimen/match_parent</dimen>
+ <dimen name="brightness_mirror_height">108dp</dimen>
+
<!-- The width of the panel that holds the quick settings. -->
<dimen name="qs_panel_width">@dimen/notification_panel_width</dimen>
@@ -300,7 +302,7 @@
<dimen name="qs_tile_height">106dp</dimen>
<dimen name="qs_tile_margin">19dp</dimen>
- <dimen name="qs_tile_margin_top">32dp</dimen>
+ <dimen name="qs_tile_margin_top">18dp</dimen>
<dimen name="qs_quick_tile_size">48dp</dimen>
<dimen name="qs_quick_tile_padding">12dp</dimen>
<dimen name="qs_header_gear_translation">16dp</dimen>
@@ -326,7 +328,6 @@
<dimen name="qs_detail_image_height">56dp</dimen>
<dimen name="qs_detail_image_padding">16dp</dimen>
<dimen name="qs_detail_item_height">48dp</dimen>
- <dimen name="qs_brightness_padding_top">6dp</dimen>
<dimen name="qs_detail_header_text_size">20sp</dimen>
<dimen name="qs_detail_button_text_size">14sp</dimen>
<dimen name="qs_detail_item_primary_text_size">16sp</dimen>
@@ -344,9 +345,7 @@
<dimen name="qs_detail_item_icon_width">32dp</dimen>
<dimen name="qs_detail_item_icon_marginStart">0dp</dimen>
<dimen name="qs_detail_item_icon_marginEnd">20dp</dimen>
- <dimen name="qs_header_padding_start">16dp</dimen>
- <dimen name="qs_header_padding_end">24dp</dimen>
- <dimen name="qs_header_tooltip_height">32dp</dimen>
+ <dimen name="qs_header_tooltip_height">30dp</dimen>
<dimen name="qs_footer_padding_start">16dp</dimen>
<dimen name="qs_footer_padding_end">24dp</dimen>
<dimen name="qs_footer_icon_size">16dp</dimen>
@@ -373,6 +372,9 @@
<!-- Padding between subtitles and the following text in the QSFooter dialog -->
<dimen name="qs_footer_dialog_subtitle_padding">20dp</dimen>
+ <dimen name="seek_bar_height">3dp</dimen>
+ <dimen name="seek_bar_corner_radius">3dp</dimen>
+
<!-- Zen mode panel: condition item button padding -->
<dimen name="zen_mode_condition_detail_button_padding">8dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 5d1bdab..b54d09a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -16,6 +16,7 @@
package com.android.keyguard;
+import android.annotation.ColorInt;
import android.app.PendingIntent;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.Observer;
@@ -34,6 +35,7 @@
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
@@ -160,8 +162,8 @@
mRow.addView(button);
PendingIntent pendingIntent = null;
- if (rc.getContentIntent() != null) {
- pendingIntent = rc.getContentIntent().getAction();
+ if (rc.getPrimaryAction() != null) {
+ pendingIntent = rc.getPrimaryAction().getAction();
}
mClickActions.put(button, pendingIntent);
@@ -307,10 +309,17 @@
}
}
- public int getTextColor() {
+ @VisibleForTesting
+ int getTextColor() {
return ColorUtils.blendARGB(mTextColor, Color.WHITE, mDarkAmount);
}
+ @VisibleForTesting
+ void setTextColor(@ColorInt int textColor) {
+ mTextColor = textColor;
+ updateTextColors();
+ }
+
/**
* Representation of an item that appears under the clock on main keyguard message.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java b/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
index f201165..be3168c 100644
--- a/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
@@ -16,6 +16,9 @@
package com.android.systemui.net;
+import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
+import static android.net.NetworkTemplate.MATCH_MOBILE;
+
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -32,11 +35,6 @@
import com.android.systemui.R;
-import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
-import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
-import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
-import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
-
/**
* Notify user that a {@link NetworkTemplate} is over its
* {@link NetworkPolicy#limitBytes}, giving them the choice of acknowledging or
@@ -85,11 +83,7 @@
private static int getLimitedDialogTitleForTemplate(NetworkTemplate template) {
switch (template.getMatchRule()) {
- case MATCH_MOBILE_3G_LOWER:
- return R.string.data_usage_disabled_dialog_3g_title;
- case MATCH_MOBILE_4G:
- return R.string.data_usage_disabled_dialog_4g_title;
- case MATCH_MOBILE_ALL:
+ case MATCH_MOBILE:
return R.string.data_usage_disabled_dialog_mobile_title;
default:
return R.string.data_usage_disabled_dialog_title;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java
index f0e4ccc..1e0d4d0 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java
@@ -26,12 +26,14 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Handler;
import android.util.Pair;
public class PipAppOpsListener {
private static final String TAG = PipAppOpsListener.class.getSimpleName();
private Context mContext;
+ private Handler mHandler;
private IActivityManager mActivityManager;
private AppOpsManager mAppOpsManager;
@@ -50,7 +52,7 @@
if (appInfo.packageName.equals(topPipActivityInfo.first.getPackageName()) &&
mAppOpsManager.checkOpNoThrow(OP_PICTURE_IN_PICTURE, appInfo.uid,
packageName) != MODE_ALLOWED) {
- mMotionHelper.dismissPip();
+ mHandler.post(() -> mMotionHelper.dismissPip());
}
}
} catch (NameNotFoundException e) {
@@ -63,6 +65,7 @@
public PipAppOpsListener(Context context, IActivityManager activityManager,
PipMotionHelper motionHelper) {
mContext = context;
+ mHandler = new Handler(mContext.getMainLooper());
mActivityManager = activityManager;
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mMotionHelper = motionHelper;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 476cb40..a92e346 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -254,8 +254,10 @@
public void updateResources() {
final Resources res = mContext.getResources();
- setPadding(0, res.getDimensionPixelSize(R.dimen.qs_brightness_padding_top),
- 0, res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom));
+ setPadding(0, 0, 0, res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom));
+ mTooltipView.getLayoutParams().height =
+ res.getDimensionPixelSize(R.dimen.qs_header_tooltip_height);
+ mTooltipView.setLayoutParams(mTooltipView.getLayoutParams());
for (TileRecord r : mRecords) {
r.tile.clearState();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
index 3597929..5aace97 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -16,12 +16,16 @@
package com.android.systemui.qs.tiles;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_QS_MODE;
+
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.Intent;
+import android.metrics.LogMaker;
import android.provider.Settings;
import android.service.quicksettings.Tile;
import android.support.annotation.StringRes;
+import android.util.Log;
import android.widget.Switch;
import com.android.internal.app.ColorDisplayController;
@@ -65,6 +69,15 @@
@Override
protected void handleClick() {
+ // Enroll in forced auto mode if eligible.
+ if ("1".equals(Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE))
+ && mController.getAutoModeRaw() == -1) {
+ mController.setAutoMode(ColorDisplayController.AUTO_MODE_CUSTOM);
+ Log.i("NightDisplayTile", "Enrolled in forced night display auto mode");
+ }
+
+ // Change current activation state.
final boolean activated = !mState.value;
mController.setActivated(activated);
}
@@ -147,6 +160,11 @@
}
@Override
+ public LogMaker populate(LogMaker logMaker) {
+ return super.populate(logMaker).addTaggedData(FIELD_QS_MODE, mController.getAutoModeRaw());
+ }
+
+ @Override
public Intent getLongClickIntent() {
return new Intent(Settings.ACTION_NIGHT_DISPLAY_SETTINGS);
}
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 dc400e6..e86d88d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -580,8 +580,7 @@
private boolean shouldDisableNavbarGestures() {
return !mStatusBar.isDeviceProvisioned()
- || (mDisabledFlags1 & StatusBarManager.DISABLE_SEARCH) != 0
- || mNavigationBarView.getRecentsButton().getVisibility() != View.VISIBLE;
+ || (mDisabledFlags1 & StatusBarManager.DISABLE_SEARCH) != 0;
}
private void repositionNavigationBar() {
@@ -600,13 +599,10 @@
// Change the cancel pin gesture to home and back if recents button is invisible
boolean recentsVisible = mNavigationBarView.isRecentsButtonVisible();
- ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
ButtonDispatcher backButton = mNavigationBarView.getBackButton();
if (recentsVisible) {
- homeButton.setOnLongClickListener(this::onHomeLongClick);
backButton.setOnLongClickListener(this::onLongPressBackRecents);
} else {
- homeButton.setOnLongClickListener(this::onLongPressBackHome);
backButton.setOnLongClickListener(this::onLongPressBackHome);
}
}
@@ -629,6 +625,7 @@
ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
homeButton.setOnTouchListener(this::onHomeTouch);
+ homeButton.setOnLongClickListener(this::onHomeLongClick);
ButtonDispatcher accessibilityButton = mNavigationBarView.getAccessibilityButton();
accessibilityButton.setOnClickListener(this::onAccessibilityClick);
@@ -681,6 +678,9 @@
@VisibleForTesting
boolean onHomeLongClick(View v) {
+ if (!mNavigationBarView.isRecentsButtonVisible() && mNavigationBarView.inScreenPinning()) {
+ return onLongPressBackHome(v);
+ }
if (shouldDisableNavbarGestures()) {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
index dd4d1f6..b82b0ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
@@ -380,7 +380,7 @@
}
private void startQuickScrub() {
- if (!mQuickScrubActive) {
+ if (!mQuickScrubActive && mDraggingActive) {
mQuickScrubActive = true;
mLightTrackColor = mContext.getColor(R.color.quick_step_track_background_light);
mDarkTrackColor = mContext.getColor(R.color.quick_step_track_background_dark);
@@ -394,6 +394,9 @@
} catch (RemoteException e) {
Log.e(TAG, "Failed to send start of quick scrub.", e);
}
+ } else {
+ // After long press do not allow quick scrub/switch
+ mTouchDownX = -1;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index a011952..06a56ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.policy;
import android.annotation.NonNull;
+import android.content.res.Resources;
import android.util.ArraySet;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
@@ -111,10 +112,10 @@
public void updateResources() {
FrameLayout.LayoutParams lp =
(FrameLayout.LayoutParams) mBrightnessMirror.getLayoutParams();
- lp.width = mBrightnessMirror.getResources().getDimensionPixelSize(
- R.dimen.qs_panel_width);
- lp.gravity = mBrightnessMirror.getResources().getInteger(
- R.integer.notification_panel_layout_gravity);
+ Resources r = mBrightnessMirror.getResources();
+ lp.width = r.getDimensionPixelSize(R.dimen.qs_panel_width);
+ lp.height = r.getDimensionPixelSize(R.dimen.brightness_mirror_height);
+ lp.gravity = r.getInteger(R.integer.notification_panel_layout_gravity);
mBrightnessMirror.setLayoutParams(lp);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
new file mode 100644
index 0000000..7686948
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.keyguard;
+
+import android.graphics.Color;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.LayoutInflater;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWithLooper
+@RunWith(AndroidTestingRunner.class)
+public class KeyguardSliceViewTest extends SysuiTestCase {
+ private KeyguardSliceView mKeyguardSliceView;
+
+ @Before
+ public void setUp() throws Exception {
+ mKeyguardSliceView = (KeyguardSliceView) LayoutInflater.from(getContext())
+ .inflate(R.layout.keyguard_status_area, null);
+ }
+
+ @Test
+ public void getTextColor_whiteTextWhenAOD() {
+ // Set text color to red since the default is white and test would always pass
+ mKeyguardSliceView.setTextColor(Color.RED);
+ mKeyguardSliceView.setDark(0);
+ Assert.assertEquals("Should be using regular text color", Color.RED,
+ mKeyguardSliceView.getTextColor());
+ mKeyguardSliceView.setDark(1);
+ Assert.assertEquals("Should be using AOD text color", Color.WHITE,
+ mKeyguardSliceView.getTextColor());
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index 7d4d31e..7ab69b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -47,7 +47,7 @@
private static final String TEST_RESULT_KEY = "test_result_key";
private static final String TEST_REPLY = "hello";
- private static final String TEST_ACTION = "com.android.ACTION";
+ private static final String TEST_ACTION = "com.android.REMOTE_INPUT_VIEW_ACTION";
@Mock private RemoteInputController mController;
@Mock private ShortcutManager mShortcutManager;
@@ -93,6 +93,7 @@
@Test
public void testNoCrashWithoutVisibilityListener() {
mView.setOnVisibilityChangedListener(null);
- mView.onVisibilityChanged(mView, View.VISIBLE);
+ mView.setVisibility(View.INVISIBLE);
+ mView.setVisibility(View.VISIBLE);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index 92e60f9..fc043c5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -26,7 +26,6 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
-import android.support.test.filters.FlakyTest;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -47,7 +46,7 @@
@SmallTest
public class SmartReplyViewTest extends SysuiTestCase {
private static final String TEST_RESULT_KEY = "test_result_key";
- private static final String TEST_ACTION = "com.android.ACTION";
+ private static final String TEST_ACTION = "com.android.SMART_REPLY_VIEW_ACTION";
private static final String[] TEST_CHOICES = new String[]{"Hello", "What's up?", "I'm here"};
@@ -77,7 +76,6 @@
mSpacing = res.getDimensionPixelSize(R.dimen.smart_reply_button_spacing);
}
- @FlakyTest
@Test
public void testSendSmartReply_intentContainsResultsAndSource() throws InterruptedException {
setRepliesFromRemoteInput(TEST_CHOICES);
@@ -182,7 +180,6 @@
assertEqualLayouts(expectedView.getChildAt(2), mView.getChildAt(2));
}
- @FlakyTest
@Test
public void testMeasure_choiceWithThreeLines() {
final CharSequence[] choices = new CharSequence[]{"Hi", "Hello\nevery\nbody", "Bye"};
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index eba9830..50968a0 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -22,6 +22,7 @@
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS;
import static com.android.internal.util.FunctionalUtils.ignoreRemoteException;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.Manifest;
import android.accessibilityservice.AccessibilityService;
@@ -100,18 +101,20 @@
import android.view.accessibility.IAccessibilityManagerClient;
import com.android.internal.R;
+import com.android.internal.accessibility.AccessibilityShortcutController;
+import com.android.internal.accessibility.AccessibilityShortcutController.ToggleableFrameworkFeatureInfo;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IntPair;
+import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
-import com.android.internal.accessibility.AccessibilityShortcutController;
-import com.android.internal.accessibility.AccessibilityShortcutController.ToggleableFrameworkFeatureInfo;
import com.android.server.wm.WindowManagerInternal;
import libcore.util.EmptyArray;
+
import org.xmlpull.v1.XmlPullParserException;
import java.io.FileDescriptor;
@@ -126,8 +129,8 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
+import java.util.function.IntSupplier;
/**
* This class is instantiated by the system as a system level service and can be
@@ -293,6 +296,12 @@
return mFingerprintGestureDispatcher;
}
+ private UserState getUserState(int userId) {
+ synchronized (mLock) {
+ return getUserStateLocked(userId);
+ }
+ }
+
private UserState getUserStateLocked(int userId) {
UserState state = mUserStates.get(userId);
if (state == null) {
@@ -540,9 +549,9 @@
dispatchEvent = true;
}
if (mHasInputFilter && mInputFilter != null) {
- mMainHandler.obtainMessage(
- MainHandler.MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER,
- AccessibilityEvent.obtain(event)).sendToTarget();
+ mMainHandler.sendMessage(obtainMessage(
+ AccessibilityManagerService::sendAccessibilityEventToInputFilter,
+ this, AccessibilityEvent.obtain(event)));
}
}
}
@@ -568,6 +577,15 @@
}
}
+ private void sendAccessibilityEventToInputFilter(AccessibilityEvent event) {
+ synchronized (mLock) {
+ if (mHasInputFilter && mInputFilter != null) {
+ mInputFilter.notifyAccessibilityEvent(event);
+ }
+ }
+ event.recycle();
+ }
+
@Override
public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) {
synchronized (mLock) {
@@ -1024,8 +1042,9 @@
// Disable the local managers for the old user.
if (oldUserState.mUserClients.getRegisteredCallbackCount() > 0) {
- mMainHandler.obtainMessage(MainHandler.MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER,
- oldUserState.mUserId, 0).sendToTarget();
+ mMainHandler.sendMessage(obtainMessage(
+ AccessibilityManagerService::sendStateToClients,
+ this, 0, oldUserState.mUserId));
}
// Announce user changes only if more that one exist.
@@ -1045,12 +1064,29 @@
if (announceNewUser) {
// Schedule announcement of the current user if needed.
- mMainHandler.sendEmptyMessageDelayed(MainHandler.MSG_ANNOUNCE_NEW_USER_IF_NEEDED,
+ mMainHandler.sendMessageDelayed(
+ obtainMessage(AccessibilityManagerService::announceNewUserIfNeeded, this),
WAIT_FOR_USER_STATE_FULLY_INITIALIZED_MILLIS);
}
}
}
+ private void announceNewUserIfNeeded() {
+ synchronized (mLock) {
+ UserState userState = getCurrentUserStateLocked();
+ if (userState.isHandlingAccessibilityEvents()) {
+ UserManager userManager = (UserManager) mContext.getSystemService(
+ Context.USER_SERVICE);
+ String message = mContext.getString(R.string.user_switched,
+ userManager.getUserInfo(mCurrentUserId).name);
+ AccessibilityEvent event = AccessibilityEvent.obtain(
+ AccessibilityEvent.TYPE_ANNOUNCEMENT);
+ event.getText().add(message);
+ sendAccessibilityEventLocked(event, mCurrentUserId);
+ }
+ }
+ }
+
private void unlockUser(int userId) {
synchronized (mLock) {
int parentUserId = mSecurityPolicy.resolveProfileParentLocked(userId);
@@ -1154,8 +1190,8 @@
}
if (potentialTargets == 1) {
if (state.mIsNavBarMagnificationEnabled) {
- mMainHandler.obtainMessage(
- MainHandler.MSG_SEND_ACCESSIBILITY_BUTTON_TO_INPUT_FILTER).sendToTarget();
+ mMainHandler.sendMessage(obtainMessage(
+ AccessibilityManagerService::sendAccessibilityButtonToInputFilter, this));
return;
} else {
for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
@@ -1169,12 +1205,12 @@
} else {
if (state.mServiceAssignedToAccessibilityButton == null
&& !state.mIsNavBarMagnificationAssignedToAccessibilityButton) {
- mMainHandler.obtainMessage(
- MainHandler.MSG_SHOW_ACCESSIBILITY_BUTTON_CHOOSER).sendToTarget();
+ mMainHandler.sendMessage(obtainMessage(
+ AccessibilityManagerService::showAccessibilityButtonTargetSelection, this));
} else if (state.mIsNavBarMagnificationEnabled
&& state.mIsNavBarMagnificationAssignedToAccessibilityButton) {
- mMainHandler.obtainMessage(
- MainHandler.MSG_SEND_ACCESSIBILITY_BUTTON_TO_INPUT_FILTER).sendToTarget();
+ mMainHandler.sendMessage(obtainMessage(
+ AccessibilityManagerService::sendAccessibilityButtonToInputFilter, this));
return;
} else {
for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
@@ -1187,11 +1223,25 @@
}
}
// The user may have turned off the assigned service or feature
- mMainHandler.obtainMessage(
- MainHandler.MSG_SHOW_ACCESSIBILITY_BUTTON_CHOOSER).sendToTarget();
+ mMainHandler.sendMessage(obtainMessage(
+ AccessibilityManagerService::showAccessibilityButtonTargetSelection, this));
}
}
+ private void sendAccessibilityButtonToInputFilter() {
+ synchronized (mLock) {
+ if (mHasInputFilter && mInputFilter != null) {
+ mInputFilter.notifyAccessibilityButtonClicked();
+ }
+ }
+ }
+
+ private void showAccessibilityButtonTargetSelection() {
+ Intent intent = new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ mContext.startActivityAsUser(intent, UserHandle.of(mCurrentUserId));
+ }
+
private void notifyAccessibilityButtonVisibilityChangedLocked(boolean available) {
final UserState state = getCurrentUserStateLocked();
mIsAccessibilityButtonShown = available;
@@ -1555,28 +1605,54 @@
&& (mGlobalClients.getRegisteredCallbackCount() > 0
|| userState.mUserClients.getRegisteredCallbackCount() > 0)) {
userState.mLastSentClientState = clientState;
- mMainHandler.obtainMessage(MainHandler.MSG_SEND_STATE_TO_CLIENTS,
- clientState, userState.mUserId).sendToTarget();
+ mMainHandler.sendMessage(obtainMessage(
+ AccessibilityManagerService::sendStateToAllClients,
+ this, clientState, userState.mUserId));
}
}
- private void showAccessibilityButtonTargetSelection() {
- Intent intent = new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- mContext.startActivityAsUser(intent, UserHandle.of(mCurrentUserId));
+ private void sendStateToAllClients(int clientState, int userId) {
+ sendStateToClients(clientState, mGlobalClients);
+ sendStateToClients(clientState, userId);
+ }
+
+ private void sendStateToClients(int clientState, int userId) {
+ sendStateToClients(clientState, getUserState(userId).mUserClients);
+ }
+
+ private void sendStateToClients(int clientState,
+ RemoteCallbackList<IAccessibilityManagerClient> clients) {
+ clients.broadcast(ignoreRemoteException(
+ client -> client.setState(clientState)));
}
private void scheduleNotifyClientsOfServicesStateChange(UserState userState) {
- mMainHandler.obtainMessage(MainHandler.MSG_SEND_SERVICES_STATE_CHANGED_TO_CLIENTS,
- userState.mUserId).sendToTarget();
+ mMainHandler.sendMessage(obtainMessage(
+ AccessibilityManagerService::sendServicesStateChanged,
+ this, userState.mUserClients));
+ }
+
+ private void sendServicesStateChanged(
+ RemoteCallbackList<IAccessibilityManagerClient> userClients) {
+ notifyClientsOfServicesStateChange(mGlobalClients);
+ notifyClientsOfServicesStateChange(userClients);
+ }
+
+ private void notifyClientsOfServicesStateChange(
+ RemoteCallbackList<IAccessibilityManagerClient> clients) {
+ clients.broadcast(ignoreRemoteException(
+ client -> client.notifyServicesStateChanged()));
}
private void scheduleUpdateInputFilter(UserState userState) {
- mMainHandler.obtainMessage(MainHandler.MSG_UPDATE_INPUT_FILTER, userState).sendToTarget();
+ mMainHandler.sendMessage(obtainMessage(
+ AccessibilityManagerService::updateInputFilter, this, userState));
}
private void scheduleUpdateFingerprintGestureHandling(UserState userState) {
- mMainHandler.obtainMessage(MainHandler.MSG_UPDATE_FINGERPRINT, userState).sendToTarget();
+ mMainHandler.sendMessage(obtainMessage(
+ AccessibilityManagerService::updateFingerprintGestureHandling,
+ this, userState));
}
private void updateInputFilter(UserState userState) {
@@ -2039,9 +2115,9 @@
return true;
} else if (mEnableTouchExplorationDialog == null
|| !mEnableTouchExplorationDialog.isShowing()) {
- mMainHandler.obtainMessage(
- MainHandler.MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG,
- service).sendToTarget();
+ mMainHandler.sendMessage(obtainMessage(
+ AccessibilityManagerService::showEnableTouchExplorationDialog,
+ this, service));
}
} else {
// Starting in JB-MR2 we request an accessibility service to declare
@@ -2293,9 +2369,9 @@
private void sendAccessibilityEventLocked(AccessibilityEvent event, int userId) {
// Resync to avoid calling out with the lock held
event.setEventTime(SystemClock.uptimeMillis());
- mMainHandler.obtainMessage(
- MainHandler.MSG_SEND_ACCESSIBILITY_EVENT, userId, 0 /* unused */, event)
- .sendToTarget();
+ mMainHandler.sendMessage(obtainMessage(
+ AccessibilityManagerService::sendAccessibilityEvent,
+ this, event, userId));
}
/**
@@ -2419,22 +2495,9 @@
}
}
+ //TODO remove after refactoring KeyEventDispatcherTest
final class MainHandler extends Handler {
- public static final int MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER = 1;
- public static final int MSG_SEND_STATE_TO_CLIENTS = 2;
- public static final int MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER = 3;
- public static final int MSG_ANNOUNCE_NEW_USER_IF_NEEDED = 5;
- public static final int MSG_UPDATE_INPUT_FILTER = 6;
- public static final int MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG = 7;
public static final int MSG_SEND_KEY_EVENT_TO_INPUT_FILTER = 8;
- public static final int MSG_CLEAR_ACCESSIBILITY_FOCUS = 9;
- public static final int MSG_SEND_SERVICES_STATE_CHANGED_TO_CLIENTS = 10;
- public static final int MSG_UPDATE_FINGERPRINT = 11;
- public static final int MSG_SEND_RELEVANT_EVENTS_CHANGED_TO_CLIENTS = 12;
- public static final int MSG_SEND_ACCESSIBILITY_BUTTON_TO_INPUT_FILTER = 13;
- public static final int MSG_SHOW_ACCESSIBILITY_BUTTON_CHOOSER = 14;
- public static final int MSG_INIT_SERVICE = 15;
- public static final int MSG_SEND_ACCESSIBILITY_EVENT = 16;
public MainHandler(Looper looper) {
super(looper);
@@ -2442,143 +2505,25 @@
@Override
public void handleMessage(Message msg) {
- final int type = msg.what;
- switch (type) {
- case MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER: {
- AccessibilityEvent event = (AccessibilityEvent) msg.obj;
- synchronized (mLock) {
- if (mHasInputFilter && mInputFilter != null) {
- mInputFilter.notifyAccessibilityEvent(event);
- }
+ if (msg.what == MSG_SEND_KEY_EVENT_TO_INPUT_FILTER) {
+ KeyEvent event = (KeyEvent) msg.obj;
+ final int policyFlags = msg.arg1;
+ synchronized (mLock) {
+ if (mHasInputFilter && mInputFilter != null) {
+ mInputFilter.sendInputEvent(event, policyFlags);
}
- event.recycle();
- } break;
-
- case MSG_SEND_KEY_EVENT_TO_INPUT_FILTER: {
- KeyEvent event = (KeyEvent) msg.obj;
- final int policyFlags = msg.arg1;
- synchronized (mLock) {
- if (mHasInputFilter && mInputFilter != null) {
- mInputFilter.sendInputEvent(event, policyFlags);
- }
- }
- event.recycle();
- } break;
-
- case MSG_SEND_STATE_TO_CLIENTS: {
- final int clientState = msg.arg1;
- final int userId = msg.arg2;
- sendStateToClients(clientState, mGlobalClients);
- sendStateToClients(clientState, getUserClientsForId(userId));
- } break;
-
- case MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER: {
- final int userId = msg.arg1;
- sendStateToClients(0, getUserClientsForId(userId));
- } break;
-
- case MSG_ANNOUNCE_NEW_USER_IF_NEEDED: {
- announceNewUserIfNeeded();
- } break;
-
- case MSG_UPDATE_INPUT_FILTER: {
- UserState userState = (UserState) msg.obj;
- updateInputFilter(userState);
- } break;
-
- case MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG: {
- AccessibilityServiceConnection service =
- (AccessibilityServiceConnection) msg.obj;
- showEnableTouchExplorationDialog(service);
- } break;
-
- case MSG_CLEAR_ACCESSIBILITY_FOCUS: {
- final int windowId = msg.arg1;
- getInteractionBridge().clearAccessibilityFocusNotLocked(windowId);
- } break;
-
- case MSG_SEND_SERVICES_STATE_CHANGED_TO_CLIENTS: {
- final int userId = msg.arg1;
- notifyClientsOfServicesStateChange(mGlobalClients);
- notifyClientsOfServicesStateChange(getUserClientsForId(userId));
- } break;
-
- case MSG_UPDATE_FINGERPRINT: {
- updateFingerprintGestureHandling((UserState) msg.obj);
- } break;
-
- case MSG_SEND_RELEVANT_EVENTS_CHANGED_TO_CLIENTS: {
- final int userId = msg.arg1;
- final int relevantEventTypes = msg.arg2;
- final UserState userState;
- synchronized (mLock) {
- userState = getUserStateLocked(userId);
- }
- broadcastToClients(userState, ignoreRemoteException(
- client -> client.mCallback.setRelevantEventTypes(relevantEventTypes)));
- } break;
-
- case MSG_SEND_ACCESSIBILITY_BUTTON_TO_INPUT_FILTER: {
- synchronized (mLock) {
- if (mHasInputFilter && mInputFilter != null) {
- mInputFilter.notifyAccessibilityButtonClicked();
- }
- }
- } break;
-
- case MSG_SHOW_ACCESSIBILITY_BUTTON_CHOOSER: {
- showAccessibilityButtonTargetSelection();
- } break;
-
- case MSG_INIT_SERVICE: {
- final AccessibilityServiceConnection service =
- (AccessibilityServiceConnection) msg.obj;
- service.initializeService();
- } break;
-
- case MSG_SEND_ACCESSIBILITY_EVENT: {
- final AccessibilityEvent event = (AccessibilityEvent) msg.obj;
- final int userId = msg.arg1;
- sendAccessibilityEvent(event, userId);
}
+ event.recycle();
}
}
+ }
- private void announceNewUserIfNeeded() {
- synchronized (mLock) {
- UserState userState = getCurrentUserStateLocked();
- if (userState.isHandlingAccessibilityEvents()) {
- UserManager userManager = (UserManager) mContext.getSystemService(
- Context.USER_SERVICE);
- String message = mContext.getString(R.string.user_switched,
- userManager.getUserInfo(mCurrentUserId).name);
- AccessibilityEvent event = AccessibilityEvent.obtain(
- AccessibilityEvent.TYPE_ANNOUNCEMENT);
- event.getText().add(message);
- sendAccessibilityEventLocked(event, mCurrentUserId);
- }
- }
- }
+ void clearAccessibilityFocus(IntSupplier windowId) {
+ clearAccessibilityFocus(windowId.getAsInt());
+ }
- private RemoteCallbackList<IAccessibilityManagerClient> getUserClientsForId(int userId) {
- final UserState userState;
- synchronized (mLock) {
- userState = getUserStateLocked(userId);
- }
- return userState.mUserClients;
- }
-
- private void sendStateToClients(int clientState,
- RemoteCallbackList<IAccessibilityManagerClient> clients) {
- clients.broadcast(ignoreRemoteException(
- client -> client.setState(clientState)));
- }
-
- private void notifyClientsOfServicesStateChange(
- RemoteCallbackList<IAccessibilityManagerClient> clients) {
- clients.broadcast(ignoreRemoteException(
- client -> client.notifyServicesStateChanged()));
- }
+ void clearAccessibilityFocus(int windowId) {
+ getInteractionBridge().clearAccessibilityFocusNotLocked(windowId);
}
private int findWindowIdLocked(IBinder token) {
@@ -2912,7 +2857,7 @@
* Has no effect if no item has accessibility focus, if the item with accessibility
* focus does not expose the specified action, or if the action fails.
*
- * @param actionId The id of the action to perform.
+ * @param action The action to perform.
*
* @return {@code true} if the action was performed. {@code false} if it was not.
*/
@@ -3353,8 +3298,9 @@
case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
synchronized (mLock) {
if (mAccessibilityFocusedWindowId != windowId) {
- mMainHandler.obtainMessage(MainHandler.MSG_CLEAR_ACCESSIBILITY_FOCUS,
- mAccessibilityFocusedWindowId, 0).sendToTarget();
+ mMainHandler.sendMessage(obtainMessage(
+ AccessibilityManagerService::clearAccessibilityFocus,
+ AccessibilityManagerService.this, 0));
mSecurityPolicy.setAccessibilityFocusedWindowLocked(windowId);
mAccessibilityFocusNodeId = nodeId;
}
@@ -3406,12 +3352,17 @@
if (oldActiveWindow != mSecurityPolicy.mActiveWindowId
&& mAccessibilityFocusedWindowId == oldActiveWindow
&& getCurrentUserStateLocked().mAccessibilityFocusOnlyInActiveWindow) {
- mMainHandler.obtainMessage(MainHandler.MSG_CLEAR_ACCESSIBILITY_FOCUS,
- oldActiveWindow, 0).sendToTarget();
+ mMainHandler.sendMessage(obtainMessage(
+ AccessibilityManagerService::clearAccessibilityFocus,
+ AccessibilityManagerService.this, box(oldActiveWindow)));
}
}
}
+ private IntSupplier box(int value) {
+ return PooledLambda.obtainSupplier(value).recycleOnUse();
+ }
+
public int getActiveWindowId() {
if (mActiveWindowId == INVALID_WINDOW_ID && !mTouchInteractionInProgress) {
mActiveWindowId = getFocusedWindowId();
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 96b8979..89bf82d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -18,6 +18,8 @@
import static android.provider.Settings.Secure.SHOW_MODE_AUTO;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.IAccessibilityServiceClient;
import android.content.ComponentName;
@@ -158,8 +160,8 @@
mSystemSupport.onClientChange(false);
// Initialize the service on the main handler after we're done setting up for
// the new configuration (for example, initializing the input filter).
- mMainHandler.obtainMessage(
- AccessibilityManagerService.MainHandler.MSG_INIT_SERVICE, this).sendToTarget();
+ mMainHandler.sendMessage(obtainMessage(
+ AccessibilityServiceConnection::initializeService, this));
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index db62961..05237af 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -524,6 +524,7 @@
private void addCompatibilityModeRequestsLocked(@NonNull AutofillManagerServiceImpl service
, int userId) {
+ mAutofillCompatState.reset();
final ArrayMap<String, Pair<Long, String>> compatPackages =
service.getCompatibilityPackagesLocked();
if (compatPackages == null || compatPackages.isEmpty()) {
@@ -626,6 +627,15 @@
}
}
}
+
+ void reset() {
+ synchronized (mLock) {
+ if (mUserSpecs != null) {
+ mUserSpecs.clear();
+ mUserSpecs = null;
+ }
+ }
+ }
}
final class AutoFillManagerServiceStub extends IAutoFillManager.Stub {
@@ -1045,6 +1055,9 @@
Settings.Secure.AUTOFILL_SERVICE), false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.USER_SETUP_COMPLETE), false, this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.AUTOFILL_COMPAT_ALLOWED_PACKAGES), false, this,
+ UserHandle.USER_ALL);
}
@Override
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 32f03b3..bcfe1b6 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -76,6 +76,7 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
+import android.view.KeyEvent;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
@@ -812,6 +813,27 @@
}
}
+ @Override
+ public void dispatchUnhandledKey(AutofillId id, KeyEvent keyEvent) {
+ synchronized (mLock) {
+ if (mDestroyed) {
+ Slog.w(TAG, "Call to Session#dispatchUnhandledKey() rejected - session: "
+ + id + " destroyed");
+ return;
+ }
+ if (id.equals(mCurrentViewId)) {
+ try {
+ mClient.dispatchUnhandledKey(this.id, id, keyEvent);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error requesting to dispatch unhandled key", e);
+ }
+ } else {
+ Slog.w(TAG, "Do not dispatch unhandled key on " + id
+ + " as it is not the current view (" + mCurrentViewId + ") anymore");
+ }
+ }
+ }
+
// AutoFillUiCallback
@Override
public void requestHideFillUi(AutofillId id) {
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index dc36518..e28a204 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -34,6 +34,7 @@
import android.service.autofill.ValueFinder;
import android.text.TextUtils;
import android.util.Slog;
+import android.view.KeyEvent;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.IAutofillWindowPresenter;
@@ -78,6 +79,7 @@
IAutofillWindowPresenter presenter);
void requestHideFillUi(AutofillId id);
void startIntentSender(IntentSender intentSender);
+ void dispatchUnhandledKey(AutofillId id, KeyEvent keyEvent);
}
public AutoFillUI(@NonNull Context context) {
@@ -240,6 +242,13 @@
mCallback.startIntentSender(intentSender);
}
}
+
+ @Override
+ public void dispatchUnhandledKey(KeyEvent keyEvent) {
+ if (mCallback != null) {
+ mCallback.dispatchUnhandledKey(focusedId, keyEvent);
+ }
+ }
});
});
}
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 d64244d..7278e83 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -18,6 +18,7 @@
import static com.android.server.autofill.Helper.sDebug;
import static com.android.server.autofill.Helper.sVerbose;
+import android.annotation.AttrRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PendingIntent;
@@ -31,8 +32,10 @@
import android.service.autofill.Dataset.DatasetFieldFilter;
import android.service.autofill.FillResponse;
import android.text.TextUtils;
+import android.util.AttributeSet;
import android.util.Slog;
import android.util.TypedValue;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -47,6 +50,7 @@
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
+import android.widget.FrameLayout;
import android.widget.ListView;
import android.widget.RemoteViews;
@@ -69,6 +73,28 @@
private static final TypedValue sTempTypedValue = new TypedValue();
+ public static final class AutofillFrameLayout extends FrameLayout {
+
+ OnKeyListener mUnhandledListener;
+
+ public AutofillFrameLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public AutofillFrameLayout(Context context, AttributeSet attrs, @AttrRes int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ boolean handled = super.dispatchKeyEvent(event);
+ if (!handled) {
+ handled = mUnhandledListener.onKey(this, event.getKeyCode(), event);
+ }
+ return handled;
+ }
+ }
+
interface Callback {
void onResponsePicked(@NonNull FillResponse response);
void onDatasetPicked(@NonNull Dataset dataset);
@@ -78,6 +104,7 @@
IAutofillWindowPresenter windowPresenter);
void requestHideFillUi();
void startIntentSender(IntentSender intentSender);
+ void dispatchUnhandledKey(KeyEvent keyEvent);
}
private final @NonNull Point mTempPoint = new Point();
@@ -122,6 +149,31 @@
mFullScreen ? R.layout.autofill_dataset_picker_fullscreen
: R.layout.autofill_dataset_picker, null);
+ // if autofill ui is not fullscreen, send unhandled keyevent to app window.
+ if (!mFullScreen) {
+ if (decor instanceof AutofillFrameLayout) {
+ ((AutofillFrameLayout) decor).mUnhandledListener =
+ (View view, int keyCode, KeyEvent event) -> {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_BACK:
+ case KeyEvent.KEYCODE_ESCAPE:
+ case KeyEvent.KEYCODE_ENTER:
+ case KeyEvent.KEYCODE_DPAD_CENTER:
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ case KeyEvent.KEYCODE_DPAD_UP:
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ return false;
+ default:
+ mCallback.dispatchUnhandledKey(event);
+ return true;
+ }
+ };
+ } else {
+ Slog.wtf(TAG, "Unable to send unhandled key");
+ }
+ }
+
final RemoteViews.OnClickHandler interceptionHandler = new RemoteViews.OnClickHandler() {
@Override
public boolean onClickHandler(View view, PendingIntent pendingIntent,
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 83367f3..782bf71 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -2357,7 +2357,7 @@
// If the caller does not hold the BACKUP permission, it can only request a
// wipe of its own backed-up data.
- HashSet<String> apps;
+ Set<String> apps;
if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
apps = mBackupParticipants.get(Binder.getCallingUid());
@@ -2365,10 +2365,9 @@
// a caller with full permission can ask to back up any participating app
// !!! TODO: allow data-clear of ANY app?
if (MORE_DEBUG) Slog.v(TAG, "Privileged caller, allowing clear of other apps");
- apps = SparseArrayUtils.union(mBackupParticipants);
+ apps = mProcessedPackagesJournal.getPackagesCopy();
}
- // Is the given app an available participant?
if (apps.contains(packageName)) {
// found it; fire off the clear request
if (MORE_DEBUG) Slog.v(TAG, "Found the app - running clear process");
diff --git a/services/core/java/com/android/server/AppStateTracker.java b/services/core/java/com/android/server/AppStateTracker.java
index 9b29b32..fc4d463 100644
--- a/services/core/java/com/android/server/AppStateTracker.java
+++ b/services/core/java/com/android/server/AppStateTracker.java
@@ -53,6 +53,7 @@
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.ForceAppStandbyTrackerProto.ExemptedPackage;
import com.android.server.ForceAppStandbyTrackerProto.RunAnyInBackgroundRestrictedPackages;
@@ -1182,72 +1183,67 @@
}
}
- public void dump(PrintWriter pw, String indent) {
+ @Deprecated
+ public void dump(PrintWriter pw, String prefix) {
+ dump(new IndentingPrintWriter(pw, " ").setIndent(prefix));
+ }
+
+ public void dump(IndentingPrintWriter pw) {
synchronized (mLock) {
- pw.print(indent);
pw.println("Forced App Standby Feature enabled: " + mForcedAppStandbyEnabled);
- pw.print(indent);
pw.print("Force all apps standby: ");
pw.println(isForceAllAppsStandbyEnabled());
- pw.print(indent);
pw.print("Small Battery Device: ");
pw.println(isSmallBatteryDevice());
- pw.print(indent);
pw.print("Force all apps standby for small battery device: ");
pw.println(mForceAllAppStandbyForSmallBattery);
- pw.print(indent);
pw.print("Plugged In: ");
pw.println(mIsPluggedIn);
- pw.print(indent);
pw.print("Active uids: ");
dumpUids(pw, mActiveUids);
- pw.print(indent);
pw.print("Foreground uids: ");
dumpUids(pw, mForegroundUids);
- pw.print(indent);
pw.print("Whitelist appids: ");
pw.println(Arrays.toString(mPowerWhitelistedAllAppIds));
- pw.print(indent);
pw.print("Temp whitelist appids: ");
pw.println(Arrays.toString(mTempWhitelistedAppIds));
- pw.print(indent);
pw.println("Exempted packages:");
+ pw.increaseIndent();
for (int i = 0; i < mExemptedPackages.size(); i++) {
- pw.print(indent);
- pw.print(" User ");
+ pw.print("User ");
pw.print(mExemptedPackages.keyAt(i));
pw.println();
+ pw.increaseIndent();
for (int j = 0; j < mExemptedPackages.sizeAt(i); j++) {
- pw.print(indent);
- pw.print(" ");
pw.print(mExemptedPackages.valueAt(i, j));
pw.println();
}
+ pw.decreaseIndent();
}
+ pw.decreaseIndent();
pw.println();
- pw.print(indent);
pw.println("Restricted packages:");
+ pw.increaseIndent();
for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
- pw.print(indent);
- pw.print(" ");
pw.print(UserHandle.formatUid(uidAndPackage.first));
pw.print(" ");
pw.print(uidAndPackage.second);
pw.println();
}
+ pw.decreaseIndent();
- mStatLogger.dump(pw, indent);
+ mStatLogger.dump(pw);
}
}
diff --git a/services/core/java/com/android/server/StatLogger.java b/services/core/java/com/android/server/StatLogger.java
index 0e6f5e2..d85810d 100644
--- a/services/core/java/com/android/server/StatLogger.java
+++ b/services/core/java/com/android/server/StatLogger.java
@@ -21,6 +21,7 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.StatLoggerProto.Event;
import java.io.PrintWriter;
@@ -78,19 +79,23 @@
}
}
+ @Deprecated
public void dump(PrintWriter pw, String prefix) {
+ dump(new IndentingPrintWriter(pw, " ").setIndent(prefix));
+ }
+
+ public void dump(IndentingPrintWriter pw) {
synchronized (mLock) {
- pw.print(prefix);
pw.println("Stats:");
+ pw.increaseIndent();
for (int i = 0; i < SIZE; i++) {
- pw.print(prefix);
- pw.print(" ");
final int count = mCountStats[i];
final double durationMs = mDurationStats[i] / 1000.0;
pw.println(String.format("%s: count=%d, total=%.1fms, avg=%.3fms",
mLabels[i], count, durationMs,
(count == 0 ? 0 : ((double) durationMs) / count)));
}
+ pw.decreaseIndent();
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index efe5172..6fcdc3e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5689,8 +5689,7 @@
final long origId = Binder.clearCallingIdentity();
- if (self.state == ActivityState.RESUMED
- || self.state == ActivityState.PAUSING) {
+ if (self.isState(ActivityState.RESUMED, ActivityState.PAUSING)) {
mWindowManager.overridePendingAppTransition(packageName,
enterAnim, exitAnim, null);
}
@@ -22774,7 +22773,7 @@
}
}
break;
- } else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) {
+ } else if (r.isState(ActivityState.PAUSING, ActivityState.PAUSED)) {
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
app.adjType = "pause-activity";
@@ -22789,7 +22788,7 @@
app.cached = false;
app.empty = false;
foregroundActivities = true;
- } else if (r.state == ActivityState.STOPPING) {
+ } else if (r.isState(ActivityState.STOPPING)) {
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
app.adjType = "stop-activity";
@@ -23183,9 +23182,8 @@
}
final ActivityRecord a = cr.activity;
if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
- if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ &&
- (a.visible || a.state == ActivityState.RESUMED ||
- a.state == ActivityState.PAUSING)) {
+ if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ && (a.visible
+ || a.isState(ActivityState.RESUMED, ActivityState.PAUSING))) {
adj = ProcessList.FOREGROUND_APP_ADJ;
if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index dadd869..07e27bc 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -25,6 +25,7 @@
import android.app.IUidObserver;
import android.app.ProfilerInfo;
import android.app.WaitResult;
+import android.app.usage.AppStandbyInfo;
import android.app.usage.ConfigurationStats;
import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageStatsManager;
@@ -1944,15 +1945,16 @@
if (!multiple) {
usm.setAppStandbyBucket(packageName, bucketNameToBucketValue(value), userId);
} else {
- HashMap<String, Integer> buckets = new HashMap<>();
- buckets.put(packageName, bucket);
+ ArrayList<AppStandbyInfo> bucketInfoList = new ArrayList<>();
+ bucketInfoList.add(new AppStandbyInfo(packageName, bucket));
while ((packageName = getNextArg()) != null) {
value = getNextArgRequired();
bucket = bucketNameToBucketValue(value);
if (bucket < 0) continue;
- buckets.put(packageName, bucket);
+ bucketInfoList.add(new AppStandbyInfo(packageName, bucket));
}
- usm.setAppStandbyBuckets(buckets, userId);
+ ParceledListSlice<AppStandbyInfo> slice = new ParceledListSlice<>(bucketInfoList);
+ usm.setAppStandbyBuckets(slice, userId);
}
return 0;
}
@@ -1977,11 +1979,11 @@
int bucket = usm.getAppStandbyBucket(packageName, null, userId);
pw.println(bucket);
} else {
- Map<String, Integer> buckets = (Map<String, Integer>) usm.getAppStandbyBuckets(
+ ParceledListSlice<AppStandbyInfo> buckets = usm.getAppStandbyBuckets(
SHELL_PACKAGE_NAME, userId);
- for (Map.Entry<String, Integer> entry: buckets.entrySet()) {
- pw.print(entry.getKey()); pw.print(": ");
- pw.println(entry.getValue());
+ for (AppStandbyInfo bucketInfo : buckets.getList()) {
+ pw.print(bucketInfo.mPackageName); pw.print(": ");
+ pw.println(bucketInfo.mStandbyBucket);
}
}
return 0;
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index e6c1cd5..06faeb9 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -288,7 +288,7 @@
HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold
UriPermissionOwner uriPermissions; // current special URI access perms.
ProcessRecord app; // if non-null, hosting application
- ActivityState state; // current state we are in
+ private ActivityState mState; // current state we are in
Bundle icicle; // last saved activity state
PersistableBundle persistentState; // last persistently saved activity state
// TODO: See if this is still needed.
@@ -381,8 +381,8 @@
String getLifecycleDescription(String reason) {
return "name= " + this + ", component=" + intent.getComponent().flattenToShortString()
- + ", package=" + packageName + ", state=" + state + ", reason=" + reason + ", time="
- + System.currentTimeMillis();
+ + ", package=" + packageName + ", state=" + mState + ", reason=" + reason
+ + ", time=" + System.currentTimeMillis();
}
void dump(PrintWriter pw, String prefix) {
@@ -503,7 +503,7 @@
pw.println();
pw.print(prefix); pw.print("haveState="); pw.print(haveState);
pw.print(" icicle="); pw.println(icicle);
- pw.print(prefix); pw.print("state="); pw.print(state);
+ pw.print(prefix); pw.print("state="); pw.print(mState);
pw.print(" stopped="); pw.print(stopped);
pw.print(" delayedResume="); pw.print(delayedResume);
pw.print(" finishing="); pw.println(finishing);
@@ -841,7 +841,7 @@
resultTo = _resultTo;
resultWho = _resultWho;
requestCode = _reqCode;
- state = INITIALIZING;
+ setState(INITIALIZING, "ActivityRecord ctor");
frontOfTask = false;
launchFailed = false;
stopped = false;
@@ -1000,6 +1000,11 @@
}
void removeWindowContainer() {
+ // Do not try to remove a window container if we have already removed it.
+ if (mWindowContainerController == null) {
+ return;
+ }
+
// Resume key dispatching if it is currently paused before we remove the container.
resumeKeyDispatchingLocked();
@@ -1259,7 +1264,7 @@
return false;
}
- switch (state) {
+ switch (mState) {
case RESUMED:
// When visible, allow entering PiP if the app is not locked. If it is over the
// keyguard, then we will prompt to unlock in the caller before entering PiP.
@@ -1385,13 +1390,13 @@
// - It is currently resumed or paused. i.e. it is currently visible to the user and we want
// the user to see the visual effects caused by the intent delivery now.
// - The device is sleeping and it is the top activity behind the lock screen (b/6700897).
- if ((state == RESUMED || state == PAUSED
+ if ((mState == RESUMED || mState == PAUSED
|| isTopActivityWhileSleeping) && app != null && app.thread != null) {
try {
ArrayList<ReferrerIntent> ar = new ArrayList<>(1);
ar.add(rintent);
service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
- NewIntentItem.obtain(ar, state == PAUSED));
+ NewIntentItem.obtain(ar, mState == PAUSED));
unsent = false;
} catch (RemoteException e) {
Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
@@ -1573,6 +1578,63 @@
mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
}
+ void setState(ActivityState state, String reason) {
+ if (DEBUG_STATES) Slog.v(TAG_STATES, "State movement: " + this + " from:" + getState()
+ + " to:" + state + " reason:" + reason);
+ final boolean stateChanged = mState != state;
+ mState = state;
+
+ if (stateChanged && isState(DESTROYING, DESTROYED)) {
+ makeFinishingLocked();
+
+ // When moving to the destroyed state, immediately destroy the activity in the
+ // associated stack. Most paths for finishing an activity will handle an activity's path
+ // to destroy through mechanisms such as ActivityStackSupervisor#mFinishingActivities.
+ // However, moving to the destroyed state directly (as in the case of an app dying) and
+ // marking it as finished will lead to cleanup steps that will prevent later handling
+ // from happening.
+ if (isState(DESTROYED)) {
+ final ActivityStack stack = getStack();
+ if (stack != null) {
+ stack.activityDestroyedLocked(this, reason);
+ }
+ }
+ }
+ }
+
+ ActivityState getState() {
+ return mState;
+ }
+
+ /**
+ * Returns {@code true} if the Activity is in the specified state.
+ */
+ boolean isState(ActivityState state) {
+ return state == mState;
+ }
+
+ /**
+ * Returns {@code true} if the Activity is in one of the specified states.
+ */
+ boolean isState(ActivityState state1, ActivityState state2) {
+ return state1 == mState || state2 == mState;
+ }
+
+ /**
+ * Returns {@code true} if the Activity is in one of the specified states.
+ */
+ boolean isState(ActivityState state1, ActivityState state2, ActivityState state3) {
+ return state1 == mState || state2 == mState || state3 == mState;
+ }
+
+ /**
+ * Returns {@code true} if the Activity is in one of the specified states.
+ */
+ boolean isState(ActivityState state1, ActivityState state2, ActivityState state3,
+ ActivityState state4) {
+ return state1 == mState || state2 == mState || state3 == mState || state4 == mState;
+ }
+
void notifyAppResumed(boolean wasStopped) {
mWindowContainerController.notifyAppResumed(wasStopped);
}
@@ -1602,9 +1664,9 @@
void makeVisibleIfNeeded(ActivityRecord starting) {
// This activity is not currently visible, but is running. Tell it to become visible.
- if (state == RESUMED || this == starting) {
+ if (mState == RESUMED || this == starting) {
if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY,
- "Not making visible, r=" + this + " state=" + state + " starting=" + starting);
+ "Not making visible, r=" + this + " state=" + mState + " starting=" + starting);
return;
}
@@ -1627,13 +1689,13 @@
mStackSupervisor.mGoingToSleepActivities.remove(this);
// If the activity is stopped or stopping, cycle to the paused state.
- if (state == STOPPED || state == STOPPING) {
+ if (isState(STOPPED, STOPPING)) {
// 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}.
- state = PAUSING;
+ setState(PAUSING, "makeVisibleIfNeeded");
service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
PauseActivityItem.obtain(finishing, false /* userLeaving */,
configChangeFlags, false /* dontReport */)
@@ -1654,7 +1716,7 @@
}
} catch(RemoteException e) {
}
- return state == RESUMED;
+ return mState == RESUMED;
}
static void activityResumedLocked(IBinder token) {
@@ -1728,7 +1790,7 @@
final void activityStoppedLocked(Bundle newIcicle, PersistableBundle newPersistentState,
CharSequence description) {
final ActivityStack stack = getStack();
- if (state != STOPPING) {
+ if (mState != STOPPING) {
Slog.i(TAG, "Activity reported stop, but no longer stopping: " + this);
stack.mHandler.removeMessages(STOP_TIMEOUT_MSG, this);
return;
@@ -1751,7 +1813,7 @@
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to STOPPED: " + this + " (stop complete)");
stack.mHandler.removeMessages(STOP_TIMEOUT_MSG, this);
stopped = true;
- state = STOPPED;
+ setState(STOPPED, "activityStoppedLocked");
mWindowContainerController.notifyAppStopped();
@@ -2021,8 +2083,7 @@
* currently pausing, or is resumed.
*/
public boolean isInterestingToUserLocked() {
- return visible || nowVisible || state == PAUSING ||
- state == RESUMED;
+ return visible || nowVisible || mState == PAUSING || mState == RESUMED;
}
void setSleeping(boolean _sleeping) {
@@ -2084,8 +2145,7 @@
}
final boolean isDestroyable() {
- if (finishing || app == null || state == DESTROYING
- || state == DESTROYED) {
+ if (finishing || app == null) {
// This would be redundant.
return false;
}
@@ -2151,7 +2211,7 @@
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
allowTaskSnapshot(),
- state.ordinal() >= RESUMED.ordinal() && state.ordinal() <= STOPPED.ordinal(),
+ mState.ordinal() >= RESUMED.ordinal() && mState.ordinal() <= STOPPED.ordinal(),
fromRecents);
if (shown) {
mStartingWindowState = STARTING_WINDOW_SHOWN;
@@ -2328,7 +2388,7 @@
}
// Skip updating configuration for activity that are stopping or stopped.
- if (state == STOPPING || state == STOPPED) {
+ if (mState == STOPPING || mState == STOPPED) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Skipping config check stopped or stopping: " + this);
return true;
@@ -2378,7 +2438,7 @@
setLastReportedConfiguration(service.getGlobalConfiguration(), newMergedOverrideConfig);
- if (state == INITIALIZING) {
+ if (mState == INITIALIZING) {
// No need to relaunch or schedule new config for activity that hasn't been launched
// yet. We do, however, return after applying the config to activity record, so that
// it will use it for launch transaction.
@@ -2431,7 +2491,7 @@
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Config is destroying non-running " + this);
stack.destroyActivityLocked(this, true, "config");
- } else if (state == PAUSING) {
+ } else if (mState == PAUSING) {
// A little annoying: we are waiting for this activity to finish pausing. Let's not
// do anything now, but just flag that it needs to be restarted when done pausing.
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
@@ -2439,7 +2499,7 @@
deferRelaunchUntilPaused = true;
preserveWindowOnDeferredRelaunch = preserveWindow;
return true;
- } else if (state == RESUMED) {
+ } else if (mState == RESUMED) {
// Try to optimize this case: the configuration is changing and we need to restart
// the top, resumed activity. Instead of doing the normal handshaking, just say
// "restart!".
@@ -2609,7 +2669,7 @@
service.showAskCompatModeDialogLocked(this);
} else {
service.mHandler.removeMessages(PAUSE_TIMEOUT_MSG, this);
- state = PAUSED;
+ setState(PAUSED, "relaunchActivityLocked");
// if the app is relaunched when it's stopped, and we're not resuming,
// put it back into stopped state.
if (stopped) {
@@ -2853,7 +2913,7 @@
final long token = proto.start(fieldId);
super.writeToProto(proto, CONFIGURATION_CONTAINER, false /* trim */);
writeIdentifierToProto(proto, IDENTIFIER);
- proto.write(STATE, state.toString());
+ proto.write(STATE, mState.toString());
proto.write(VISIBLE, visible);
proto.write(FRONT_OF_TASK, frontOfTask);
if (app != null) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index fe10670..817b699 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -70,7 +70,12 @@
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
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.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.PAUSED;
+import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
+import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
import static com.android.server.am.ActivityStackSupervisor.FindTaskResult;
@@ -1353,8 +1358,7 @@
final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
- if (r.state == STOPPING || r.state == STOPPED
- || r.state == ActivityState.PAUSED || r.state == ActivityState.PAUSING) {
+ if (r.isState(STOPPING, STOPPED, PAUSED, PAUSING)) {
r.setSleeping(true);
}
}
@@ -1401,7 +1405,7 @@
ActivityRecord resuming, boolean pauseImmediately) {
if (mPausingActivity != null) {
Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity
- + " state=" + mPausingActivity.state);
+ + " state=" + mPausingActivity.getState());
if (!shouldSleepActivities()) {
// Avoid recursion among check for sleep and complete pause during sleeping.
// Because activity will be paused immediately after resume, just let pause
@@ -1431,7 +1435,7 @@
mLastPausedActivity = prev;
mLastNoHistoryActivity = (prev.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (prev.info.flags & ActivityInfo.FLAG_NO_HISTORY) != 0 ? prev : null;
- prev.state = ActivityState.PAUSING;
+ prev.setState(PAUSING, "startPausingLocked");
prev.getTask().touchActiveTime();
clearLaunchTime(prev);
final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
@@ -1525,8 +1529,8 @@
r.userId, System.identityHashCode(r), r.shortComponentName,
mPausingActivity != null
? mPausingActivity.shortComponentName : "(none)");
- if (r.state == ActivityState.PAUSING) {
- r.state = ActivityState.PAUSED;
+ if (r.isState(PAUSING)) {
+ r.setState(PAUSED, "activityPausedLocked");
if (r.finishing) {
if (DEBUG_PAUSE) Slog.v(TAG,
"Executing finish of failed to pause activity: " + r);
@@ -1544,8 +1548,8 @@
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Complete pause: " + prev);
if (prev != null) {
- final boolean wasStopping = prev.state == STOPPING;
- prev.state = ActivityState.PAUSED;
+ final boolean wasStopping = prev.isState(STOPPING);
+ prev.setState(PAUSED, "completePausedLocked");
if (prev.finishing) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false,
@@ -1566,7 +1570,7 @@
// We are also stopping, the stop request must have gone soon after the pause.
// We can't clobber it, because the stop confirmation will not be handled.
// We don't need to schedule another stop, we only need to let it happen.
- prev.state = STOPPING;
+ prev.setState(STOPPING, "completePausedLocked");
} else if (!prev.visible || shouldSleepOrShutDownActivities()) {
// Clear out any deferred client hide we might currently have.
prev.setDeferHidingClient(false);
@@ -1843,7 +1847,7 @@
}
if (reallyVisible) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make visible? " + r
- + " finishing=" + r.finishing + " state=" + r.state);
+ + " finishing=" + r.finishing + " state=" + r.getState());
// First: if this is not the current activity being started, make
// sure it matches the current configuration.
if (r != starting) {
@@ -1875,7 +1879,7 @@
configChanges |= r.configChangeFlags;
} else {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make invisible? " + r
- + " finishing=" + r.finishing + " state=" + r.state
+ + " finishing=" + r.finishing + " state=" + r.getState()
+ " stackShouldBeVisible=" + stackShouldBeVisible
+ " behindFullscreenActivity=" + behindFullscreenActivity
+ " mLaunchTaskBehind=" + r.mLaunchTaskBehind);
@@ -2059,7 +2063,7 @@
}
// Now for any activities that aren't visible to the user, make sure they no longer are
// keeping the screen frozen.
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making invisible: " + r + " " + r.state);
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making invisible: " + r + " " + r.getState());
try {
final boolean canEnterPictureInPicture = r.checkEnterPictureInPictureState(
"makeInvisible", true /* beforeStopping */);
@@ -2071,11 +2075,11 @@
// the current contract for "auto-Pip" is that the app should enter it before onPause
// returns. Just need to confirm this reasoning makes sense.
final boolean deferHidingClient = canEnterPictureInPicture
- && r.state != STOPPING && r.state != STOPPED && r.state != PAUSED;
+ && !r.isState(STOPPING, STOPPED, PAUSED);
r.setDeferHidingClient(deferHidingClient);
r.setVisible(false);
- switch (r.state) {
+ switch (r.getState()) {
case STOPPING:
case STOPPED:
if (r.app != null && r.app.thread != null) {
@@ -2255,7 +2259,7 @@
// TODO: move mResumedActivity to stack supervisor,
// there should only be 1 global copy of resumed activity.
mResumedActivity = r;
- r.state = ActivityState.RESUMED;
+ r.setState(RESUMED, "setResumedActivityLocked");
mService.setResumedActivityUncheckLocked(r, reason);
mStackSupervisor.mRecentTasks.add(r.getTask());
}
@@ -2294,8 +2298,8 @@
next.delayedResume = false;
// If the top activity is the resumed one, nothing to do.
- if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
- mStackSupervisor.allResumedActivitiesComplete()) {
+ if (mResumedActivity == next && next.isState(RESUMED)
+ && mStackSupervisor.allResumedActivitiesComplete()) {
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
executeAppTransition(options);
@@ -2389,8 +2393,8 @@
}
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return true;
- } else if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
- mStackSupervisor.allResumedActivitiesComplete()) {
+ } else if (mResumedActivity == next && next.isState(RESUMED)
+ && mStackSupervisor.allResumedActivitiesComplete()) {
// It is possible for the activity to be resumed when we paused back stacks above if the
// next activity doesn't have to wait for pause to complete.
// So, nothing else to-do except:
@@ -2539,7 +2543,7 @@
ActivityRecord lastResumedActivity =
lastStack == null ? null :lastStack.mResumedActivity;
- ActivityState lastState = next.state;
+ final ActivityState lastState = next.getState();
mService.updateCpuStats();
@@ -2645,7 +2649,7 @@
// Whoops, need to restart this activity!
if (DEBUG_STATES) Slog.v(TAG_STATES, "Resume failed; resetting state to "
+ lastState + ": " + next);
- next.state = lastState;
+ next.setState(lastState, "resumeTopActivityInnerLocked");
if (lastStack != null) {
lastStack.mResumedActivity = lastResumedActivity;
}
@@ -3408,7 +3412,7 @@
r.stopped = false;
if (DEBUG_STATES) Slog.v(TAG_STATES,
"Moving to STOPPING: " + r + " (stop requested)");
- r.state = STOPPING;
+ r.setState(STOPPING, "stopActivityLocked");
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
"Stopping visible=" + r.visible + " for " + r);
if (!r.visible) {
@@ -3432,7 +3436,7 @@
// Just in case, assume it to be stopped.
r.stopped = true;
if (DEBUG_STATES) Slog.v(TAG_STATES, "Stop failed; moving to STOPPED: " + r);
- r.state = STOPPED;
+ r.setState(STOPPED, "stopActivityLocked");
if (r.deferRelaunchUntilPaused) {
destroyActivityLocked(r, true, "stop-except");
}
@@ -3505,9 +3509,7 @@
}
if (activityNdx >= 0) {
r = mTaskHistory.get(taskNdx).mActivities.get(activityNdx);
- if (r.state == ActivityState.RESUMED
- || r.state == ActivityState.PAUSING
- || r.state == ActivityState.PAUSED) {
+ if (r.isState(RESUMED, PAUSING, PAUSED)) {
if (!r.isActivityTypeHome() || mService.mHomeProcess != r.app) {
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
@@ -3671,7 +3673,7 @@
if (endTask) {
mService.mLockTaskController.clearLockedTask(task);
}
- } else if (r.state != ActivityState.PAUSING) {
+ } else if (!r.isState(PAUSING)) {
// If the activity is PAUSING, we will complete the finish once
// it is done pausing; else we can just directly finish it here.
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish not pausing: " + r);
@@ -3738,7 +3740,7 @@
}
if (DEBUG_STATES) Slog.v(TAG_STATES,
"Moving to STOPPING: "+ r + " (finish requested)");
- r.state = STOPPING;
+ r.setState(STOPPING, "finishCurrentActivityLocked");
if (oomAdj) {
mService.updateOomAdjLocked();
}
@@ -3752,15 +3754,15 @@
if (mResumedActivity == r) {
mResumedActivity = null;
}
- final ActivityState prevState = r.state;
+ final ActivityState prevState = r.getState();
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to FINISHING: " + r);
- r.state = ActivityState.FINISHING;
+ r.setState(FINISHING, "finishCurrentActivityLocked");
final boolean finishingActivityInNonFocusedStack
= r.getStack() != mStackSupervisor.getFocusedStack()
- && prevState == ActivityState.PAUSED && mode == FINISH_AFTER_VISIBLE;
+ && prevState == PAUSED && mode == FINISH_AFTER_VISIBLE;
if (mode == FINISH_IMMEDIATELY
- || (prevState == ActivityState.PAUSED
+ || (prevState == PAUSED
&& (mode == FINISH_AFTER_PAUSE || inPinnedWindowingMode()))
|| finishingActivityInNonFocusedStack
|| prevState == STOPPING
@@ -3981,7 +3983,7 @@
if (setState) {
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to DESTROYED: " + r + " (cleaning up)");
- r.state = ActivityState.DESTROYED;
+ r.setState(DESTROYED, "cleanupActivityLocked");
if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during cleanUp for activity " + r);
r.app = null;
}
@@ -4030,7 +4032,7 @@
removeTimeoutsForActivityLocked(r);
if (DEBUG_STATES) Slog.v(TAG_STATES,
"Moving to DESTROYED: " + r + " (removed from history)");
- r.state = ActivityState.DESTROYED;
+ r.setState(DESTROYED, "removeActivityFromHistoryLocked");
if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + r);
r.app = null;
r.removeWindowContainer();
@@ -4114,7 +4116,8 @@
continue;
}
if (r.isDestroyable()) {
- if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Destroying " + r + " in state " + r.state
+ if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Destroying " + r
+ + " in state " + r.getState()
+ " resumed=" + mResumedActivity
+ " pausing=" + mPausingActivity + " for reason " + reason);
if (destroyActivityLocked(r, true, reason)) {
@@ -4131,7 +4134,7 @@
final boolean safelyDestroyActivityLocked(ActivityRecord r, String reason) {
if (r.isDestroyable()) {
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
- "Destroying " + r + " in state " + r.state + " resumed=" + mResumedActivity
+ "Destroying " + r + " in state " + r.getState() + " resumed=" + mResumedActivity
+ " pausing=" + mPausingActivity + " for reason " + reason);
return destroyActivityLocked(r, true, reason);
}
@@ -4159,7 +4162,7 @@
final ActivityRecord activity = activities.get(actNdx);
if (activity.app == app && activity.isDestroyable()) {
if (DEBUG_RELEASE) Slog.v(TAG_RELEASE, "Destroying " + activity
- + " in state " + activity.state + " resumed=" + mResumedActivity
+ + " in state " + activity.getState() + " resumed=" + mResumedActivity
+ " pausing=" + mPausingActivity + " for reason " + reason);
destroyActivityLocked(activity, true, reason);
if (activities.get(actNdx) != activity) {
@@ -4253,13 +4256,15 @@
if (r.finishing && !skipDestroy) {
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to DESTROYING: " + r
+ " (destroy requested)");
- r.state = ActivityState.DESTROYING;
+ r.setState(DESTROYING,
+ "destroyActivityLocked. finishing and not skipping destroy");
Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG, r);
mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
} else {
if (DEBUG_STATES) Slog.v(TAG_STATES,
"Moving to DESTROYED: " + r + " (destroy skipped)");
- r.state = ActivityState.DESTROYED;
+ r.setState(DESTROYED,
+ "destroyActivityLocked. not finishing or skipping destroy");
if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during destroy for activity " + r);
r.app = null;
}
@@ -4270,7 +4275,7 @@
removedFromHistory = true;
} else {
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to DESTROYED: " + r + " (no app)");
- r.state = ActivityState.DESTROYED;
+ r.setState(DESTROYED, "destroyActivityLocked. not finishing and had no app");
if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during destroy for activity " + r);
r.app = null;
}
@@ -4288,24 +4293,29 @@
final void activityDestroyedLocked(IBinder token, String reason) {
final long origId = Binder.clearCallingIdentity();
try {
- ActivityRecord r = ActivityRecord.forTokenLocked(token);
- if (r != null) {
- mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
- }
- if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS, "activityDestroyedLocked: r=" + r);
-
- if (isInStackLocked(r) != null) {
- if (r.state == ActivityState.DESTROYING) {
- cleanUpActivityLocked(r, true, false);
- removeActivityFromHistoryLocked(r, reason);
- }
- }
- mStackSupervisor.resumeFocusedStackTopActivityLocked();
+ activityDestroyedLocked(ActivityRecord.forTokenLocked(token), reason);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
+ final void activityDestroyedLocked(ActivityRecord record, String reason) {
+ if (record != null) {
+ mHandler.removeMessages(DESTROY_TIMEOUT_MSG, record);
+ }
+
+ if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS, "activityDestroyedLocked: r=" + record);
+
+ if (isInStackLocked(record) != null) {
+ if (record.isState(DESTROYING, DESTROYED)) {
+ cleanUpActivityLocked(record, true, false);
+ removeActivityFromHistoryLocked(record, reason);
+ }
+ }
+
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
+ }
+
private void removeHistoryRecordsForAppLocked(ArrayList<ActivityRecord> list,
ProcessRecord app, String listName) {
int i = list.size();
@@ -4374,14 +4384,14 @@
+ ": haveState=" + r.haveState
+ " stateNotNeeded=" + r.stateNotNeeded
+ " finishing=" + r.finishing
- + " state=" + r.state + " callers=" + Debug.getCallers(5));
+ + " state=" + r.getState() + " callers=" + Debug.getCallers(5));
if (!r.finishing) {
Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
r.userId, System.identityHashCode(r),
r.getTask().taskId, r.shortComponentName,
"proc died without state saved");
- if (r.state == ActivityState.RESUMED) {
+ if (r.getState() == RESUMED) {
mService.updateUsageStats(r, false);
}
}
@@ -4417,7 +4427,7 @@
private void updateTransitLocked(int transit, ActivityOptions options) {
if (options != null) {
ActivityRecord r = topRunningActivityLocked();
- if (r != null && r.state != ActivityState.RESUMED) {
+ if (r != null && !r.isState(RESUMED)) {
r.updateOptionsLocked(options);
} else {
ActivityOptions.abort(options);
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 9a3b102..5577186 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1005,7 +1005,7 @@
final ActivityStack stack = display.getChildAt(stackNdx);
if (isFocusedStack(stack)) {
final ActivityRecord r = stack.mResumedActivity;
- if (r != null && r.state != RESUMED) {
+ if (r != null && !r.isState(RESUMED)) {
return false;
}
}
@@ -1069,10 +1069,10 @@
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getChildAt(stackNdx);
final ActivityRecord r = stack.mPausingActivity;
- if (r != null && r.state != PAUSED && r.state != STOPPED && r.state != STOPPING) {
+ if (r != null && !r.isState(PAUSED, STOPPED, STOPPING)) {
if (DEBUG_STATES) {
Slog.d(TAG_STATES,
- "allPausedActivitiesComplete: r=" + r + " state=" + r.state);
+ "allPausedActivitiesComplete: r=" + r + " state=" + r.getState());
pausing = false;
} else {
return false;
@@ -1522,7 +1522,7 @@
// current icicle and other state.
if (DEBUG_STATES) Slog.v(TAG_STATES,
"Moving to PAUSED: " + r + " (starting in paused state)");
- r.state = PAUSED;
+ r.setState(PAUSED, "realStartActivityLocked");
}
// Launch the new version setup screen if needed. We do this -after-
@@ -2099,9 +2099,9 @@
}
final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
- if (r == null || r.state != RESUMED) {
+ if (r == null || !r.isState(RESUMED)) {
mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
- } else if (r.state == RESUMED) {
+ } else if (r.isState(RESUMED)) {
// Kick off any lingering app transitions form the MoveTaskToFront operation.
mFocusedStack.executeAppTransition(targetOptions);
}
@@ -3540,14 +3540,14 @@
// First, if we find an activity that is in the process of being destroyed,
// then we just aren't going to do anything for now; we want things to settle
// down before we try to prune more activities.
- if (r.finishing || r.state == DESTROYING || r.state == DESTROYED) {
+ if (r.finishing || r.isState(DESTROYING, DESTROYED)) {
if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Abort release; already destroying: " + r);
return;
}
// Don't consider any activies that are currently not in a state where they
// can be destroyed.
- if (r.visible || !r.stopped || !r.haveState || r.state == RESUMED || r.state == PAUSING
- || r.state == PAUSED || r.state == STOPPING) {
+ if (r.visible || !r.stopped || !r.haveState
+ || r.isState(RESUMED, PAUSING, PAUSED, STOPPING)) {
if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Not releasing in-use activity: " + r);
continue;
}
@@ -3683,7 +3683,7 @@
? stack.shouldSleepOrShutDownActivities()
: mService.isSleepingOrShuttingDownLocked();
if (!waitingVisible || shouldSleepOrShutDown) {
- if (!processPausingActivities && s.state == PAUSING) {
+ if (!processPausingActivities && s.isState(PAUSING)) {
// Defer processing pausing activities in this iteration and reschedule
// a delayed idle to reprocess it again
removeTimeoutsForActivityLocked(idleActivity);
@@ -3710,7 +3710,7 @@
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getChildAt(stackNdx);
final ActivityRecord r = stack.topRunningActivityLocked();
- final ActivityState state = r == null ? DESTROYED : r.state;
+ final ActivityState state = r == null ? DESTROYED : r.getState();
if (isFocusedStack(stack)) {
if (r == null) Slog.e(TAG,
"validateTop...: null top activity, stack=" + stack);
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 8205265..fcdf3d2 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1107,7 +1107,7 @@
case START_TASK_TO_FRONT: {
// ActivityRecord may represent a different activity, but it should not be
// in the resumed state.
- if (r.nowVisible && r.state == RESUMED) {
+ if (r.nowVisible && r.isState(RESUMED)) {
outResult.timeout = false;
outResult.who = r.realActivity;
outResult.totalTime = 0;
@@ -1516,7 +1516,7 @@
final TaskRecord task = mSupervisor.anyTaskForIdLocked(
mOptions.getLaunchTaskId());
final ActivityRecord top = task != null ? task.getTopActivity() : null;
- if (top != null && top.state != RESUMED) {
+ if (top != null && !top.isState(RESUMED)) {
// The caller specifies that we'd like to be avoided to be moved to the
// front, so be it!
diff --git a/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java
index 71fd71b8..d7d18a9 100644
--- a/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java
@@ -42,6 +42,7 @@
{Settings.Global.SYS_VDSO, "sys.vdso"},
{Settings.Global.FPS_DEVISOR, ThreadedRenderer.DEBUG_FPS_DIVISOR},
{Settings.Global.DISPLAY_PANEL_LPM, "sys.display_panel_lpm"},
+ {Settings.Global.SYS_UIDCPUPOWER, "sys.uidcpupower"},
};
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index d679439..a07afde 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -1103,7 +1103,7 @@
// Increment the total number of non-finishing activities
reportOut.numActivities++;
- if (reportOut.top == null || (reportOut.top.state == ActivityState.INITIALIZING)) {
+ if (reportOut.top == null || (reportOut.top.isState(ActivityState.INITIALIZING))) {
reportOut.top = r;
// Reset the number of running activities until we hit the first non-initializing
// activity
diff --git a/services/core/java/com/android/server/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
similarity index 85%
rename from services/core/java/com/android/server/MultipathPolicyTracker.java
rename to services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index 9e0a230..296b9ac 100644
--- a/services/core/java/com/android/server/MultipathPolicyTracker.java
+++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
@@ -16,11 +16,17 @@
package com.android.server.connectivity;
+import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER;
+import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+
+import static com.android.server.net.NetworkPolicyManagerInternal.QUOTA_TYPE_MULTIPATH;
+
import android.app.usage.NetworkStatsManager;
import android.app.usage.NetworkStatsManager.UsageCallback;
import android.content.Context;
-import android.net.INetworkStatsService;
-import android.net.INetworkPolicyManager;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
@@ -31,29 +37,17 @@
import android.net.NetworkTemplate;
import android.net.StringNetworkSpecifier;
import android.os.Handler;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.telephony.TelephonyManager;
import android.util.DebugUtils;
import android.util.Slog;
-import java.util.Calendar;
-import java.util.concurrent.ConcurrentHashMap;
-
-import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.net.NetworkPolicyManagerInternal;
+import com.android.server.net.NetworkStatsManagerInternal;
-import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER;
-import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY;
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI;
-import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
-import static com.android.server.net.NetworkPolicyManagerInternal.QUOTA_TYPE_MULTIPATH;
+import java.util.Calendar;
+import java.util.concurrent.ConcurrentHashMap;
/**
* Manages multipath data budgets.
@@ -76,10 +70,8 @@
private final Handler mHandler;
private ConnectivityManager mCM;
- private NetworkStatsManager mStatsManager;
private NetworkPolicyManager mNPM;
- private TelephonyManager mTelephonyManager;
- private INetworkStatsService mStatsService;
+ private NetworkStatsManager mStatsManager;
private NetworkCallback mMobileNetworkCallback;
private NetworkPolicyManager.Listener mPolicyListener;
@@ -87,8 +79,6 @@
// STOPSHIP: replace this with a configurable mechanism.
private static final long DEFAULT_DAILY_MULTIPATH_QUOTA = 2_500_000;
- private volatile int mMeteredMultipathPreference;
-
public MultipathPolicyTracker(Context ctx, Handler handler) {
mContext = ctx;
mHandler = handler;
@@ -97,12 +87,9 @@
}
public void start() {
- mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- mNPM = (NetworkPolicyManager) mContext.getSystemService(Context.NETWORK_POLICY_SERVICE);
- mStatsManager = (NetworkStatsManager) mContext.getSystemService(
- Context.NETWORK_STATS_SERVICE);
- mStatsService = INetworkStatsService.Stub.asInterface(
- ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+ mCM = mContext.getSystemService(ConnectivityManager.class);
+ mNPM = mContext.getSystemService(NetworkPolicyManager.class);
+ mStatsManager = mContext.getSystemService(NetworkStatsManager.class);
registerTrackMobileCallback();
registerNetworkPolicyListener();
@@ -119,6 +106,9 @@
// Called on an arbitrary binder thread.
public Integer getMultipathPreference(Network network) {
+ if (network == null) {
+ return null;
+ }
MultipathTracker t = mMultipathTrackers.get(network);
if (t != null) {
return t.getMultipathPreference();
@@ -149,8 +139,7 @@
network, nc, e.getMessage()));
}
- TelephonyManager tele = (TelephonyManager) mContext.getSystemService(
- Context.TELEPHONY_SERVICE);
+ TelephonyManager tele = mContext.getSystemService(TelephonyManager.class);
if (tele == null) {
throw new IllegalStateException(String.format("Missing TelephonyManager"));
}
@@ -162,7 +151,7 @@
subscriberId = tele.getSubscriberId();
mNetworkTemplate = new NetworkTemplate(
- NetworkTemplate.MATCH_MOBILE_ALL, subscriberId, new String[] { subscriberId },
+ NetworkTemplate.MATCH_MOBILE, subscriberId, new String[] { subscriberId },
null, NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
NetworkStats.DEFAULT_NETWORK_NO);
mUsageCallback = new UsageCallback() {
@@ -185,26 +174,21 @@
start.set(Calendar.SECOND, 0);
start.set(Calendar.MILLISECOND, 0);
- long bytes;
try {
- // TODO: Consider using NetworkStatsManager.getSummaryForDevice instead.
- bytes = mStatsService.getNetworkTotalBytes(mNetworkTemplate,
- start.getTimeInMillis(), end.getTimeInMillis());
- if (DBG) Slog.w(TAG, "Non-default data usage: " + bytes);
- } catch (RemoteException e) {
- Slog.w(TAG, "Can't fetch daily data usage: " + e);
- bytes = -1;
- } catch (IllegalStateException e) {
- // Bandwidth control disabled?
- bytes = -1;
+ final long bytes = LocalServices.getService(NetworkStatsManagerInternal.class)
+ .getNetworkTotalBytes(mNetworkTemplate, start.getTimeInMillis(),
+ end.getTimeInMillis());
+ if (DBG) Slog.d(TAG, "Non-default data usage: " + bytes);
+ return bytes;
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failed to get data usage: " + e);
+ return -1;
}
- return bytes;
}
void updateMultipathBudget() {
- NetworkPolicyManagerInternal npms = LocalServices.getService(
- NetworkPolicyManagerInternal.class);
- long quota = npms.getSubscriptionOpportunisticQuota(this.network, QUOTA_TYPE_MULTIPATH);
+ long quota = LocalServices.getService(NetworkPolicyManagerInternal.class)
+ .getSubscriptionOpportunisticQuota(this.network, QUOTA_TYPE_MULTIPATH);
if (DBG) Slog.d(TAG, "Opportunistic quota from data plan: " + quota + " bytes");
if (quota == 0) {
@@ -223,8 +207,10 @@
}
mQuota = quota;
- long usage = getDailyNonDefaultDataUsage();
- long budget = Math.max(0, quota - usage);
+ // If we can't get current usage, assume the worst and don't give
+ // ourselves any budget to work with.
+ final long usage = getDailyNonDefaultDataUsage();
+ final long budget = (usage == -1) ? 0 : Math.max(0, quota - usage);
if (budget > 0) {
if (DBG) Slog.d(TAG, "Setting callback for " + budget +
" bytes on network " + network);
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 692535c..3da3551 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -421,7 +421,7 @@
byteToken[i] = token.get(i);
}
// Send to Keystore
- KeyStore.getInstance().addAuthToken(byteToken, mCurrentUserId);
+ KeyStore.getInstance().addAuthToken(byteToken);
}
if (client != null && client.onAuthenticated(fingerId, groupId)) {
removeClient(client);
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index f3f4dfd..740866c 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -79,6 +79,7 @@
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.AppStateTracker;
import com.android.server.DeviceIdleController;
@@ -86,7 +87,6 @@
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob;
-import com.android.server.job.JobStore.JobStatusFunctor;
import com.android.server.job.controllers.AppIdleController;
import com.android.server.job.controllers.BackgroundJobsController;
import com.android.server.job.controllers.BatteryController;
@@ -110,6 +110,7 @@
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
+import java.util.function.Consumer;
import java.util.function.Predicate;
/**
@@ -163,15 +164,16 @@
* {@link JobStatus#getServiceToken()}
*/
final List<JobServiceContext> mActiveServices = new ArrayList<>();
+
/** List of controllers that will notify this service of updates to jobs. */
- List<StateController> mControllers;
+ private final List<StateController> mControllers;
/** Need direct access to this for testing. */
- BatteryController mBatteryController;
+ private final BatteryController mBatteryController;
/** Need direct access to this for testing. */
- StorageController mStorageController;
+ private final StorageController mStorageController;
/** Need directly for sending uid state changes */
- private BackgroundJobsController mBackgroundJobsController;
- private DeviceIdleJobsController mDeviceIdleJobsController;
+ private final DeviceIdleJobsController mDeviceIdleJobsController;
+
/**
* Queue of pending jobs. The JobServiceContext class will receive jobs from this list
* when ready to execute them.
@@ -253,12 +255,48 @@
*/
int[] mTmpAssignPreferredUidForContext = new int[MAX_JOB_CONTEXTS_COUNT];
+ private class ConstantsObserver extends ContentObserver {
+ private ContentResolver mResolver;
+
+ public ConstantsObserver(Handler handler) {
+ super(handler);
+ }
+
+ public void start(ContentResolver resolver) {
+ mResolver = resolver;
+ mResolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.JOB_SCHEDULER_CONSTANTS), false, this);
+ updateConstants();
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ updateConstants();
+ }
+
+ private void updateConstants() {
+ synchronized (mLock) {
+ try {
+ mConstants.updateConstantsLocked(Settings.Global.getString(mResolver,
+ Settings.Global.JOB_SCHEDULER_CONSTANTS));
+ } catch (IllegalArgumentException e) {
+ // Failed to parse the settings string, log this and move on
+ // with defaults.
+ Slog.e(TAG, "Bad jobscheduler settings", e);
+ }
+ }
+
+ // Reset the heartbeat alarm based on the new heartbeat duration
+ setNextHeartbeatAlarm();
+ }
+ }
+
/**
* All times are in milliseconds. These constants are kept synchronized with the system
* global Settings. Any access to this class or its fields should be done while
* holding the JobSchedulerService.mLock lock.
*/
- private final class Constants extends ContentObserver {
+ public static class Constants {
// Key names stored in the settings value.
private static final String KEY_MIN_IDLE_COUNT = "min_idle_count";
private static final String KEY_MIN_CHARGING_COUNT = "min_charging_count";
@@ -283,6 +321,8 @@
private static final String KEY_STANDBY_WORKING_BEATS = "standby_working_beats";
private static final String KEY_STANDBY_FREQUENT_BEATS = "standby_frequent_beats";
private static final String KEY_STANDBY_RARE_BEATS = "standby_rare_beats";
+ private static final String KEY_CONN_CONGESTION_DELAY_FRAC = "conn_congestion_delay_frac";
+ private static final String KEY_CONN_PREFETCH_RELAX_FRAC = "conn_prefetch_relax_frac";
private static final int DEFAULT_MIN_IDLE_COUNT = 1;
private static final int DEFAULT_MIN_CHARGING_COUNT = 1;
@@ -306,6 +346,8 @@
private static final int DEFAULT_STANDBY_WORKING_BEATS = 11; // ~ 2 hours, with 11min beats
private static final int DEFAULT_STANDBY_FREQUENT_BEATS = 43; // ~ 8 hours
private static final int DEFAULT_STANDBY_RARE_BEATS = 130; // ~ 24 hours
+ private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f;
+ private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f;
/**
* Minimum # of idle jobs that must be ready in order to force the JMS to schedule things
@@ -400,7 +442,6 @@
* hour or day, so that the heartbeat drifts relative to wall-clock milestones.
*/
long STANDBY_HEARTBEAT_TIME = DEFAULT_STANDBY_HEARTBEAT_TIME;
-
/**
* Mapping: standby bucket -> number of heartbeats between each sweep of that
* bucket's jobs.
@@ -415,171 +456,126 @@
DEFAULT_STANDBY_FREQUENT_BEATS,
DEFAULT_STANDBY_RARE_BEATS
};
+ /**
+ * The fraction of a job's running window that must pass before we
+ * consider running it when the network is congested.
+ */
+ public float CONN_CONGESTION_DELAY_FRAC = DEFAULT_CONN_CONGESTION_DELAY_FRAC;
+ /**
+ * The fraction of a prefetch job's running window that must pass before
+ * we consider matching it against a metered network.
+ */
+ public float CONN_PREFETCH_RELAX_FRAC = DEFAULT_CONN_PREFETCH_RELAX_FRAC;
- private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
- public Constants(Handler handler) {
- super(handler);
- }
-
- public void start(ContentResolver resolver) {
- mResolver = resolver;
- mResolver.registerContentObserver(Settings.Global.getUriFor(
- Settings.Global.JOB_SCHEDULER_CONSTANTS), false, this);
- updateConstants();
- }
-
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- updateConstants();
- }
-
- private void updateConstants() {
- synchronized (mLock) {
- try {
- mParser.setString(Settings.Global.getString(mResolver,
- Settings.Global.JOB_SCHEDULER_CONSTANTS));
- } catch (IllegalArgumentException e) {
- // Failed to parse the settings string, log this and move on
- // with defaults.
- Slog.e(TAG, "Bad jobscheduler settings", e);
- }
-
- MIN_IDLE_COUNT = mParser.getInt(KEY_MIN_IDLE_COUNT,
- DEFAULT_MIN_IDLE_COUNT);
- MIN_CHARGING_COUNT = mParser.getInt(KEY_MIN_CHARGING_COUNT,
- DEFAULT_MIN_CHARGING_COUNT);
- MIN_BATTERY_NOT_LOW_COUNT = mParser.getInt(KEY_MIN_BATTERY_NOT_LOW_COUNT,
- DEFAULT_MIN_BATTERY_NOT_LOW_COUNT);
- MIN_STORAGE_NOT_LOW_COUNT = mParser.getInt(KEY_MIN_STORAGE_NOT_LOW_COUNT,
- DEFAULT_MIN_STORAGE_NOT_LOW_COUNT);
- MIN_CONNECTIVITY_COUNT = mParser.getInt(KEY_MIN_CONNECTIVITY_COUNT,
- DEFAULT_MIN_CONNECTIVITY_COUNT);
- MIN_CONTENT_COUNT = mParser.getInt(KEY_MIN_CONTENT_COUNT,
- DEFAULT_MIN_CONTENT_COUNT);
- MIN_READY_JOBS_COUNT = mParser.getInt(KEY_MIN_READY_JOBS_COUNT,
- DEFAULT_MIN_READY_JOBS_COUNT);
- HEAVY_USE_FACTOR = mParser.getFloat(KEY_HEAVY_USE_FACTOR,
- DEFAULT_HEAVY_USE_FACTOR);
- MODERATE_USE_FACTOR = mParser.getFloat(KEY_MODERATE_USE_FACTOR,
- DEFAULT_MODERATE_USE_FACTOR);
- FG_JOB_COUNT = mParser.getInt(KEY_FG_JOB_COUNT,
- DEFAULT_FG_JOB_COUNT);
- BG_NORMAL_JOB_COUNT = mParser.getInt(KEY_BG_NORMAL_JOB_COUNT,
- DEFAULT_BG_NORMAL_JOB_COUNT);
- if ((FG_JOB_COUNT+BG_NORMAL_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) {
- BG_NORMAL_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT;
- }
- BG_MODERATE_JOB_COUNT = mParser.getInt(KEY_BG_MODERATE_JOB_COUNT,
- DEFAULT_BG_MODERATE_JOB_COUNT);
- if ((FG_JOB_COUNT+BG_MODERATE_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) {
- BG_MODERATE_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT;
- }
- BG_LOW_JOB_COUNT = mParser.getInt(KEY_BG_LOW_JOB_COUNT,
- DEFAULT_BG_LOW_JOB_COUNT);
- if ((FG_JOB_COUNT+BG_LOW_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) {
- BG_LOW_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT;
- }
- BG_CRITICAL_JOB_COUNT = mParser.getInt(KEY_BG_CRITICAL_JOB_COUNT,
- DEFAULT_BG_CRITICAL_JOB_COUNT);
- if ((FG_JOB_COUNT+BG_CRITICAL_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) {
- BG_CRITICAL_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT;
- }
- MAX_STANDARD_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_STANDARD_RESCHEDULE_COUNT,
- DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT);
- MAX_WORK_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_WORK_RESCHEDULE_COUNT,
- DEFAULT_MAX_WORK_RESCHEDULE_COUNT);
- MIN_LINEAR_BACKOFF_TIME = mParser.getDurationMillis(KEY_MIN_LINEAR_BACKOFF_TIME,
- DEFAULT_MIN_LINEAR_BACKOFF_TIME);
- MIN_EXP_BACKOFF_TIME = mParser.getDurationMillis(KEY_MIN_EXP_BACKOFF_TIME,
- DEFAULT_MIN_EXP_BACKOFF_TIME);
- STANDBY_HEARTBEAT_TIME = mParser.getDurationMillis(KEY_STANDBY_HEARTBEAT_TIME,
- DEFAULT_STANDBY_HEARTBEAT_TIME);
- STANDBY_BEATS[1] = mParser.getInt(KEY_STANDBY_WORKING_BEATS,
- DEFAULT_STANDBY_WORKING_BEATS);
- STANDBY_BEATS[2] = mParser.getInt(KEY_STANDBY_FREQUENT_BEATS,
- DEFAULT_STANDBY_FREQUENT_BEATS);
- STANDBY_BEATS[3] = mParser.getInt(KEY_STANDBY_RARE_BEATS,
- DEFAULT_STANDBY_RARE_BEATS);
+ void updateConstantsLocked(String value) {
+ try {
+ mParser.setString(value);
+ } catch (Exception e) {
+ // Failed to parse the settings string, log this and move on
+ // with defaults.
+ Slog.e(TAG, "Bad jobscheduler settings", e);
}
- // Reset the heartbeat alarm based on the new heartbeat duration
- setNextHeartbeatAlarm();
+ MIN_IDLE_COUNT = mParser.getInt(KEY_MIN_IDLE_COUNT,
+ DEFAULT_MIN_IDLE_COUNT);
+ MIN_CHARGING_COUNT = mParser.getInt(KEY_MIN_CHARGING_COUNT,
+ DEFAULT_MIN_CHARGING_COUNT);
+ MIN_BATTERY_NOT_LOW_COUNT = mParser.getInt(KEY_MIN_BATTERY_NOT_LOW_COUNT,
+ DEFAULT_MIN_BATTERY_NOT_LOW_COUNT);
+ MIN_STORAGE_NOT_LOW_COUNT = mParser.getInt(KEY_MIN_STORAGE_NOT_LOW_COUNT,
+ DEFAULT_MIN_STORAGE_NOT_LOW_COUNT);
+ MIN_CONNECTIVITY_COUNT = mParser.getInt(KEY_MIN_CONNECTIVITY_COUNT,
+ DEFAULT_MIN_CONNECTIVITY_COUNT);
+ MIN_CONTENT_COUNT = mParser.getInt(KEY_MIN_CONTENT_COUNT,
+ DEFAULT_MIN_CONTENT_COUNT);
+ MIN_READY_JOBS_COUNT = mParser.getInt(KEY_MIN_READY_JOBS_COUNT,
+ DEFAULT_MIN_READY_JOBS_COUNT);
+ HEAVY_USE_FACTOR = mParser.getFloat(KEY_HEAVY_USE_FACTOR,
+ DEFAULT_HEAVY_USE_FACTOR);
+ MODERATE_USE_FACTOR = mParser.getFloat(KEY_MODERATE_USE_FACTOR,
+ DEFAULT_MODERATE_USE_FACTOR);
+ FG_JOB_COUNT = mParser.getInt(KEY_FG_JOB_COUNT,
+ DEFAULT_FG_JOB_COUNT);
+ BG_NORMAL_JOB_COUNT = mParser.getInt(KEY_BG_NORMAL_JOB_COUNT,
+ DEFAULT_BG_NORMAL_JOB_COUNT);
+ if ((FG_JOB_COUNT+BG_NORMAL_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) {
+ BG_NORMAL_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT;
+ }
+ BG_MODERATE_JOB_COUNT = mParser.getInt(KEY_BG_MODERATE_JOB_COUNT,
+ DEFAULT_BG_MODERATE_JOB_COUNT);
+ if ((FG_JOB_COUNT+BG_MODERATE_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) {
+ BG_MODERATE_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT;
+ }
+ BG_LOW_JOB_COUNT = mParser.getInt(KEY_BG_LOW_JOB_COUNT,
+ DEFAULT_BG_LOW_JOB_COUNT);
+ if ((FG_JOB_COUNT+BG_LOW_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) {
+ BG_LOW_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT;
+ }
+ BG_CRITICAL_JOB_COUNT = mParser.getInt(KEY_BG_CRITICAL_JOB_COUNT,
+ DEFAULT_BG_CRITICAL_JOB_COUNT);
+ if ((FG_JOB_COUNT+BG_CRITICAL_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) {
+ BG_CRITICAL_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT;
+ }
+ MAX_STANDARD_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_STANDARD_RESCHEDULE_COUNT,
+ DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT);
+ MAX_WORK_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_WORK_RESCHEDULE_COUNT,
+ DEFAULT_MAX_WORK_RESCHEDULE_COUNT);
+ MIN_LINEAR_BACKOFF_TIME = mParser.getDurationMillis(KEY_MIN_LINEAR_BACKOFF_TIME,
+ DEFAULT_MIN_LINEAR_BACKOFF_TIME);
+ MIN_EXP_BACKOFF_TIME = mParser.getDurationMillis(KEY_MIN_EXP_BACKOFF_TIME,
+ DEFAULT_MIN_EXP_BACKOFF_TIME);
+ STANDBY_HEARTBEAT_TIME = mParser.getDurationMillis(KEY_STANDBY_HEARTBEAT_TIME,
+ DEFAULT_STANDBY_HEARTBEAT_TIME);
+ STANDBY_BEATS[1] = mParser.getInt(KEY_STANDBY_WORKING_BEATS,
+ DEFAULT_STANDBY_WORKING_BEATS);
+ STANDBY_BEATS[2] = mParser.getInt(KEY_STANDBY_FREQUENT_BEATS,
+ DEFAULT_STANDBY_FREQUENT_BEATS);
+ STANDBY_BEATS[3] = mParser.getInt(KEY_STANDBY_RARE_BEATS,
+ DEFAULT_STANDBY_RARE_BEATS);
+ CONN_CONGESTION_DELAY_FRAC = mParser.getFloat(KEY_CONN_CONGESTION_DELAY_FRAC,
+ DEFAULT_CONN_CONGESTION_DELAY_FRAC);
+ CONN_PREFETCH_RELAX_FRAC = mParser.getFloat(KEY_CONN_PREFETCH_RELAX_FRAC,
+ DEFAULT_CONN_PREFETCH_RELAX_FRAC);
}
- void dump(PrintWriter pw) {
- pw.println(" Settings:");
-
- pw.print(" "); pw.print(KEY_MIN_IDLE_COUNT); pw.print("=");
- pw.print(MIN_IDLE_COUNT); pw.println();
-
- pw.print(" "); pw.print(KEY_MIN_CHARGING_COUNT); pw.print("=");
- pw.print(MIN_CHARGING_COUNT); pw.println();
-
- pw.print(" "); pw.print(KEY_MIN_BATTERY_NOT_LOW_COUNT); pw.print("=");
- pw.print(MIN_BATTERY_NOT_LOW_COUNT); pw.println();
-
- pw.print(" "); pw.print(KEY_MIN_STORAGE_NOT_LOW_COUNT); pw.print("=");
- pw.print(MIN_STORAGE_NOT_LOW_COUNT); pw.println();
-
- pw.print(" "); pw.print(KEY_MIN_CONNECTIVITY_COUNT); pw.print("=");
- pw.print(MIN_CONNECTIVITY_COUNT); pw.println();
-
- pw.print(" "); pw.print(KEY_MIN_CONTENT_COUNT); pw.print("=");
- pw.print(MIN_CONTENT_COUNT); pw.println();
-
- pw.print(" "); pw.print(KEY_MIN_READY_JOBS_COUNT); pw.print("=");
- pw.print(MIN_READY_JOBS_COUNT); pw.println();
-
- pw.print(" "); pw.print(KEY_HEAVY_USE_FACTOR); pw.print("=");
- pw.print(HEAVY_USE_FACTOR); pw.println();
-
- pw.print(" "); pw.print(KEY_MODERATE_USE_FACTOR); pw.print("=");
- pw.print(MODERATE_USE_FACTOR); pw.println();
-
- pw.print(" "); pw.print(KEY_FG_JOB_COUNT); pw.print("=");
- pw.print(FG_JOB_COUNT); pw.println();
-
- pw.print(" "); pw.print(KEY_BG_NORMAL_JOB_COUNT); pw.print("=");
- pw.print(BG_NORMAL_JOB_COUNT); pw.println();
-
- pw.print(" "); pw.print(KEY_BG_MODERATE_JOB_COUNT); pw.print("=");
- pw.print(BG_MODERATE_JOB_COUNT); pw.println();
-
- pw.print(" "); pw.print(KEY_BG_LOW_JOB_COUNT); pw.print("=");
- pw.print(BG_LOW_JOB_COUNT); pw.println();
-
- pw.print(" "); pw.print(KEY_BG_CRITICAL_JOB_COUNT); pw.print("=");
- pw.print(BG_CRITICAL_JOB_COUNT); pw.println();
-
- pw.print(" "); pw.print(KEY_MAX_STANDARD_RESCHEDULE_COUNT); pw.print("=");
- pw.print(MAX_STANDARD_RESCHEDULE_COUNT); pw.println();
-
- pw.print(" "); pw.print(KEY_MAX_WORK_RESCHEDULE_COUNT); pw.print("=");
- pw.print(MAX_WORK_RESCHEDULE_COUNT); pw.println();
-
- pw.print(" "); pw.print(KEY_MIN_LINEAR_BACKOFF_TIME); pw.print("=");
- pw.print(MIN_LINEAR_BACKOFF_TIME); pw.println();
-
- pw.print(" "); pw.print(KEY_MIN_EXP_BACKOFF_TIME); pw.print("=");
- pw.print(MIN_EXP_BACKOFF_TIME); pw.println();
-
- pw.print(" "); pw.print(KEY_STANDBY_HEARTBEAT_TIME); pw.print("=");
- pw.print(STANDBY_HEARTBEAT_TIME); pw.println();
-
- pw.print(" standby_beats={");
+ void dump(IndentingPrintWriter pw) {
+ pw.println("Settings:");
+ pw.increaseIndent();
+ pw.printPair(KEY_MIN_IDLE_COUNT, MIN_IDLE_COUNT).println();
+ pw.printPair(KEY_MIN_CHARGING_COUNT, MIN_CHARGING_COUNT).println();
+ pw.printPair(KEY_MIN_BATTERY_NOT_LOW_COUNT, MIN_BATTERY_NOT_LOW_COUNT).println();
+ pw.printPair(KEY_MIN_STORAGE_NOT_LOW_COUNT, MIN_STORAGE_NOT_LOW_COUNT).println();
+ pw.printPair(KEY_MIN_CONNECTIVITY_COUNT, MIN_CONNECTIVITY_COUNT).println();
+ pw.printPair(KEY_MIN_CONTENT_COUNT, MIN_CONTENT_COUNT).println();
+ pw.printPair(KEY_MIN_READY_JOBS_COUNT, MIN_READY_JOBS_COUNT).println();
+ pw.printPair(KEY_HEAVY_USE_FACTOR, HEAVY_USE_FACTOR).println();
+ pw.printPair(KEY_MODERATE_USE_FACTOR, MODERATE_USE_FACTOR).println();
+ pw.printPair(KEY_FG_JOB_COUNT, FG_JOB_COUNT).println();
+ pw.printPair(KEY_BG_NORMAL_JOB_COUNT, BG_NORMAL_JOB_COUNT).println();
+ pw.printPair(KEY_BG_MODERATE_JOB_COUNT, BG_MODERATE_JOB_COUNT).println();
+ pw.printPair(KEY_BG_LOW_JOB_COUNT, BG_LOW_JOB_COUNT).println();
+ pw.printPair(KEY_BG_CRITICAL_JOB_COUNT, BG_CRITICAL_JOB_COUNT).println();
+ pw.printPair(KEY_MAX_STANDARD_RESCHEDULE_COUNT, MAX_STANDARD_RESCHEDULE_COUNT).println();
+ pw.printPair(KEY_MAX_WORK_RESCHEDULE_COUNT, MAX_WORK_RESCHEDULE_COUNT).println();
+ pw.printPair(KEY_MIN_LINEAR_BACKOFF_TIME, MIN_LINEAR_BACKOFF_TIME).println();
+ pw.printPair(KEY_MIN_EXP_BACKOFF_TIME, MIN_EXP_BACKOFF_TIME).println();
+ pw.printPair(KEY_STANDBY_HEARTBEAT_TIME, STANDBY_HEARTBEAT_TIME).println();
+ pw.print("standby_beats={");
pw.print(STANDBY_BEATS[0]);
for (int i = 1; i < STANDBY_BEATS.length; i++) {
pw.print(", ");
pw.print(STANDBY_BEATS[i]);
}
pw.println('}');
+ pw.printPair(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println();
+ pw.printPair(KEY_CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC).println();
+ pw.decreaseIndent();
}
void dump(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
-
proto.write(ConstantsProto.MIN_IDLE_COUNT, MIN_IDLE_COUNT);
proto.write(ConstantsProto.MIN_CHARGING_COUNT, MIN_CHARGING_COUNT);
proto.write(ConstantsProto.MIN_BATTERY_NOT_LOW_COUNT, MIN_BATTERY_NOT_LOW_COUNT);
@@ -599,16 +595,17 @@
proto.write(ConstantsProto.MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME);
proto.write(ConstantsProto.MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME);
proto.write(ConstantsProto.STANDBY_HEARTBEAT_TIME_MS, STANDBY_HEARTBEAT_TIME);
-
for (int period : STANDBY_BEATS) {
proto.write(ConstantsProto.STANDBY_BEATS, period);
}
-
+ proto.write(ConstantsProto.CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC);
+ proto.write(ConstantsProto.CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC);
proto.end(token);
}
}
final Constants mConstants;
+ final ConstantsObserver mConstantsObserver;
static final Comparator<JobStatus> mEnqueueTimeComparator = (o1, o2) -> {
if (o1.enqueueTime < o2.enqueueTime) {
@@ -778,6 +775,10 @@
return mJobs;
}
+ public Constants getConstants() {
+ return mConstants;
+ }
+
@Override
public void onStartUser(int userHandle) {
mStartedUsers = ArrayUtils.appendInt(mStartedUsers, userHandle);
@@ -1097,7 +1098,8 @@
LocalServices.getService(ActivityManagerInternal.class));
mHandler = new JobHandler(context.getMainLooper());
- mConstants = new Constants(mHandler);
+ mConstants = new Constants();
+ mConstantsObserver = new ConstantsObserver(mHandler);
mJobSchedulerStub = new JobSchedulerStub();
// Set up the app standby bucketing tracker
@@ -1113,17 +1115,17 @@
// Create the controllers.
mControllers = new ArrayList<StateController>();
- mControllers.add(ConnectivityController.get(this));
- mControllers.add(TimeController.get(this));
- mControllers.add(IdleController.get(this));
- mBatteryController = BatteryController.get(this);
+ mControllers.add(new ConnectivityController(this));
+ mControllers.add(new TimeController(this));
+ mControllers.add(new IdleController(this));
+ mBatteryController = new BatteryController(this);
mControllers.add(mBatteryController);
- mStorageController = StorageController.get(this);
+ mStorageController = new StorageController(this);
mControllers.add(mStorageController);
- mControllers.add(BackgroundJobsController.get(this));
- mControllers.add(AppIdleController.get(this));
- mControllers.add(ContentObserverController.get(this));
- mDeviceIdleJobsController = DeviceIdleJobsController.get(this);
+ mControllers.add(new BackgroundJobsController(this));
+ mControllers.add(new AppIdleController(this));
+ mControllers.add(new ContentObserverController(this));
+ mDeviceIdleJobsController = new DeviceIdleJobsController(this);
mControllers.add(mDeviceIdleJobsController);
// If the job store determined that it can't yet reschedule persisted jobs,
@@ -1184,7 +1186,7 @@
@Override
public void onBootPhase(int phase) {
if (PHASE_SYSTEM_SERVICES_READY == phase) {
- mConstants.start(getContext().getContentResolver());
+ mConstantsObserver.start(getContext().getContentResolver());
mAppStateTracker = Preconditions.checkNotNull(
LocalServices.getService(AppStateTracker.class));
@@ -1227,13 +1229,10 @@
getContext().getMainLooper()));
}
// Attach jobs to their controllers.
- mJobs.forEachJob(new JobStatusFunctor() {
- @Override
- public void process(JobStatus job) {
- for (int controller = 0; controller < mControllers.size(); controller++) {
- final StateController sc = mControllers.get(controller);
- sc.maybeStartTrackingJobLocked(job, null);
- }
+ mJobs.forEachJob((job) -> {
+ for (int controller = 0; controller < mControllers.size(); controller++) {
+ final StateController sc = mControllers.get(controller);
+ sc.maybeStartTrackingJobLocked(job, null);
}
});
// GO GO GO!
@@ -1602,11 +1601,11 @@
}
}
- final class ReadyJobQueueFunctor implements JobStatusFunctor {
+ final class ReadyJobQueueFunctor implements Consumer<JobStatus> {
ArrayList<JobStatus> newReadyJobs;
@Override
- public void process(JobStatus job) {
+ public void accept(JobStatus job) {
if (isReadyToBeExecutedLocked(job)) {
if (DEBUG) {
Slog.d(TAG, " queued " + job.toShortString());
@@ -1640,7 +1639,7 @@
* If more than 4 jobs total are ready we send them all off.
* TODO: It would be nice to consolidate these sort of high-level policies somewhere.
*/
- final class MaybeReadyJobQueueFunctor implements JobStatusFunctor {
+ final class MaybeReadyJobQueueFunctor implements Consumer<JobStatus> {
int chargingCount;
int batteryNotLowCount;
int storageNotLowCount;
@@ -1656,7 +1655,7 @@
// Functor method invoked for each job via JobStore.forEachJob()
@Override
- public void process(JobStatus job) {
+ public void accept(JobStatus job) {
if (isReadyToBeExecutedLocked(job)) {
try {
if (ActivityManager.getService().isAppStartModeDisabled(job.getUid(),
@@ -2173,12 +2172,9 @@
public List<JobInfo> getSystemScheduledPendingJobs() {
synchronized (mLock) {
final List<JobInfo> pendingJobs = new ArrayList<JobInfo>();
- mJobs.forEachJob(Process.SYSTEM_UID, new JobStatusFunctor() {
- @Override
- public void process(JobStatus job) {
- if (job.getJob().isPeriodic() || !isCurrentlyActiveLocked(job)) {
- pendingJobs.add(job.getJob());
- }
+ mJobs.forEachJob(Process.SYSTEM_UID, (job) -> {
+ if (job.getJob().isPeriodic() || !isCurrentlyActiveLocked(job)) {
+ pendingJobs.add(job.getJob());
}
});
return pendingJobs;
@@ -2307,7 +2303,7 @@
}
}
- static class DeferredJobCounter implements JobStatusFunctor {
+ static class DeferredJobCounter implements Consumer<JobStatus> {
private int mDeferred = 0;
public int numDeferred() {
@@ -2315,7 +2311,7 @@
}
@Override
- public void process(JobStatus job) {
+ public void accept(JobStatus job) {
if (job.getWhenStandbyDeferred() > 0) {
mDeferred++;
}
@@ -2596,12 +2592,13 @@
}
}
- long identityToken = Binder.clearCallingIdentity();
+ final long identityToken = Binder.clearCallingIdentity();
try {
if (proto) {
JobSchedulerService.this.dumpInternalProto(fd, filterUid);
} else {
- JobSchedulerService.this.dumpInternal(pw, filterUid);
+ JobSchedulerService.this.dumpInternal(new IndentingPrintWriter(pw, " "),
+ filterUid);
}
} finally {
Binder.restoreCallingIdentity(identityToken);
@@ -2900,10 +2897,14 @@
});
}
- void dumpInternal(final PrintWriter pw, int filterUid) {
+ void dumpInternal(final IndentingPrintWriter pw, int filterUid) {
final int filterUidFinal = UserHandle.getAppId(filterUid);
final long nowElapsed = sElapsedRealtimeClock.millis();
final long nowUptime = sUptimeMillisClock.millis();
+ final Predicate<JobStatus> predicate = (js) -> {
+ return filterUidFinal == -1 || UserHandle.getAppId(js.getUid()) == filterUidFinal
+ || UserHandle.getAppId(js.getSourceUid()) == filterUidFinal;
+ };
synchronized (mLock) {
mConstants.dump(pw);
pw.println();
@@ -2919,7 +2920,7 @@
pw.println(job.toShortStringExceptUniqueId());
// Skip printing details if the caller requested a filter
- if (!job.shouldDump(filterUidFinal)) {
+ if (!predicate.test(job)) {
continue;
}
@@ -2953,7 +2954,10 @@
}
for (int i=0; i<mControllers.size(); i++) {
pw.println();
- mControllers.get(i).dumpControllerStateLocked(pw, filterUidFinal);
+ pw.println(mControllers.get(i).getClass().getSimpleName() + ":");
+ pw.increaseIndent();
+ mControllers.get(i).dumpControllerStateLocked(pw, predicate);
+ pw.decreaseIndent();
}
pw.println();
pw.println("Uid priority overrides:");
@@ -3056,6 +3060,10 @@
final int filterUidFinal = UserHandle.getAppId(filterUid);
final long nowElapsed = sElapsedRealtimeClock.millis();
final long nowUptime = sUptimeMillisClock.millis();
+ final Predicate<JobStatus> predicate = (js) -> {
+ return filterUidFinal == -1 || UserHandle.getAppId(js.getUid()) == filterUidFinal
+ || UserHandle.getAppId(js.getSourceUid()) == filterUidFinal;
+ };
synchronized (mLock) {
mConstants.dump(proto, JobSchedulerServiceDumpProto.SETTINGS);
@@ -3070,7 +3078,7 @@
job.writeToShortProto(proto, JobSchedulerServiceDumpProto.RegisteredJob.INFO);
// Skip printing details if the caller requested a filter
- if (!job.shouldDump(filterUidFinal)) {
+ if (!predicate.test(job)) {
continue;
}
@@ -3103,7 +3111,7 @@
}
for (StateController controller : mControllers) {
controller.dumpControllerStateLocked(
- proto, JobSchedulerServiceDumpProto.CONTROLLERS, filterUidFinal);
+ proto, JobSchedulerServiceDumpProto.CONTROLLERS, predicate);
}
for (int i=0; i< mUidPriorityOverride.size(); i++) {
int uid = mUidPriorityOverride.keyAt(i);
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index cf27882..7235faa 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -19,6 +19,7 @@
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import static com.android.server.job.JobSchedulerService.sSystemClock;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.app.job.JobInfo;
@@ -62,6 +63,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
+import java.util.function.Consumer;
import java.util.function.Predicate;
/**
@@ -286,22 +288,23 @@
* transient unified collections for them to iterate over and then discard, or creating
* iterators every time a client needs to perform a sweep.
*/
- public void forEachJob(JobStatusFunctor functor) {
- mJobSet.forEachJob(functor);
+ public void forEachJob(Consumer<JobStatus> functor) {
+ mJobSet.forEachJob(null, functor);
}
- public void forEachJob(int uid, JobStatusFunctor functor) {
+ public void forEachJob(@Nullable Predicate<JobStatus> filterPredicate,
+ Consumer<JobStatus> functor) {
+ mJobSet.forEachJob(filterPredicate, functor);
+ }
+
+ public void forEachJob(int uid, Consumer<JobStatus> functor) {
mJobSet.forEachJob(uid, functor);
}
- public void forEachJobForSourceUid(int sourceUid, JobStatusFunctor functor) {
+ public void forEachJobForSourceUid(int sourceUid, Consumer<JobStatus> functor) {
mJobSet.forEachJobForSourceUid(sourceUid, functor);
}
- public interface JobStatusFunctor {
- public void process(JobStatus jobStatus);
- }
-
/** Version of the db schema. */
private static final int JOBS_FILE_VERSION = 0;
/** Tag corresponds to constraints this job needs. */
@@ -342,12 +345,9 @@
final List<JobStatus> storeCopy = new ArrayList<JobStatus>();
synchronized (mLock) {
// Clone the jobs so we can release the lock before writing.
- mJobSet.forEachJob(new JobStatusFunctor() {
- @Override
- public void process(JobStatus job) {
- if (job.isPersisted()) {
- storeCopy.add(new JobStatus(job));
- }
+ mJobSet.forEachJob(null, (job) -> {
+ if (job.isPersisted()) {
+ storeCopy.add(new JobStatus(job));
}
});
}
@@ -1184,31 +1184,35 @@
return total;
}
- public void forEachJob(JobStatusFunctor functor) {
+ public void forEachJob(@Nullable Predicate<JobStatus> filterPredicate,
+ Consumer<JobStatus> functor) {
for (int uidIndex = mJobs.size() - 1; uidIndex >= 0; uidIndex--) {
ArraySet<JobStatus> jobs = mJobs.valueAt(uidIndex);
if (jobs != null) {
for (int i = jobs.size() - 1; i >= 0; i--) {
- functor.process(jobs.valueAt(i));
+ final JobStatus jobStatus = jobs.valueAt(i);
+ if ((filterPredicate == null) || filterPredicate.test(jobStatus)) {
+ functor.accept(jobStatus);
+ }
}
}
}
}
- public void forEachJob(int callingUid, JobStatusFunctor functor) {
+ public void forEachJob(int callingUid, Consumer<JobStatus> functor) {
ArraySet<JobStatus> jobs = mJobs.get(callingUid);
if (jobs != null) {
for (int i = jobs.size() - 1; i >= 0; i--) {
- functor.process(jobs.valueAt(i));
+ functor.accept(jobs.valueAt(i));
}
}
}
- public void forEachJobForSourceUid(int sourceUid, JobStatusFunctor functor) {
+ public void forEachJobForSourceUid(int sourceUid, Consumer<JobStatus> functor) {
final ArraySet<JobStatus> jobs = mJobsPerSourceUid.get(sourceUid);
if (jobs != null) {
for (int i = jobs.size() - 1; i >= 0; i--) {
- functor.process(jobs.valueAt(i));
+ functor.accept(jobs.valueAt(i));
}
}
}
diff --git a/services/core/java/com/android/server/job/controllers/AppIdleController.java b/services/core/java/com/android/server/job/controllers/AppIdleController.java
index 021eccd..bd8fe28 100644
--- a/services/core/java/com/android/server/job/controllers/AppIdleController.java
+++ b/services/core/java/com/android/server/job/controllers/AppIdleController.java
@@ -17,18 +17,18 @@
package com.android.server.job.controllers;
import android.app.usage.UsageStatsManagerInternal;
-import android.content.Context;
import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerService;
-import com.android.server.job.JobStore;
import com.android.server.job.StateControllerProto;
-import java.io.PrintWriter;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
/**
* Controls when apps are considered idle and if jobs pertaining to those apps should
@@ -41,18 +41,15 @@
private static final boolean DEBUG = JobSchedulerService.DEBUG
|| Log.isLoggable(TAG, Log.DEBUG);
- // Singleton factory
- private static Object sCreationLock = new Object();
- private static volatile AppIdleController sController;
- private final JobSchedulerService mJobSchedulerService;
private final UsageStatsManagerInternal mUsageStatsInternal;
private boolean mInitializedParoleOn;
boolean mAppIdleParoleOn;
- final class GlobalUpdateFunc implements JobStore.JobStatusFunctor {
+ final class GlobalUpdateFunc implements Consumer<JobStatus> {
boolean mChanged;
- @Override public void process(JobStatus jobStatus) {
+ @Override
+ public void accept(JobStatus jobStatus) {
String packageName = jobStatus.getSourcePackageName();
final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
jobStatus.getSourceUid(), jobStatus.getSourceUserId());
@@ -63,9 +60,9 @@
mChanged = true;
}
}
- };
+ }
- final static class PackageUpdateFunc implements JobStore.JobStatusFunctor {
+ final static class PackageUpdateFunc implements Consumer<JobStatus> {
final int mUserId;
final String mPackage;
final boolean mIdle;
@@ -77,7 +74,8 @@
mIdle = idle;
}
- @Override public void process(JobStatus jobStatus) {
+ @Override
+ public void accept(JobStatus jobStatus) {
if (jobStatus.getSourcePackageName().equals(mPackage)
&& jobStatus.getSourceUserId() == mUserId) {
if (jobStatus.setAppNotIdleConstraintSatisfied(!mIdle)) {
@@ -89,21 +87,10 @@
}
}
}
- };
-
- public static AppIdleController get(JobSchedulerService service) {
- synchronized (sCreationLock) {
- if (sController == null) {
- sController = new AppIdleController(service, service.getContext(),
- service.getLock());
- }
- return sController;
- }
}
- private AppIdleController(JobSchedulerService service, Context context, Object lock) {
- super(service, context, lock);
- mJobSchedulerService = service;
+ public AppIdleController(JobSchedulerService service) {
+ super(service);
mUsageStatsInternal = LocalServices.getService(UsageStatsManagerInternal.class);
mAppIdleParoleOn = true;
mUsageStatsInternal.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
@@ -131,56 +118,46 @@
}
@Override
- public void dumpControllerStateLocked(final PrintWriter pw, final int filterUid) {
- pw.print("AppIdle: parole on = ");
- pw.println(mAppIdleParoleOn);
- mJobSchedulerService.getJobStore().forEachJob(new JobStore.JobStatusFunctor() {
- @Override public void process(JobStatus jobStatus) {
- // Skip printing details if the caller requested a filter
- if (!jobStatus.shouldDump(filterUid)) {
- return;
- }
- pw.print(" #");
- jobStatus.printUniqueId(pw);
- pw.print(" from ");
- UserHandle.formatUid(pw, jobStatus.getSourceUid());
- pw.print(": ");
- pw.print(jobStatus.getSourcePackageName());
- if ((jobStatus.satisfiedConstraints&JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0) {
- pw.println(" RUNNABLE");
- } else {
- pw.println(" WAITING");
- }
+ public void dumpControllerStateLocked(final IndentingPrintWriter pw,
+ final Predicate<JobStatus> predicate) {
+ pw.println("Parole on: " + mAppIdleParoleOn);
+ pw.println();
+
+ mService.getJobStore().forEachJob(predicate, (jobStatus) -> {
+ pw.print("#");
+ jobStatus.printUniqueId(pw);
+ pw.print(" from ");
+ UserHandle.formatUid(pw, jobStatus.getSourceUid());
+ pw.print(": ");
+ pw.print(jobStatus.getSourcePackageName());
+ if ((jobStatus.satisfiedConstraints&JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0) {
+ pw.println(" RUNNABLE");
+ } else {
+ pw.println(" WAITING");
}
});
}
@Override
- public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) {
+ public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
+ Predicate<JobStatus> predicate) {
final long token = proto.start(fieldId);
final long mToken = proto.start(StateControllerProto.APP_IDLE);
proto.write(StateControllerProto.AppIdleController.IS_PAROLE_ON, mAppIdleParoleOn);
- mJobSchedulerService.getJobStore().forEachJob(new JobStore.JobStatusFunctor() {
- @Override public void process(JobStatus js) {
- // Skip printing details if the caller requested a filter
- if (!js.shouldDump(filterUid)) {
- return;
- }
-
- final long jsToken =
- proto.start(StateControllerProto.AppIdleController.TRACKED_JOBS);
- js.writeToShortProto(proto, StateControllerProto.AppIdleController.TrackedJob.INFO);
- proto.write(StateControllerProto.AppIdleController.TrackedJob.SOURCE_UID,
- js.getSourceUid());
- proto.write(StateControllerProto.AppIdleController.TrackedJob.SOURCE_PACKAGE_NAME,
- js.getSourcePackageName());
- proto.write(
- StateControllerProto.AppIdleController.TrackedJob.ARE_CONSTRAINTS_SATISFIED,
- (js.satisfiedConstraints & JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0);
- proto.end(jsToken);
- }
+ mService.getJobStore().forEachJob(predicate, (js) -> {
+ final long jsToken =
+ proto.start(StateControllerProto.AppIdleController.TRACKED_JOBS);
+ js.writeToShortProto(proto, StateControllerProto.AppIdleController.TrackedJob.INFO);
+ proto.write(StateControllerProto.AppIdleController.TrackedJob.SOURCE_UID,
+ js.getSourceUid());
+ proto.write(StateControllerProto.AppIdleController.TrackedJob.SOURCE_PACKAGE_NAME,
+ js.getSourcePackageName());
+ proto.write(
+ StateControllerProto.AppIdleController.TrackedJob.ARE_CONSTRAINTS_SATISFIED,
+ (js.satisfiedConstraints & JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0);
+ proto.end(jsToken);
});
proto.end(mToken);
@@ -196,7 +173,7 @@
}
mAppIdleParoleOn = isAppIdleParoleOn;
GlobalUpdateFunc update = new GlobalUpdateFunc();
- mJobSchedulerService.getJobStore().forEachJob(update);
+ mService.getJobStore().forEachJob(update);
if (update.mChanged) {
changed = true;
}
@@ -217,7 +194,7 @@
}
PackageUpdateFunc update = new PackageUpdateFunc(userId, packageName, idle);
- mJobSchedulerService.getJobStore().forEachJob(update);
+ mService.getJobStore().forEachJob(update);
if (update.mChanged) {
changed = true;
}
diff --git a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
index 46ec5e5..36e75115 100644
--- a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -16,50 +16,33 @@
package com.android.server.job.controllers;
-import android.content.Context;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.AppStateTracker;
import com.android.server.AppStateTracker.Listener;
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerService;
-import com.android.server.job.JobStore;
import com.android.server.job.StateControllerProto;
import com.android.server.job.StateControllerProto.BackgroundJobsController.TrackedJob;
-import java.io.PrintWriter;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
public final class BackgroundJobsController extends StateController {
private static final String TAG = "JobScheduler.Background";
private static final boolean DEBUG = JobSchedulerService.DEBUG
|| Log.isLoggable(TAG, Log.DEBUG);
- // Singleton factory
- private static final Object sCreationLock = new Object();
- private static volatile BackgroundJobsController sController;
-
- private final JobSchedulerService mJobSchedulerService;
-
private final AppStateTracker mAppStateTracker;
- public static BackgroundJobsController get(JobSchedulerService service) {
- synchronized (sCreationLock) {
- if (sController == null) {
- sController = new BackgroundJobsController(service, service.getContext(),
- service.getLock());
- }
- return sController;
- }
- }
-
- private BackgroundJobsController(JobSchedulerService service, Context context, Object lock) {
- super(service, context, lock);
- mJobSchedulerService = service;
+ public BackgroundJobsController(JobSchedulerService service) {
+ super(service);
mAppStateTracker = Preconditions.checkNotNull(
LocalServices.getService(AppStateTracker.class));
@@ -77,19 +60,15 @@
}
@Override
- public void dumpControllerStateLocked(final PrintWriter pw, final int filterUid) {
- pw.println("BackgroundJobsController");
+ public void dumpControllerStateLocked(final IndentingPrintWriter pw,
+ final Predicate<JobStatus> predicate) {
+ mAppStateTracker.dump(pw);
+ pw.println();
- mAppStateTracker.dump(pw, "");
-
- pw.println("Job state:");
- mJobSchedulerService.getJobStore().forEachJob((jobStatus) -> {
- if (!jobStatus.shouldDump(filterUid)) {
- return;
- }
+ mService.getJobStore().forEachJob(predicate, (jobStatus) -> {
final int uid = jobStatus.getSourceUid();
final String sourcePkg = jobStatus.getSourcePackageName();
- pw.print(" #");
+ pw.print("#");
jobStatus.printUniqueId(pw);
pw.print(" from ");
UserHandle.formatUid(pw, uid);
@@ -115,17 +94,15 @@
}
@Override
- public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) {
+ public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
+ Predicate<JobStatus> predicate) {
final long token = proto.start(fieldId);
final long mToken = proto.start(StateControllerProto.BACKGROUND);
mAppStateTracker.dumpProto(proto,
StateControllerProto.BackgroundJobsController.FORCE_APP_STANDBY_TRACKER);
- mJobSchedulerService.getJobStore().forEachJob((jobStatus) -> {
- if (!jobStatus.shouldDump(filterUid)) {
- return;
- }
+ mService.getJobStore().forEachJob(predicate, (jobStatus) -> {
final long jsToken =
proto.start(StateControllerProto.BackgroundJobsController.TRACKED_JOBS);
@@ -176,7 +153,7 @@
final long start = DEBUG ? SystemClock.elapsedRealtimeNanos() : 0;
- mJobSchedulerService.getJobStore().forEachJob(updateTrackedJobs);
+ mService.getJobStore().forEachJob(updateTrackedJobs);
final long time = DEBUG ? (SystemClock.elapsedRealtimeNanos() - start) : 0;
if (DEBUG) {
@@ -205,7 +182,7 @@
return jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun);
}
- private final class UpdateJobFunctor implements JobStore.JobStatusFunctor {
+ private final class UpdateJobFunctor implements Consumer<JobStatus> {
private final int mFilterUid;
boolean mChanged = false;
@@ -217,7 +194,7 @@
}
@Override
- public void process(JobStatus jobStatus) {
+ public void accept(JobStatus jobStatus) {
mTotalCount++;
if ((mFilterUid > 0) && (mFilterUid != jobStatus.getSourceUid())) {
return;
diff --git a/services/core/java/com/android/server/job/controllers/BatteryController.java b/services/core/java/com/android/server/job/controllers/BatteryController.java
index 263d99b..46658ad 100644
--- a/services/core/java/com/android/server/job/controllers/BatteryController.java
+++ b/services/core/java/com/android/server/job/controllers/BatteryController.java
@@ -31,12 +31,12 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerService;
-import com.android.server.job.StateChangedListener;
import com.android.server.job.StateControllerProto;
-import java.io.PrintWriter;
+import java.util.function.Predicate;
/**
* Simple controller that tracks whether the phone is charging or not. The phone is considered to
@@ -48,36 +48,16 @@
private static final boolean DEBUG = JobSchedulerService.DEBUG
|| Log.isLoggable(TAG, Log.DEBUG);
- private static final Object sCreationLock = new Object();
- private static volatile BatteryController sController;
-
private final ArraySet<JobStatus> mTrackedTasks = new ArraySet<>();
private ChargingTracker mChargeTracker;
- public static BatteryController get(JobSchedulerService taskManagerService) {
- synchronized (sCreationLock) {
- if (sController == null) {
- sController = new BatteryController(taskManagerService,
- taskManagerService.getContext(), taskManagerService.getLock());
- }
- }
- return sController;
- }
-
@VisibleForTesting
public ChargingTracker getTracker() {
return mChargeTracker;
}
- @VisibleForTesting
- public static BatteryController getForTesting(StateChangedListener stateChangedListener,
- Context context) {
- return new BatteryController(stateChangedListener, context, new Object());
- }
-
- private BatteryController(StateChangedListener stateChangedListener, Context context,
- Object lock) {
- super(stateChangedListener, context, lock);
+ public BatteryController(JobSchedulerService service) {
+ super(service);
mChargeTracker = new ChargingTracker();
mChargeTracker.startTracking();
}
@@ -244,24 +224,23 @@
}
@Override
- public void dumpControllerStateLocked(PrintWriter pw, int filterUid) {
- pw.print("Battery: stable power = ");
- pw.print(mChargeTracker.isOnStablePower());
- pw.print(", not low = ");
- pw.println(mChargeTracker.isBatteryNotLow());
+ public void dumpControllerStateLocked(IndentingPrintWriter pw,
+ Predicate<JobStatus> predicate) {
+ pw.println("Stable power: " + mChargeTracker.isOnStablePower());
+ pw.println("Not low: " + mChargeTracker.isBatteryNotLow());
+
if (mChargeTracker.isMonitoring()) {
pw.print("MONITORING: seq=");
pw.println(mChargeTracker.getSeq());
}
- pw.print("Tracking ");
- pw.print(mTrackedTasks.size());
- pw.println(":");
+ pw.println();
+
for (int i = 0; i < mTrackedTasks.size(); i++) {
final JobStatus js = mTrackedTasks.valueAt(i);
- if (!js.shouldDump(filterUid)) {
+ if (!predicate.test(js)) {
continue;
}
- pw.print(" #");
+ pw.print("#");
js.printUniqueId(pw);
pw.print(" from ");
UserHandle.formatUid(pw, js.getSourceUid());
@@ -270,7 +249,8 @@
}
@Override
- public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) {
+ public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
+ Predicate<JobStatus> predicate) {
final long token = proto.start(fieldId);
final long mToken = proto.start(StateControllerProto.BATTERY);
@@ -286,7 +266,7 @@
for (int i = 0; i < mTrackedTasks.size(); i++) {
final JobStatus js = mTrackedTasks.valueAt(i);
- if (!js.shouldDump(filterUid)) {
+ if (!predicate.test(js)) {
continue;
}
final long jsToken = proto.start(StateControllerProto.BatteryController.TRACKED_JOBS);
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index d7ef124..abe55bb 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -21,7 +21,6 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import android.app.job.JobInfo;
-import android.content.Context;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.INetworkPolicyListener;
@@ -41,12 +40,13 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.job.JobSchedulerService;
+import com.android.server.job.JobSchedulerService.Constants;
import com.android.server.job.JobServiceContext;
-import com.android.server.job.StateChangedListener;
import com.android.server.job.StateControllerProto;
-import java.io.PrintWriter;
+import java.util.function.Predicate;
/**
* Handles changes in connectivity.
@@ -68,22 +68,8 @@
@GuardedBy("mLock")
private final ArraySet<JobStatus> mTrackedJobs = new ArraySet<>();
- /** Singleton. */
- private static ConnectivityController sSingleton;
- private static Object sCreationLock = new Object();
-
- public static ConnectivityController get(JobSchedulerService jms) {
- synchronized (sCreationLock) {
- if (sSingleton == null) {
- sSingleton = new ConnectivityController(jms, jms.getContext(), jms.getLock());
- }
- return sSingleton;
- }
- }
-
- private ConnectivityController(StateChangedListener stateChangedListener, Context context,
- Object lock) {
- super(stateChangedListener, context, lock);
+ public ConnectivityController(JobSchedulerService service) {
+ super(service);
mConnManager = mContext.getSystemService(ConnectivityManager.class);
mNetPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
@@ -122,7 +108,7 @@
*/
@SuppressWarnings("unused")
private static boolean isInsane(JobStatus jobStatus, Network network,
- NetworkCapabilities capabilities) {
+ NetworkCapabilities capabilities, Constants constants) {
final long estimatedBytes = jobStatus.getEstimatedNetworkBytes();
if (estimatedBytes == JobInfo.NETWORK_BYTES_UNKNOWN) {
// We don't know how large the job is; cross our fingers!
@@ -153,11 +139,11 @@
@SuppressWarnings("unused")
private static boolean isCongestionDelayed(JobStatus jobStatus, Network network,
- NetworkCapabilities capabilities) {
+ NetworkCapabilities capabilities, Constants constants) {
// If network is congested, and job is less than 50% through the
// developer-requested window, then we're okay delaying the job.
if (!capabilities.hasCapability(NET_CAPABILITY_NOT_CONGESTED)) {
- return jobStatus.getFractionRunTime() < 0.5;
+ return jobStatus.getFractionRunTime() < constants.CONN_CONGESTION_DELAY_FRAC;
} else {
return false;
}
@@ -165,14 +151,14 @@
@SuppressWarnings("unused")
private static boolean isStrictSatisfied(JobStatus jobStatus, Network network,
- NetworkCapabilities capabilities) {
+ NetworkCapabilities capabilities, Constants constants) {
return jobStatus.getJob().getRequiredNetwork().networkCapabilities
.satisfiedByNetworkCapabilities(capabilities);
}
@SuppressWarnings("unused")
private static boolean isRelaxedSatisfied(JobStatus jobStatus, Network network,
- NetworkCapabilities capabilities) {
+ NetworkCapabilities capabilities, Constants constants) {
// Only consider doing this for prefetching jobs
if ((jobStatus.getJob().getFlags() & JobInfo.FLAG_IS_PREFETCH) == 0) {
return false;
@@ -184,7 +170,7 @@
.removeCapability(NET_CAPABILITY_NOT_METERED);
if (relaxed.satisfiedByNetworkCapabilities(capabilities)) {
// TODO: treat this as "maybe" response; need to check quotas
- return jobStatus.getFractionRunTime() > 0.5;
+ return jobStatus.getFractionRunTime() > constants.CONN_PREFETCH_RELAX_FRAC;
} else {
return false;
}
@@ -192,21 +178,21 @@
@VisibleForTesting
static boolean isSatisfied(JobStatus jobStatus, Network network,
- NetworkCapabilities capabilities) {
+ NetworkCapabilities capabilities, Constants constants) {
// Zeroth, we gotta have a network to think about being satisfied
if (network == null || capabilities == null) return false;
// First, are we insane?
- if (isInsane(jobStatus, network, capabilities)) return false;
+ if (isInsane(jobStatus, network, capabilities, constants)) return false;
// Second, is the network congested?
- if (isCongestionDelayed(jobStatus, network, capabilities)) return false;
+ if (isCongestionDelayed(jobStatus, network, capabilities, constants)) return false;
// Third, is the network a strict match?
- if (isStrictSatisfied(jobStatus, network, capabilities)) return true;
+ if (isStrictSatisfied(jobStatus, network, capabilities, constants)) return true;
// Third, is the network a relaxed match?
- if (isRelaxedSatisfied(jobStatus, network, capabilities)) return true;
+ if (isRelaxedSatisfied(jobStatus, network, capabilities, constants)) return true;
return false;
}
@@ -222,7 +208,7 @@
final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities(network);
final boolean connected = (info != null) && info.isConnected();
- final boolean satisfied = isSatisfied(jobStatus, network, capabilities);
+ final boolean satisfied = isSatisfied(jobStatus, network, capabilities, mConstants);
final boolean changed = jobStatus
.setConnectivityConstraintSatisfied(connected && satisfied);
@@ -331,18 +317,15 @@
@GuardedBy("mLock")
@Override
- public void dumpControllerStateLocked(PrintWriter pw, int filterUid) {
- pw.print("Connectivity: connected=");
- pw.println(mConnected);
-
- pw.print("Tracking ");
- pw.print(mTrackedJobs.size());
- pw.println(" jobs");
+ public void dumpControllerStateLocked(IndentingPrintWriter pw,
+ Predicate<JobStatus> predicate) {
+ pw.println("System connected: " + mConnected);
+ pw.println();
for (int i = 0; i < mTrackedJobs.size(); i++) {
final JobStatus js = mTrackedJobs.valueAt(i);
- if (js.shouldDump(filterUid)) {
- pw.print(" #");
+ if (predicate.test(js)) {
+ pw.print("#");
js.printUniqueId(pw);
pw.print(" from ");
UserHandle.formatUid(pw, js.getSourceUid());
@@ -355,7 +338,8 @@
@GuardedBy("mLock")
@Override
- public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) {
+ public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
+ Predicate<JobStatus> predicate) {
final long token = proto.start(fieldId);
final long mToken = proto.start(StateControllerProto.CONNECTIVITY);
@@ -363,7 +347,7 @@
for (int i = 0; i < mTrackedJobs.size(); i++) {
final JobStatus js = mTrackedJobs.valueAt(i);
- if (!js.shouldDump(filterUid)) {
+ if (!predicate.test(js)) {
continue;
}
final long jsToken = proto.start(StateControllerProto.ConnectivityController.TRACKED_JOBS);
diff --git a/services/core/java/com/android/server/job/controllers/ContentObserverController.java b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
index 90edde9..a775cf5 100644
--- a/services/core/java/com/android/server/job/controllers/ContentObserverController.java
+++ b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
@@ -18,7 +18,6 @@
import android.annotation.UserIdInt;
import android.app.job.JobInfo;
-import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
@@ -31,14 +30,13 @@
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
-import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.job.JobSchedulerService;
-import com.android.server.job.StateChangedListener;
import com.android.server.job.StateControllerProto;
import com.android.server.job.StateControllerProto.ContentObserverController.Observer.TriggerContentData;
-import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.function.Predicate;
/**
* Controller for monitoring changes to content URIs through a ContentObserver.
@@ -60,9 +58,6 @@
*/
private static final int URIS_URGENT_THRESHOLD = 40;
- private static final Object sCreationLock = new Object();
- private static volatile ContentObserverController sController;
-
final private ArraySet<JobStatus> mTrackedTasks = new ArraySet<>();
/**
* Per-userid {@link JobInfo.TriggerContentUri} keyed ContentObserver cache.
@@ -71,26 +66,9 @@
new SparseArray<>();
final Handler mHandler;
- public static ContentObserverController get(JobSchedulerService taskManagerService) {
- synchronized (sCreationLock) {
- if (sController == null) {
- sController = new ContentObserverController(taskManagerService,
- taskManagerService.getContext(), taskManagerService.getLock());
- }
- }
- return sController;
- }
-
- @VisibleForTesting
- public static ContentObserverController getForTesting(StateChangedListener stateChangedListener,
- Context context) {
- return new ContentObserverController(stateChangedListener, context, new Object());
- }
-
- private ContentObserverController(StateChangedListener stateChangedListener, Context context,
- Object lock) {
- super(stateChangedListener, context, lock);
- mHandler = new Handler(context.getMainLooper());
+ public ContentObserverController(JobSchedulerService service) {
+ super(service);
+ mHandler = new Handler(mContext.getMainLooper());
}
@Override
@@ -375,22 +353,25 @@
}
@Override
- public void dumpControllerStateLocked(PrintWriter pw, int filterUid) {
- pw.println("Content:");
+ public void dumpControllerStateLocked(IndentingPrintWriter pw,
+ Predicate<JobStatus> predicate) {
for (int i = 0; i < mTrackedTasks.size(); i++) {
JobStatus js = mTrackedTasks.valueAt(i);
- if (!js.shouldDump(filterUid)) {
+ if (!predicate.test(js)) {
continue;
}
- pw.print(" #");
+ pw.print("#");
js.printUniqueId(pw);
pw.print(" from ");
UserHandle.formatUid(pw, js.getSourceUid());
pw.println();
}
+ pw.println();
+
int N = mObservers.size();
if (N > 0) {
- pw.println(" Observers:");
+ pw.println("Observers:");
+ pw.increaseIndent();
for (int userIdx = 0; userIdx < N; userIdx++) {
final int userId = mObservers.keyAt(userIdx);
ArrayMap<JobInfo.TriggerContentUri, ObserverInstance> observersOfUser =
@@ -402,7 +383,7 @@
boolean shouldDump = false;
for (int j = 0; j < M; j++) {
JobInstance inst = obs.mJobs.valueAt(j);
- if (inst.mJobStatus.shouldDump(filterUid)) {
+ if (predicate.test(inst.mJobStatus)) {
shouldDump = true;
break;
}
@@ -410,7 +391,6 @@
if (!shouldDump) {
continue;
}
- pw.print(" ");
JobInfo.TriggerContentUri trigger = observersOfUser.keyAt(observerIdx);
pw.print(trigger.getUri());
pw.print(" 0x");
@@ -418,17 +398,20 @@
pw.print(" (");
pw.print(System.identityHashCode(obs));
pw.println("):");
- pw.println(" Jobs:");
+ pw.increaseIndent();
+ pw.println("Jobs:");
+ pw.increaseIndent();
for (int j = 0; j < M; j++) {
JobInstance inst = obs.mJobs.valueAt(j);
- pw.print(" #");
+ pw.print("#");
inst.mJobStatus.printUniqueId(pw);
pw.print(" from ");
UserHandle.formatUid(pw, inst.mJobStatus.getSourceUid());
if (inst.mChangedAuthorities != null) {
pw.println(":");
+ pw.increaseIndent();
if (inst.mTriggerPending) {
- pw.print(" Trigger pending: update=");
+ pw.print("Trigger pending: update=");
TimeUtils.formatDuration(
inst.mJobStatus.getTriggerContentUpdateDelay(), pw);
pw.print(", max=");
@@ -436,35 +419,38 @@
inst.mJobStatus.getTriggerContentMaxDelay(), pw);
pw.println();
}
- pw.println(" Changed Authorities:");
+ pw.println("Changed Authorities:");
for (int k = 0; k < inst.mChangedAuthorities.size(); k++) {
- pw.print(" ");
pw.println(inst.mChangedAuthorities.valueAt(k));
}
if (inst.mChangedUris != null) {
pw.println(" Changed URIs:");
for (int k = 0; k < inst.mChangedUris.size(); k++) {
- pw.print(" ");
pw.println(inst.mChangedUris.valueAt(k));
}
}
+ pw.decreaseIndent();
} else {
pw.println();
}
}
+ pw.decreaseIndent();
+ pw.decreaseIndent();
}
}
+ pw.decreaseIndent();
}
}
@Override
- public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) {
+ public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
+ Predicate<JobStatus> predicate) {
final long token = proto.start(fieldId);
final long mToken = proto.start(StateControllerProto.CONTENT_OBSERVER);
for (int i = 0; i < mTrackedTasks.size(); i++) {
JobStatus js = mTrackedTasks.valueAt(i);
- if (!js.shouldDump(filterUid)) {
+ if (!predicate.test(js)) {
continue;
}
final long jsToken =
@@ -493,7 +479,7 @@
boolean shouldDump = false;
for (int j = 0; j < m; j++) {
JobInstance inst = obs.mJobs.valueAt(j);
- if (inst.mJobStatus.shouldDump(filterUid)) {
+ if (predicate.test(inst.mJobStatus)) {
shouldDump = true;
break;
}
diff --git a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
index 323a126..127a5c8 100644
--- a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
+++ b/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
@@ -33,15 +33,16 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.DeviceIdleController;
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerService;
-import com.android.server.job.JobStore;
import com.android.server.job.StateControllerProto;
import com.android.server.job.StateControllerProto.DeviceIdleJobsController.TrackedJob;
-import java.io.PrintWriter;
import java.util.Arrays;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
/**
* When device is dozing, set constraint for all jobs, except whitelisted apps, as not satisfied.
@@ -56,10 +57,6 @@
static final int PROCESS_BACKGROUND_JOBS = 1;
- // Singleton factory
- private static Object sCreationLock = new Object();
- private static DeviceIdleJobsController sController;
-
/**
* These are jobs added with a special flag to indicate that they should be exempted from doze
* when the app is temp whitelisted or in the foreground.
@@ -68,7 +65,6 @@
private final SparseBooleanArray mForegroundUids;
private final DeviceIdleUpdateFunctor mDeviceIdleUpdateFunctor;
private final DeviceIdleJobsDelayHandler mHandler;
- private final JobSchedulerService mJobSchedulerService;
private final PowerManager mPowerManager;
private final DeviceIdleController.LocalService mLocalDeviceIdleController;
@@ -79,19 +75,6 @@
private int[] mDeviceIdleWhitelistAppIds;
private int[] mPowerSaveTempWhitelistAppIds;
- /**
- * Returns a singleton for the DeviceIdleJobsController
- */
- public static DeviceIdleJobsController get(JobSchedulerService service) {
- synchronized (sCreationLock) {
- if (sController == null) {
- sController = new DeviceIdleJobsController(service, service.getContext(),
- service.getLock());
- }
- return sController;
- }
- }
-
// onReceive
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -133,12 +116,10 @@
}
};
- private DeviceIdleJobsController(JobSchedulerService jobSchedulerService, Context context,
- Object lock) {
- super(jobSchedulerService, context, lock);
+ public DeviceIdleJobsController(JobSchedulerService service) {
+ super(service);
- mJobSchedulerService = jobSchedulerService;
- mHandler = new DeviceIdleJobsDelayHandler(context.getMainLooper());
+ mHandler = new DeviceIdleJobsDelayHandler(mContext.getMainLooper());
// Register for device idle mode changes
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mLocalDeviceIdleController =
@@ -168,13 +149,13 @@
if (DEBUG) Slog.d(TAG, "mDeviceIdleMode=" + mDeviceIdleMode);
if (enabled) {
mHandler.removeMessages(PROCESS_BACKGROUND_JOBS);
- mJobSchedulerService.getJobStore().forEachJob(mDeviceIdleUpdateFunctor);
+ mService.getJobStore().forEachJob(mDeviceIdleUpdateFunctor);
} else {
// When coming out of doze, process all foreground uids immediately, while others
// will be processed after a delay of 3 seconds.
for (int i = 0; i < mForegroundUids.size(); i++) {
if (mForegroundUids.valueAt(i)) {
- mJobSchedulerService.getJobStore().forEachJobForSourceUid(
+ mService.getJobStore().forEachJobForSourceUid(
mForegroundUids.keyAt(i), mDeviceIdleUpdateFunctor);
}
}
@@ -200,7 +181,7 @@
}
mForegroundUids.put(uid, active);
mDeviceIdleUpdateFunctor.mChanged = false;
- mJobSchedulerService.getJobStore().forEachJobForSourceUid(uid, mDeviceIdleUpdateFunctor);
+ mService.getJobStore().forEachJobForSourceUid(uid, mDeviceIdleUpdateFunctor);
if (mDeviceIdleUpdateFunctor.mChanged) {
mStateChangedListener.onControllerStateChanged();
}
@@ -247,71 +228,64 @@
}
@Override
- public void dumpControllerStateLocked(final PrintWriter pw, final int filterUid) {
- pw.println("DeviceIdleJobsController");
- pw.println("mDeviceIdleMode=" + mDeviceIdleMode);
- mJobSchedulerService.getJobStore().forEachJob(new JobStore.JobStatusFunctor() {
- @Override public void process(JobStatus jobStatus) {
- if (!jobStatus.shouldDump(filterUid)) {
- return;
- }
- pw.print(" #");
- jobStatus.printUniqueId(pw);
- pw.print(" from ");
- UserHandle.formatUid(pw, jobStatus.getSourceUid());
- pw.print(": ");
- pw.print(jobStatus.getSourcePackageName());
- pw.print((jobStatus.satisfiedConstraints
- & JobStatus.CONSTRAINT_DEVICE_NOT_DOZING) != 0
- ? " RUNNABLE" : " WAITING");
- if (jobStatus.dozeWhitelisted) {
- pw.print(" WHITELISTED");
- }
- if (mAllowInIdleJobs.contains(jobStatus)) {
- pw.print(" ALLOWED_IN_DOZE");
- }
- pw.println();
+ public void dumpControllerStateLocked(final IndentingPrintWriter pw,
+ final Predicate<JobStatus> predicate) {
+ pw.println("Idle mode: " + mDeviceIdleMode);
+ pw.println();
+
+ mService.getJobStore().forEachJob(predicate, (jobStatus) -> {
+ pw.print("#");
+ jobStatus.printUniqueId(pw);
+ pw.print(" from ");
+ UserHandle.formatUid(pw, jobStatus.getSourceUid());
+ pw.print(": ");
+ pw.print(jobStatus.getSourcePackageName());
+ pw.print((jobStatus.satisfiedConstraints
+ & JobStatus.CONSTRAINT_DEVICE_NOT_DOZING) != 0
+ ? " RUNNABLE" : " WAITING");
+ if (jobStatus.dozeWhitelisted) {
+ pw.print(" WHITELISTED");
}
+ if (mAllowInIdleJobs.contains(jobStatus)) {
+ pw.print(" ALLOWED_IN_DOZE");
+ }
+ pw.println();
});
}
@Override
- public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) {
+ public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
+ Predicate<JobStatus> predicate) {
final long token = proto.start(fieldId);
final long mToken = proto.start(StateControllerProto.DEVICE_IDLE);
proto.write(StateControllerProto.DeviceIdleJobsController.IS_DEVICE_IDLE_MODE,
mDeviceIdleMode);
- mJobSchedulerService.getJobStore().forEachJob(new JobStore.JobStatusFunctor() {
- @Override public void process(JobStatus jobStatus) {
- if (!jobStatus.shouldDump(filterUid)) {
- return;
- }
- final long jsToken =
- proto.start(StateControllerProto.DeviceIdleJobsController.TRACKED_JOBS);
+ mService.getJobStore().forEachJob(predicate, (jobStatus) -> {
+ final long jsToken =
+ proto.start(StateControllerProto.DeviceIdleJobsController.TRACKED_JOBS);
- jobStatus.writeToShortProto(proto, TrackedJob.INFO);
- proto.write(TrackedJob.SOURCE_UID, jobStatus.getSourceUid());
- proto.write(TrackedJob.SOURCE_PACKAGE_NAME, jobStatus.getSourcePackageName());
- proto.write(TrackedJob.ARE_CONSTRAINTS_SATISFIED,
- (jobStatus.satisfiedConstraints &
- JobStatus.CONSTRAINT_DEVICE_NOT_DOZING) != 0);
- proto.write(TrackedJob.IS_DOZE_WHITELISTED, jobStatus.dozeWhitelisted);
- proto.write(TrackedJob.IS_ALLOWED_IN_DOZE, mAllowInIdleJobs.contains(jobStatus));
+ jobStatus.writeToShortProto(proto, TrackedJob.INFO);
+ proto.write(TrackedJob.SOURCE_UID, jobStatus.getSourceUid());
+ proto.write(TrackedJob.SOURCE_PACKAGE_NAME, jobStatus.getSourcePackageName());
+ proto.write(TrackedJob.ARE_CONSTRAINTS_SATISFIED,
+ (jobStatus.satisfiedConstraints &
+ JobStatus.CONSTRAINT_DEVICE_NOT_DOZING) != 0);
+ proto.write(TrackedJob.IS_DOZE_WHITELISTED, jobStatus.dozeWhitelisted);
+ proto.write(TrackedJob.IS_ALLOWED_IN_DOZE, mAllowInIdleJobs.contains(jobStatus));
- proto.end(jsToken);
- }
+ proto.end(jsToken);
});
proto.end(mToken);
proto.end(token);
}
- final class DeviceIdleUpdateFunctor implements JobStore.JobStatusFunctor {
+ final class DeviceIdleUpdateFunctor implements Consumer<JobStatus> {
boolean mChanged;
@Override
- public void process(JobStatus jobStatus) {
+ public void accept(JobStatus jobStatus) {
mChanged |= updateTaskStateLocked(jobStatus);
}
}
@@ -328,7 +302,7 @@
// Just process all the jobs, the ones in foreground should already be running.
synchronized (mLock) {
mDeviceIdleUpdateFunctor.mChanged = false;
- mJobSchedulerService.getJobStore().forEachJob(mDeviceIdleUpdateFunctor);
+ mService.getJobStore().forEachJob(mDeviceIdleUpdateFunctor);
if (mDeviceIdleUpdateFunctor.mChanged) {
mStateChangedListener.onControllerStateChanged();
}
diff --git a/services/core/java/com/android/server/job/controllers/IdleController.java b/services/core/java/com/android/server/job/controllers/IdleController.java
index 78284e5..1dbcfd6 100644
--- a/services/core/java/com/android/server/job/controllers/IdleController.java
+++ b/services/core/java/com/android/server/job/controllers/IdleController.java
@@ -30,12 +30,12 @@
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.am.ActivityManagerService;
import com.android.server.job.JobSchedulerService;
-import com.android.server.job.StateChangedListener;
import com.android.server.job.StateControllerProto;
-import java.io.PrintWriter;
+import java.util.function.Predicate;
public final class IdleController extends StateController {
private static final String TAG = "JobScheduler.Idle";
@@ -49,22 +49,8 @@
final ArraySet<JobStatus> mTrackedTasks = new ArraySet<>();
IdlenessTracker mIdleTracker;
- // Singleton factory
- private static Object sCreationLock = new Object();
- private static volatile IdleController sController;
-
- public static IdleController get(JobSchedulerService service) {
- synchronized (sCreationLock) {
- if (sController == null) {
- sController = new IdleController(service, service.getContext(), service.getLock());
- }
- return sController;
- }
- }
-
- private IdleController(StateChangedListener stateChangedListener, Context context,
- Object lock) {
- super(stateChangedListener, context, lock);
+ public IdleController(JobSchedulerService service) {
+ super(service);
initIdleStateTracking();
}
@@ -203,18 +189,17 @@
}
@Override
- public void dumpControllerStateLocked(PrintWriter pw, int filterUid) {
- pw.print("Idle: ");
- pw.println(mIdleTracker.isIdle());
- pw.print("Tracking ");
- pw.print(mTrackedTasks.size());
- pw.println(":");
+ public void dumpControllerStateLocked(IndentingPrintWriter pw,
+ Predicate<JobStatus> predicate) {
+ pw.println("Currently idle: " + mIdleTracker.isIdle());
+ pw.println();
+
for (int i = 0; i < mTrackedTasks.size(); i++) {
final JobStatus js = mTrackedTasks.valueAt(i);
- if (!js.shouldDump(filterUid)) {
+ if (!predicate.test(js)) {
continue;
}
- pw.print(" #");
+ pw.print("#");
js.printUniqueId(pw);
pw.print(" from ");
UserHandle.formatUid(pw, js.getSourceUid());
@@ -223,7 +208,8 @@
}
@Override
- public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) {
+ public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
+ Predicate<JobStatus> predicate) {
final long token = proto.start(fieldId);
final long mToken = proto.start(StateControllerProto.IDLE);
@@ -231,7 +217,7 @@
for (int i = 0; i < mTrackedTasks.size(); i++) {
final JobStatus js = mTrackedTasks.valueAt(i);
- if (!js.shouldDump(filterUid)) {
+ if (!predicate.test(js)) {
continue;
}
final long jsToken = proto.start(StateControllerProto.IdleController.TRACKED_JOBS);
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index d1bb63a..5616197 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -888,11 +888,6 @@
return mLastFailedRunTime;
}
- public boolean shouldDump(int filterUid) {
- return filterUid == -1 || UserHandle.getAppId(getUid()) == filterUid
- || UserHandle.getAppId(getSourceUid()) == filterUid;
- }
-
/**
* @return Whether or not this job is ready to run, based on its requirements. This is true if
* the constraints are satisfied <strong>or</strong> the deadline on the job has expired.
diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java
index 88d6bea..495109d 100644
--- a/services/core/java/com/android/server/job/controllers/StateController.java
+++ b/services/core/java/com/android/server/job/controllers/StateController.java
@@ -19,10 +19,12 @@
import android.content.Context;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.job.JobSchedulerService;
+import com.android.server.job.JobSchedulerService.Constants;
import com.android.server.job.StateChangedListener;
-import java.io.PrintWriter;
+import java.util.function.Predicate;
/**
* Incorporates shared controller logic between the various controllers of the JobManager.
@@ -30,15 +32,18 @@
* are ready to run, or whether they must be stopped.
*/
public abstract class StateController {
+ protected final JobSchedulerService mService;
+ protected final StateChangedListener mStateChangedListener;
protected final Context mContext;
protected final Object mLock;
- protected final StateChangedListener mStateChangedListener;
+ protected final Constants mConstants;
- public StateController(StateChangedListener stateChangedListener, Context context,
- Object lock) {
- mStateChangedListener = stateChangedListener;
- mContext = context;
- mLock = lock;
+ StateController(JobSchedulerService service) {
+ mService = service;
+ mStateChangedListener = service;
+ mContext = service.getContext();
+ mLock = service.getLock();
+ mConstants = service.getConstants();
}
/**
@@ -64,7 +69,8 @@
public void rescheduleForFailureLocked(JobStatus newJob, JobStatus failureToReschedule) {
}
- public abstract void dumpControllerStateLocked(PrintWriter pw, int filterUid);
+ public abstract void dumpControllerStateLocked(IndentingPrintWriter pw,
+ Predicate<JobStatus> predicate);
public abstract void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
- int filterUid);
+ Predicate<JobStatus> predicate);
}
diff --git a/services/core/java/com/android/server/job/controllers/StorageController.java b/services/core/java/com/android/server/job/controllers/StorageController.java
index 5b79f39..c2ae53f 100644
--- a/services/core/java/com/android/server/job/controllers/StorageController.java
+++ b/services/core/java/com/android/server/job/controllers/StorageController.java
@@ -29,12 +29,12 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.job.JobSchedulerService;
-import com.android.server.job.StateChangedListener;
import com.android.server.job.StateControllerProto;
import com.android.server.storage.DeviceStorageMonitorService;
-import java.io.PrintWriter;
+import java.util.function.Predicate;
/**
* Simple controller that tracks the status of the device's storage.
@@ -44,36 +44,16 @@
private static final boolean DEBUG = JobSchedulerService.DEBUG
|| Log.isLoggable(TAG, Log.DEBUG);
- private static final Object sCreationLock = new Object();
- private static volatile StorageController sController;
-
private final ArraySet<JobStatus> mTrackedTasks = new ArraySet<JobStatus>();
- private StorageTracker mStorageTracker;
-
- public static StorageController get(JobSchedulerService taskManagerService) {
- synchronized (sCreationLock) {
- if (sController == null) {
- sController = new StorageController(taskManagerService,
- taskManagerService.getContext(), taskManagerService.getLock());
- }
- }
- return sController;
- }
+ private final StorageTracker mStorageTracker;
@VisibleForTesting
public StorageTracker getTracker() {
return mStorageTracker;
}
- @VisibleForTesting
- public static StorageController getForTesting(StateChangedListener stateChangedListener,
- Context context) {
- return new StorageController(stateChangedListener, context, new Object());
- }
-
- private StorageController(StateChangedListener stateChangedListener, Context context,
- Object lock) {
- super(stateChangedListener, context, lock);
+ public StorageController(JobSchedulerService service) {
+ super(service);
mStorageTracker = new StorageTracker();
mStorageTracker.startTracking();
}
@@ -175,20 +155,18 @@
}
@Override
- public void dumpControllerStateLocked(PrintWriter pw, int filterUid) {
- pw.print("Storage: not low = ");
- pw.print(mStorageTracker.isStorageNotLow());
- pw.print(", seq=");
- pw.println(mStorageTracker.getSeq());
- pw.print("Tracking ");
- pw.print(mTrackedTasks.size());
- pw.println(":");
+ public void dumpControllerStateLocked(IndentingPrintWriter pw,
+ Predicate<JobStatus> predicate) {
+ pw.println("Not low: " + mStorageTracker.isStorageNotLow());
+ pw.println("Sequence: " + mStorageTracker.getSeq());
+ pw.println();
+
for (int i = 0; i < mTrackedTasks.size(); i++) {
final JobStatus js = mTrackedTasks.valueAt(i);
- if (!js.shouldDump(filterUid)) {
+ if (!predicate.test(js)) {
continue;
}
- pw.print(" #");
+ pw.print("#");
js.printUniqueId(pw);
pw.print(" from ");
UserHandle.formatUid(pw, js.getSourceUid());
@@ -197,7 +175,8 @@
}
@Override
- public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) {
+ public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
+ Predicate<JobStatus> predicate) {
final long token = proto.start(fieldId);
final long mToken = proto.start(StateControllerProto.STORAGE);
@@ -208,7 +187,7 @@
for (int i = 0; i < mTrackedTasks.size(); i++) {
final JobStatus js = mTrackedTasks.valueAt(i);
- if (!js.shouldDump(filterUid)) {
+ if (!predicate.test(js)) {
continue;
}
final long jsToken = proto.start(StateControllerProto.StorageController.TRACKED_JOBS);
diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java
index cdafc3b..fa48b5e 100644
--- a/services/core/java/com/android/server/job/controllers/TimeController.java
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -30,15 +30,15 @@
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.job.JobSchedulerService;
-import com.android.server.job.StateChangedListener;
import com.android.server.job.StateControllerProto;
-import java.io.PrintWriter;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
+import java.util.function.Predicate;
/**
* This class sets an alarm for the next expiring job, and determines whether a job's minimum
@@ -62,23 +62,13 @@
private AlarmManager mAlarmService = null;
/** List of tracked jobs, sorted asc. by deadline */
private final List<JobStatus> mTrackedJobs = new LinkedList<>();
- /** Singleton. */
- private static TimeController mSingleton;
- public static synchronized TimeController get(JobSchedulerService jms) {
- if (mSingleton == null) {
- mSingleton = new TimeController(jms, jms.getContext(), jms.getLock());
- }
- return mSingleton;
- }
-
- private TimeController(StateChangedListener stateChangedListener, Context context,
- Object lock) {
- super(stateChangedListener, context, lock);
+ public TimeController(JobSchedulerService service) {
+ super(service);
mNextJobExpiredElapsedMillis = Long.MAX_VALUE;
mNextDelayExpiredElapsedMillis = Long.MAX_VALUE;
- mChainedAttributionEnabled = WorkSource.isChainedBatteryAttributionEnabled(context);
+ mChainedAttributionEnabled = WorkSource.isChainedBatteryAttributionEnabled(mContext);
}
/**
@@ -348,25 +338,24 @@
};
@Override
- public void dumpControllerStateLocked(PrintWriter pw, int filterUid) {
+ public void dumpControllerStateLocked(IndentingPrintWriter pw,
+ Predicate<JobStatus> predicate) {
final long nowElapsed = sElapsedRealtimeClock.millis();
- pw.print("Alarms: now=");
- pw.print(nowElapsed);
- pw.println();
+ pw.println("Elapsed clock: " + nowElapsed);
+
pw.print("Next delay alarm in ");
TimeUtils.formatDuration(mNextDelayExpiredElapsedMillis, nowElapsed, pw);
pw.println();
pw.print("Next deadline alarm in ");
TimeUtils.formatDuration(mNextJobExpiredElapsedMillis, nowElapsed, pw);
pw.println();
- pw.print("Tracking ");
- pw.print(mTrackedJobs.size());
- pw.println(":");
+ pw.println();
+
for (JobStatus ts : mTrackedJobs) {
- if (!ts.shouldDump(filterUid)) {
+ if (!predicate.test(ts)) {
continue;
}
- pw.print(" #");
+ pw.print("#");
ts.printUniqueId(pw);
pw.print(" from ");
UserHandle.formatUid(pw, ts.getSourceUid());
@@ -387,7 +376,8 @@
}
@Override
- public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) {
+ public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
+ Predicate<JobStatus> predicate) {
final long token = proto.start(fieldId);
final long mToken = proto.start(StateControllerProto.TIME);
@@ -399,7 +389,7 @@
mNextJobExpiredElapsedMillis - nowElapsed);
for (JobStatus ts : mTrackedJobs) {
- if (!ts.shouldDump(filterUid)) {
+ if (!predicate.test(ts)) {
continue;
}
final long tsToken = proto.start(StateControllerProto.TimeController.TRACKED_JOBS);
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 0dab528..5267f54 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1704,7 +1704,6 @@
mStarted = false;
mSingleShot = false;
native_stop();
- mTimeToFirstFix = 0;
mLastFixTime = 0;
// reset SV count to zero
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index bd9ec55..f29e0bb 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -28,6 +28,11 @@
import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.EXTRA_UID;
+import static android.content.pm.PackageManager.MATCH_ANY_USER;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
+import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
@@ -61,9 +66,7 @@
import static android.net.NetworkPolicyManager.resolveNetworkId;
import static android.net.NetworkPolicyManager.uidPoliciesToString;
import static android.net.NetworkPolicyManager.uidRulesToString;
-import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
-import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
-import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
+import static android.net.NetworkTemplate.MATCH_MOBILE;
import static android.net.NetworkTemplate.MATCH_WIFI;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.TrafficStats.MB_IN_BYTES;
@@ -71,7 +74,6 @@
import static android.telephony.CarrierConfigManager.DATA_CYCLE_THRESHOLD_DISABLED;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static com.android.internal.util.ArrayUtils.appendInt;
import static com.android.internal.util.Preconditions.checkNotNull;
@@ -139,15 +141,16 @@
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
import android.net.NetworkState;
+import android.net.NetworkStats;
import android.net.NetworkTemplate;
import android.net.StringNetworkSpecifier;
import android.net.TrafficStats;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
+import android.os.BestClock;
import android.os.Binder;
import android.os.Build;
import android.os.Environment;
-import android.os.BestClock;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IDeviceIdleController;
@@ -359,7 +362,7 @@
private final Context mContext;
private final IActivityManager mActivityManager;
- private final INetworkStatsService mNetworkStats;
+ private NetworkStatsManagerInternal mNetworkStats;
private final INetworkManagementService mNetworkManager;
private UsageStatsManagerInternal mUsageStats;
private final Clock mClock;
@@ -516,10 +519,9 @@
// TODO: migrate notifications to SystemUI
public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
- INetworkStatsService networkStats, INetworkManagementService networkManagement) {
- this(context, activityManager, networkStats, networkManagement,
- AppGlobals.getPackageManager(), getDefaultClock(), getDefaultSystemDir(),
- false);
+ INetworkManagementService networkManagement) {
+ this(context, activityManager, networkManagement, AppGlobals.getPackageManager(),
+ getDefaultClock(), getDefaultSystemDir(), false);
}
private static @NonNull File getDefaultSystemDir() {
@@ -532,11 +534,10 @@
}
public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
- INetworkStatsService networkStats, INetworkManagementService networkManagement,
- IPackageManager pm, Clock clock, File systemDir, boolean suppressDefaultPolicy) {
+ INetworkManagementService networkManagement, IPackageManager pm, Clock clock,
+ File systemDir, boolean suppressDefaultPolicy) {
mContext = checkNotNull(context, "missing context");
mActivityManager = checkNotNull(activityManager, "missing activityManager");
- mNetworkStats = checkNotNull(networkStats, "missing networkStats");
mNetworkManager = checkNotNull(networkManagement, "missing networkManagement");
mDeviceIdleController = IDeviceIdleController.Stub.asInterface(ServiceManager.getService(
Context.DEVICE_IDLE_CONTROLLER));
@@ -660,6 +661,7 @@
}
mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
+ mNetworkStats = LocalServices.getService(NetworkStatsManagerInternal.class);
synchronized (mUidRulesFirstLock) {
synchronized (mNetworkPoliciesSecondLock) {
@@ -1063,9 +1065,9 @@
if (policy.isOverLimit(totalBytes)) {
final boolean snoozedThisCycle = policy.lastLimitSnooze >= cycleStart;
if (snoozedThisCycle) {
- enqueueNotification(policy, TYPE_LIMIT_SNOOZED, totalBytes);
+ enqueueNotification(policy, TYPE_LIMIT_SNOOZED, totalBytes, null);
} else {
- enqueueNotification(policy, TYPE_LIMIT, totalBytes);
+ enqueueNotification(policy, TYPE_LIMIT, totalBytes, null);
notifyOverLimitNL(policy.template);
}
@@ -1074,7 +1076,7 @@
final boolean snoozedThisCycle = policy.lastWarningSnooze >= cycleStart;
if (policy.isOverWarning(totalBytes) && !snoozedThisCycle) {
- enqueueNotification(policy, TYPE_WARNING, totalBytes);
+ enqueueNotification(policy, TYPE_WARNING, totalBytes, null);
}
}
@@ -1082,7 +1084,9 @@
// far past the plan limits.
if (policy.limitBytes != LIMIT_DISABLED) {
final long recentDuration = TimeUnit.DAYS.toMillis(4);
- final long recentBytes = getTotalBytes(policy.template, now - recentDuration, now);
+ final long recentStart = now - recentDuration;
+ final long recentEnd = now;
+ final long recentBytes = getTotalBytes(policy.template, recentStart, recentEnd);
final long cycleDuration = cycleEnd - cycleStart;
final long projectedBytes = (recentBytes * cycleDuration) / recentDuration;
@@ -1096,7 +1100,8 @@
final boolean snoozedRecently = policy.lastRapidSnooze >= now
- DateUtils.DAY_IN_MILLIS;
if (projectedBytes > alertBytes && !snoozedRecently) {
- enqueueNotification(policy, TYPE_RAPID, 0);
+ enqueueNotification(policy, TYPE_RAPID, 0,
+ findRapidBlame(policy.template, recentStart, recentEnd));
}
}
}
@@ -1111,6 +1116,45 @@
}
/**
+ * Attempt to find a specific app to blame for rapid data usage during the
+ * given time period.
+ */
+ private @Nullable ApplicationInfo findRapidBlame(NetworkTemplate template,
+ long start, long end) {
+ long totalBytes = 0;
+ long maxBytes = 0;
+ int maxUid = 0;
+
+ final NetworkStats stats = getNetworkUidBytes(template, start, end);
+ NetworkStats.Entry entry = null;
+ for (int i = 0; i < stats.size(); i++) {
+ entry = stats.getValues(i, entry);
+ final long bytes = entry.rxBytes + entry.txBytes;
+ totalBytes += bytes;
+ if (bytes > maxBytes) {
+ maxBytes = bytes;
+ maxUid = entry.uid;
+ }
+ }
+
+ // Only point blame if the majority of usage was done by a single app.
+ // TODO: support shared UIDs
+ if (maxBytes > 0 && maxBytes > totalBytes / 2) {
+ final String[] packageNames = mContext.getPackageManager().getPackagesForUid(maxUid);
+ if (packageNames.length == 1) {
+ try {
+ return mContext.getPackageManager().getApplicationInfo(packageNames[0],
+ MATCH_ANY_USER | MATCH_DISABLED_COMPONENTS | MATCH_DIRECT_BOOT_AWARE
+ | MATCH_DIRECT_BOOT_UNAWARE | MATCH_UNINSTALLED_PACKAGES);
+ } catch (NameNotFoundException ignored) {
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
* Test if given {@link NetworkTemplate} is relevant to user based on
* current device state, such as when
* {@link TelephonyManager#getSubscriberId()} matches. This is regardless of
@@ -1157,7 +1201,8 @@
* Show notification for combined {@link NetworkPolicy} and specific type,
* like {@link #TYPE_LIMIT}. Okay to call multiple times.
*/
- private void enqueueNotification(NetworkPolicy policy, int type, long totalBytes) {
+ private void enqueueNotification(NetworkPolicy policy, int type, long totalBytes,
+ ApplicationInfo rapidBlame) {
final NotificationId notificationId = new NotificationId(policy, type);
final Notification.Builder builder =
new Notification.Builder(mContext, SystemNotificationChannels.NETWORK_ALERTS);
@@ -1167,16 +1212,15 @@
com.android.internal.R.color.system_notification_accent_color));
final Resources res = mContext.getResources();
- CharSequence body = null;
+ final CharSequence title;
+ final CharSequence body;
switch (type) {
case TYPE_WARNING: {
- final CharSequence title = res.getText(R.string.data_usage_warning_title);
- body = res.getString(R.string.data_usage_warning_body);
+ title = res.getText(R.string.data_usage_warning_title);
+ body = res.getString(R.string.data_usage_warning_body,
+ Formatter.formatFileSize(mContext, totalBytes));
builder.setSmallIcon(R.drawable.stat_notify_error);
- builder.setTicker(title);
- builder.setContentTitle(title);
- builder.setContentText(body);
final Intent snoozeIntent = buildSnoozeWarningIntent(policy.template);
builder.setDeleteIntent(PendingIntent.getBroadcast(
@@ -1189,34 +1233,20 @@
break;
}
case TYPE_LIMIT: {
- body = res.getText(R.string.data_usage_limit_body);
-
- final CharSequence title;
- int icon = R.drawable.stat_notify_disabled_data;
switch (policy.template.getMatchRule()) {
- case MATCH_MOBILE_3G_LOWER:
- title = res.getText(R.string.data_usage_3g_limit_title);
- break;
- case MATCH_MOBILE_4G:
- title = res.getText(R.string.data_usage_4g_limit_title);
- break;
- case MATCH_MOBILE_ALL:
+ case MATCH_MOBILE:
title = res.getText(R.string.data_usage_mobile_limit_title);
break;
case MATCH_WIFI:
title = res.getText(R.string.data_usage_wifi_limit_title);
- icon = R.drawable.stat_notify_error;
break;
default:
- title = null;
- break;
+ return;
}
+ body = res.getText(R.string.data_usage_limit_body);
builder.setOngoing(true);
- builder.setSmallIcon(icon);
- builder.setTicker(title);
- builder.setContentTitle(title);
- builder.setContentText(body);
+ builder.setSmallIcon(R.drawable.stat_notify_disabled_data);
final Intent intent = buildNetworkOverLimitIntent(res, policy.template);
builder.setContentIntent(PendingIntent.getActivity(
@@ -1224,34 +1254,22 @@
break;
}
case TYPE_LIMIT_SNOOZED: {
- final long overBytes = totalBytes - policy.limitBytes;
- body = res.getString(R.string.data_usage_limit_snoozed_body,
- Formatter.formatFileSize(mContext, overBytes));
-
- final CharSequence title;
switch (policy.template.getMatchRule()) {
- case MATCH_MOBILE_3G_LOWER:
- title = res.getText(R.string.data_usage_3g_limit_snoozed_title);
- break;
- case MATCH_MOBILE_4G:
- title = res.getText(R.string.data_usage_4g_limit_snoozed_title);
- break;
- case MATCH_MOBILE_ALL:
+ case MATCH_MOBILE:
title = res.getText(R.string.data_usage_mobile_limit_snoozed_title);
break;
case MATCH_WIFI:
title = res.getText(R.string.data_usage_wifi_limit_snoozed_title);
break;
default:
- title = null;
- break;
+ return;
}
+ final long overBytes = totalBytes - policy.limitBytes;
+ body = res.getString(R.string.data_usage_limit_snoozed_body,
+ Formatter.formatFileSize(mContext, overBytes));
builder.setOngoing(true);
builder.setSmallIcon(R.drawable.stat_notify_error);
- builder.setTicker(title);
- builder.setContentTitle(title);
- builder.setContentText(body);
builder.setChannelId(SystemNotificationChannels.NETWORK_STATUS);
final Intent intent = buildViewDataUsageIntent(res, policy.template);
@@ -1260,13 +1278,15 @@
break;
}
case TYPE_RAPID: {
- final CharSequence title = res.getText(R.string.data_usage_rapid_title);
- body = res.getText(R.string.data_usage_rapid_body);
+ title = res.getText(R.string.data_usage_rapid_title);
+ if (rapidBlame != null) {
+ body = res.getString(R.string.data_usage_rapid_app_body,
+ rapidBlame.loadLabel(mContext.getPackageManager()));
+ } else {
+ body = res.getString(R.string.data_usage_rapid_body);
+ }
builder.setSmallIcon(R.drawable.stat_notify_error);
- builder.setTicker(title);
- builder.setContentTitle(title);
- builder.setContentText(body);
final Intent snoozeIntent = buildSnoozeRapidIntent(policy.template);
builder.setDeleteIntent(PendingIntent.getBroadcast(
@@ -1277,11 +1297,15 @@
mContext, 0, viewIntent, PendingIntent.FLAG_UPDATE_CURRENT));
break;
}
+ default: {
+ return;
+ }
}
- if (!TextUtils.isEmpty(body)) {
- builder.setStyle(new Notification.BigTextStyle().bigText(body));
- }
+ builder.setTicker(title);
+ builder.setContentTitle(title);
+ builder.setContentText(body);
+ builder.setStyle(new Notification.BigTextStyle().bigText(body));
mContext.getSystemService(NotificationManager.class).notifyAsUser(notificationId.getTag(),
notificationId.getId(), builder.build(), UserHandle.ALL);
@@ -1537,7 +1561,7 @@
// TODO: reach into ConnectivityManager to proactively disable bringing
// up this network, since we know that traffic will be blocked.
- if (template.getMatchRule() == MATCH_MOBILE_ALL) {
+ if (template.getMatchRule() == MATCH_MOBILE) {
// If mobile data usage hits the limit or if the user resumes the data, we need to
// notify telephony.
final SubscriptionManager sm = mContext.getSystemService(SubscriptionManager.class);
@@ -1954,9 +1978,7 @@
metered = readBooleanAttribute(in, ATTR_METERED);
} else {
switch (networkTemplate) {
- case MATCH_MOBILE_3G_LOWER:
- case MATCH_MOBILE_4G:
- case MATCH_MOBILE_ALL:
+ case MATCH_MOBILE:
metered = true;
break;
default:
@@ -3243,8 +3265,6 @@
}
try {
mNetworkStats.setUidForeground(uid, uidForeground);
- } catch (RemoteException e) {
- // ignored; service lives in system_server
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
@@ -4028,13 +4048,9 @@
synchronized (mNetworkPoliciesSecondLock) {
if (mMeteredIfaces.contains(iface)) {
- try {
- // force stats update to make sure we have
- // numbers that caused alert to trigger.
- mNetworkStats.forceUpdate();
- } catch (RemoteException e) {
- // ignored; service lives in system_server
- }
+ // force stats update to make sure we have
+ // numbers that caused alert to trigger.
+ mNetworkStats.forceUpdate();
updateNetworkEnabledNL();
updateNotificationsNL();
@@ -4075,14 +4091,10 @@
}
case MSG_ADVISE_PERSIST_THRESHOLD: {
final long lowestRule = (Long) msg.obj;
- try {
- // make sure stats are recorded frequently enough; we aim
- // for 2MB threshold for 2GB/month rules.
- final long persistThreshold = lowestRule / 1000;
- mNetworkStats.advisePersistThreshold(persistThreshold);
- } catch (RemoteException e) {
- // ignored; service lives in system_server
- }
+ // make sure stats are recorded frequently enough; we aim
+ // for 2MB threshold for 2GB/month rules.
+ final long persistThreshold = lowestRule / 1000;
+ mNetworkStats.advisePersistThreshold(persistThreshold);
return true;
}
case MSG_UPDATE_INTERFACE_QUOTA: {
@@ -4366,15 +4378,26 @@
}
}
+ @Deprecated
private long getTotalBytes(NetworkTemplate template, long start, long end) {
+ return getNetworkTotalBytes(template, start, end);
+ }
+
+ private long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
try {
return mNetworkStats.getNetworkTotalBytes(template, start, end);
} catch (RuntimeException e) {
- Slog.w(TAG, "problem reading network stats: " + e);
+ Slog.w(TAG, "Failed to read network stats: " + e);
return 0;
- } catch (RemoteException e) {
- // ignored; service lives in system_server
- return 0;
+ }
+ }
+
+ private NetworkStats getNetworkUidBytes(NetworkTemplate template, long start, long end) {
+ try {
+ return mNetworkStats.getNetworkUidBytes(template, start, end);
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failed to read network stats: " + e);
+ return new NetworkStats(SystemClock.elapsedRealtime(), 0);
}
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 3cc4d83..a5f8dc7 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -106,6 +106,10 @@
reset();
}
+ public void clear() {
+ reset();
+ }
+
public void reset() {
mStats.clear();
mStartMillis = Long.MAX_VALUE;
diff --git a/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java b/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java
new file mode 100644
index 0000000..4843ede
--- /dev/null
+++ b/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java
@@ -0,0 +1,37 @@
+/*
+ * 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.net;
+
+import android.net.NetworkStats;
+import android.net.NetworkTemplate;
+
+public abstract class NetworkStatsManagerInternal {
+ /** Return network layer usage total for traffic that matches template. */
+ public abstract long getNetworkTotalBytes(NetworkTemplate template, long start, long end);
+
+ /** Return network layer usage per-UID for traffic that matches template. */
+ public abstract NetworkStats getNetworkUidBytes(NetworkTemplate template, long start, long end);
+
+ /** Mark given UID as being in foreground for stats purposes. */
+ public abstract void setUidForeground(int uid, boolean uidForeground);
+
+ /** Advise persistance threshold; may be overridden internally. */
+ public abstract void advisePersistThreshold(long thresholdBytes);
+
+ /** Force update of statistics. */
+ public abstract void forceUpdate();
+}
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 32e15c9..93c04fe 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -49,7 +49,6 @@
import static android.provider.Settings.Global.NETSTATS_GLOBAL_ALERT_BYTES;
import static android.provider.Settings.Global.NETSTATS_POLL_INTERVAL;
import static android.provider.Settings.Global.NETSTATS_SAMPLE_ENABLED;
-import static android.provider.Settings.Global.NETSTATS_TIME_CACHE_MAX_AGE;
import static android.provider.Settings.Global.NETSTATS_UID_BUCKET_DURATION;
import static android.provider.Settings.Global.NETSTATS_UID_DELETE_AGE;
import static android.provider.Settings.Global.NETSTATS_UID_PERSIST_BYTES;
@@ -95,10 +94,10 @@
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.TrafficStats;
+import android.os.BestClock;
import android.os.Binder;
import android.os.DropBoxManager;
import android.os.Environment;
-import android.os.BestClock;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -134,6 +133,7 @@
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.EventLogTags;
+import com.android.server.LocalServices;
import com.android.server.connectivity.Tethering;
import java.io.File;
@@ -333,6 +333,9 @@
mStatsObservers = checkNotNull(statsObservers, "missing NetworkStatsObservers");
mSystemDir = checkNotNull(systemDir, "missing systemDir");
mBaseDir = checkNotNull(baseDir, "missing baseDir");
+
+ LocalServices.addService(NetworkStatsManagerInternal.class,
+ new NetworkStatsManagerInternalImpl());
}
@VisibleForTesting
@@ -640,7 +643,7 @@
private SubscriptionPlan resolveSubscriptionPlan(NetworkTemplate template, int flags) {
SubscriptionPlan plan = null;
if ((flags & NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN) != 0
- && (template.getMatchRule() == NetworkTemplate.MATCH_MOBILE_ALL)
+ && (template.getMatchRule() == NetworkTemplate.MATCH_MOBILE)
&& mSettings.getAugmentEnabled()) {
if (LOGD) Slog.d(TAG, "Resolving plan for " + template);
final long token = Binder.clearCallingIdentity();
@@ -701,12 +704,8 @@
}
}
- @Override
- public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
- // Special case - since this is for internal use only, don't worry about
- // a full access level check and just require the signature/privileged
- // permission.
- mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
+ private long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
+ assertSystemReady();
assertBandwidthControlEnabled();
// NOTE: if callers want to get non-augmented data, they should go
@@ -716,6 +715,18 @@
NetworkStatsAccess.Level.DEVICE, Binder.getCallingUid()).getTotalBytes();
}
+ private NetworkStats getNetworkUidBytes(NetworkTemplate template, long start, long end) {
+ assertSystemReady();
+ assertBandwidthControlEnabled();
+
+ final NetworkStatsCollection uidComplete;
+ synchronized (mStatsLock) {
+ uidComplete = mUidRecorder.getOrLoadCompleteLocked();
+ }
+ return uidComplete.getSummary(template, start, end, NetworkStatsAccess.Level.DEVICE,
+ android.os.Process.SYSTEM_UID);
+ }
+
@Override
public NetworkStats getDataLayerSnapshotForUid(int uid) throws RemoteException {
if (Binder.getCallingUid() != uid) {
@@ -777,10 +788,8 @@
}
}
- @Override
- public void setUidForeground(int uid, boolean uidForeground) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-
+ @VisibleForTesting
+ void setUidForeground(int uid, boolean uidForeground) {
synchronized (mStatsLock) {
final int set = uidForeground ? SET_FOREGROUND : SET_DEFAULT;
final int oldSet = mActiveUidCounterSet.get(uid, SET_DEFAULT);
@@ -817,9 +826,7 @@
}
}
- @Override
- public void advisePersistThreshold(long thresholdBytes) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ private void advisePersistThreshold(long thresholdBytes) {
assertBandwidthControlEnabled();
// clamp threshold into safe range
@@ -1330,6 +1337,33 @@
removeUidsLocked(uids);
}
+ private class NetworkStatsManagerInternalImpl extends NetworkStatsManagerInternal {
+ @Override
+ public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
+ return NetworkStatsService.this.getNetworkTotalBytes(template, start, end);
+ }
+
+ @Override
+ public NetworkStats getNetworkUidBytes(NetworkTemplate template, long start, long end) {
+ return NetworkStatsService.this.getNetworkUidBytes(template, start, end);
+ }
+
+ @Override
+ public void setUidForeground(int uid, boolean uidForeground) {
+ NetworkStatsService.this.setUidForeground(uid, uidForeground);
+ }
+
+ @Override
+ public void advisePersistThreshold(long thresholdBytes) {
+ NetworkStatsService.this.advisePersistThreshold(thresholdBytes);
+ }
+
+ @Override
+ public void forceUpdate() {
+ NetworkStatsService.this.forceUpdate();
+ }
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter rawWriter, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, rawWriter)) return;
@@ -1550,6 +1584,12 @@
}
}
+ private void assertSystemReady() {
+ if (!mSystemReady) {
+ throw new IllegalStateException("System not ready");
+ }
+ }
+
private void assertBandwidthControlEnabled() {
if (!isBandwidthControlEnabled()) {
throw new IllegalStateException("Bandwidth module disabled");
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 7467954..fd51be5 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -64,6 +64,8 @@
import com.android.server.pm.Installer;
import com.android.server.pm.UserManagerService;
+import libcore.util.EmptyArray;
+
import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
@@ -303,10 +305,10 @@
schedulePersistSettings();
}
- private static Set<String> getDefaultOverlayPackages() {
+ private static String[] getDefaultOverlayPackages() {
final String str = SystemProperties.get(DEFAULT_OVERLAYS_PROP);
if (TextUtils.isEmpty(str)) {
- return Collections.emptySet();
+ return EmptyArray.STRING;
}
final ArraySet<String> defaultPackages = new ArraySet<>();
@@ -315,7 +317,7 @@
defaultPackages.add(packageName);
}
}
- return defaultPackages;
+ return defaultPackages.toArray(new String[defaultPackages.size()]);
}
private final class PackageReceiver extends BroadcastReceiver {
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 43b1708..74eb2ea 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -60,13 +60,13 @@
private final PackageManagerHelper mPackageManager;
private final IdmapManager mIdmapManager;
private final OverlayManagerSettings mSettings;
- private final Set<String> mDefaultOverlays;
+ private final String[] mDefaultOverlays;
private final OverlayChangeListener mListener;
OverlayManagerServiceImpl(@NonNull final PackageManagerHelper packageManager,
@NonNull final IdmapManager idmapManager,
@NonNull final OverlayManagerSettings settings,
- @NonNull final Set<String> defaultOverlays,
+ @NonNull final String[] defaultOverlays,
@NonNull final OverlayChangeListener listener) {
mPackageManager = packageManager;
mIdmapManager = idmapManager;
@@ -104,31 +104,27 @@
for (int i = 0; i < overlayPackagesSize; i++) {
final PackageInfo overlayPackage = overlayPackages.get(i);
final OverlayInfo oi = storedOverlayInfos.get(overlayPackage.packageName);
- if (oi == null || !oi.targetPackageName.equals(overlayPackage.overlayTarget)
- || !Objects.equals(oi.category, overlayPackage.overlayCategory)) {
- // Update the overlay if it didn't exist or had the wrong target package.
+ if (oi == null || !oi.targetPackageName.equals(overlayPackage.overlayTarget)) {
+ // Reset the overlay if it didn't exist or had the wrong target package.
mSettings.init(overlayPackage.packageName, newUserId,
overlayPackage.overlayTarget,
overlayPackage.applicationInfo.getBaseCodePath(),
- overlayPackage.isStaticOverlayPackage(), overlayPackage.overlayPriority,
+ overlayPackage.isStaticOverlayPackage(),
+ overlayPackage.overlayPriority,
overlayPackage.overlayCategory);
- if (oi == null) {
- // This overlay does not exist in our settings.
- if (overlayPackage.isStaticOverlayPackage() ||
- mDefaultOverlays.contains(overlayPackage.packageName)) {
- // Enable this overlay by default.
- if (DEBUG) {
- Slog.d(TAG, "Enabling overlay " + overlayPackage.packageName
- + " for user " + newUserId + " by default");
- }
- mSettings.setEnabled(overlayPackage.packageName, newUserId, true);
- }
- } else {
+ if (oi != null) {
// The targetPackageName we have stored doesn't match the overlay's target.
// Queue the old target for an update as well.
packagesToUpdateAssets.add(oi.targetPackageName);
}
+ } else {
+ // Update all other components of an overlay that don't require a hard reset.
+ if (!Objects.equals(oi.category, overlayPackage.overlayCategory)) {
+ // When changing categories, it is ok just to update our internal state.
+ mSettings.setCategory(overlayPackage.packageName, newUserId,
+ overlayPackage.overlayCategory);
+ }
}
try {
@@ -160,6 +156,42 @@
iter.remove();
}
}
+
+ // Collect all of the categories in which we have at least one overlay enabled.
+ final ArraySet<String> enabledCategories = new ArraySet<>();
+ final ArrayMap<String, List<OverlayInfo>> userOverlays =
+ mSettings.getOverlaysForUser(newUserId);
+ final int userOverlayTargetCount = userOverlays.size();
+ for (int i = 0; i < userOverlayTargetCount; i++) {
+ final List<OverlayInfo> overlayList = userOverlays.valueAt(i);
+ final int overlayCount = overlayList != null ? overlayList.size() : 0;
+ for (int j = 0; j < overlayCount; j++) {
+ final OverlayInfo oi = overlayList.get(j);
+ if (oi.isEnabled()) {
+ enabledCategories.add(oi.category);
+ }
+ }
+ }
+
+ // Enable the default overlay if its category does not have a single overlay enabled.
+ for (final String defaultOverlay : mDefaultOverlays) {
+ try {
+ final OverlayInfo oi = mSettings.getOverlayInfo(defaultOverlay, newUserId);
+ if (!enabledCategories.contains(oi.category)) {
+ Slog.w(TAG, "Enabling default overlay '" + defaultOverlay + "' for target '"
+ + oi.targetPackageName + "' in category '" + oi.category + "' for user "
+ + newUserId);
+ mSettings.setEnabled(oi.packageName, newUserId, true);
+ if (updateState(oi.targetPackageName, oi.packageName, newUserId, 0)) {
+ packagesToUpdateAssets.add(oi.targetPackageName);
+ }
+ }
+ } catch (OverlayManagerSettings.BadKeyException e) {
+ Slog.e(TAG, "Failed to set default overlay '" + defaultOverlay + "' for user "
+ + newUserId, e);
+ }
+ }
+
return new ArrayList<>(packagesToUpdateAssets);
}
@@ -325,6 +357,11 @@
mSettings.init(packageName, userId, pkg.overlayTarget,
pkg.applicationInfo.getBaseCodePath(), pkg.isStaticOverlayPackage(),
pkg.overlayPriority, pkg.overlayCategory);
+ } else {
+ if (!Objects.equals(oldOi.category, pkg.overlayCategory)) {
+ // Update the category in-place.
+ mSettings.setCategory(packageName, userId, pkg.overlayCategory);
+ }
}
if (updateState(pkg.overlayTarget, packageName, userId, 0)) {
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index e57fa0b..0b9412b 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -20,6 +20,7 @@
import static com.android.server.om.OverlayManagerService.TAG;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.om.OverlayInfo;
import android.util.ArrayMap;
import android.util.Slog;
@@ -39,6 +40,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -70,6 +72,9 @@
new SettingsItem(packageName, userId, targetPackageName, baseCodePath,
isStatic, priority, overlayCategory);
if (isStatic) {
+ // All static overlays are always enabled.
+ item.setEnabled(true);
+
int i;
for (i = mItems.size() - 1; i >= 0; i--) {
SettingsItem parentItem = mItems.get(i);
@@ -122,6 +127,15 @@
return mItems.get(idx).setBaseCodePath(path);
}
+ boolean setCategory(@NonNull final String packageName, final int userId,
+ @Nullable String category) throws BadKeyException {
+ final int idx = select(packageName, userId);
+ if (idx < 0) {
+ throw new BadKeyException(packageName, userId);
+ }
+ return mItems.get(idx).setCategory(category);
+ }
+
boolean getEnabled(@NonNull final String packageName, final int userId) throws BadKeyException {
final int idx = select(packageName, userId);
if (idx < 0) {
@@ -420,7 +434,7 @@
private OverlayInfo mCache;
private boolean mIsStatic;
private int mPriority;
- private final String mCategory;
+ private String mCategory;
SettingsItem(@NonNull final String packageName, final int userId,
@NonNull final String targetPackageName, @NonNull final String baseCodePath,
@@ -431,7 +445,7 @@
mTargetPackageName = targetPackageName;
mBaseCodePath = baseCodePath;
mState = state;
- mIsEnabled = isEnabled;
+ mIsEnabled = isEnabled || isStatic;
mCategory = category;
mCache = null;
mIsStatic = isStatic;
@@ -483,7 +497,11 @@
return mIsEnabled;
}
- private boolean setEnabled(final boolean enable) {
+ private boolean setEnabled(boolean enable) {
+ if (mIsStatic) {
+ return false;
+ }
+
if (mIsEnabled != enable) {
mIsEnabled = enable;
invalidateCache();
@@ -492,6 +510,15 @@
return false;
}
+ private boolean setCategory(String category) {
+ if (!Objects.equals(mCategory, category)) {
+ mCategory = category.intern();
+ invalidateCache();
+ return true;
+ }
+ return false;
+ }
+
private OverlayInfo getOverlayInfo() {
if (mCache == null) {
mCache = new OverlayInfo(mPackageName, mTargetPackageName, mCategory, mBaseCodePath,
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 7a5a6c5..e40dc4f 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2655,6 +2655,11 @@
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
break;
+ case TYPE_DREAM:
+ // Dreams don't have an app window token and can thus not be letterboxed.
+ // Hence always let them extend under the cutout.
+ attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+ break;
case TYPE_STATUS_BAR:
// If the Keyguard is in a hidden state (occluded by another window), we force to
@@ -5244,9 +5249,7 @@
final boolean attachedInParent = attached != null && !layoutInScreen;
// Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
// the cutout safe zone.
- // Windows that are attached to a parent and laid out in said parent are already avoiding
- // the cutout according to that parent and don't need to be further constrained.
- if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS && !attachedInParent) {
+ if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
final Rect displayCutoutSafeExceptMaybeTop = mTmpRect;
displayCutoutSafeExceptMaybeTop.set(displayFrames.mDisplayCutoutSafe);
if (layoutInScreen && layoutInsetDecor && !requestedFullscreen
@@ -5257,7 +5260,14 @@
// the window from that area.
displayCutoutSafeExceptMaybeTop.top = Integer.MIN_VALUE;
}
- pf.intersectUnchecked(displayCutoutSafeExceptMaybeTop);
+ // Windows that are attached to a parent and laid out in said parent are already
+ // avoidingthe cutout according to that parent and don't need to be further constrained.
+ if (!attachedInParent) {
+ pf.intersectUnchecked(displayCutoutSafeExceptMaybeTop);
+ }
+ // Make sure that NO_LIMITS windows clipped to the display don't extend into the display
+ // don't extend under the cutout.
+ df.intersectUnchecked(displayCutoutSafeExceptMaybeTop);
}
// Content should never appear in the cutout.
@@ -6695,7 +6705,7 @@
mWindowManagerDrawComplete = false;
mScreenOnListener = screenOnListener;
- if (mKeyguardDelegate != null) {
+ if (mKeyguardDelegate != null && mKeyguardDelegate.hasKeyguard()) {
mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT,
getKeyguardDrawnTimeout());
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 18f4a3c..58e8f77 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -242,6 +242,10 @@
return false;
}
+ public boolean hasKeyguard() {
+ return mKeyguardState.deviceHasKeyguard;
+ }
+
public boolean isInputRestricted() {
if (mKeyguardService != null) {
mKeyguardState.inputRestricted = mKeyguardService.isInputRestricted();
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index efcadad..941cd44 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -19,8 +19,6 @@
import android.app.ActivityManager;
import android.content.Context;
import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.security.IKeystoreService;
import android.util.Slog;
import com.android.internal.policy.IKeyguardService;
@@ -53,16 +51,11 @@
private final LockPatternUtils mLockPatternUtils;
private final StateCallback mCallback;
- IKeystoreService mKeystoreService;
-
public KeyguardStateMonitor(Context context, IKeyguardService service, StateCallback callback) {
mLockPatternUtils = new LockPatternUtils(context);
mCurrentUserId = ActivityManager.getCurrentUser();
mCallback = callback;
- mKeystoreService = IKeystoreService.Stub.asInterface(ServiceManager
- .getService("android.security.keystore"));
-
try {
service.addStateMonitorCallback(this);
} catch (RemoteException e) {
@@ -93,12 +86,6 @@
@Override // Binder interface
public void onShowingStateChanged(boolean showing) {
mIsShowing = showing;
-
- if (showing) try {
- mKeystoreService.lock(mCurrentUserId); // as long as this doesn't recur...
- } catch (RemoteException e) {
- Slog.e(TAG, "Error locking keystore", e);
- }
}
@Override // Binder interface
diff --git a/services/core/java/com/android/server/slice/PinnedSliceState.java b/services/core/java/com/android/server/slice/PinnedSliceState.java
index 8da16d7..f9a4ea2 100644
--- a/services/core/java/com/android/server/slice/PinnedSliceState.java
+++ b/services/core/java/com/android/server/slice/PinnedSliceState.java
@@ -16,7 +16,6 @@
import static android.app.slice.SliceManager.PERMISSION_GRANTED;
-import android.app.slice.ISliceListener;
import android.app.slice.Slice;
import android.app.slice.SliceProvider;
import android.app.slice.SliceSpec;
@@ -106,10 +105,6 @@
setSlicePinned(false);
}
- public void onChange() {
- mService.getHandler().post(this::handleBind);
- }
-
private void setSlicePinned(boolean pinned) {
synchronized (mLock) {
if (mSlicePinned == pinned) return;
@@ -122,45 +117,23 @@
}
}
- public void addSliceListener(ISliceListener listener, String pkg, SliceSpec[] specs,
- boolean hasPermission) {
+ public void pin(String pkg, SliceSpec[] specs, IBinder token) {
synchronized (mLock) {
- if (mListeners.size() == 0) {
- mService.listen(mUri);
- }
+ mListeners.put(token, new ListenerInfo(token, pkg, true,
+ Binder.getCallingUid(), Binder.getCallingPid()));
try {
- listener.asBinder().linkToDeath(mDeathRecipient, 0);
+ token.linkToDeath(mDeathRecipient, 0);
} catch (RemoteException e) {
}
- mListeners.put(listener.asBinder(), new ListenerInfo(listener, pkg, hasPermission,
- Binder.getCallingUid(), Binder.getCallingPid()));
mergeSpecs(specs);
- setSlicePinned(hasPermission);
- }
- }
-
- public boolean removeSliceListener(ISliceListener listener) {
- synchronized (mLock) {
- listener.asBinder().unlinkToDeath(mDeathRecipient, 0);
- if (mListeners.containsKey(listener.asBinder()) && mListeners.size() == 1) {
- mService.unlisten(mUri);
- }
- mListeners.remove(listener.asBinder());
- }
- return !hasPinOrListener();
- }
-
- public void pin(String pkg, SliceSpec[] specs) {
- synchronized (mLock) {
setSlicePinned(true);
- mPinnedPkgs.add(pkg);
- mergeSpecs(specs);
}
}
- public boolean unpin(String pkg) {
+ public boolean unpin(String pkg, IBinder token) {
synchronized (mLock) {
- mPinnedPkgs.remove(pkg);
+ token.unlinkToDeath(mDeathRecipient, 0);
+ mListeners.remove(token);
}
return !hasPinOrListener();
}
@@ -171,30 +144,6 @@
}
}
- public void recheckPackage(String pkg) {
- synchronized (mLock) {
- for (int i = 0; i < mListeners.size(); i++) {
- ListenerInfo info = mListeners.valueAt(i);
- if (!info.hasPermission && Objects.equals(info.pkg, pkg)) {
- mService.getHandler().post(() -> {
- // This bind lets the app itself participate in the permission grant.
- Slice s = doBind(info);
- if (mService.checkAccess(info.pkg, mUri, info.callingUid, info.callingPid)
- == PERMISSION_GRANTED) {
- info.hasPermission = true;
- setSlicePinned(true);
- try {
- info.listener.onSliceUpdated(s);
- } catch (RemoteException e) {
- checkSelfRemove();
- }
- }
- });
- }
- }
- }
- }
-
@VisibleForTesting
public boolean hasPinOrListener() {
synchronized (mLock) {
@@ -213,7 +162,6 @@
private void checkSelfRemove() {
if (!hasPinOrListener()) {
// All the listeners died, remove from pinned state.
- mService.unlisten(mUri);
mService.removePinnedSlice(mUri);
}
}
@@ -223,7 +171,7 @@
synchronized (mLock) {
for (int i = mListeners.size() - 1; i >= 0; i--) {
ListenerInfo l = mListeners.valueAt(i);
- if (!l.listener.asBinder().isBinderAlive()) {
+ if (!l.token.isBinderAlive()) {
mListeners.removeAt(i);
}
}
@@ -231,62 +179,6 @@
}
}
- private void handleBind() {
- Slice cachedSlice = doBind(null);
- synchronized (mLock) {
- if (!hasPinOrListener()) return;
- for (int i = mListeners.size() - 1; i >= 0; i--) {
- ListenerInfo info = mListeners.valueAt(i);
- Slice s = cachedSlice;
- if (s == null || s.hasHint(Slice.HINT_CALLER_NEEDED)
- || !info.hasPermission) {
- s = doBind(info);
- }
- if (s == null) {
- mListeners.removeAt(i);
- continue;
- }
- try {
- info.listener.onSliceUpdated(s);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to notify slice " + mUri, e);
- mListeners.removeAt(i);
- continue;
- }
- }
- checkSelfRemove();
- }
- }
-
- private Slice doBind(ListenerInfo info) {
- try (ContentProviderClient client = getClient()) {
- if (client == null) return null;
- Bundle extras = new Bundle();
- extras.putParcelable(SliceProvider.EXTRA_BIND_URI, mUri);
- extras.putParcelableArrayList(SliceProvider.EXTRA_SUPPORTED_SPECS,
- new ArrayList<>(Arrays.asList(mSupportedSpecs)));
- if (info != null) {
- extras.putString(SliceProvider.EXTRA_OVERRIDE_PKG, info.pkg);
- extras.putInt(SliceProvider.EXTRA_OVERRIDE_UID, info.callingUid);
- extras.putInt(SliceProvider.EXTRA_OVERRIDE_PID, info.callingPid);
- }
- final Bundle res;
- try {
- res = client.call(SliceProvider.METHOD_SLICE, null, extras);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to bind slice " + mUri, e);
- return null;
- }
- if (res == null) return null;
- Bundle.setDefusable(res, true);
- return res.getParcelable(SliceProvider.EXTRA_SLICE);
- } catch (Throwable t) {
- // Calling out of the system process, make sure they don't throw anything at us.
- Log.e(TAG, "Caught throwable while binding " + mUri, t);
- return null;
- }
- }
-
private void handleSendPinned() {
try (ContentProviderClient client = getClient()) {
if (client == null) return;
@@ -315,15 +207,15 @@
private class ListenerInfo {
- private ISliceListener listener;
+ private IBinder token;
private String pkg;
private boolean hasPermission;
private int callingUid;
private int callingPid;
- public ListenerInfo(ISliceListener listener, String pkg, boolean hasPermission,
+ public ListenerInfo(IBinder token, String pkg, boolean hasPermission,
int callingUid, int callingPid) {
- this.listener = listener;
+ this.token = token;
this.pkg = pkg;
this.hasPermission = hasPermission;
this.callingUid = callingUid;
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index a1def44..51e4709 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -28,7 +28,6 @@
import android.app.AppOpsManager;
import android.app.ContentProviderHolder;
import android.app.IActivityManager;
-import android.app.slice.ISliceListener;
import android.app.slice.ISliceManager;
import android.app.slice.SliceManager;
import android.app.slice.SliceSpec;
@@ -39,7 +38,6 @@
import android.content.IntentFilter;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
-import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
@@ -52,7 +50,6 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
-import android.util.Log;
import android.util.Slog;
import android.util.Xml.Encoding;
@@ -94,7 +91,6 @@
@GuardedBy("mLock")
private final ArraySet<SliceGrant> mUserGrants = new ArraySet<>();
private final Handler mHandler;
- private final ContentObserver mObserver;
@GuardedBy("mSliceAccessFile")
private final AtomicFile mSliceAccessFile;
@GuardedBy("mAccessList")
@@ -113,16 +109,6 @@
mAssistUtils = new AssistUtils(context);
mHandler = new Handler(looper);
- mObserver = new ContentObserver(mHandler) {
- @Override
- public void onChange(boolean selfChange, Uri uri, int userId) {
- try {
- getPinnedSlice(maybeAddUserId(uri, userId)).onChange();
- } catch (IllegalStateException e) {
- Log.e(TAG, "Received change for unpinned slice " + uri, e);
- }
- }
- };
final File systemDir = new File(Environment.getDataDirectory(), "system");
mSliceAccessFile = new AtomicFile(new File(systemDir, "slice_access.xml"));
mAccessList = new SliceFullAccessList(mContext);
@@ -163,40 +149,19 @@
/// ----- ISliceManager stuff -----
@Override
- public void addSliceListener(Uri uri, String pkg, ISliceListener listener, SliceSpec[] specs)
- throws RemoteException {
+ public void pinSlice(String pkg, Uri uri, SliceSpec[] specs, IBinder token) throws RemoteException {
verifyCaller(pkg);
+ enforceAccess(pkg, uri);
uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
- enforceCrossUser(pkg, uri);
- getOrCreatePinnedSlice(uri).addSliceListener(listener, pkg, specs,
- checkAccess(pkg, uri, Binder.getCallingUid(), Binder.getCallingUid())
- == PERMISSION_GRANTED);
+ getOrCreatePinnedSlice(uri).pin(pkg, specs, token);
}
@Override
- public void removeSliceListener(Uri uri, String pkg, ISliceListener listener)
- throws RemoteException {
+ public void unpinSlice(String pkg, Uri uri, IBinder token) throws RemoteException {
verifyCaller(pkg);
+ enforceAccess(pkg, uri);
uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
- if (getPinnedSlice(uri).removeSliceListener(listener)) {
- removePinnedSlice(uri);
- }
- }
-
- @Override
- public void pinSlice(String pkg, Uri uri, SliceSpec[] specs) throws RemoteException {
- verifyCaller(pkg);
- enforceFullAccess(pkg, "pinSlice", uri);
- uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
- getOrCreatePinnedSlice(uri).pin(pkg, specs);
- }
-
- @Override
- public void unpinSlice(String pkg, Uri uri) throws RemoteException {
- verifyCaller(pkg);
- enforceFullAccess(pkg, "unpinSlice", uri);
- uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
- if (getPinnedSlice(uri).unpin(pkg)) {
+ if (getPinnedSlice(uri).unpin(pkg, token)) {
removePinnedSlice(uri);
}
}
@@ -253,11 +218,6 @@
} finally {
Binder.restoreCallingIdentity(ident);
}
- synchronized (mLock) {
- for (PinnedSliceState p : mPinnedSlicesByUri.values()) {
- p.recheckPackage(pkg);
- }
- }
}
// Backup/restore interface
@@ -457,21 +417,6 @@
return cn.getPackageName().equals(pkg);
}
- public void listen(Uri uri) {
- mContext.getContentResolver().registerContentObserver(uri, true, mObserver);
- }
-
- public void unlisten(Uri uri) {
- mContext.getContentResolver().unregisterContentObserver(mObserver);
- synchronized (mLock) {
- mPinnedSlicesByUri.forEach((u, s) -> {
- if (s.isListening()) {
- listen(u);
- }
- });
- }
- }
-
private boolean isDefaultHomeApp(String pkg, int userId) {
String defaultHome = getDefaultHome(userId);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 13357b8..75a6338 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1211,7 +1211,7 @@
if (rotation == ROTATION_0) {
return cutout.computeSafeInsets(mInitialDisplayWidth, mInitialDisplayHeight);
}
- final boolean rotated = (rotation == ROTATION_90 || mRotation == ROTATION_270);
+ final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
final Path bounds = cutout.getBounds().getBoundaryPath();
transformPhysicalToLogicalCoordinates(rotation, mInitialDisplayWidth, mInitialDisplayHeight,
mTmpMatrix);
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 5c8fadb..46c59c5 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -242,7 +242,7 @@
final int appWidth = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, rotation,
baseConfig.uiMode, displayId, displayCutout);
final int appHeight = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, rotation,
- baseConfig.uiMode, displayId, mDisplayContent.getDisplayInfo().displayCutout);
+ baseConfig.uiMode, displayId, displayCutout);
mService.mPolicy.getNonDecorInsetsLw(rotation, dw, dh, displayCutout, mTmpRect);
final int leftInset = mTmpRect.left;
final int topInset = mTmpRect.top;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 7d970d9..2e86351 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -687,11 +687,12 @@
pw.println(doublePrefix + "mTempInsetBounds=" + mTempInsetBounds.toShortString());
final String triplePrefix = doublePrefix + " ";
+ final String quadruplePrefix = triplePrefix + " ";
for (int i = mChildren.size() - 1; i >= 0; i--) {
final AppWindowToken wtoken = mChildren.get(i);
pw.println(triplePrefix + "Activity #" + i + " " + wtoken);
- wtoken.dump(pw, triplePrefix, dumpAll);
+ wtoken.dump(pw, quadruplePrefix, dumpAll);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 26ac79e..be1aa46 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -50,6 +50,7 @@
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
@@ -1913,6 +1914,11 @@
// No move or resize, but the controller checks for title changes as well
mAccessibilityController.onSomeWindowResizedOrMovedLocked();
}
+
+ if ((flagChanges & PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
+ updateNonSystemOverlayWindowsVisibilityIfNeeded(
+ win, win.mWinAnimator.getShown());
+ }
}
if (DEBUG_LAYOUT) Slog.v(TAG_WM, "Relayout " + win + ": viewVisibility=" + viewVisibility
@@ -1960,15 +1966,36 @@
win.setDisplayLayoutNeeded();
win.mGivenInsetsPending = (flags & WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
- // We may be deferring layout passes at the moment, but since the client is interested
- // in the new out values right now we need to force a layout.
- mWindowPlacerLocked.performSurfacePlacement(true /* force */);
-
// We should only relayout if the view is visible, it is a starting window, or the
// associated appToken is not hidden.
final boolean shouldRelayout = viewVisibility == View.VISIBLE &&
- (win.mAppToken == null || win.mAttrs.type == TYPE_APPLICATION_STARTING
- || !win.mAppToken.isClientHidden());
+ (win.mAppToken == null || win.mAttrs.type == TYPE_APPLICATION_STARTING
+ || !win.mAppToken.isClientHidden());
+
+ // If we are not currently running the exit animation, we need to see about starting
+ // one.
+ // We don't want to animate visibility of windows which are pending replacement.
+ // In the case of activity relaunch child windows could request visibility changes as
+ // they are detached from the main application window during the tear down process.
+ // If we satisfied these visibility changes though, we would cause a visual glitch
+ // hiding the window before it's replacement was available. So we just do nothing on
+ // our side.
+ // This must be called before the call to performSurfacePlacement.
+ if (!shouldRelayout && winAnimator.hasSurface() && !win.mAnimatingExit) {
+ if (DEBUG_VISIBILITY) {
+ Slog.i(TAG_WM,
+ "Relayout invis " + win + ": mAnimatingExit=" + win.mAnimatingExit);
+ }
+ result |= RELAYOUT_RES_SURFACE_CHANGED;
+ if (!win.mWillReplaceWindow) {
+ focusMayChange = tryStartExitingAnimation(win, winAnimator, isDefaultDisplay,
+ focusMayChange);
+ }
+ }
+
+ // We may be deferring layout passes at the moment, but since the client is interested
+ // in the new out values right now we need to force a layout.
+ mWindowPlacerLocked.performSurfacePlacement(true /* force */);
if (shouldRelayout) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_1");
@@ -2001,24 +2028,6 @@
winAnimator.mEnterAnimationPending = false;
winAnimator.mEnteringAnimation = false;
- if (winAnimator.hasSurface() && !win.mAnimatingExit) {
- if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Relayout invis " + win
- + ": mAnimatingExit=" + win.mAnimatingExit);
- // If we are not currently running the exit animation, we
- // need to see about starting one.
- // We don't want to animate visibility of windows which are pending
- // replacement. In the case of activity relaunch child windows
- // could request visibility changes as they are detached from the main
- // application window during the tear down process. If we satisfied
- // these visibility changes though, we would cause a visual glitch
- // hiding the window before it's replacement was available.
- // So we just do nothing on our side.
- if (!win.mWillReplaceWindow) {
- focusMayChange = tryStartExitingAnimation(
- win, winAnimator, isDefaultDisplay, focusMayChange);
- }
- result |= RELAYOUT_RES_SURFACE_CHANGED;
- }
if (viewVisibility == View.VISIBLE && winAnimator.hasSurface()) {
// We already told the client to go invisible, but the message may not be
// handled yet, or it might want to draw a last frame. If we already have a
@@ -7397,7 +7406,8 @@
}
void updateNonSystemOverlayWindowsVisibilityIfNeeded(WindowState win, boolean surfaceShown) {
- if (!win.hideNonSystemOverlayWindowsWhenVisible()) {
+ if (!win.hideNonSystemOverlayWindowsWhenVisible()
+ && !mHidingNonSystemOverlayWindows.contains(win)) {
return;
}
final boolean systemAlertWindowsHidden = !mHidingNonSystemOverlayWindows.isEmpty();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index d24b3ee..5b5de0e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1088,8 +1088,8 @@
traceBeginAndSlog("StartNetworkPolicyManagerService");
try {
- networkPolicy = new NetworkPolicyManagerService(context,
- mActivityManagerService, networkStats, networkManagement);
+ networkPolicy = new NetworkPolicyManagerService(context, mActivityManagerService,
+ networkManagement);
ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy);
} catch (Throwable e) {
reportWtf("starting NetworkPolicy Service", e);
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index d3a97b3..1f370a5 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -72,6 +72,7 @@
import java.util.List;
import java.util.Set;
import java.util.StringJoiner;
+import java.util.concurrent.CountDownLatch;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -100,6 +101,11 @@
/**
* Callbacks for handling IpClient events.
+ *
+ * These methods are called by IpClient on its own thread. Implementations
+ * of this class MUST NOT carry out long-running computations or hold locks
+ * for which there might be contention with other code calling public
+ * methods of the same IpClient instance.
*/
public static class Callback {
// In order to receive onPreDhcpAction(), call #withPreDhcpAction()
@@ -545,6 +551,7 @@
private final String mClatInterfaceName;
@VisibleForTesting
protected final Callback mCallback;
+ private final CountDownLatch mShutdownLatch;
private final INetworkManagementService mNwService;
private final NetlinkTracker mNetlinkTracker;
private final WakeupMessage mProvisioningTimeoutAlarm;
@@ -597,6 +604,7 @@
mInterfaceName = ifName;
mClatInterfaceName = CLAT_PREFIX + ifName;
mCallback = new LoggingCallbackWrapper(callback);
+ mShutdownLatch = new CountDownLatch(1);
mNwService = nwService;
mLog = new SharedLog(MAX_LOG_RECORDS, mTag);
@@ -704,6 +712,7 @@
@Override
protected void onQuitting() {
mCallback.onQuit();
+ mShutdownLatch.countDown();
}
// Shut down this IpClient instance altogether.
@@ -712,6 +721,17 @@
sendMessage(CMD_TERMINATE_AFTER_STOP);
}
+ // In order to avoid deadlock, this method MUST NOT be called on the
+ // IpClient instance's thread. This prohibition includes code executed by
+ // when methods on the passed-in IpClient.Callback instance are called.
+ public void awaitShutdown() {
+ try {
+ mShutdownLatch.await();
+ } catch (InterruptedException e) {
+ mLog.e("Interrupted while awaiting shutdown: " + e);
+ }
+ }
+
public static ProvisioningConfiguration.Builder buildProvisioningConfiguration() {
return new ProvisioningConfiguration.Builder();
}
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index 84c1bb2..3c09cb1 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -38,7 +38,6 @@
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Icon;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -236,15 +235,6 @@
return null;
}
- // Spin the spooler to add the job and show the config UI.
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... params) {
- mSpooler.createPrintJob(printJob);
- return null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
-
final long identity = Binder.clearCallingIdentity();
try {
Intent intent = new Intent(PrintManager.ACTION_PRINT_DIALOG);
diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk
index d825533..cd8163d 100644
--- a/services/robotests/Android.mk
+++ b/services/robotests/Android.mk
@@ -58,14 +58,14 @@
LOCAL_SRC_FILES := \
$(call all-java-files-under, src) \
$(call all-Iaidl-files-under, $(INTERNAL_BACKUP)) \
+ $(call all-java-files-under, ../../core/java/android/app/backup) \
+ $(call all-Iaidl-files-under, ../../core/java/android/app/backup) \
../../core/java/android/content/pm/PackageInfo.java \
- ../../core/java/android/app/backup/BackupAgent.java \
- ../../core/java/android/app/backup/BackupDataOutput.java \
- ../../core/java/android/app/backup/FullBackupDataOutput.java \
../../core/java/android/app/IBackupAgent.aidl
LOCAL_AIDL_INCLUDES := \
$(call all-Iaidl-files-under, $(INTERNAL_BACKUP)) \
+ $(call all-Iaidl-files-under, ../../core/java/android/app/backup) \
../../core/java/android/app/IBackupAgent.aidl
LOCAL_STATIC_JAVA_LIBRARIES := \
diff --git a/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java b/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
index d0e6658..60704e7 100644
--- a/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
+++ b/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
@@ -112,11 +112,8 @@
ShadowQueuedWork.class
}
)
-@SystemLoaderPackages({"com.android.server.backup"})
+@SystemLoaderPackages({"com.android.server.backup", "android.app.backup"})
@SystemLoaderClasses({
- BackupDataOutput.class,
- FullBackupDataOutput.class,
- BackupAgent.class,
IBackupTransport.class,
IBackupAgent.class,
PackageInfo.class
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index e1b4422..d31d550 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -26,6 +26,9 @@
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.uidPoliciesToString;
+import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.SET_ALL;
+import static android.net.NetworkStats.TAG_ALL;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
@@ -42,8 +45,6 @@
import static com.android.server.net.NetworkPolicyManagerService.TYPE_RAPID;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING;
-import static com.google.common.truth.Truth.assertThat;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -86,7 +87,6 @@
import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkPolicyListener;
-import android.net.INetworkStatsService;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
@@ -105,6 +105,7 @@
import android.os.PowerSaveState;
import android.os.RemoteException;
import android.os.SimpleClock;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
@@ -125,6 +126,7 @@
import com.android.internal.util.test.BroadcastInterceptingContext.FutureIntent;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.net.NetworkPolicyManagerService;
+import com.android.server.net.NetworkStatsManagerInternal;
import libcore.io.IoUtils;
import libcore.io.Streams;
@@ -214,7 +216,6 @@
private String mNetpolicyXml;
private @Mock IActivityManager mActivityManager;
- private @Mock INetworkStatsService mStatsService;
private @Mock INetworkManagementService mNetworkManager;
private @Mock IConnectivityManager mConnManager;
private @Mock NotificationManager mNotifManager;
@@ -224,7 +225,8 @@
private @Mock CarrierConfigManager mCarrierConfigManager;
private @Mock TelephonyManager mTelephonyManager;
- private static ActivityManagerInternal mActivityManagerInternal;
+ private ActivityManagerInternal mActivityManagerInternal;
+ private NetworkStatsManagerInternal mStatsService;
private IUidObserver mUidObserver;
private INetworkManagementEventObserver mNetworkObserver;
@@ -264,6 +266,8 @@
private static final int UID_F = UserHandle.getUid(USER_ID, APP_ID_F);
private static final String PKG_NAME_A = "name.is.A,pkg.A";
+ private static final String PKG_NAME_B = "name.is.B,pkg.B";
+ private static final String PKG_NAME_C = "name.is.C,pkg.C";
public final @Rule NetPolicyMethodRule mNetPolicyXmlRule = new NetPolicyMethodRule();
@@ -287,6 +291,8 @@
.setBatterySaverEnabled(false).build();
final PowerManagerInternal pmInternal = addLocalServiceMock(PowerManagerInternal.class);
when(pmInternal.getLowPowerState(anyInt())).thenReturn(state);
+
+ mStatsService = addLocalServiceMock(NetworkStatsManagerInternal.class);
}
@Before
@@ -347,7 +353,7 @@
eq(ActivityManager.PROCESS_STATE_UNKNOWN), isNull(String.class));
mFutureIntent = newRestrictBackgroundChangedFuture();
- mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, mStatsService,
+ mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager,
mNetworkManager, mIpm, mClock, mPolicyDir, true);
mService.bindConnectivityManager(mConnManager);
mPolicyListener = new NetworkPolicyListenerAnswer(mService);
@@ -375,6 +381,14 @@
when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
.thenReturn(new ApplicationInfo());
when(mPackageManager.getPackagesForUid(UID_A)).thenReturn(new String[] {PKG_NAME_A});
+ when(mPackageManager.getPackagesForUid(UID_B)).thenReturn(new String[] {PKG_NAME_B});
+ when(mPackageManager.getPackagesForUid(UID_C)).thenReturn(new String[] {PKG_NAME_C});
+ when(mPackageManager.getApplicationInfo(eq(PKG_NAME_A), anyInt()))
+ .thenReturn(buildApplicationInfo(PKG_NAME_A));
+ when(mPackageManager.getApplicationInfo(eq(PKG_NAME_B), anyInt()))
+ .thenReturn(buildApplicationInfo(PKG_NAME_B));
+ when(mPackageManager.getApplicationInfo(eq(PKG_NAME_C), anyInt()))
+ .thenReturn(buildApplicationInfo(PKG_NAME_C));
when(mNetworkManager.isBandwidthControlEnabled()).thenReturn(true);
when(mNetworkManager.setDataSaverModeEnabled(anyBoolean())).thenReturn(true);
@@ -409,6 +423,7 @@
LocalServices.removeServiceForTest(PowerManagerInternal.class);
LocalServices.removeServiceForTest(DeviceIdleController.LocalService.class);
LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
+ LocalServices.removeServiceForTest(NetworkStatsManagerInternal.class);
}
@After
@@ -515,7 +530,7 @@
mService.updateRestrictBackgroundByLowPowerModeUL(stateOn);
// RestrictBackground should be on even though battery saver want to turn it off
- assertThat(mService.getRestrictBackground()).isTrue();
+ assertTrue(mService.getRestrictBackground());
PowerSaveState stateOff = new PowerSaveState.Builder()
.setGlobalBatterySaverEnabled(false)
@@ -524,7 +539,7 @@
mService.updateRestrictBackgroundByLowPowerModeUL(stateOff);
// RestrictBackground should be on, following its previous state
- assertThat(mService.getRestrictBackground()).isTrue();
+ assertTrue(mService.getRestrictBackground());
}
@Test
@@ -539,7 +554,7 @@
mService.updateRestrictBackgroundByLowPowerModeUL(stateOn);
// RestrictBackground should be turned on because of battery saver
- assertThat(mService.getRestrictBackground()).isTrue();
+ assertTrue(mService.getRestrictBackground());
PowerSaveState stateOff = new PowerSaveState.Builder()
.setGlobalBatterySaverEnabled(false)
@@ -548,7 +563,7 @@
mService.updateRestrictBackgroundByLowPowerModeUL(stateOff);
// RestrictBackground should be off, following its previous state
- assertThat(mService.getRestrictBackground()).isFalse();
+ assertFalse(mService.getRestrictBackground());
}
@Test
@@ -562,7 +577,7 @@
mService.updateRestrictBackgroundByLowPowerModeUL(stateOn);
// RestrictBackground should still be on
- assertThat(mService.getRestrictBackground()).isTrue();
+ assertTrue(mService.getRestrictBackground());
// User turns off RestrictBackground manually
setRestrictBackground(false);
@@ -571,7 +586,7 @@
mService.updateRestrictBackgroundByLowPowerModeUL(stateOff);
// RestrictBackground should be off because user changes it manually
- assertThat(mService.getRestrictBackground()).isFalse();
+ assertFalse(mService.getRestrictBackground());
}
private void removeRestrictBackgroundWhitelist(boolean expectIntent) throws Exception {
@@ -974,6 +989,7 @@
public void testNotificationWarningLimitSnooze() throws Exception {
// Create a place to store fake usage
final NetworkStatsHistory history = new NetworkStatsHistory(TimeUnit.HOURS.toMillis(1));
+ final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong()))
.thenAnswer(new Answer<Long>() {
@Override
@@ -983,6 +999,13 @@
return entry.rxBytes + entry.txBytes;
}
});
+ when(mStatsService.getNetworkUidBytes(any(), anyLong(), anyLong()))
+ .thenAnswer(new Answer<NetworkStats>() {
+ @Override
+ public NetworkStats answer(InvocationOnMock invocation) throws Throwable {
+ return stats;
+ }
+ });
// Get active mobile network in place
expectMobileDefaults();
@@ -1003,7 +1026,7 @@
// Normal usage means no notification
{
- history.removeBucketsBefore(Long.MAX_VALUE);
+ history.clear();
history.recordData(start, end,
new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(360), 0L, 0L, 0L, 0));
@@ -1020,7 +1043,7 @@
// Push over warning
{
- history.removeBucketsBefore(Long.MAX_VALUE);
+ history.clear();
history.recordData(start, end,
new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1799), 0L, 0L, 0L, 0));
@@ -1038,7 +1061,7 @@
// Push over limit
{
- history.removeBucketsBefore(Long.MAX_VALUE);
+ history.clear();
history.recordData(start, end,
new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1810), 0L, 0L, 0L, 0));
@@ -1073,6 +1096,7 @@
public void testNotificationRapid() throws Exception {
// Create a place to store fake usage
final NetworkStatsHistory history = new NetworkStatsHistory(TimeUnit.HOURS.toMillis(1));
+ final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong()))
.thenAnswer(new Answer<Long>() {
@Override
@@ -1082,6 +1106,13 @@
return entry.rxBytes + entry.txBytes;
}
});
+ when(mStatsService.getNetworkUidBytes(any(), anyLong(), anyLong()))
+ .thenAnswer(new Answer<NetworkStats>() {
+ @Override
+ public NetworkStats answer(InvocationOnMock invocation) throws Throwable {
+ return stats;
+ }
+ });
// Get active mobile network in place
expectMobileDefaults();
@@ -1102,7 +1133,7 @@
// Using 20% data in 20% time is normal
{
- history.removeBucketsBefore(Long.MAX_VALUE);
+ history.clear();
history.recordData(start, end,
new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(360), 0L, 0L, 0L, 0));
@@ -1111,16 +1142,58 @@
verify(mNotifManager, never()).notifyAsUser(any(), anyInt(), any(), any());
}
- // Using 80% data in 20% time is alarming
+ // Using 80% data in 20% time is alarming; but spread equally among
+ // three UIDs means we get generic alert
{
- history.removeBucketsBefore(Long.MAX_VALUE);
+ history.clear();
history.recordData(start, end,
new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1440), 0L, 0L, 0L, 0));
+ stats.clear();
+ stats.addValues(IFACE_ALL, UID_A, SET_ALL, TAG_ALL,
+ DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0);
+ stats.addValues(IFACE_ALL, UID_B, SET_ALL, TAG_ALL,
+ DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0);
+ stats.addValues(IFACE_ALL, UID_C, SET_ALL, TAG_ALL,
+ DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0);
reset(mNotifManager);
mService.updateNetworks();
+
+ final ArgumentCaptor<Notification> notif = ArgumentCaptor.forClass(Notification.class);
verify(mNotifManager, atLeastOnce()).notifyAsUser(any(), eq(TYPE_RAPID),
- isA(Notification.class), eq(UserHandle.ALL));
+ notif.capture(), eq(UserHandle.ALL));
+
+ final String text = notif.getValue().extras.getCharSequence(Notification.EXTRA_TEXT)
+ .toString();
+ assertFalse(text.contains(PKG_NAME_A));
+ assertFalse(text.contains(PKG_NAME_B));
+ assertFalse(text.contains(PKG_NAME_C));
+ }
+
+ // Using 80% data in 20% time is alarming; but mostly done by one UID
+ // means we get specific alert
+ {
+ history.clear();
+ history.recordData(start, end,
+ new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1440), 0L, 0L, 0L, 0));
+ stats.clear();
+ stats.addValues(IFACE_ALL, UID_A, SET_ALL, TAG_ALL,
+ DataUnit.MEGABYTES.toBytes(960), 0, 0, 0, 0);
+ stats.addValues(IFACE_ALL, UID_B, SET_ALL, TAG_ALL,
+ DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0);
+
+ reset(mNotifManager);
+ mService.updateNetworks();
+
+ final ArgumentCaptor<Notification> notif = ArgumentCaptor.forClass(Notification.class);
+ verify(mNotifManager, atLeastOnce()).notifyAsUser(any(), eq(TYPE_RAPID),
+ notif.capture(), eq(UserHandle.ALL));
+
+ final String text = notif.getValue().extras.getCharSequence(Notification.EXTRA_TEXT)
+ .toString();
+ assertTrue(text.contains(PKG_NAME_A));
+ assertFalse(text.contains(PKG_NAME_B));
+ assertFalse(text.contains(PKG_NAME_C));
}
}
@@ -1411,6 +1484,12 @@
true);
}
+ private ApplicationInfo buildApplicationInfo(String label) {
+ final ApplicationInfo ai = new ApplicationInfo();
+ ai.nonLocalizedLabel = label;
+ return ai;
+ }
+
private NetworkInfo buildNetworkInfo() {
final NetworkInfo ni = new NetworkInfo(ConnectivityManager.TYPE_MOBILE,
TelephonyManager.NETWORK_TYPE_LTE, null, null);
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 d3df924..5161114 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -22,6 +22,8 @@
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.view.Display.DEFAULT_DISPLAY;
+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.INITIALIZING;
import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
@@ -119,20 +121,20 @@
}
return null;
}).when(mActivity.app.thread).scheduleTransaction(any());
- mActivity.state = STOPPED;
+ mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
mActivity.makeVisibleIfNeeded(null /* starting */);
- assertEquals(mActivity.state, PAUSING);
+ assertTrue(mActivity.isState(PAUSING));
assertTrue(pauseFound.value);
// Make sure that the state does not change for current non-stopping states.
- mActivity.state = INITIALIZING;
+ mActivity.setState(INITIALIZING, "testPausingWhenVisibleFromStopped");
mActivity.makeVisibleIfNeeded(null /* starting */);
- assertEquals(mActivity.state, INITIALIZING);
+ assertTrue(mActivity.isState(INITIALIZING));
}
@Test
@@ -197,7 +199,23 @@
record.canBeLaunchedOnDisplay(DEFAULT_DISPLAY);
- verify(mService.mStackSupervisor, times(1)).canPlaceEntityOnDisplay(anyInt(), eq(expected), anyInt(), anyInt(),
- eq(record.info));
+ verify(mService.mStackSupervisor, times(1)).canPlaceEntityOnDisplay(anyInt(), eq(expected),
+ anyInt(), anyInt(), eq(record.info));
+ }
+
+ @Test
+ public void testFinishingAfterDestroying() throws Exception {
+ assertFalse(mActivity.finishing);
+ mActivity.setState(DESTROYING, "testFinishingAfterDestroying");
+ assertTrue(mActivity.isState(DESTROYING));
+ assertTrue(mActivity.finishing);
+ }
+
+ @Test
+ public void testFinishingAfterDestroyed() throws Exception {
+ assertFalse(mActivity.finishing);
+ mActivity.setState(DESTROYED, "testFinishingAfterDestroyed");
+ assertTrue(mActivity.isState(DESTROYED));
+ assertTrue(mActivity.finishing);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/appops/AppOpsServiceTest.java b/services/tests/servicestests/src/com/android/server/appops/AppOpsServiceTest.java
new file mode 100644
index 0000000..ad21a78
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/appops/AppOpsServiceTest.java
@@ -0,0 +1,228 @@
+/*
+ * 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;
+
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_ERRORED;
+import static android.app.AppOpsManager.OP_READ_SMS;
+import static android.app.AppOpsManager.OP_WRITE_SMS;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.app.AppOpsManager.OpEntry;
+import android.app.AppOpsManager.PackageOps;
+import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * Unit tests for AppOpsService. Covers functionality that is difficult to test using CTS tests
+ * or for which we can write more detailed unit tests than CTS tests (because the internal APIs are
+ * more finegrained data than the public ones).
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AppOpsServiceTest {
+
+ private static final String TAG = AppOpsServiceTest.class.getSimpleName();
+ // State will be persisted into this XML file.
+ private static final String APP_OPS_FILENAME = "appops-service-test.xml";
+
+ private File mAppOpsFile;
+ private Context mContext;
+ private Handler mHandler;
+ private AppOpsService mAppOpsService;
+ private String mMyPackageName;
+ private int mMyUid;
+ private long mTestStartMillis;
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mAppOpsFile = new File(mContext.getFilesDir(), APP_OPS_FILENAME);
+ if (mAppOpsFile.exists()) {
+ // Start with a clean state (persisted into XML).
+ mAppOpsFile.delete();
+ }
+
+ HandlerThread handlerThread = new HandlerThread(TAG);
+ handlerThread.start();
+ mHandler = new Handler(handlerThread.getLooper());
+ mMyPackageName = mContext.getOpPackageName();
+ mMyUid = Process.myUid();
+
+ mAppOpsService = new AppOpsService(mAppOpsFile, mHandler);
+ mAppOpsService.mContext = mContext;
+ mTestStartMillis = System.currentTimeMillis();
+ }
+
+ @Test
+ public void testGetOpsForPackage_noOpsLogged() {
+ assertThat(getLoggedOps()).isNull();
+ }
+
+ @Test
+ public void testNoteOperationAndGetOpsForPackage() {
+ mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
+ mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, mMyPackageName, MODE_ERRORED);
+
+ // Note an op that's allowed.
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
+ List<PackageOps> loggedOps = getLoggedOps();
+ assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
+
+ // Note another op that's not allowed.
+ mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, mMyPackageName);
+ loggedOps = getLoggedOps();
+ assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
+ assertContainsOp(loggedOps, OP_WRITE_SMS, -1, mTestStartMillis, MODE_ERRORED);
+ }
+
+ // Tests the dumping and restoring of the in-memory state to/from XML.
+ @Test
+ public void testStatePersistence() {
+ mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
+ mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, mMyPackageName, MODE_ERRORED);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
+ mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, mMyPackageName);
+ mAppOpsService.writeState();
+
+ // Create a new app ops service, and initialize its state from XML.
+ mAppOpsService = new AppOpsService(mAppOpsFile, mHandler);
+ mAppOpsService.mContext = mContext;
+ mAppOpsService.readState();
+
+ // Query the state of the 2nd service.
+ List<PackageOps> loggedOps = getLoggedOps();
+ assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
+ assertContainsOp(loggedOps, OP_WRITE_SMS, -1, mTestStartMillis, MODE_ERRORED);
+ }
+
+ // Tests that ops are persisted during shutdown.
+ @Test
+ public void testShutdown() {
+ mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
+ mAppOpsService.shutdown();
+
+ // Create a new app ops service, and initialize its state from XML.
+ mAppOpsService = new AppOpsService(mAppOpsFile, mHandler);
+ mAppOpsService.mContext = mContext;
+ mAppOpsService.readState();
+
+ // Query the state of the 2nd service.
+ List<PackageOps> loggedOps = getLoggedOps();
+ assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
+ }
+
+ @Test
+ public void testGetOpsForPackage() {
+ mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
+
+ // Query all ops
+ List<PackageOps> loggedOps = mAppOpsService.getOpsForPackage(
+ mMyUid, mMyPackageName, null /* all ops */);
+ assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
+
+ // Query specific ops
+ loggedOps = mAppOpsService.getOpsForPackage(
+ mMyUid, mMyPackageName, new int[]{OP_READ_SMS, OP_WRITE_SMS});
+ assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
+
+ // Query unknown UID
+ loggedOps = mAppOpsService.getOpsForPackage(mMyUid + 1, mMyPackageName, null /* all ops */);
+ assertThat(loggedOps).isNull();
+
+ // Query unknown package name
+ loggedOps = mAppOpsService.getOpsForPackage(mMyUid, "fake.package", null /* all ops */);
+ assertThat(loggedOps).isNull();
+
+ // Query op code that's not been logged
+ loggedOps = mAppOpsService.getOpsForPackage(mMyUid, mMyPackageName,
+ new int[]{OP_WRITE_SMS});
+ assertThat(loggedOps).isNull();
+ }
+
+ @Test
+ public void testPackageRemoved() {
+ mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
+
+ List<PackageOps> loggedOps = getLoggedOps();
+ assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
+
+ mAppOpsService.packageRemoved(mMyUid, mMyPackageName);
+ assertThat(getLoggedOps()).isNull();
+ }
+
+ @Test
+ public void testUidRemoved() {
+ mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
+
+ List<PackageOps> loggedOps = getLoggedOps();
+ assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
+
+ mAppOpsService.uidRemoved(mMyUid);
+ assertThat(getLoggedOps()).isNull();
+ }
+
+ private List<PackageOps> getLoggedOps() {
+ return mAppOpsService.getOpsForPackage(mMyUid, mMyPackageName, null /* all ops */);
+ }
+
+ private void assertContainsOp(List<PackageOps> loggedOps, int opCode, long minMillis,
+ long minRejectMillis, int mode) {
+
+ boolean opLogged = false;
+ for (PackageOps pkgOps : loggedOps) {
+ assertWithMessage("Unexpected UID").that(mMyUid).isEqualTo(pkgOps.getUid());
+ assertWithMessage("Unexpected package name").that(mMyPackageName).isEqualTo(
+ pkgOps.getPackageName());
+
+ for (OpEntry opEntry : pkgOps.getOps()) {
+ if (opCode != opEntry.getOp()) {
+ continue;
+ }
+ opLogged = true;
+
+ assertWithMessage("Unexpected mode").that(mode).isEqualTo(opEntry.getMode());
+ if (minMillis > 0) {
+ assertWithMessage("Unexpected timestamp")
+ .that(opEntry.getTime()).isAtLeast(minMillis);
+ }
+ if (minRejectMillis > 0) {
+ assertWithMessage("Unexpected rejection timestamp")
+ .that(opEntry.getRejectTime()).isAtLeast(minRejectMillis);
+ }
+ }
+ }
+ assertWithMessage("Op was not logged").that(opLogged).isTrue();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/servicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index 35cba18..8874894 100644
--- a/services/tests/servicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -33,12 +33,14 @@
import android.net.Network;
import android.net.NetworkCapabilities;
import android.os.Build;
+import android.os.Handler;
import android.os.SystemClock;
import android.support.test.runner.AndroidJUnit4;
import android.util.DataUnit;
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerService;
+import com.android.server.job.JobSchedulerService.Constants;
import org.junit.Before;
import org.junit.Test;
@@ -49,6 +51,8 @@
@RunWith(AndroidJUnit4.class)
public class ConnectivityControllerTest {
+ private Constants mConstants;
+
@Before
public void setUp() throws Exception {
// Assume all packages are current SDK
@@ -65,23 +69,26 @@
Clock.fixed(SystemClock.uptimeMillisClock().instant(), ZoneOffset.UTC);
JobSchedulerService.sElapsedRealtimeClock =
Clock.fixed(SystemClock.elapsedRealtimeClock().instant(), ZoneOffset.UTC);
+
+ // Assume default constants for now
+ mConstants = new Constants();
}
@Test
public void testInsane() throws Exception {
- final Network network = new Network(101);
+ final Network net = new Network(101);
final JobInfo.Builder job = createJob()
.setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
// Slow network is too slow
- assertFalse(ConnectivityController.isSatisfied(createJobStatus(job), network,
+ assertFalse(ConnectivityController.isSatisfied(createJobStatus(job), net,
createCapabilities().setLinkUpstreamBandwidthKbps(1)
- .setLinkDownstreamBandwidthKbps(1)));
+ .setLinkDownstreamBandwidthKbps(1), mConstants));
// Fast network looks great
- assertTrue(ConnectivityController.isSatisfied(createJobStatus(job), network,
+ assertTrue(ConnectivityController.isSatisfied(createJobStatus(job), net,
createCapabilities().setLinkUpstreamBandwidthKbps(1024)
- .setLinkDownstreamBandwidthKbps(1024)));
+ .setLinkDownstreamBandwidthKbps(1024), mConstants));
}
@Test
@@ -95,19 +102,19 @@
// Uncongested network is whenever
{
- final Network network = new Network(101);
- final NetworkCapabilities capabilities = createCapabilities()
+ final Network net = new Network(101);
+ final NetworkCapabilities caps = createCapabilities()
.addCapability(NET_CAPABILITY_NOT_CONGESTED);
- assertTrue(ConnectivityController.isSatisfied(early, network, capabilities));
- assertTrue(ConnectivityController.isSatisfied(late, network, capabilities));
+ assertTrue(ConnectivityController.isSatisfied(early, net, caps, mConstants));
+ assertTrue(ConnectivityController.isSatisfied(late, net, caps, mConstants));
}
// Congested network is more selective
{
- final Network network = new Network(101);
- final NetworkCapabilities capabilities = createCapabilities();
- assertFalse(ConnectivityController.isSatisfied(early, network, capabilities));
- assertTrue(ConnectivityController.isSatisfied(late, network, capabilities));
+ final Network net = new Network(101);
+ final NetworkCapabilities caps = createCapabilities();
+ assertFalse(ConnectivityController.isSatisfied(early, net, caps, mConstants));
+ assertTrue(ConnectivityController.isSatisfied(late, net, caps, mConstants));
}
}
@@ -126,25 +133,25 @@
// Unmetered network is whenever
{
- final Network network = new Network(101);
- final NetworkCapabilities capabilities = createCapabilities()
+ final Network net = new Network(101);
+ final NetworkCapabilities caps = createCapabilities()
.addCapability(NET_CAPABILITY_NOT_CONGESTED)
.addCapability(NET_CAPABILITY_NOT_METERED);
- assertTrue(ConnectivityController.isSatisfied(early, network, capabilities));
- assertTrue(ConnectivityController.isSatisfied(late, network, capabilities));
- assertTrue(ConnectivityController.isSatisfied(earlyPrefetch, network, capabilities));
- assertTrue(ConnectivityController.isSatisfied(latePrefetch, network, capabilities));
+ assertTrue(ConnectivityController.isSatisfied(early, net, caps, mConstants));
+ assertTrue(ConnectivityController.isSatisfied(late, net, caps, mConstants));
+ assertTrue(ConnectivityController.isSatisfied(earlyPrefetch, net, caps, mConstants));
+ assertTrue(ConnectivityController.isSatisfied(latePrefetch, net, caps, mConstants));
}
// Metered network is only when prefetching and late
{
- final Network network = new Network(101);
- final NetworkCapabilities capabilities = createCapabilities()
+ final Network net = new Network(101);
+ final NetworkCapabilities caps = createCapabilities()
.addCapability(NET_CAPABILITY_NOT_CONGESTED);
- assertFalse(ConnectivityController.isSatisfied(early, network, capabilities));
- assertFalse(ConnectivityController.isSatisfied(late, network, capabilities));
- assertFalse(ConnectivityController.isSatisfied(earlyPrefetch, network, capabilities));
- assertTrue(ConnectivityController.isSatisfied(latePrefetch, network, capabilities));
+ assertFalse(ConnectivityController.isSatisfied(early, net, caps, mConstants));
+ assertFalse(ConnectivityController.isSatisfied(late, net, caps, mConstants));
+ assertFalse(ConnectivityController.isSatisfied(earlyPrefetch, net, caps, mConstants));
+ assertTrue(ConnectivityController.isSatisfied(latePrefetch, net, caps, mConstants));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java
index 293f9af..c6800be 100644
--- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java
+++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java
@@ -77,6 +77,7 @@
assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mAppWindow.decorFrame, 0, 0);
+ assertInsetBy(mAppWindow.displayFrame, 0, 0, 0, 0);
}
@Test
@@ -91,6 +92,7 @@
assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mAppWindow.decorFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mAppWindow.displayFrame, 0, NAV_BAR_HEIGHT);
}
@Test
@@ -106,6 +108,7 @@
assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mAppWindow.decorFrame, 0, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mAppWindow.displayFrame, 0, NAV_BAR_HEIGHT);
}
@Test
@@ -130,6 +133,7 @@
assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mAppWindow.decorFrame, 0, 0);
+ assertInsetByTopBottom(mAppWindow.displayFrame, 0, 0);
}
@Test
@@ -146,6 +150,7 @@
assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mAppWindow.decorFrame, 0, 0);
+ assertInsetByTopBottom(mAppWindow.displayFrame, STATUS_BAR_HEIGHT, 0);
}
@Test
@@ -162,6 +167,7 @@
assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mAppWindow.decorFrame, 0, 0);
+ assertInsetBy(mAppWindow.displayFrame, 0, 0, 0, 0);
}
@Test
@@ -178,6 +184,7 @@
assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mAppWindow.decorFrame, 0, 0);
+ assertInsetByTopBottom(mAppWindow.displayFrame, STATUS_BAR_HEIGHT, 0);
}
@Test
@@ -195,6 +202,7 @@
assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mAppWindow.decorFrame, 0, 0);
+ assertInsetByTopBottom(mAppWindow.displayFrame, 0, 0);
}
@@ -212,6 +220,7 @@
assertInsetBy(mAppWindow.contentFrame,
DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
assertInsetBy(mAppWindow.decorFrame, 0, 0, 0, 0);
+ assertInsetBy(mAppWindow.displayFrame, DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
}
@Test
@@ -228,6 +237,7 @@
assertInsetBy(mAppWindow.contentFrame,
NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, DISPLAY_CUTOUT_HEIGHT, 0);
assertInsetBy(mAppWindow.decorFrame, 0, 0, 0, 0);
+ assertInsetBy(mAppWindow.displayFrame, 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
index cfd155e..1052e8f 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
@@ -71,6 +71,7 @@
private PinnedSliceState mPinnedSliceManager;
private IContentProvider mIContentProvider;
private ContentProvider mContentProvider;
+ private IBinder mToken = new Binder();
@Before
public void setup() {
@@ -108,7 +109,7 @@
TestableLooper.get(this).processAllMessages();
// When pinned for the first time, a pinned message should be sent.
- mPinnedSliceManager.pin("pkg", FIRST_SPECS);
+ mPinnedSliceManager.pin("pkg", FIRST_SPECS, mToken);
TestableLooper.get(this).processAllMessages();
verify(mIContentProvider).call(anyString(), eq(SliceProvider.METHOD_PIN), eq(null),
@@ -119,112 +120,27 @@
}
@Test
- public void testSendPinnedOnListen() throws RemoteException {
- TestableLooper.get(this).processAllMessages();
-
- // When a listener is added for the first time, a pinned message should be sent.
- ISliceListener listener = mock(ISliceListener.class);
- when(listener.asBinder()).thenReturn(new Binder());
-
- mPinnedSliceManager.addSliceListener(listener, mContext.getPackageName(), FIRST_SPECS,
- true);
- TestableLooper.get(this).processAllMessages();
-
- verify(mIContentProvider).call(anyString(), eq(SliceProvider.METHOD_PIN), eq(null),
- argThat(b -> {
- assertEquals(TEST_URI, b.getParcelable(SliceProvider.EXTRA_BIND_URI));
- return true;
- }));
- }
-
- @Test
- public void testNoSendPinnedWithoutPermission() throws RemoteException {
- TestableLooper.get(this).processAllMessages();
-
- // When a listener is added for the first time, a pinned message should be sent.
- ISliceListener listener = mock(ISliceListener.class);
- when(listener.asBinder()).thenReturn(new Binder());
-
- mPinnedSliceManager.addSliceListener(listener, mContext.getPackageName(), FIRST_SPECS,
- false);
- TestableLooper.get(this).processAllMessages();
-
- verify(mIContentProvider, never()).call(anyString(), eq(SliceProvider.METHOD_PIN), eq(null),
- any());
- }
-
- @Test
- public void testSendUnpinnedOnDestroy() throws RemoteException {
- TestableLooper.get(this).processAllMessages();
- clearInvocations(mIContentProvider);
-
- mPinnedSliceManager.pin("pkg", FIRST_SPECS);
- mPinnedSliceManager.destroy();
- TestableLooper.get(this).processAllMessages();
-
- verify(mIContentProvider).call(anyString(), eq(SliceProvider.METHOD_UNPIN), eq(null),
- argThat(b -> {
- assertEquals(TEST_URI, b.getParcelable(SliceProvider.EXTRA_BIND_URI));
- return true;
- }));
- }
-
- @Test
public void testPkgPin() {
assertFalse(mPinnedSliceManager.hasPinOrListener());
- mPinnedSliceManager.pin("pkg", FIRST_SPECS);
+ mPinnedSliceManager.pin("pkg", FIRST_SPECS, mToken);
assertTrue(mPinnedSliceManager.hasPinOrListener());
- assertTrue(mPinnedSliceManager.unpin("pkg"));
+ assertTrue(mPinnedSliceManager.unpin("pkg", mToken));
assertFalse(mPinnedSliceManager.hasPinOrListener());
}
@Test
public void testMultiPkgPin() {
+ IBinder t2 = new Binder();
assertFalse(mPinnedSliceManager.hasPinOrListener());
- mPinnedSliceManager.pin("pkg", FIRST_SPECS);
+ mPinnedSliceManager.pin("pkg", FIRST_SPECS, mToken);
assertTrue(mPinnedSliceManager.hasPinOrListener());
- mPinnedSliceManager.pin("pkg2", FIRST_SPECS);
+ mPinnedSliceManager.pin("pkg2", FIRST_SPECS, t2);
- assertFalse(mPinnedSliceManager.unpin("pkg"));
- assertTrue(mPinnedSliceManager.unpin("pkg2"));
- assertFalse(mPinnedSliceManager.hasPinOrListener());
- }
-
- @Test
- public void testListenerPin() {
- ISliceListener listener = mock(ISliceListener.class);
- when(listener.asBinder()).thenReturn(new Binder());
- assertFalse(mPinnedSliceManager.hasPinOrListener());
-
- mPinnedSliceManager.addSliceListener(listener, mContext.getPackageName(), FIRST_SPECS,
- true);
- assertTrue(mPinnedSliceManager.hasPinOrListener());
-
- assertTrue(mPinnedSliceManager.removeSliceListener(listener));
- assertFalse(mPinnedSliceManager.hasPinOrListener());
- }
-
- @Test
- public void testMultiListenerPin() {
- ISliceListener listener = mock(ISliceListener.class);
- Binder value = new Binder();
- when(listener.asBinder()).thenReturn(value);
- ISliceListener listener2 = mock(ISliceListener.class);
- Binder value2 = new Binder();
- when(listener2.asBinder()).thenReturn(value2);
- assertFalse(mPinnedSliceManager.hasPinOrListener());
-
- mPinnedSliceManager.addSliceListener(listener, mContext.getPackageName(), FIRST_SPECS,
- true);
- assertTrue(mPinnedSliceManager.hasPinOrListener());
- mPinnedSliceManager.addSliceListener(listener2, mContext.getPackageName(), FIRST_SPECS,
- true);
-
- assertFalse(mPinnedSliceManager.removeSliceListener(listener));
- assertTrue(mPinnedSliceManager.removeSliceListener(listener2));
+ assertFalse(mPinnedSliceManager.unpin("pkg", mToken));
+ assertTrue(mPinnedSliceManager.unpin("pkg2", t2));
assertFalse(mPinnedSliceManager.hasPinOrListener());
}
@@ -236,8 +152,7 @@
when(listener.asBinder()).thenReturn(binder);
assertFalse(mPinnedSliceManager.hasPinOrListener());
- mPinnedSliceManager.addSliceListener(listener, mContext.getPackageName(), FIRST_SPECS,
- true);
+ mPinnedSliceManager.pin(mContext.getPackageName(), FIRST_SPECS, binder);
assertTrue(mPinnedSliceManager.hasPinOrListener());
ArgumentCaptor<DeathRecipient> arg = ArgumentCaptor.forClass(DeathRecipient.class);
@@ -246,79 +161,7 @@
when(binder.isBinderAlive()).thenReturn(false);
arg.getValue().binderDied();
- verify(mSliceService).unlisten(eq(TEST_URI));
verify(mSliceService).removePinnedSlice(eq(TEST_URI));
assertFalse(mPinnedSliceManager.hasPinOrListener());
}
-
- @Test
- public void testPkgListenerPin() {
- ISliceListener listener = mock(ISliceListener.class);
- when(listener.asBinder()).thenReturn(new Binder());
- assertFalse(mPinnedSliceManager.hasPinOrListener());
-
- mPinnedSliceManager.addSliceListener(listener, mContext.getPackageName(), FIRST_SPECS,
- true);
- assertTrue(mPinnedSliceManager.hasPinOrListener());
- mPinnedSliceManager.pin("pkg", FIRST_SPECS);
-
- assertFalse(mPinnedSliceManager.removeSliceListener(listener));
- assertTrue(mPinnedSliceManager.unpin("pkg"));
- assertFalse(mPinnedSliceManager.hasPinOrListener());
- }
-
- @Test
- public void testBind() throws RemoteException {
- TestableLooper.get(this).processAllMessages();
- clearInvocations(mIContentProvider);
-
- ISliceListener listener = mock(ISliceListener.class);
- when(listener.asBinder()).thenReturn(new Binder());
- Slice s = new Slice.Builder(TEST_URI).build();
- Bundle b = new Bundle();
- b.putParcelable(SliceProvider.EXTRA_SLICE, s);
- when(mIContentProvider.call(anyString(), eq(SliceProvider.METHOD_SLICE), eq(null),
- any())).thenReturn(b);
-
- assertFalse(mPinnedSliceManager.hasPinOrListener());
-
- mPinnedSliceManager.addSliceListener(listener, mContext.getPackageName(), FIRST_SPECS,
- true);
-
- mPinnedSliceManager.onChange();
- TestableLooper.get(this).processAllMessages();
-
- verify(mIContentProvider).call(anyString(), eq(SliceProvider.METHOD_SLICE), eq(null),
- argThat(bundle -> {
- assertEquals(TEST_URI, bundle.getParcelable(SliceProvider.EXTRA_BIND_URI));
- return true;
- }));
- verify(listener).onSliceUpdated(eq(s));
- }
-
- @Test
- public void testRecheckPackage() throws RemoteException {
- TestableLooper.get(this).processAllMessages();
-
- ISliceListener listener = mock(ISliceListener.class);
- when(listener.asBinder()).thenReturn(new Binder());
-
- mPinnedSliceManager.addSliceListener(listener, mContext.getPackageName(), FIRST_SPECS,
- false);
- TestableLooper.get(this).processAllMessages();
-
- verify(mIContentProvider, never()).call(anyString(), eq(SliceProvider.METHOD_PIN), eq(null),
- any());
-
- when(mSliceService.checkAccess(any(), any(), anyInt(), anyInt()))
- .thenReturn(PERMISSION_GRANTED);
- mPinnedSliceManager.recheckPackage(mContext.getPackageName());
- TestableLooper.get(this).processAllMessages();
-
- verify(mIContentProvider).call(anyString(), eq(SliceProvider.METHOD_PIN), eq(null),
- argThat(b -> {
- assertEquals(TEST_URI, b.getParcelable(SliceProvider.EXTRA_BIND_URI));
- return true;
- }));
- }
}
\ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
index fe9ea7a..6fc3009 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
@@ -32,6 +32,8 @@
import android.app.slice.SliceSpec;
import android.content.pm.PackageManagerInternal;
import android.net.Uri;
+import android.os.Binder;
+import android.os.IBinder;
import android.os.RemoteException;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -59,6 +61,7 @@
private SliceManagerService mService;
private PinnedSliceState mCreatedSliceState;
+ private IBinder mToken = new Binder();
@Before
public void setup() {
@@ -77,43 +80,11 @@
}
@Test
- public void testAddListenerCreatesPinned() throws RemoteException {
- mService.addSliceListener(TEST_URI, "pkg", mock(ISliceListener.class), EMPTY_SPECS);
- verify(mService, times(1)).createPinnedSlice(eq(TEST_URI));
- }
-
- @Test
- public void testAddListenerCreatesOnePinned() throws RemoteException {
- mService.addSliceListener(TEST_URI, "pkg", mock(ISliceListener.class), EMPTY_SPECS);
- mService.addSliceListener(TEST_URI, "pkg", mock(ISliceListener.class), EMPTY_SPECS);
- verify(mService, times(1)).createPinnedSlice(eq(TEST_URI));
- }
-
- @Test
- public void testRemoveListenerDestroysPinned() throws RemoteException {
- ISliceListener listener = mock(ISliceListener.class);
- mService.addSliceListener(TEST_URI, "pkg", listener, EMPTY_SPECS);
-
- when(mCreatedSliceState.removeSliceListener(eq(listener))).thenReturn(false);
- mService.removeSliceListener(TEST_URI, "pkg", listener);
- verify(mCreatedSliceState, never()).destroy();
-
- when(mCreatedSliceState.removeSliceListener(eq(listener))).thenReturn(true);
- mService.removeSliceListener(TEST_URI, "pkg", listener);
- verify(mCreatedSliceState).destroy();
- }
-
- @Test(expected = IllegalStateException.class)
- public void testUnrecognizedThrows() throws RemoteException {
- mService.removeSliceListener(TEST_URI, "pkg", mock(ISliceListener.class));
- }
-
- @Test
public void testAddPinCreatesPinned() throws RemoteException {
doReturn("pkg").when(mService).getDefaultHome(anyInt());
- mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS);
- mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS);
+ mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS, mToken);
+ mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS, mToken);
verify(mService, times(1)).createPinnedSlice(eq(TEST_URI));
}
@@ -121,15 +92,11 @@
public void testRemovePinDestroysPinned() throws RemoteException {
doReturn("pkg").when(mService).getDefaultHome(anyInt());
- mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS);
+ mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS, mToken);
- when(mCreatedSliceState.unpin(eq("pkg"))).thenReturn(false);
- mService.unpinSlice("pkg", TEST_URI);
+ when(mCreatedSliceState.unpin(eq("pkg"), eq(mToken))).thenReturn(false);
+ mService.unpinSlice("pkg", TEST_URI, mToken);
verify(mCreatedSliceState, never()).destroy();
-
- when(mCreatedSliceState.unpin(eq("pkg"))).thenReturn(true);
- mService.unpinSlice("pkg", TEST_URI);
- verify(mCreatedSliceState).destroy();
}
}
\ No newline at end of file
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index f26c2ae..8e5a418 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -25,6 +25,7 @@
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
+import android.app.usage.AppStandbyInfo;
import android.app.usage.UsageStatsManager;
import android.os.SystemClock;
import android.util.ArrayMap;
@@ -37,8 +38,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.LocalServices;
-import com.android.server.job.JobSchedulerInternal;
import libcore.io.IoUtils;
@@ -53,8 +52,7 @@
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.ArrayList;
/**
* Keeps track of recent active state changes in apps.
@@ -384,14 +382,13 @@
return appUsageHistory.currentBucket;
}
- public Map<String, Integer> getAppStandbyBuckets(int userId, long elapsedRealtime,
- boolean appIdleEnabled) {
+ public ArrayList<AppStandbyInfo> getAppStandbyBuckets(int userId, boolean appIdleEnabled) {
ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
int size = userHistory.size();
- HashMap<String, Integer> buckets = new HashMap<>(size);
+ ArrayList<AppStandbyInfo> buckets = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
- buckets.put(userHistory.keyAt(i),
- appIdleEnabled ? userHistory.valueAt(i).currentBucket : STANDBY_BUCKET_ACTIVE);
+ buckets.add(new AppStandbyInfo(userHistory.keyAt(i),
+ appIdleEnabled ? userHistory.valueAt(i).currentBucket : STANDBY_BUCKET_ACTIVE));
}
return buckets;
}
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index c31809e..f40aa5b 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -33,6 +33,7 @@
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AppGlobals;
+import android.app.usage.AppStandbyInfo;
import android.app.usage.UsageStatsManager.StandbyBuckets;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
@@ -954,9 +955,9 @@
}
}
- public Map<String, Integer> getAppStandbyBuckets(int userId, long elapsedRealtime) {
+ public List<AppStandbyInfo> getAppStandbyBuckets(int userId) {
synchronized (mAppIdleLock) {
- return mAppIdleHistory.getAppStandbyBuckets(userId, elapsedRealtime, mAppIdleEnabled);
+ return mAppIdleHistory.getAppStandbyBuckets(userId, mAppIdleEnabled);
}
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 3b0fd1f..dedf967 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -20,6 +20,7 @@
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.IUidObserver;
+import android.app.usage.AppStandbyInfo;
import android.app.usage.ConfigurationStats;
import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageEvents;
@@ -758,7 +759,8 @@
}
@Override
- public Map getAppStandbyBuckets(String callingPackageName, int userId) {
+ public ParceledListSlice<AppStandbyInfo> getAppStandbyBuckets(String callingPackageName,
+ int userId) {
final int callingUid = Binder.getCallingUid();
try {
userId = ActivityManager.getService().handleIncomingUser(
@@ -773,15 +775,17 @@
}
final long token = Binder.clearCallingIdentity();
try {
- return mAppStandby.getAppStandbyBuckets(userId,
- SystemClock.elapsedRealtime());
+ final List<AppStandbyInfo> standbyBucketList =
+ mAppStandby.getAppStandbyBuckets(userId);
+ return (standbyBucketList == null) ? ParceledListSlice.emptyList()
+ : new ParceledListSlice<>(standbyBucketList);
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
- public void setAppStandbyBuckets(Map appBuckets, int userId) {
+ public void setAppStandbyBuckets(ParceledListSlice appBuckets, int userId) {
getContext().enforceCallingPermission(Manifest.permission.CHANGE_APP_IDLE_STATE,
"No permission to change app standby state");
@@ -800,10 +804,10 @@
final long token = Binder.clearCallingIdentity();
try {
final long elapsedRealtime = SystemClock.elapsedRealtime();
- Map<String, Integer> buckets = (Map<String, Integer>) appBuckets;
- for (Map.Entry<String, Integer> entry: buckets.entrySet()) {
- String packageName = entry.getKey();
- int bucket = entry.getValue();
+ List<AppStandbyInfo> bucketList = appBuckets.getList();
+ for (AppStandbyInfo bucketInfo : bucketList) {
+ final String packageName = bucketInfo.mPackageName;
+ final int bucket = bucketInfo.mStandbyBucket;
if (bucket < UsageStatsManager.STANDBY_BUCKET_ACTIVE
|| bucket > UsageStatsManager.STANDBY_BUCKET_NEVER) {
throw new IllegalArgumentException(
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index ec12da2..8afc511 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -24,6 +24,7 @@
import android.content.res.Configuration;
import android.os.SystemClock;
import android.content.Context;
+import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -474,25 +475,25 @@
mDatabase.checkinDailyFiles(new UsageStatsDatabase.CheckinAction() {
@Override
public boolean checkin(IntervalStats stats) {
- printIntervalStats(pw, stats, false, null);
+ printIntervalStats(pw, stats, true, null);
return true;
}
});
}
void dump(IndentingPrintWriter pw, String pkg) {
- // This is not a check-in, only dump in-memory stats.
+ printLast24HrEvents(pw, true, pkg);
for (int interval = 0; interval < mCurrentStats.length; interval++) {
pw.print("In-memory ");
pw.print(intervalToString(interval));
pw.println(" stats");
- printIntervalStats(pw, mCurrentStats[interval], true, pkg);
+ printIntervalStats(pw, mCurrentStats[interval], false, pkg);
}
}
private String formatDateTime(long dateTime, boolean pretty) {
if (pretty) {
- return "\"" + DateUtils.formatDateTime(mContext, dateTime, sDateFormatFlags) + "\"";
+ return "\"" + DateFormat.format("yyyy-MM-dd HH:mm:ss", dateTime).toString() + "\"";
}
return Long.toString(dateTime);
}
@@ -504,8 +505,82 @@
return Long.toString(elapsedTime);
}
+
+ void printEvent(IndentingPrintWriter pw, UsageEvents.Event event, boolean prettyDates) {
+ pw.printPair("time", formatDateTime(event.mTimeStamp, prettyDates));
+ pw.printPair("type", eventToString(event.mEventType));
+ pw.printPair("package", event.mPackage);
+ if (event.mClass != null) {
+ pw.printPair("class", event.mClass);
+ }
+ if (event.mConfiguration != null) {
+ pw.printPair("config", Configuration.resourceQualifierString(event.mConfiguration));
+ }
+ if (event.mShortcutId != null) {
+ pw.printPair("shortcutId", event.mShortcutId);
+ }
+ if (event.mEventType == UsageEvents.Event.STANDBY_BUCKET_CHANGED) {
+ pw.printPair("standbyBucket", event.mBucket);
+ }
+ pw.printHexPair("flags", event.mFlags);
+ pw.println();
+ }
+
+ void printLast24HrEvents(IndentingPrintWriter pw, boolean prettyDates, final String pkg) {
+ final long endTime = System.currentTimeMillis();
+ UnixCalendar yesterday = new UnixCalendar(endTime);
+ yesterday.addDays(-1);
+
+ final long beginTime = yesterday.getTimeInMillis();
+
+ List<UsageEvents.Event> events = queryStats(UsageStatsManager.INTERVAL_DAILY,
+ beginTime, endTime, new StatCombiner<UsageEvents.Event>() {
+ @Override
+ public void combine(IntervalStats stats, boolean mutable,
+ List<UsageEvents.Event> 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;
+ }
+
+ UsageEvents.Event event = stats.events.valueAt(i);
+ if (pkg != null && !pkg.equals(event.mPackage)) {
+ continue;
+ }
+ accumulatedResult.add(event);
+ }
+ }
+ });
+
+ pw.print("Last 24 hour events (");
+ if (prettyDates) {
+ pw.printPair("timeRange", "\"" + DateUtils.formatDateRange(mContext,
+ beginTime, endTime, sDateFormatFlags) + "\"");
+ } else {
+ pw.printPair("beginTime", beginTime);
+ pw.printPair("endTime", endTime);
+ }
+ pw.println(")");
+ pw.increaseIndent();
+ for (UsageEvents.Event event : events) {
+ printEvent(pw, event, prettyDates);
+ }
+ pw.decreaseIndent();
+ }
+
void printIntervalStats(IndentingPrintWriter pw, IntervalStats stats,
- boolean prettyDates, String pkg) {
+ boolean checkin, String pkg) {
+ boolean prettyDates = !checkin;
if (prettyDates) {
pw.printPair("timeRange", "\"" + DateUtils.formatDateRange(mContext,
stats.beginTime, stats.endTime, sDateFormatFlags) + "\"");
@@ -578,35 +653,23 @@
pw.decreaseIndent();
}
- pw.println("events");
- pw.increaseIndent();
- final TimeSparseArray<UsageEvents.Event> events = stats.events;
- final int eventCount = events != null ? events.size() : 0;
- for (int i = 0; i < eventCount; i++) {
- final UsageEvents.Event event = events.valueAt(i);
- if (pkg != null && !pkg.equals(event.mPackage)) {
- continue;
+ // The last 24 hours of events is already printed in the non checkin dump
+ // No need to repeat here.
+ if (checkin) {
+ pw.println("events");
+ pw.increaseIndent();
+ final TimeSparseArray<UsageEvents.Event> events = stats.events;
+ final int eventCount = events != null ? events.size() : 0;
+ for (int i = 0; i < eventCount; i++) {
+ final UsageEvents.Event event = events.valueAt(i);
+ if (pkg != null && !pkg.equals(event.mPackage)) {
+ continue;
+ }
+ printEvent(pw, event, prettyDates);
}
- pw.printPair("time", formatDateTime(event.mTimeStamp, prettyDates));
- pw.printPair("type", eventToString(event.mEventType));
- pw.printPair("package", event.mPackage);
- if (event.mClass != null) {
- pw.printPair("class", event.mClass);
- }
- if (event.mConfiguration != null) {
- pw.printPair("config", Configuration.resourceQualifierString(event.mConfiguration));
- }
- if (event.mShortcutId != null) {
- pw.printPair("shortcutId", event.mShortcutId);
- }
- if (event.mEventType == UsageEvents.Event.STANDBY_BUCKET_CHANGED) {
- pw.printPair("standbyBucket", event.mBucket);
- }
- pw.printHexPair("flags", event.mFlags);
- pw.println();
+ pw.decreaseIndent();
}
pw.decreaseIndent();
- pw.decreaseIndent();
}
private static String intervalToString(int interval) {
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 63263bd..e7f0cc2 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -2732,6 +2732,7 @@
* This should be spread to other technologies,
* but is currently only used for LTE (14) and eHRPD (13).
* <P>Type: INTEGER</P>
+ * @deprecated this column is no longer supported, use {@link #NETWORK_TYPE_BITMASK} instead
*/
@Deprecated
public static final String BEARER = "bearer";
@@ -2744,13 +2745,14 @@
* Bitmask for a radio tech R is (1 << (R - 1))
* <P>Type: INTEGER</P>
* @hide
+ * @deprecated this column is no longer supported, use {@link #NETWORK_TYPE_BITMASK} instead
*/
@Deprecated
public static final String BEARER_BITMASK = "bearer_bitmask";
/**
* Radio technology (network type) bitmask.
- * To check what values can be contained, refer to
+ * To check what values can be contained, refer to the NETWORK_TYPE_ constants in
* {@link android.telephony.TelephonyManager}.
* Bitmask for a radio tech R is (1 << (R - 1))
* <P>Type: INTEGER</P>
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index ec348df..b6be3c5 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -178,7 +178,6 @@
/**
* Number of radio technologies for GSM, UMTS and CDMA.
- * @hide
*/
private static final int NEXT_RIL_RADIO_TECHNOLOGY = 20;
@@ -340,6 +339,8 @@
mIsEmergencyOnly = s.mIsEmergencyOnly;
mIsDataRoamingFromRegistration = s.mIsDataRoamingFromRegistration;
mIsUsingCarrierAggregation = s.mIsUsingCarrierAggregation;
+ mChannelNumber = s.mChannelNumber;
+ mCellBandwidths = Arrays.copyOf(s.mCellBandwidths, s.mCellBandwidths.length);
mLteEarfcnRsrpBoost = s.mLteEarfcnRsrpBoost;
mNetworkRegistrationStates = new ArrayList<>(s.mNetworkRegistrationStates);
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 28f8122..2aea1d7 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -914,8 +914,10 @@
mock(INetworkPolicyManager.class),
mock(IpConnectivityLog.class));
- mService.systemReady();
+ // Create local CM before sending system ready so that we can answer
+ // getSystemService() correctly.
mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService);
+ mService.systemReady();
mCm.bindProcessToNetwork(null);
// Ensure that the default setting for Captive Portals is used for most tests
@@ -3412,8 +3414,10 @@
@Test
public void testNetworkCallbackMaximum() {
- final int MAX_REQUESTS = 100;
- final int CALLBACKS = 90;
+ // We can only have 99 callbacks, because MultipathPolicyTracker is
+ // already one of them.
+ final int MAX_REQUESTS = 99;
+ final int CALLBACKS = 89;
final int INTENTS = 10;
assertEquals(MAX_REQUESTS, CALLBACKS + INTENTS);
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index b1b05e8..49b2643 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -95,6 +95,7 @@
import com.android.internal.net.VpnInfo;
import com.android.internal.util.test.BroadcastInterceptingContext;
+import com.android.server.LocalServices;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;
@@ -221,6 +222,9 @@
@After
public void tearDown() throws Exception {
+ // Registered by NetworkStatsService's constructor.
+ LocalServices.removeServiceForTest(NetworkStatsManagerInternal.class);
+
IoUtils.deleteContents(mStatsDir);
mServiceContext = null;