Merge "Add data_stall_event.proto to atom.proto"
diff --git a/Android.bp b/Android.bp
index e3bc07b..980aa04 100644
--- a/Android.bp
+++ b/Android.bp
@@ -104,6 +104,11 @@
"core/java/android/app/backup/IRestoreObserver.aidl",
"core/java/android/app/backup/IRestoreSession.aidl",
"core/java/android/app/backup/ISelectBackupTransportCallback.aidl",
+ "core/java/android/app/contentsuggestions/IClassificationsCallback.aidl",
+ "core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl",
+ "core/java/android/app/contentsuggestions/ISelectionsCallback.aidl",
+ "core/java/android/app/prediction/IPredictionCallback.aidl",
+ "core/java/android/app/prediction/IPredictionManager.aidl",
"core/java/android/app/role/IOnRoleHoldersChangedListener.aidl",
"core/java/android/app/role/IRoleManager.aidl",
"core/java/android/app/role/IRoleManagerCallback.aidl",
@@ -273,6 +278,7 @@
"core/java/android/rolecontrollerservice/IRoleControllerService.aidl",
":keystore_aidl",
"core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl",
+ "core/java/android/service/appprediction/IPredictionService.aidl",
"core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl",
"core/java/android/service/autofill/augmented/IFillCallback.aidl",
"core/java/android/service/autofill/IAutoFillService.aidl",
@@ -282,6 +288,7 @@
"core/java/android/service/carrier/ICarrierService.aidl",
"core/java/android/service/carrier/ICarrierMessagingCallback.aidl",
"core/java/android/service/carrier/ICarrierMessagingService.aidl",
+ "core/java/android/service/contentsuggestions/IContentSuggestionsService.aidl",
"core/java/android/service/euicc/IDeleteSubscriptionCallback.aidl",
"core/java/android/service/euicc/IDownloadSubscriptionCallback.aidl",
"core/java/android/service/euicc/IEraseSubscriptionsCallback.aidl",
@@ -593,7 +600,7 @@
"telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl",
"telephony/java/com/android/internal/telephony/ISms.aidl",
"telephony/java/com/android/internal/telephony/ISub.aidl",
- "telephony/java/com/android/internal/telephony/IAns.aidl",
+ "telephony/java/com/android/internal/telephony/IOns.aidl",
"telephony/java/com/android/internal/telephony/ITelephony.aidl",
"telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl",
"telephony/java/com/android/internal/telephony/IWapPushManager.aidl",
@@ -746,6 +753,7 @@
"android.hardware.radio-V1.3-java",
"android.hardware.radio-V1.4-java",
"android.hardware.usb.gadget-V1.0-java",
+ "networkstack-aidl-interfaces-java",
"netd_aidl_interface-java",
"devicepolicyprotosnano",
],
@@ -875,12 +883,14 @@
srcs: [
"core/java/android/net/INetworkMonitor.aidl",
"core/java/android/net/INetworkMonitorCallbacks.aidl",
+ "core/java/android/net/IIpMemoryStore.aidl",
"core/java/android/net/INetworkStackConnector.aidl",
"core/java/android/net/INetworkStackStatusCallback.aidl",
"core/java/android/net/PrivateDnsConfigParcel.aidl",
"core/java/android/net/dhcp/DhcpServingParamsParcel.aidl",
"core/java/android/net/dhcp/IDhcpServer.aidl",
"core/java/android/net/dhcp/IDhcpServerCallbacks.aidl",
+ "core/java/android/net/ipmemorystore/**/*.aidl",
],
api_dir: "aidl/networkstack",
}
diff --git a/api/current.txt b/api/current.txt
index c9e5e1d..584aedf 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7379,7 +7379,9 @@
method public boolean isRoleHeld(java.lang.String);
field public static final java.lang.String ROLE_BROWSER = "android.app.role.BROWSER";
field public static final java.lang.String ROLE_DIALER = "android.app.role.DIALER";
+ field public static final java.lang.String ROLE_EMERGENCY = "android.app.role.EMERGENCY";
field public static final java.lang.String ROLE_GALLERY = "android.app.role.GALLERY";
+ field public static final java.lang.String ROLE_HOME = "android.app.role.HOME";
field public static final java.lang.String ROLE_MUSIC = "android.app.role.MUSIC";
field public static final java.lang.String ROLE_SMS = "android.app.role.SMS";
}
@@ -26076,6 +26078,46 @@
field public static final int URI_COLUMN_INDEX = 2; // 0x2
}
+ public final class Session2Command implements android.os.Parcelable {
+ ctor public Session2Command(int);
+ ctor public Session2Command(java.lang.String, android.os.Bundle);
+ method public int describeContents();
+ method public int getCommandCode();
+ method public java.lang.String getCustomCommand();
+ method public android.os.Bundle getExtras();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int COMMAND_CODE_CUSTOM = 0; // 0x0
+ field public static final android.os.Parcelable.Creator<android.media.Session2Command> CREATOR;
+ field public static final int RESULT_ERROR_UNKNOWN_ERROR = -1; // 0xffffffff
+ field public static final int RESULT_INFO_SKIPPED = 1; // 0x1
+ field public static final int RESULT_SUCCESS = 0; // 0x0
+ }
+
+ public static final class Session2Command.Result {
+ ctor public Session2Command.Result(int, android.os.Bundle);
+ method public int getResultCode();
+ method public android.os.Bundle getResultData();
+ }
+
+ public final class Session2CommandGroup implements android.os.Parcelable {
+ method public int describeContents();
+ method public java.util.Set<android.media.Session2Command> getCommands();
+ method public boolean hasCommand(android.media.Session2Command);
+ method public boolean hasCommand(int);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.media.Session2CommandGroup> CREATOR;
+ }
+
+ public static final class Session2CommandGroup.Builder {
+ ctor public Session2CommandGroup.Builder();
+ ctor public Session2CommandGroup.Builder(android.media.Session2CommandGroup);
+ method public android.media.Session2CommandGroup.Builder addCommand(android.media.Session2Command);
+ method public android.media.Session2CommandGroup.Builder addCommand(int);
+ method public android.media.Session2CommandGroup build();
+ method public android.media.Session2CommandGroup.Builder removeCommand(android.media.Session2Command);
+ method public android.media.Session2CommandGroup.Builder removeCommand(int);
+ }
+
public class SoundPool {
ctor public deprecated SoundPool(int, int, int);
method public final void autoPause();
@@ -27121,6 +27163,21 @@
package android.media.session {
+ public final class ControllerCallbackLink implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.os.IBinder getBinder();
+ method public void notifyEvent(java.lang.String, android.os.Bundle);
+ method public void notifyExtrasChanged(android.os.Bundle);
+ method public void notifyMetadataChanged(android.media.MediaMetadata);
+ method public void notifyPlaybackStateChanged(android.media.session.PlaybackState);
+ method public void notifyQueueChanged(java.util.List<android.media.session.MediaSession.QueueItem>);
+ method public void notifyQueueTitleChanged(java.lang.CharSequence);
+ method public void notifySessionDestroyed();
+ method public void notifyVolumeInfoChanged(android.media.session.MediaController.PlaybackInfo);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.media.session.ControllerCallbackLink> CREATOR;
+ }
+
public final class MediaController {
ctor public MediaController(android.content.Context, android.media.session.MediaSession.Token);
method public void adjustVolume(int, int);
@@ -27355,6 +27412,36 @@
method public android.media.session.PlaybackState.CustomAction.Builder setExtras(android.os.Bundle);
}
+ public final class SessionCallbackLink implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.os.IBinder getBinder();
+ method public void notifyAdjustVolume(java.lang.String, int, int, android.media.session.ControllerCallbackLink, int);
+ method public void notifyCommand(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+ method public void notifyCustomAction(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle);
+ method public void notifyFastForward(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
+ method public void notifyMediaButton(java.lang.String, int, int, android.content.Intent, int, android.os.ResultReceiver);
+ method public void notifyMediaButtonFromController(java.lang.String, int, int, android.media.session.ControllerCallbackLink, android.content.Intent);
+ method public void notifyNext(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
+ method public void notifyPause(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
+ method public void notifyPlay(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
+ method public void notifyPlayFromMediaId(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle);
+ method public void notifyPlayFromSearch(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle);
+ method public void notifyPlayFromUri(java.lang.String, int, int, android.media.session.ControllerCallbackLink, android.net.Uri, android.os.Bundle);
+ method public void notifyPrepare(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
+ method public void notifyPrepareFromMediaId(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle);
+ method public void notifyPrepareFromSearch(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle);
+ method public void notifyPrepareFromUri(java.lang.String, int, int, android.media.session.ControllerCallbackLink, android.net.Uri, android.os.Bundle);
+ method public void notifyPrevious(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
+ method public void notifyRate(java.lang.String, int, int, android.media.session.ControllerCallbackLink, android.media.Rating);
+ method public void notifyRewind(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
+ method public void notifySeekTo(java.lang.String, int, int, android.media.session.ControllerCallbackLink, long);
+ method public void notifySetVolumeTo(java.lang.String, int, int, android.media.session.ControllerCallbackLink, int);
+ method public void notifySkipToTrack(java.lang.String, int, int, android.media.session.ControllerCallbackLink, long);
+ method public void notifyStop(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.media.session.SessionCallbackLink> CREATOR;
+ }
+
}
package android.media.tv {
@@ -29415,7 +29502,7 @@
field public java.lang.String SSID;
field public java.util.BitSet allowedAuthAlgorithms;
field public java.util.BitSet allowedGroupCiphers;
- field public java.util.BitSet allowedGroupMgmtCiphers;
+ field public java.util.BitSet allowedGroupManagementCiphers;
field public java.util.BitSet allowedKeyManagement;
field public java.util.BitSet allowedPairwiseCiphers;
field public java.util.BitSet allowedProtocols;
@@ -29682,9 +29769,6 @@
method public void setReferenceCounted(boolean);
}
- public static abstract class WifiManager.NetworkSuggestionsStatusCode implements java.lang.annotation.Annotation {
- }
-
public class WifiManager.WifiLock {
method public void acquire();
method public boolean isHeld();
@@ -30006,7 +30090,8 @@
method public android.net.wifi.p2p.WifiP2pConfig build();
method public android.net.wifi.p2p.WifiP2pConfig.Builder enablePersistentMode(boolean);
method public android.net.wifi.p2p.WifiP2pConfig.Builder setDeviceAddress(android.net.MacAddress);
- method public android.net.wifi.p2p.WifiP2pConfig.Builder setGroupOwnerBand(int);
+ method public android.net.wifi.p2p.WifiP2pConfig.Builder setGroupOperatingBand(int);
+ method public android.net.wifi.p2p.WifiP2pConfig.Builder setGroupOperatingFrequency(int);
method public android.net.wifi.p2p.WifiP2pConfig.Builder setNetworkName(java.lang.String);
method public android.net.wifi.p2p.WifiP2pConfig.Builder setPassphrase(java.lang.String);
}
@@ -34374,6 +34459,8 @@
method public java.util.ArrayList<java.lang.String> createStringArrayList();
method public <T> T[] createTypedArray(android.os.Parcelable.Creator<T>);
method public <T> java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>);
+ method public <T extends android.os.Parcelable> android.util.ArrayMap<java.lang.String, T> createTypedArrayMap(android.os.Parcelable.Creator<T>);
+ method public <T extends android.os.Parcelable> android.util.SparseArray<T> createTypedSparseArray(android.os.Parcelable.Creator<T>);
method public int dataAvail();
method public int dataCapacity();
method public int dataPosition();
@@ -34415,7 +34502,7 @@
method public java.io.Serializable readSerializable();
method public android.util.Size readSize();
method public android.util.SizeF readSizeF();
- method public android.util.SparseArray readSparseArray(java.lang.ClassLoader);
+ method public <T> android.util.SparseArray<T> readSparseArray(java.lang.ClassLoader);
method public android.util.SparseBooleanArray readSparseBooleanArray();
method public java.lang.String readString();
method public void readStringArray(java.lang.String[]);
@@ -34461,7 +34548,7 @@
method public void writeSerializable(java.io.Serializable);
method public void writeSize(android.util.Size);
method public void writeSizeF(android.util.SizeF);
- method public void writeSparseArray(android.util.SparseArray<java.lang.Object>);
+ method public <T> void writeSparseArray(android.util.SparseArray<T>);
method public void writeSparseBooleanArray(android.util.SparseBooleanArray);
method public void writeString(java.lang.String);
method public void writeStringArray(java.lang.String[]);
@@ -34469,8 +34556,10 @@
method public void writeStrongBinder(android.os.IBinder);
method public void writeStrongInterface(android.os.IInterface);
method public <T extends android.os.Parcelable> void writeTypedArray(T[], int);
+ method public <T extends android.os.Parcelable> void writeTypedArrayMap(android.util.ArrayMap<java.lang.String, T>, int);
method public <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>);
method public <T extends android.os.Parcelable> void writeTypedObject(T, int);
+ method public <T extends android.os.Parcelable> void writeTypedSparseArray(android.util.SparseArray<T>, int);
method public void writeValue(java.lang.Object);
field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR;
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 354a9c4..a4b3978 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -86,11 +86,13 @@
field public static final java.lang.String MANAGE_ACCESSIBILITY = "android.permission.MANAGE_ACCESSIBILITY";
field public static final java.lang.String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
field public static final java.lang.String MANAGE_APP_OPS_RESTRICTIONS = "android.permission.MANAGE_APP_OPS_RESTRICTIONS";
+ field public static final java.lang.String MANAGE_APP_PREDICTIONS = "android.permission.MANAGE_APP_PREDICTIONS";
field public static final java.lang.String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
field public static final java.lang.String MANAGE_AUTO_FILL = "android.permission.MANAGE_AUTO_FILL";
field public static final java.lang.String MANAGE_CARRIER_OEM_UNLOCK_STATE = "android.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE";
field public static final java.lang.String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES";
field public static final java.lang.String MANAGE_CONTENT_CAPTURE = "android.permission.MANAGE_CONTENT_CAPTURE";
+ field public static final java.lang.String MANAGE_CONTENT_SUGGESTIONS = "android.permission.MANAGE_CONTENT_SUGGESTIONS";
field public static final java.lang.String MANAGE_DEBUGGING = "android.permission.MANAGE_DEBUGGING";
field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
field public static final java.lang.String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
@@ -284,10 +286,11 @@
}
public class AppOpsManager {
- method public java.util.List<android.app.AppOpsManager.HistoricalPackageOps> getAllHistoricPackagesOps(java.lang.String[], long, long);
- method public android.app.AppOpsManager.HistoricalPackageOps getHistoricalPackagesOps(int, java.lang.String, java.lang.String[], long, long);
+ method public void getHistoricalOps(int, java.lang.String, java.lang.String[], long, long, java.util.concurrent.Executor, java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
method public static java.lang.String[] getOpStrs();
- method public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, java.lang.String, int[]);
+ method public deprecated java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, java.lang.String, int[]);
+ method public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, java.lang.String, java.lang.String...);
+ method public java.util.List<android.app.AppOpsManager.PackageOps> getPackagesForOps(java.lang.String[]);
method public static int opToDefaultMode(java.lang.String);
method public static java.lang.String opToPermission(java.lang.String);
method public void setMode(java.lang.String, int, java.lang.String, int);
@@ -343,7 +346,7 @@
field public static final int UID_STATE_TOP = 1; // 0x1
}
- public static final class AppOpsManager.HistoricalOpEntry implements android.os.Parcelable {
+ public static final class AppOpsManager.HistoricalOp implements android.os.Parcelable {
method public int describeContents();
method public long getAccessCount(int);
method public long getAccessDuration(int);
@@ -353,23 +356,43 @@
method public long getForegroundAccessCount();
method public long getForegroundAccessDuration();
method public long getForegroundRejectCount();
- method public java.lang.String getOp();
+ method public java.lang.String getOpName();
method public long getRejectCount(int);
method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOpEntry> CREATOR;
+ field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOp> CREATOR;
+ }
+
+ public static final class AppOpsManager.HistoricalOps implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getBeginTimeMillis();
+ method public long getEndTimeMillis();
+ method public int getUidCount();
+ method public android.app.AppOpsManager.HistoricalUidOps getUidOps(int);
+ method public android.app.AppOpsManager.HistoricalUidOps getUidOpsAt(int);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOps> CREATOR;
}
public static final class AppOpsManager.HistoricalPackageOps implements android.os.Parcelable {
method public int describeContents();
- method public android.app.AppOpsManager.HistoricalOpEntry getEntry(java.lang.String);
- method public android.app.AppOpsManager.HistoricalOpEntry getEntryAt(int);
- method public int getEntryCount();
+ method public android.app.AppOpsManager.HistoricalOp getOp(java.lang.String);
+ method public android.app.AppOpsManager.HistoricalOp getOpAt(int);
+ method public int getOpCount();
method public java.lang.String getPackageName();
- method public int getUid();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalPackageOps> CREATOR;
}
+ public static final class AppOpsManager.HistoricalUidOps implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getPackageCount();
+ method public android.app.AppOpsManager.HistoricalPackageOps getPackageOps(java.lang.String);
+ method public android.app.AppOpsManager.HistoricalPackageOps getPackageOpsAt(int);
+ method public int getUid();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalUidOps> CREATOR;
+ }
+
public static final class AppOpsManager.OpEntry implements android.os.Parcelable {
method public int describeContents();
method public int getDuration();
@@ -848,6 +871,73 @@
}
+package android.app.contentsuggestions {
+
+ public final class ClassificationsRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.os.Bundle getExtras();
+ method public java.util.List<android.app.contentsuggestions.ContentSelection> getSelections();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.contentsuggestions.ClassificationsRequest> CREATOR;
+ }
+
+ public static final class ClassificationsRequest.Builder {
+ ctor public ClassificationsRequest.Builder(java.util.List<android.app.contentsuggestions.ContentSelection>);
+ method public android.app.contentsuggestions.ClassificationsRequest build();
+ method public android.app.contentsuggestions.ClassificationsRequest.Builder setExtras(android.os.Bundle);
+ }
+
+ public final class ContentClassification implements android.os.Parcelable {
+ ctor public ContentClassification(java.lang.String, android.os.Bundle);
+ method public int describeContents();
+ method public android.os.Bundle getExtras();
+ method public java.lang.String getId();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.contentsuggestions.ContentClassification> CREATOR;
+ }
+
+ public final class ContentSelection implements android.os.Parcelable {
+ ctor public ContentSelection(java.lang.String, android.os.Bundle);
+ method public int describeContents();
+ method public android.os.Bundle getExtras();
+ method public java.lang.String getId();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.contentsuggestions.ContentSelection> CREATOR;
+ }
+
+ public final class ContentSuggestionsManager {
+ method public void classifyContentSelections(android.app.contentsuggestions.ClassificationsRequest, java.util.concurrent.Executor, android.app.contentsuggestions.ContentSuggestionsManager.ClassificationsCallback);
+ method public void notifyInteraction(java.lang.String, android.os.Bundle);
+ method public void provideContextImage(int, android.os.Bundle);
+ method public void suggestContentSelections(android.app.contentsuggestions.SelectionsRequest, java.util.concurrent.Executor, android.app.contentsuggestions.ContentSuggestionsManager.SelectionsCallback);
+ }
+
+ public static abstract interface ContentSuggestionsManager.ClassificationsCallback {
+ method public abstract void onContentClassificationsAvailable(int, java.util.List<android.app.contentsuggestions.ContentClassification>);
+ }
+
+ public static abstract interface ContentSuggestionsManager.SelectionsCallback {
+ method public abstract void onContentSelectionsAvailable(int, java.util.List<android.app.contentsuggestions.ContentSelection>);
+ }
+
+ public final class SelectionsRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.os.Bundle getExtras();
+ method public android.graphics.Point getInterestPoint();
+ method public int getTaskId();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.contentsuggestions.SelectionsRequest> CREATOR;
+ }
+
+ public static final class SelectionsRequest.Builder {
+ ctor public SelectionsRequest.Builder(int);
+ method public android.app.contentsuggestions.SelectionsRequest build();
+ method public android.app.contentsuggestions.SelectionsRequest.Builder setExtras(android.os.Bundle);
+ method public android.app.contentsuggestions.SelectionsRequest.Builder setInterestPoint(android.graphics.Point);
+ }
+
+}
+
package android.app.job {
public abstract class JobScheduler {
@@ -856,6 +946,87 @@
}
+package android.app.prediction {
+
+ public final class AppPredictionContext implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.os.Bundle getExtras();
+ method public java.lang.String getPackageName();
+ method public int getPredictedTargetCount();
+ method public java.lang.String getUiSurface();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.prediction.AppPredictionContext> CREATOR;
+ }
+
+ public static final class AppPredictionContext.Builder {
+ method public android.app.prediction.AppPredictionContext build();
+ method public android.app.prediction.AppPredictionContext.Builder setExtras(android.os.Bundle);
+ method public android.app.prediction.AppPredictionContext.Builder setPredictedTargetCount(int);
+ method public android.app.prediction.AppPredictionContext.Builder setUiSurface(java.lang.String);
+ }
+
+ public final class AppPredictionManager {
+ method public android.app.prediction.AppPredictor createAppPredictionSession(android.app.prediction.AppPredictionContext);
+ }
+
+ public final class AppPredictionSessionId implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.prediction.AppPredictionSessionId> CREATOR;
+ }
+
+ public final class AppPredictor {
+ method public void destroy();
+ method public void notifyAppTargetEvent(android.app.prediction.AppTargetEvent);
+ method public void notifyLocationShown(java.lang.String, java.util.List<android.app.prediction.AppTargetId>);
+ method public void registerPredictionUpdates(java.util.concurrent.Executor, android.app.prediction.AppPredictor.Callback);
+ method public void requestPredictionUpdate();
+ method public void sortTargets(java.util.List<android.app.prediction.AppTarget>, java.util.concurrent.Executor, java.util.function.Consumer<java.util.List<android.app.prediction.AppTarget>>);
+ method public void unregisterPredictionUpdates(android.app.prediction.AppPredictor.Callback);
+ }
+
+ public static abstract interface AppPredictor.Callback {
+ method public abstract void onTargetsAvailable(java.util.List<android.app.prediction.AppTarget>);
+ }
+
+ public final class AppTarget implements android.os.Parcelable {
+ method public int describeContents();
+ method public java.lang.String getClassName();
+ method public android.app.prediction.AppTargetId getId();
+ method public java.lang.String getPackageName();
+ method public int getRank();
+ method public android.content.pm.ShortcutInfo getShortcutInfo();
+ method public android.os.UserHandle getUser();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.prediction.AppTarget> CREATOR;
+ }
+
+ public final class AppTargetEvent implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getAction();
+ method public java.lang.String getLaunchLocation();
+ method public android.app.prediction.AppTarget getTarget();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int ACTION_DISMISS = 2; // 0x2
+ field public static final int ACTION_LAUNCH = 1; // 0x1
+ field public static final int ACTION_PIN = 3; // 0x3
+ field public static final android.os.Parcelable.Creator<android.app.prediction.AppTargetEvent> CREATOR;
+ }
+
+ public static final class AppTargetEvent.Builder {
+ ctor public AppTargetEvent.Builder(android.app.prediction.AppTarget, int);
+ method public android.app.prediction.AppTargetEvent build();
+ method public android.app.prediction.AppTargetEvent.Builder setLaunchLocation(java.lang.String);
+ }
+
+ public final class AppTargetId implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.prediction.AppTargetId> CREATOR;
+ }
+
+}
+
package android.app.role {
public abstract interface OnRoleHoldersChangedListener {
@@ -1042,7 +1213,9 @@
method public abstract void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.os.Bundle);
method public abstract void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.os.Bundle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
method public void startActivityAsUser(android.content.Intent, android.os.UserHandle);
+ field public static final java.lang.String APP_PREDICTION_SERVICE = "app_prediction";
field public static final java.lang.String BACKUP_SERVICE = "backup";
+ field public static final java.lang.String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
field public static final java.lang.String CONTEXTHUB_SERVICE = "contexthub";
field public static final java.lang.String EUICC_CARD_SERVICE = "euicc_card";
field public static final java.lang.String HDMI_CONTROL_SERVICE = "hdmi_control";
@@ -1110,6 +1283,7 @@
field public static final java.lang.String EXTRA_ORIGINATING_UID = "android.intent.extra.ORIGINATING_UID";
field public static final java.lang.String EXTRA_PACKAGES = "android.intent.extra.PACKAGES";
field public static final java.lang.String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME";
+ field public static final java.lang.String EXTRA_PERMISSION_GROUP_NAME = "android.intent.extra.PERMISSION_GROUP_NAME";
field public static final java.lang.String EXTRA_REASON = "android.intent.extra.REASON";
field public static final java.lang.String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK";
field public static final java.lang.String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED";
@@ -1128,6 +1302,7 @@
package android.content.pm {
public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
+ method public boolean isEncryptionAware();
method public boolean isInstantApp();
field public java.lang.String credentialProtectedDataDir;
field public int targetSandboxVersion;
@@ -1548,6 +1723,10 @@
field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessCorrection> CREATOR;
}
+ public final class ColorDisplayManager {
+ method public boolean setSaturationLevel(int);
+ }
+
public final class DisplayManager {
method public java.util.List<android.hardware.display.AmbientBrightnessDayStats> getAmbientBrightnessStats();
method public android.hardware.display.BrightnessConfiguration getBrightnessConfiguration();
@@ -1556,7 +1735,7 @@
method public android.util.Pair<float[], float[]> getMinimumBrightnessCurve();
method public android.graphics.Point getStableDisplaySize();
method public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
- method public void setSaturationLevel(float);
+ method public deprecated void setSaturationLevel(float);
}
}
@@ -3214,6 +3393,22 @@
package android.media.session {
+ public final class ControllerCallbackLink implements android.os.Parcelable {
+ ctor public ControllerCallbackLink(android.media.session.ControllerCallbackLink.CallbackStub);
+ }
+
+ public static abstract class ControllerCallbackLink.CallbackStub {
+ ctor public ControllerCallbackLink.CallbackStub();
+ method public void onEvent(java.lang.String, android.os.Bundle);
+ method public void onExtrasChanged(android.os.Bundle);
+ method public void onMetadataChanged(android.media.MediaMetadata);
+ method public void onPlaybackStateChanged(android.media.session.PlaybackState);
+ method public void onQueueChanged(java.util.List<android.media.session.MediaSession.QueueItem>);
+ method public void onQueueTitleChanged(java.lang.CharSequence);
+ method public void onSessionDestroyed();
+ method public void onVolumeInfoChanged(android.media.session.MediaController.PlaybackInfo);
+ }
+
public final class MediaSessionManager {
method public void setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, android.os.Handler);
method public void setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, android.os.Handler);
@@ -5146,6 +5341,24 @@
}
+package android.service.appprediction {
+
+ public abstract class AppPredictionService extends android.app.Service {
+ ctor public AppPredictionService();
+ method public abstract void onAppTargetEvent(android.app.prediction.AppPredictionSessionId, android.app.prediction.AppTargetEvent);
+ method public final android.os.IBinder onBind(android.content.Intent);
+ method public void onCreatePredictionSession(android.app.prediction.AppPredictionContext, android.app.prediction.AppPredictionSessionId);
+ method public void onDestroyPredictionSession(android.app.prediction.AppPredictionSessionId);
+ method public abstract void onLocationShown(android.app.prediction.AppPredictionSessionId, java.lang.String, java.util.List<android.app.prediction.AppTargetId>);
+ method public abstract void onRequestPredictionUpdate(android.app.prediction.AppPredictionSessionId);
+ method public abstract void onSortAppTargets(android.app.prediction.AppPredictionSessionId, java.util.List<android.app.prediction.AppTarget>, android.os.CancellationSignal, java.util.function.Consumer<java.util.List<android.app.prediction.AppTarget>>);
+ method public void onStartPredictionUpdates();
+ method public void onStopPredictionUpdates();
+ method public final void updatePredictions(android.app.prediction.AppPredictionSessionId, java.util.List<android.app.prediction.AppTarget>);
+ }
+
+}
+
package android.service.autofill {
public abstract class AutofillFieldClassificationService extends android.app.Service {
@@ -5274,6 +5487,19 @@
}
+package android.service.contentsuggestions {
+
+ public abstract class ContentSuggestionsService extends android.app.Service {
+ ctor public ContentSuggestionsService();
+ method public abstract void classifyContentSelections(android.app.contentsuggestions.ClassificationsRequest, android.app.contentsuggestions.ContentSuggestionsManager.ClassificationsCallback);
+ method public abstract void notifyInteraction(java.lang.String, android.os.Bundle);
+ method public abstract void processContextImage(int, android.graphics.Bitmap, android.os.Bundle);
+ method public abstract void suggestContentSelections(android.app.contentsuggestions.SelectionsRequest, android.app.contentsuggestions.ContentSuggestionsManager.SelectionsCallback);
+ field public static final java.lang.String SERVICE_INTERFACE = "android.service.contentsuggestions.ContentSuggestionsService";
+ }
+
+}
+
package android.service.euicc {
public final class DownloadSubscriptionResult implements android.os.Parcelable {
@@ -6118,6 +6344,18 @@
field public static final int WIFI_LOST = 59; // 0x3b
}
+ public final class LteVopsSupportInfo implements android.os.Parcelable {
+ ctor public LteVopsSupportInfo(int, int);
+ method public int describeContents();
+ method public int getEmcBearerSupport();
+ method public int getVopsSupport();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.LteVopsSupportInfo> CREATOR;
+ field public static final int LTE_STATUS_NOT_AVAILABLE = 1; // 0x1
+ field public static final int LTE_STATUS_NOT_SUPPORTED = 3; // 0x3
+ field public static final int LTE_STATUS_SUPPORTED = 2; // 0x2
+ }
+
public class MbmsDownloadSession implements java.lang.AutoCloseable {
field public static final java.lang.String MBMS_DOWNLOAD_SERVICE_ACTION = "android.telephony.action.EmbmsDownload";
}
diff --git a/api/test-current.txt b/api/test-current.txt
index ae3c1e0..575875d 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -89,18 +89,26 @@
}
public class AppOpsManager {
- method public java.util.List<android.app.AppOpsManager.HistoricalPackageOps> getAllHistoricPackagesOps(java.lang.String[], long, long);
- method public android.app.AppOpsManager.HistoricalPackageOps getHistoricalPackagesOps(int, java.lang.String, java.lang.String[], long, long);
+ method public void addHistoricalOps(android.app.AppOpsManager.HistoricalOps);
+ method public void clearHistory();
+ method public void getHistoricalOps(int, java.lang.String, java.lang.String[], long, long, java.util.concurrent.Executor, java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
+ method public void getHistoricalOpsFromDiskRaw(int, java.lang.String, java.lang.String[], long, long, java.util.concurrent.Executor, java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
method public static int getNumOps();
method public static java.lang.String[] getOpStrs();
method public boolean isOperationActive(int, int, java.lang.String);
+ method public void offsetHistory(long);
method public static java.lang.String opToPermission(int);
method public static int permissionToOpCode(java.lang.String);
+ method public void resetHistoryParameters();
+ method public void setHistoryParameters(int, long, int);
method public void setMode(int, int, java.lang.String, int);
method public void setUidMode(java.lang.String, int, int);
method public void startWatchingActive(int[], android.app.AppOpsManager.OnOpActiveChangedListener);
method public void stopWatchingActive(android.app.AppOpsManager.OnOpActiveChangedListener);
method public static int strOpToOp(java.lang.String);
+ field public static final int HISTORICAL_MODE_DISABLED = 0; // 0x0
+ field public static final int HISTORICAL_MODE_ENABLED_ACTIVE = 1; // 0x1
+ field public static final int HISTORICAL_MODE_ENABLED_PASSIVE = 2; // 0x2
field public static final java.lang.String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
field public static final java.lang.String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications";
field public static final java.lang.String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
@@ -144,11 +152,18 @@
field public static final java.lang.String OPSTR_WRITE_ICC_SMS = "android:write_icc_sms";
field public static final java.lang.String OPSTR_WRITE_SMS = "android:write_sms";
field public static final java.lang.String OPSTR_WRITE_WALLPAPER = "android:write_wallpaper";
+ field public static final int OP_COARSE_LOCATION = 0; // 0x0
field public static final int OP_RECORD_AUDIO = 27; // 0x1b
field public static final int OP_SYSTEM_ALERT_WINDOW = 24; // 0x18
+ field public static final int UID_STATE_BACKGROUND = 4; // 0x4
+ field public static final int UID_STATE_CACHED = 5; // 0x5
+ field public static final int UID_STATE_FOREGROUND = 3; // 0x3
+ field public static final int UID_STATE_FOREGROUND_SERVICE = 2; // 0x2
+ field public static final int UID_STATE_PERSISTENT = 0; // 0x0
+ field public static final int UID_STATE_TOP = 1; // 0x1
}
- public static final class AppOpsManager.HistoricalOpEntry implements android.os.Parcelable {
+ public static final class AppOpsManager.HistoricalOp implements android.os.Parcelable {
method public int describeContents();
method public long getAccessCount(int);
method public long getAccessDuration(int);
@@ -158,23 +173,48 @@
method public long getForegroundAccessCount();
method public long getForegroundAccessDuration();
method public long getForegroundRejectCount();
- method public java.lang.String getOp();
+ method public java.lang.String getOpName();
method public long getRejectCount(int);
method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOpEntry> CREATOR;
+ field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOp> CREATOR;
+ }
+
+ public static final class AppOpsManager.HistoricalOps implements android.os.Parcelable {
+ ctor public AppOpsManager.HistoricalOps(long, long);
+ method public int describeContents();
+ method public long getBeginTimeMillis();
+ method public long getEndTimeMillis();
+ method public int getUidCount();
+ method public android.app.AppOpsManager.HistoricalUidOps getUidOps(int);
+ method public android.app.AppOpsManager.HistoricalUidOps getUidOpsAt(int);
+ method public void increaseAccessCount(int, int, java.lang.String, int, long);
+ method public void increaseAccessDuration(int, int, java.lang.String, int, long);
+ method public void increaseRejectCount(int, int, java.lang.String, int, long);
+ method public void offsetBeginAndEndTime(long);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOps> CREATOR;
}
public static final class AppOpsManager.HistoricalPackageOps implements android.os.Parcelable {
method public int describeContents();
- method public android.app.AppOpsManager.HistoricalOpEntry getEntry(java.lang.String);
- method public android.app.AppOpsManager.HistoricalOpEntry getEntryAt(int);
- method public int getEntryCount();
+ method public android.app.AppOpsManager.HistoricalOp getOp(java.lang.String);
+ method public android.app.AppOpsManager.HistoricalOp getOpAt(int);
+ method public int getOpCount();
method public java.lang.String getPackageName();
- method public int getUid();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalPackageOps> CREATOR;
}
+ public static final class AppOpsManager.HistoricalUidOps implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getPackageCount();
+ method public android.app.AppOpsManager.HistoricalPackageOps getPackageOps(java.lang.String);
+ method public android.app.AppOpsManager.HistoricalPackageOps getPackageOpsAt(int);
+ method public int getUid();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalUidOps> CREATOR;
+ }
+
public static abstract interface AppOpsManager.OnOpActiveChangedListener {
method public abstract void onOpActiveChanged(int, int, java.lang.String, boolean);
}
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index 4918747..4f88127 100644
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ b/cmds/idmap2/idmap2/Scan.cpp
@@ -39,6 +39,17 @@
using android::idmap2::utils::FindFiles;
namespace {
+
+struct InputOverlay {
+ bool operator<(InputOverlay const& rhs) const {
+ return priority < rhs.priority || (priority == rhs.priority && apk_path < rhs.apk_path);
+ }
+
+ std::string apk_path; // NOLINT(misc-non-private-member-variables-in-classes)
+ std::string idmap_path; // NOLINT(misc-non-private-member-variables-in-classes)
+ int priority; // NOLINT(misc-non-private-member-variables-in-classes)
+};
+
std::unique_ptr<std::vector<std::string>> FindApkFiles(const std::vector<std::string>& dirs,
bool recursive, std::ostream& out_error) {
const auto predicate = [](unsigned char type, const std::string& path) -> bool {
@@ -58,6 +69,7 @@
}
return std::make_unique<std::vector<std::string>>(paths.cbegin(), paths.cend());
}
+
} // namespace
bool Scan(const std::vector<std::string>& args, std::ostream& out_error) {
@@ -87,7 +99,7 @@
return false;
}
- std::vector<std::string> interesting_apks;
+ std::vector<InputOverlay> interesting_apks;
for (const std::string& path : *apk_paths) {
std::unique_ptr<const ZipFile> zip = ZipFile::Open(path);
if (!zip) {
@@ -132,27 +144,29 @@
continue;
}
+ // Sort the static overlays in ascending priority order
+ std::string idmap_path = Idmap::CanonicalIdmapPathFor(output_directory, path);
+ InputOverlay input{path, idmap_path, priority};
interesting_apks.insert(
- std::lower_bound(interesting_apks.begin(), interesting_apks.end(), path), path);
+ std::lower_bound(interesting_apks.begin(), interesting_apks.end(), input), input);
}
std::stringstream stream;
- for (const auto& apk : interesting_apks) {
- const std::string idmap_path = Idmap::CanonicalIdmapPathFor(output_directory, apk);
+ for (const auto& overlay : interesting_apks) {
std::stringstream dev_null;
- if (!Verify(std::vector<std::string>({"--idmap-path", idmap_path}), dev_null) &&
+ if (!Verify(std::vector<std::string>({"--idmap-path", overlay.idmap_path}), dev_null) &&
!Create(std::vector<std::string>({
"--target-apk-path",
target_apk_path,
"--overlay-apk-path",
- apk,
+ overlay.apk_path,
"--idmap-path",
- idmap_path,
+ overlay.idmap_path,
}),
out_error)) {
return false;
}
- stream << idmap_path << std::endl;
+ stream << overlay.idmap_path << std::endl;
}
std::cout << stream.str();
diff --git a/cmds/idmap2/static-checks.sh b/cmds/idmap2/static-checks.sh
index 560ccb6..ad9830b 100755
--- a/cmds/idmap2/static-checks.sh
+++ b/cmds/idmap2/static-checks.sh
@@ -70,7 +70,15 @@
function _cpplint()
{
local cpplint="${ANDROID_BUILD_TOP}/tools/repohooks/tools/cpplint.py"
- $cpplint --quiet $cpp_files
+ local output="$($cpplint --quiet $cpp_files 2>&1 >/dev/null | grep -v \
+ -e 'Found C system header after C++ system header.' \
+ -e 'Unknown NOLINT error category: misc-non-private-member-variables-in-classes' \
+ )"
+ if [[ "$output" ]]; then
+ echo "$output"
+ return 1
+ fi
+ return 0
}
function _parse_args()
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java
index 6788f7d..d160b73 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/cmds/media/src/com/android/commands/media/Media.java
@@ -19,12 +19,12 @@
import android.app.ActivityManager;
import android.content.Context;
-import android.content.pm.ParceledListSlice;
import android.media.MediaMetadata;
+import android.media.session.ControllerCallbackLink;
import android.media.session.ISessionController;
-import android.media.session.ISessionControllerCallback;
import android.media.session.ISessionManager;
import android.media.session.MediaController.PlaybackInfo;
+import android.media.session.MediaSession.QueueItem;
import android.media.session.PlaybackState;
import android.os.Bundle;
import android.os.HandlerThread;
@@ -178,13 +178,7 @@
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
}
- class ControllerMonitor extends ISessionControllerCallback.Stub {
- private final ISessionController mController;
-
- public ControllerMonitor(ISessionController controller) {
- mController = controller;
- }
-
+ class ControllerCallbackStub extends ControllerCallbackLink.CallbackStub {
@Override
public void onSessionDestroyed() {
System.out.println("onSessionDestroyed. Enter q to quit.");
@@ -208,25 +202,35 @@
}
@Override
- public void onQueueChanged(ParceledListSlice queue) throws RemoteException {
+ public void onQueueChanged(List<QueueItem> queue) {
System.out.println("onQueueChanged, "
- + (queue == null ? "null queue" : " size=" + queue.getList().size()));
+ + (queue == null ? "null queue" : " size=" + queue.size()));
}
@Override
- public void onQueueTitleChanged(CharSequence title) throws RemoteException {
+ public void onQueueTitleChanged(CharSequence title) {
System.out.println("onQueueTitleChange " + title);
}
@Override
- public void onExtrasChanged(Bundle extras) throws RemoteException {
+ public void onExtrasChanged(Bundle extras) {
System.out.println("onExtrasChanged " + extras);
}
@Override
- public void onVolumeInfoChanged(PlaybackInfo info) throws RemoteException {
+ public void onVolumeInfoChanged(PlaybackInfo info) {
System.out.println("onVolumeInfoChanged " + info);
}
+ }
+
+ private class ControllerMonitor {
+ private final ISessionController mController;
+ private final ControllerCallbackLink mControllerCallbackLink;
+
+ ControllerMonitor(ISessionController controller) {
+ mController = controller;
+ mControllerCallbackLink = new ControllerCallbackLink(new ControllerCallbackStub());
+ }
void printUsageMessage() {
try {
@@ -244,7 +248,7 @@
@Override
protected void onLooperPrepared() {
try {
- mController.registerCallbackListener(PACKAGE_NAME, ControllerMonitor.this);
+ mController.registerCallbackListener(PACKAGE_NAME, mControllerCallbackLink);
} catch (RemoteException e) {
System.out.println("Error registering monitor callback");
}
@@ -287,7 +291,7 @@
} finally {
cbThread.getLooper().quit();
try {
- mController.unregisterCallbackListener(this);
+ mController.unregisterCallbackListener(mControllerCallbackLink);
} catch (Exception e) {
// ignoring
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 4eb2838..1d3b384 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -219,7 +219,7 @@
NumFingerprints num_fingerprints = 10031;
DiskIo disk_io = 10032;
PowerProfile power_profile = 10033;
- ProcStats proc_stats_pkg_proc = 10034;
+ ProcStatsPkgProc proc_stats_pkg_proc = 10034;
ProcessCpuTime process_cpu_time = 10035;
NativeProcessMemoryState native_process_memory_state = 10036;
CpuTimePerThreadFreq cpu_time_per_thread_freq = 10037;
@@ -3275,6 +3275,13 @@
optional ProcessStatsSectionProto proc_stats_section = 1;
}
+/**
+ * Pulled from ProcessStatsService.java
+ */
+message ProcStatsPkgProc {
+ optional ProcessStatsSectionProto proc_stats_section = 1;
+}
+
message PowerProfileProto {
optional double cpu_suspend = 1;
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index ed22df5..4d3c5d1 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -3565,11 +3565,9 @@
Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mContext:Landroid/content/Context;
Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mCurrentlyActiveUserId:I
Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mIccId:[Ljava/lang/String;
-Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mInsertSimState:[I
Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mPackageManager:Landroid/content/pm/IPackageManager;
Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mPhone:[Lcom/android/internal/telephony/Phone;
Lcom/android/internal/telephony/SubscriptionInfoUpdater;->PROJECT_SIM_NUM:I
-Lcom/android/internal/telephony/SubscriptionInfoUpdater;->updateSubscriptionInfoByIccId()V
Lcom/android/internal/telephony/TelephonyCapabilities;->supportsAdn(I)Z
Lcom/android/internal/telephony/TelephonyProperties;->PROPERTY_ICC_OPERATOR_NUMERIC:Ljava/lang/String;
Lcom/android/internal/telephony/test/InterpreterEx;-><init>(Ljava/lang/String;)V
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index f2ad268..35098a0 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -1090,7 +1090,7 @@
* called) or the service has been disconnected, this method will have
* no effect and return {@code false}.
*
- * @param scale the magnification scale to set, must be >= 1 and <= 5
+ * @param scale the magnification scale to set, must be >= 1 and <= 8
* @param animate {@code true} to animate from the current scale or
* {@code false} to set the scale immediately
* @return {@code true} on success, {@code false} on failure
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 9d44e58..c90e404 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -258,8 +258,8 @@
Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized,
boolean sticky, int userId, boolean allowBackgroundActivityStarts);
public abstract ComponentName startServiceInPackage(int uid, Intent service,
- String resolvedType, boolean fgRequired, String callingPackage, int userId)
- throws TransactionTooLargeException;
+ String resolvedType, boolean fgRequired, String callingPackage, int userId,
+ boolean allowBackgroundActivityStarts) throws TransactionTooLargeException;
public abstract void disconnectActivityFromServices(Object connectionHolder);
public abstract void cleanUpServices(int userId, ComponentName component, Intent baseIntent);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 8faf08a..7767f04 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -271,6 +271,13 @@
@UnsupportedAppUsage
final H mH = new H();
final Executor mExecutor = new HandlerExecutor(mH);
+ /**
+ * Maps from activity token to local record of running activities in this process.
+ *
+ * This variable is readable if the code is running in activity thread or holding {@link
+ * #mResourcesManager}. It's only writable if the code is running in activity thread and holding
+ * {@link #mResourcesManager}.
+ */
@UnsupportedAppUsage
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
/** The activities to be truly destroyed (not include relaunch). */
@@ -434,6 +441,10 @@
Configuration newConfig;
Configuration createdConfig;
Configuration overrideConfig;
+ // Used to save the last reported configuration from server side so that activity
+ // configuration transactions can always use the latest configuration.
+ @GuardedBy("this")
+ private Configuration mPendingOverrideConfig;
// Used for consolidating configs before sending on to Activity.
private Configuration tmpConfig = new Configuration();
// Callback used for updating activity override config.
@@ -3064,7 +3075,12 @@
}
r.setState(ON_CREATE);
- mActivities.put(r.token, r);
+ // updatePendingActivityConfiguration() reads from mActivities to update
+ // ActivityClientRecord which runs in a different thread. Protect modifications to
+ // mActivities to avoid race.
+ synchronized (mResourcesManager) {
+ mActivities.put(r.token, r);
+ }
} catch (SuperNotCalledException e) {
throw e;
@@ -4639,7 +4655,12 @@
r.setState(ON_DESTROY);
}
schedulePurgeIdler();
- mActivities.remove(token);
+ // updatePendingActivityConfiguration() reads from mActivities to update
+ // ActivityClientRecord which runs in a different thread. Protect modifications to
+ // mActivities to avoid race.
+ synchronized (mResourcesManager) {
+ mActivities.remove(token);
+ }
StrictMode.decrementExpectedActivityCount(activityClass);
return r;
}
@@ -5382,6 +5403,26 @@
}
}
+ @Override
+ public void updatePendingActivityConfiguration(IBinder activityToken,
+ Configuration overrideConfig) {
+ final ActivityClientRecord r;
+ synchronized (mResourcesManager) {
+ r = mActivities.get(activityToken);
+ }
+
+ if (r == null) {
+ if (DEBUG_CONFIGURATION) {
+ Slog.w(TAG, "Not found target activity to update its pending config.");
+ }
+ return;
+ }
+
+ synchronized (r) {
+ r.mPendingOverrideConfig = overrideConfig;
+ }
+ }
+
/**
* Handle new activity configuration and/or move to a different display.
* @param activityToken Target activity token.
@@ -5401,6 +5442,24 @@
final boolean movedToDifferentDisplay = displayId != INVALID_DISPLAY
&& displayId != r.activity.getDisplayId();
+ synchronized (r) {
+ if (r.mPendingOverrideConfig != null
+ && !r.mPendingOverrideConfig.isOtherSeqNewer(overrideConfig)) {
+ overrideConfig = r.mPendingOverrideConfig;
+ }
+ r.mPendingOverrideConfig = null;
+ }
+
+ if (r.overrideConfig != null && !r.overrideConfig.isOtherSeqNewer(overrideConfig)
+ && !movedToDifferentDisplay) {
+ if (DEBUG_CONFIGURATION) {
+ Slog.v(TAG, "Activity already handled newer configuration so drop this"
+ + " transaction. overrideConfig=" + overrideConfig + " r.overrideConfig="
+ + r.overrideConfig);
+ }
+ return;
+ }
+
// Perform updates.
r.overrideConfig = overrideConfig;
final ViewRootImpl viewRoot = r.activity.mDecor != null
diff --git a/core/java/android/app/AppOpsManager.aidl b/core/java/android/app/AppOpsManager.aidl
index 9329fbc..2240302 100644
--- a/core/java/android/app/AppOpsManager.aidl
+++ b/core/java/android/app/AppOpsManager.aidl
@@ -19,5 +19,7 @@
parcelable AppOpsManager.PackageOps;
parcelable AppOpsManager.OpEntry;
+parcelable AppOpsManager.HistoricalOp;
+parcelable AppOpsManager.HistoricalOps;
parcelable AppOpsManager.HistoricalPackageOps;
-parcelable AppOpsManager.HistoricalOpEntry;
+parcelable AppOpsManager.HistoricalUidOps;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 78fe002..e155fe2 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -36,26 +36,33 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
+import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.UserManager;
import android.provider.Settings;
import android.util.ArrayMap;
import com.android.internal.annotations.GuardedBy;
+import android.util.SparseArray;
import com.android.internal.app.IAppOpsActiveCallback;
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsNotedCallback;
import com.android.internal.app.IAppOpsService;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
/**
* API for interacting with "application operation" tracking.
@@ -106,6 +113,51 @@
static IBinder sToken;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "HISTORICAL_MODE_" }, value = {
+ HISTORICAL_MODE_DISABLED,
+ HISTORICAL_MODE_ENABLED_ACTIVE,
+ HISTORICAL_MODE_ENABLED_PASSIVE
+ })
+ public @interface HistoricalMode {}
+
+ /**
+ * Mode in which app op history is completely disabled.
+ * @hide
+ */
+ @TestApi
+ public static final int HISTORICAL_MODE_DISABLED = 0;
+
+ /**
+ * Mode in which app op history is enabled and app ops performed by apps would
+ * be tracked. This is the mode in which the feature is completely enabled.
+ * @hide
+ */
+ @TestApi
+ public static final int HISTORICAL_MODE_ENABLED_ACTIVE = 1;
+
+ /**
+ * Mode in which app op history is enabled but app ops performed by apps would
+ * not be tracked and the only way to add ops to the history is via explicit calls
+ * to dedicated APIs. This mode is useful for testing to allow full control of
+ * the historical content.
+ * @hide
+ */
+ @TestApi
+ public static final int HISTORICAL_MODE_ENABLED_PASSIVE = 2;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "MODE_" }, value = {
+ MODE_ALLOWED,
+ MODE_IGNORED,
+ MODE_ERRORED,
+ MODE_DEFAULT,
+ MODE_FOREGROUND
+ })
+ public @interface Mode {}
+
/**
* Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller is
* allowed to perform the given operation.
@@ -159,7 +211,6 @@
"foreground", // MODE_FOREGROUND
};
-
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = { "UID_STATE_" }, value = {
@@ -173,9 +224,16 @@
public @interface UidState {}
/**
+ * Invalid UID state.
+ * @hide
+ */
+ public static final int UID_STATE_INVALID = -1;
+
+ /**
* Metrics about an op when its uid is persistent.
* @hide
*/
+ @TestApi
@SystemApi
public static final int UID_STATE_PERSISTENT = 0;
@@ -183,6 +241,7 @@
* Metrics about an op when its uid is at the top.
* @hide
*/
+ @TestApi
@SystemApi
public static final int UID_STATE_TOP = 1;
@@ -190,6 +249,7 @@
* Metrics about an op when its uid is running a foreground service.
* @hide
*/
+ @TestApi
@SystemApi
public static final int UID_STATE_FOREGROUND_SERVICE = 2;
@@ -203,6 +263,7 @@
* Metrics about an op when its uid is in the foreground for any other reasons.
* @hide
*/
+ @TestApi
@SystemApi
public static final int UID_STATE_FOREGROUND = 3;
@@ -210,6 +271,7 @@
* Metrics about an op when its uid is in the background for any reason.
* @hide
*/
+ @TestApi
@SystemApi
public static final int UID_STATE_BACKGROUND = 4;
@@ -217,6 +279,7 @@
* Metrics about an op when its uid is cached.
* @hide
*/
+ @TestApi
@SystemApi
public static final int UID_STATE_CACHED = 5;
@@ -237,7 +300,7 @@
@UnsupportedAppUsage
public static final int OP_NONE = -1;
/** @hide Access to coarse location information. */
- @UnsupportedAppUsage
+ @TestApi
public static final int OP_COARSE_LOCATION = 0;
/** @hide Access to fine location information. */
@UnsupportedAppUsage
@@ -1645,6 +1708,9 @@
}
}
+ /** @hide */
+ public static final String KEY_HISTORICAL_OPS = "historical_ops";
+
/**
* Retrieve the op switch that controls the given operation.
* @hide
@@ -1731,7 +1797,7 @@
* Retrieve the default mode for the operation.
* @hide
*/
- public static int opToDefaultMode(int op) {
+ public static @Mode int opToDefaultMode(int op) {
// STOPSHIP b/118520006: Hardcode the default values once the feature is stable.
switch (op) {
// SMS permissions
@@ -1795,7 +1861,7 @@
* Retrieve the human readable mode.
* @hide
*/
- public static String modeToName(int mode) {
+ public static String modeToName(@Mode int mode) {
if (mode >= 0 && mode < MODE_NAMES.length) {
return MODE_NAMES[mode];
}
@@ -1885,7 +1951,7 @@
@SystemApi
public static final class OpEntry implements Parcelable {
private final int mOp;
- private final int mMode;
+ private final @Mode int mMode;
private final long[] mTimes;
private final long[] mRejectTimes;
private final int mDuration;
@@ -1896,7 +1962,7 @@
/**
* @hide
*/
- public OpEntry(int op, int mode, long time, long rejectTime, int duration,
+ public OpEntry(int op, @Mode int mode, long time, long rejectTime, int duration,
int proxyUid, String proxyPackage) {
mOp = op;
mMode = mode;
@@ -1913,7 +1979,7 @@
/**
* @hide
*/
- public OpEntry(int op, int mode, long[] times, long[] rejectTimes, int duration,
+ public OpEntry(int op, @Mode int mode, long[] times, long[] rejectTimes, int duration,
boolean running, int proxyUid, String proxyPackage) {
mOp = op;
mMode = mode;
@@ -1930,7 +1996,7 @@
/**
* @hide
*/
- public OpEntry(int op, int mode, long[] times, long[] rejectTimes, int duration,
+ public OpEntry(int op, @Mode int mode, long[] times, long[] rejectTimes, int duration,
int proxyUid, String proxyPackage) {
this(op, mode, times, rejectTimes, duration, duration == -1, proxyUid, proxyPackage);
}
@@ -1953,7 +2019,7 @@
/**
* Return this entry's current mode, such as {@link #MODE_ALLOWED}.
*/
- public int getMode() {
+ public @Mode int getMode() {
return mMode;
}
@@ -2086,41 +2152,774 @@
};
}
+ /** @hide */
+ public interface HistoricalOpsVisitor {
+ void visitHistoricalOps(@NonNull HistoricalOps ops);
+ void visitHistoricalUidOps(@NonNull HistoricalUidOps ops);
+ void visitHistoricalPackageOps(@NonNull HistoricalPackageOps ops);
+ void visitHistoricalOp(@NonNull HistoricalOp ops);
+ }
+
/**
- * This class represents historical app op information about a package. The history
- * is aggregated information about ops for a certain amount of time such
- * as the times the op was accessed, the times the op was rejected, the total
- * duration the app op has been accessed.
+ * This class represents historical app op state of all UIDs for a given time interval.
+ *
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ public static final class HistoricalOps implements Parcelable {
+ private long mBeginTimeMillis;
+ private long mEndTimeMillis;
+ private @Nullable SparseArray<HistoricalUidOps> mHistoricalUidOps;
+
+ /** @hide */
+ @TestApi
+ public HistoricalOps(long beginTimeMillis, long endTimeMillis) {
+ Preconditions.checkState(beginTimeMillis <= endTimeMillis);
+ mBeginTimeMillis = beginTimeMillis;
+ mEndTimeMillis = endTimeMillis;
+ }
+
+ /** @hide */
+ public HistoricalOps(@NonNull HistoricalOps other) {
+ mBeginTimeMillis = other.mBeginTimeMillis;
+ mEndTimeMillis = other.mEndTimeMillis;
+ Preconditions.checkState(mBeginTimeMillis <= mEndTimeMillis);
+ if (other.mHistoricalUidOps != null) {
+ final int opCount = other.getUidCount();
+ for (int i = 0; i < opCount; i++) {
+ final HistoricalUidOps origOps = other.getUidOpsAt(i);
+ final HistoricalUidOps clonedOps = new HistoricalUidOps(origOps);
+ if (mHistoricalUidOps == null) {
+ mHistoricalUidOps = new SparseArray<>(opCount);
+ }
+ mHistoricalUidOps.put(clonedOps.getUid(), clonedOps);
+ }
+ }
+ }
+
+ private HistoricalOps(Parcel parcel) {
+ mBeginTimeMillis = parcel.readLong();
+ mEndTimeMillis = parcel.readLong();
+ final int[] uids = parcel.createIntArray();
+ if (!ArrayUtils.isEmpty(uids)) {
+ final ParceledListSlice<HistoricalUidOps> listSlice = parcel.readParcelable(
+ HistoricalOps.class.getClassLoader());
+ final List<HistoricalUidOps> uidOps = (listSlice != null)
+ ? listSlice.getList() : null;
+ if (uidOps == null) {
+ return;
+ }
+ for (int i = 0; i < uids.length; i++) {
+ if (mHistoricalUidOps == null) {
+ mHistoricalUidOps = new SparseArray<>();
+ }
+ mHistoricalUidOps.put(uids[i], uidOps.get(i));
+ }
+ }
+ }
+
+ /**
+ * Splice a piece from the beginning of these ops.
+ *
+ * @param splicePoint The fraction of the data to be spliced off.
+ *
+ * @hide
+ */
+ public @NonNull HistoricalOps spliceFromBeginning(double splicePoint) {
+ return splice(splicePoint, true);
+ }
+
+ /**
+ * Splice a piece from the end of these ops.
+ *
+ * @param fractionToRemove The fraction of the data to be spliced off.
+ *
+ * @hide
+ */
+ public @NonNull HistoricalOps spliceFromEnd(double fractionToRemove) {
+ return splice(fractionToRemove, false);
+ }
+
+ /**
+ * Splice a piece from the beginning or end of these ops.
+ *
+ * @param fractionToRemove The fraction of the data to be spliced off.
+ * @param beginning Whether to splice off the beginning or the end.
+ *
+ * @return The spliced off part.
+ *
+ * @hide
+ */
+ private @Nullable HistoricalOps splice(double fractionToRemove, boolean beginning) {
+ final long spliceBeginTimeMills;
+ final long spliceEndTimeMills;
+ if (beginning) {
+ spliceBeginTimeMills = mBeginTimeMillis;
+ spliceEndTimeMills = (long) (mBeginTimeMillis
+ + getDurationMillis() * fractionToRemove);
+ mBeginTimeMillis = spliceEndTimeMills;
+ } else {
+ spliceBeginTimeMills = (long) (mEndTimeMillis
+ - getDurationMillis() * fractionToRemove);
+ spliceEndTimeMills = mEndTimeMillis;
+ mEndTimeMillis = spliceBeginTimeMills;
+ }
+
+ HistoricalOps splice = null;
+ final int uidCount = getUidCount();
+ for (int i = 0; i < uidCount; i++) {
+ final HistoricalUidOps origOps = getUidOpsAt(i);
+ final HistoricalUidOps spliceOps = origOps.splice(fractionToRemove);
+ if (spliceOps != null) {
+ if (splice == null) {
+ splice = new HistoricalOps(spliceBeginTimeMills, spliceEndTimeMills);
+ }
+ if (splice.mHistoricalUidOps == null) {
+ splice.mHistoricalUidOps = new SparseArray<>();
+ }
+ splice.mHistoricalUidOps.put(spliceOps.getUid(), spliceOps);
+ }
+ }
+ return splice;
+ }
+
+ /**
+ * Merge the passed ops into the current ones. The time interval is a
+ * union of the current and passed in one and the passed in data is
+ * folded into the data of this instance.
+ *
+ * @hide
+ */
+ public void merge(@NonNull HistoricalOps other) {
+ mBeginTimeMillis = Math.min(mBeginTimeMillis, other.mBeginTimeMillis);
+ mEndTimeMillis = Math.max(mEndTimeMillis, other.mEndTimeMillis);
+ final int uidCount = other.getUidCount();
+ for (int i = 0; i < uidCount; i++) {
+ final HistoricalUidOps otherUidOps = other.getUidOpsAt(i);
+ final HistoricalUidOps thisUidOps = getUidOps(otherUidOps.getUid());
+ if (thisUidOps != null) {
+ thisUidOps.merge(otherUidOps);
+ } else {
+ if (mHistoricalUidOps == null) {
+ mHistoricalUidOps = new SparseArray<>();
+ }
+ mHistoricalUidOps.put(otherUidOps.getUid(), otherUidOps);
+ }
+ }
+ }
+
+ /**
+ * AppPermissionUsage the ops to leave only the data we filter for.
+ *
+ * @param uid Uid to filter for or {@link android.os.Process#INCIDENTD_UID} for all.
+ * @param packageName Package to filter for or null for all.
+ * @param opNames Ops to filter for or null for all.
+ * @param beginTimeMillis The begin time to filter for or {@link Long#MIN_VALUE} for all.
+ * @param endTimeMillis The end time to filter for or {@link Long#MAX_VALUE} for all.
+ *
+ * @hide
+ */
+ public void filter(int uid, @Nullable String packageName, @Nullable String[] opNames,
+ long beginTimeMillis, long endTimeMillis) {
+ final long durationMillis = getDurationMillis();
+ mBeginTimeMillis = Math.max(mBeginTimeMillis, beginTimeMillis);
+ mEndTimeMillis = Math.min(mEndTimeMillis, endTimeMillis);
+ final double scaleFactor = Math.min((double) (endTimeMillis - beginTimeMillis)
+ / (double) durationMillis, 1);
+ final int uidCount = getUidCount();
+ for (int i = uidCount - 1; i >= 0; i--) {
+ final HistoricalUidOps uidOp = mHistoricalUidOps.valueAt(i);
+ if (uid != Process.INVALID_UID && uid != uidOp.getUid()) {
+ mHistoricalUidOps.removeAt(i);
+ } else {
+ uidOp.filter(packageName, opNames, scaleFactor);
+ }
+ }
+ }
+
+ /** @hide */
+ public boolean isEmpty() {
+ if (getBeginTimeMillis() >= getEndTimeMillis()) {
+ return true;
+ }
+ final int uidCount = getUidCount();
+ for (int i = uidCount - 1; i >= 0; i--) {
+ final HistoricalUidOps uidOp = mHistoricalUidOps.valueAt(i);
+ if (!uidOp.isEmpty()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /** @hide */
+ public long getDurationMillis() {
+ return mEndTimeMillis - mBeginTimeMillis;
+ }
+
+ /** @hide */
+ @TestApi
+ public void increaseAccessCount(int opCode, int uid, @NonNull String packageName,
+ @UidState int uidState, long increment) {
+ getOrCreateHistoricalUidOps(uid).increaseAccessCount(opCode,
+ packageName, uidState, increment);
+ }
+
+ /** @hide */
+ @TestApi
+ public void increaseRejectCount(int opCode, int uid, @NonNull String packageName,
+ @UidState int uidState, long increment) {
+ getOrCreateHistoricalUidOps(uid).increaseRejectCount(opCode,
+ packageName, uidState, increment);
+ }
+
+ /** @hide */
+ @TestApi
+ public void increaseAccessDuration(int opCode, int uid, @NonNull String packageName,
+ @UidState int uidState, long increment) {
+ getOrCreateHistoricalUidOps(uid).increaseAccessDuration(opCode,
+ packageName, uidState, increment);
+ }
+
+ /** @hide */
+ @TestApi
+ public void offsetBeginAndEndTime(long offsetMillis) {
+ mBeginTimeMillis += offsetMillis;
+ mEndTimeMillis += offsetMillis;
+ }
+
+ /** @hide */
+ public void setBeginAndEndTime(long beginTimeMillis, long endTimeMillis) {
+ mBeginTimeMillis = beginTimeMillis;
+ mEndTimeMillis = endTimeMillis;
+ }
+
+ /** @hide */
+ public void setBeginTime(long beginTimeMillis) {
+ mBeginTimeMillis = beginTimeMillis;
+ }
+
+ /** @hide */
+ public void setEndTime(long endTimeMillis) {
+ mEndTimeMillis = endTimeMillis;
+ }
+
+ /**
+ * @return The beginning of the interval in milliseconds since
+ * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
+ */
+ public long getBeginTimeMillis() {
+ return mBeginTimeMillis;
+ }
+
+ /**
+ * @return The end of the interval in milliseconds since
+ * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
+ */
+ public long getEndTimeMillis() {
+ return mEndTimeMillis;
+ }
+
+ /**
+ * Gets number of UIDs with historical ops.
+ *
+ * @return The number of UIDs with historical ops.
+ *
+ * @see #getUidOpsAt(int)
+ */
+ public int getUidCount() {
+ if (mHistoricalUidOps == null) {
+ return 0;
+ }
+ return mHistoricalUidOps.size();
+ }
+
+ /**
+ * Gets the historical UID ops at a given index.
+ *
+ * @param index The index.
+ *
+ * @return The historical UID ops at the given index.
+ *
+ * @see #getUidCount()
+ */
+ public @NonNull HistoricalUidOps getUidOpsAt(int index) {
+ if (mHistoricalUidOps == null) {
+ throw new IndexOutOfBoundsException();
+ }
+ return mHistoricalUidOps.valueAt(index);
+ }
+
+ /**
+ * Gets the historical UID ops for a given UID.
+ *
+ * @param uid The UID.
+ *
+ * @return The historical ops for the UID.
+ */
+ public @Nullable HistoricalUidOps getUidOps(int uid) {
+ if (mHistoricalUidOps == null) {
+ return null;
+ }
+ return mHistoricalUidOps.get(uid);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeLong(mBeginTimeMillis);
+ parcel.writeLong(mEndTimeMillis);
+ if (mHistoricalUidOps != null) {
+ final int uidCount = mHistoricalUidOps.size();
+ parcel.writeInt(uidCount);
+ for (int i = 0; i < uidCount; i++) {
+ parcel.writeInt(mHistoricalUidOps.keyAt(i));
+ }
+ final List<HistoricalUidOps> opsList = new ArrayList<>(uidCount);
+ for (int i = 0; i < uidCount; i++) {
+ opsList.add(mHistoricalUidOps.valueAt(i));
+ }
+ parcel.writeParcelable(new ParceledListSlice<>(opsList), flags);
+ } else {
+ parcel.writeInt(-1);
+ }
+ }
+
+ /**
+ * Accepts a visitor to traverse the ops tree.
+ *
+ * @param visitor The visitor.
+ *
+ * @hide
+ */
+ public void accept(@NonNull HistoricalOpsVisitor visitor) {
+ visitor.visitHistoricalOps(this);
+ final int uidCount = getUidCount();
+ for (int i = 0; i < uidCount; i++) {
+ getUidOpsAt(i).accept(visitor);
+ }
+ }
+
+ private @NonNull HistoricalUidOps getOrCreateHistoricalUidOps(int uid) {
+ if (mHistoricalUidOps == null) {
+ mHistoricalUidOps = new SparseArray<>();
+ }
+ HistoricalUidOps historicalUidOp = mHistoricalUidOps.get(uid);
+ if (historicalUidOp == null) {
+ historicalUidOp = new HistoricalUidOps(uid);
+ mHistoricalUidOps.put(uid, historicalUidOp);
+ }
+ return historicalUidOp;
+ }
+
+ /**
+ * @return Rounded value up at the 0.5 boundary.
+ *
+ * @hide
+ */
+ public static double round(double value) {
+ final BigDecimal decimalScale = new BigDecimal(value);
+ return decimalScale.setScale(0, RoundingMode.HALF_UP).doubleValue();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ final HistoricalOps other = (HistoricalOps) obj;
+ if (mBeginTimeMillis != other.mBeginTimeMillis) {
+ return false;
+ }
+ if (mEndTimeMillis != other.mEndTimeMillis) {
+ return false;
+ }
+ if (mHistoricalUidOps == null) {
+ if (other.mHistoricalUidOps != null) {
+ return false;
+ }
+ } else if (!mHistoricalUidOps.equals(other.mHistoricalUidOps)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (int) (mBeginTimeMillis ^ (mBeginTimeMillis >>> 32));
+ result = 31 * result + mHistoricalUidOps.hashCode();
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "[from:"
+ + mBeginTimeMillis + " to:" + mEndTimeMillis + "]";
+ }
+
+ public static final Creator<HistoricalOps> CREATOR = new Creator<HistoricalOps>() {
+ @Override
+ public @NonNull HistoricalOps createFromParcel(@NonNull Parcel parcel) {
+ return new HistoricalOps(parcel);
+ }
+
+ @Override
+ public @NonNull HistoricalOps[] newArray(int size) {
+ return new HistoricalOps[size];
+ }
+ };
+ }
+
+ /**
+ * This class represents historical app op state for a UID.
+ *
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ public static final class HistoricalUidOps implements Parcelable {
+ private final int mUid;
+ private @Nullable ArrayMap<String, HistoricalPackageOps> mHistoricalPackageOps;
+
+ /** @hide */
+ public HistoricalUidOps(int uid) {
+ mUid = uid;
+ }
+
+ private HistoricalUidOps(@NonNull HistoricalUidOps other) {
+ mUid = other.mUid;
+ final int opCount = other.getPackageCount();
+ for (int i = 0; i < opCount; i++) {
+ final HistoricalPackageOps origOps = other.getPackageOpsAt(i);
+ final HistoricalPackageOps cloneOps = new HistoricalPackageOps(origOps);
+ if (mHistoricalPackageOps == null) {
+ mHistoricalPackageOps = new ArrayMap<>(opCount);
+ }
+ mHistoricalPackageOps.put(cloneOps.getPackageName(), cloneOps);
+ }
+ }
+
+ private HistoricalUidOps(@NonNull Parcel parcel) {
+ // No arg check since we always read from a trusted source.
+ mUid = parcel.readInt();
+ mHistoricalPackageOps = parcel.createTypedArrayMap(HistoricalPackageOps.CREATOR);
+ }
+
+ private @Nullable HistoricalUidOps splice(double fractionToRemove) {
+ HistoricalUidOps splice = null;
+ final int packageCount = getPackageCount();
+ for (int i = 0; i < packageCount; i++) {
+ final HistoricalPackageOps origOps = getPackageOpsAt(i);
+ final HistoricalPackageOps spliceOps = origOps.splice(fractionToRemove);
+ if (spliceOps != null) {
+ if (splice == null) {
+ splice = new HistoricalUidOps(mUid);
+ }
+ if (splice.mHistoricalPackageOps == null) {
+ splice.mHistoricalPackageOps = new ArrayMap<>();
+ }
+ splice.mHistoricalPackageOps.put(spliceOps.getPackageName(), spliceOps);
+ }
+ }
+ return splice;
+ }
+
+ private void merge(@NonNull HistoricalUidOps other) {
+ final int packageCount = other.getPackageCount();
+ for (int i = 0; i < packageCount; i++) {
+ final HistoricalPackageOps otherPackageOps = other.getPackageOpsAt(i);
+ final HistoricalPackageOps thisPackageOps = getPackageOps(
+ otherPackageOps.getPackageName());
+ if (thisPackageOps != null) {
+ thisPackageOps.merge(otherPackageOps);
+ } else {
+ if (mHistoricalPackageOps == null) {
+ mHistoricalPackageOps = new ArrayMap<>();
+ }
+ mHistoricalPackageOps.put(otherPackageOps.getPackageName(), otherPackageOps);
+ }
+ }
+ }
+
+ private void filter(@Nullable String packageName, @Nullable String[] opNames,
+ double fractionToRemove) {
+ final int packageCount = getPackageCount();
+ for (int i = packageCount - 1; i >= 0; i--) {
+ final HistoricalPackageOps packageOps = getPackageOpsAt(i);
+ if (packageName != null && !packageName.equals(packageOps.getPackageName())) {
+ mHistoricalPackageOps.removeAt(i);
+ } else {
+ packageOps.filter(opNames, fractionToRemove);
+ }
+ }
+ }
+
+ private boolean isEmpty() {
+ final int packageCount = getPackageCount();
+ for (int i = packageCount - 1; i >= 0; i--) {
+ final HistoricalPackageOps packageOps = mHistoricalPackageOps.valueAt(i);
+ if (!packageOps.isEmpty()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private void increaseAccessCount(int opCode, @NonNull String packageName,
+ @UidState int uidState, long increment) {
+ getOrCreateHistoricalPackageOps(packageName).increaseAccessCount(
+ opCode, uidState, increment);
+ }
+
+ private void increaseRejectCount(int opCode, @NonNull String packageName,
+ @UidState int uidState, long increment) {
+ getOrCreateHistoricalPackageOps(packageName).increaseRejectCount(
+ opCode, uidState, increment);
+ }
+
+ private void increaseAccessDuration(int opCode, @NonNull String packageName,
+ @UidState int uidState, long increment) {
+ getOrCreateHistoricalPackageOps(packageName).increaseAccessDuration(
+ opCode, uidState, increment);
+ }
+
+ /**
+ * @return The UID for which the data is related.
+ */
+ public int getUid() {
+ return mUid;
+ }
+
+ /**
+ * Gets number of packages with historical ops.
+ *
+ * @return The number of packages with historical ops.
+ *
+ * @see #getPackageOpsAt(int)
+ */
+ public int getPackageCount() {
+ if (mHistoricalPackageOps == null) {
+ return 0;
+ }
+ return mHistoricalPackageOps.size();
+ }
+
+ /**
+ * Gets the historical package ops at a given index.
+ *
+ * @param index The index.
+ *
+ * @return The historical package ops at the given index.
+ *
+ * @see #getPackageCount()
+ */
+ public @NonNull HistoricalPackageOps getPackageOpsAt(int index) {
+ if (mHistoricalPackageOps == null) {
+ throw new IndexOutOfBoundsException();
+ }
+ return mHistoricalPackageOps.valueAt(index);
+ }
+
+ /**
+ * Gets the historical package ops for a given package.
+ *
+ * @param packageName The package.
+ *
+ * @return The historical ops for the package.
+ */
+ public @Nullable HistoricalPackageOps getPackageOps(@NonNull String packageName) {
+ if (mHistoricalPackageOps == null) {
+ return null;
+ }
+ return mHistoricalPackageOps.get(packageName);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeInt(mUid);
+ parcel.writeTypedArrayMap(mHistoricalPackageOps, flags);
+ }
+
+ private void accept(@NonNull HistoricalOpsVisitor visitor) {
+ visitor.visitHistoricalUidOps(this);
+ final int packageCount = getPackageCount();
+ for (int i = 0; i < packageCount; i++) {
+ getPackageOpsAt(i).accept(visitor);
+ }
+ }
+
+ private @NonNull HistoricalPackageOps getOrCreateHistoricalPackageOps(
+ @NonNull String packageName) {
+ if (mHistoricalPackageOps == null) {
+ mHistoricalPackageOps = new ArrayMap<>();
+ }
+ HistoricalPackageOps historicalPackageOp = mHistoricalPackageOps.get(packageName);
+ if (historicalPackageOp == null) {
+ historicalPackageOp = new HistoricalPackageOps(packageName);
+ mHistoricalPackageOps.put(packageName, historicalPackageOp);
+ }
+ return historicalPackageOp;
+ }
+
+
+ public static final Creator<HistoricalUidOps> CREATOR = new Creator<HistoricalUidOps>() {
+ @Override
+ public @NonNull HistoricalUidOps createFromParcel(@NonNull Parcel parcel) {
+ return new HistoricalUidOps(parcel);
+ }
+
+ @Override
+ public @NonNull HistoricalUidOps[] newArray(int size) {
+ return new HistoricalUidOps[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ final HistoricalUidOps other = (HistoricalUidOps) obj;
+ if (mUid != other.mUid) {
+ return false;
+ }
+ if (mHistoricalPackageOps == null) {
+ if (other.mHistoricalPackageOps != null) {
+ return false;
+ }
+ } else if (!mHistoricalPackageOps.equals(other.mHistoricalPackageOps)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = mUid;
+ result = 31 * result + (mHistoricalPackageOps != null
+ ? mHistoricalPackageOps.hashCode() : 0);
+ return result;
+ }
+ }
+
+ /**
+ * This class represents historical app op information about a package.
*
* @hide
*/
@TestApi
@SystemApi
public static final class HistoricalPackageOps implements Parcelable {
- private final int mUid;
private final @NonNull String mPackageName;
- private final @NonNull List<HistoricalOpEntry> mEntries;
+ private @Nullable ArrayMap<String, HistoricalOp> mHistoricalOps;
- /**
- * @hide
- */
- public HistoricalPackageOps(int uid, @NonNull String packageName) {
- mUid = uid;
+ /** @hide */
+ public HistoricalPackageOps(@NonNull String packageName) {
mPackageName = packageName;
- mEntries = new ArrayList<>();
}
- HistoricalPackageOps(@NonNull Parcel parcel) {
- mUid = parcel.readInt();
+ private HistoricalPackageOps(@NonNull HistoricalPackageOps other) {
+ mPackageName = other.mPackageName;
+ final int opCount = other.getOpCount();
+ for (int i = 0; i < opCount; i++) {
+ final HistoricalOp origOp = other.getOpAt(i);
+ final HistoricalOp cloneOp = new HistoricalOp(origOp);
+ if (mHistoricalOps == null) {
+ mHistoricalOps = new ArrayMap<>(opCount);
+ }
+ mHistoricalOps.put(cloneOp.getOpName(), cloneOp);
+ }
+ }
+
+ private HistoricalPackageOps(@NonNull Parcel parcel) {
mPackageName = parcel.readString();
- mEntries = parcel.createTypedArrayList(HistoricalOpEntry.CREATOR);
+ mHistoricalOps = parcel.createTypedArrayMap(HistoricalOp.CREATOR);
}
- /**
- * @hide
- */
- public void addEntry(@NonNull HistoricalOpEntry entry) {
- mEntries.add(entry);
+ private @Nullable HistoricalPackageOps splice(double fractionToRemove) {
+ HistoricalPackageOps splice = null;
+ final int opCount = getOpCount();
+ for (int i = 0; i < opCount; i++) {
+ final HistoricalOp origOps = getOpAt(i);
+ final HistoricalOp spliceOps = origOps.splice(fractionToRemove);
+ if (spliceOps != null) {
+ if (splice == null) {
+ splice = new HistoricalPackageOps(mPackageName);
+ }
+ if (splice.mHistoricalOps == null) {
+ splice.mHistoricalOps = new ArrayMap<>();
+ }
+ splice.mHistoricalOps.put(spliceOps.getOpName(), spliceOps);
+ }
+ }
+ return splice;
+ }
+
+ private void merge(@NonNull HistoricalPackageOps other) {
+ final int opCount = other.getOpCount();
+ for (int i = 0; i < opCount; i++) {
+ final HistoricalOp otherOp = other.getOpAt(i);
+ final HistoricalOp thisOp = getOp(otherOp.getOpName());
+ if (thisOp != null) {
+ thisOp.merge(otherOp);
+ } else {
+ if (mHistoricalOps == null) {
+ mHistoricalOps = new ArrayMap<>();
+ }
+ mHistoricalOps.put(otherOp.getOpName(), otherOp);
+ }
+ }
+ }
+
+ private void filter(@Nullable String[] opNames, double scaleFactor) {
+ final int opCount = getOpCount();
+ for (int i = opCount - 1; i >= 0; i--) {
+ final HistoricalOp op = mHistoricalOps.valueAt(i);
+ if (opNames != null && !ArrayUtils.contains(opNames, op.getOpName())) {
+ mHistoricalOps.removeAt(i);
+ } else {
+ op.filter(scaleFactor);
+ }
+ }
+ }
+
+ private boolean isEmpty() {
+ final int opCount = getOpCount();
+ for (int i = opCount - 1; i >= 0; i--) {
+ final HistoricalOp op = mHistoricalOps.valueAt(i);
+ if (!op.isEmpty()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private void increaseAccessCount(int opCode, @UidState int uidState, long increment) {
+ getOrCreateHistoricalOp(opCode).increaseAccessCount(uidState, increment);
+ }
+
+ private void increaseRejectCount(int opCode, @UidState int uidState, long increment) {
+ getOrCreateHistoricalOp(opCode).increaseRejectCount(uidState, increment);
+ }
+
+ private void increaseAccessDuration(int opCode, @UidState int uidState, long increment) {
+ getOrCreateHistoricalOp(opCode).increaseAccessDuration(uidState, increment);
}
/**
@@ -2133,36 +2932,33 @@
}
/**
- * Gets the UID which the data represents.
+ * Gets number historical app ops.
*
- * @return The UID which the data represents.
+ * @return The number historical app ops.
+ *
+ * @see #getOpAt(int)
*/
- public int getUid() {
- return mUid;
+ public int getOpCount() {
+ if (mHistoricalOps == null) {
+ return 0;
+ }
+ return mHistoricalOps.size();
}
/**
- * Gets number historical app op entries.
- *
- * @return The number historical app op entries.
- *
- * @see #getEntryAt(int)
- */
- public int getEntryCount() {
- return mEntries.size();
- }
-
- /**
- * Gets the historical at a given index.
+ * Gets the historical op at a given index.
*
* @param index The index to lookup.
*
- * @return The entry at the given index.
+ * @return The op at the given index.
*
- * @see #getEntryCount()
+ * @see #getOpCount()
*/
- public @NonNull HistoricalOpEntry getEntryAt(int index) {
- return mEntries.get(index);
+ public @NonNull HistoricalOp getOpAt(int index) {
+ if (mHistoricalOps == null) {
+ throw new IndexOutOfBoundsException();
+ }
+ return mHistoricalOps.valueAt(index);
}
/**
@@ -2172,15 +2968,11 @@
*
* @return The historical entry for that op name.
*/
- public @Nullable HistoricalOpEntry getEntry(@NonNull String opName) {
- final int entryCount = mEntries.size();
- for (int i = 0; i < entryCount; i++) {
- final HistoricalOpEntry entry = mEntries.get(i);
- if (entry.getOp().equals(opName)) {
- return entry;
- }
+ public @Nullable HistoricalOp getOp(@NonNull String opName) {
+ if (mHistoricalOps == null) {
+ return null;
}
- return null;
+ return mHistoricalOps.get(opName);
}
@Override
@@ -2190,9 +2982,29 @@
@Override
public void writeToParcel(@NonNull Parcel parcel, int flags) {
- parcel.writeInt(mUid);
parcel.writeString(mPackageName);
- parcel.writeTypedList(mEntries, flags);
+ parcel.writeTypedArrayMap(mHistoricalOps, flags);
+ }
+
+ private void accept(@NonNull HistoricalOpsVisitor visitor) {
+ visitor.visitHistoricalPackageOps(this);
+ final int opCount = getOpCount();
+ for (int i = 0; i < opCount; i++) {
+ getOpAt(i).accept(visitor);
+ }
+ }
+
+ private @NonNull HistoricalOp getOrCreateHistoricalOp(int opCode) {
+ if (mHistoricalOps == null) {
+ mHistoricalOps = new ArrayMap<>();
+ }
+ final String opStr = sOpToString[opCode];
+ HistoricalOp op = mHistoricalOps.get(opStr);
+ if (op == null) {
+ op = new HistoricalOp(opCode);
+ mHistoricalOps.put(opStr, op);
+ }
+ return op;
}
public static final Creator<HistoricalPackageOps> CREATOR =
@@ -2207,49 +3019,177 @@
return new HistoricalPackageOps[size];
}
};
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ final HistoricalPackageOps other = (HistoricalPackageOps) obj;
+ if (!mPackageName.equals(other.mPackageName)) {
+ return false;
+ }
+ if (mHistoricalOps == null) {
+ if (other.mHistoricalOps != null) {
+ return false;
+ }
+ } else if (!mHistoricalOps.equals(other.mHistoricalOps)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = mPackageName != null ? mPackageName.hashCode() : 0;
+ result = 31 * result + (mHistoricalOps != null ? mHistoricalOps.hashCode() : 0);
+ return result;
+ }
}
/**
- * This class represents historical information about an app op. The history
- * is aggregated information about the op for a certain amount of time such
- * as the times the op was accessed, the times the op was rejected, the total
- * duration the app op has been accessed.
+ * This class represents historical information about an app op.
*
* @hide
*/
@TestApi
@SystemApi
- public static final class HistoricalOpEntry implements Parcelable {
+ public static final class HistoricalOp implements Parcelable {
private final int mOp;
- private final long[] mAccessCount;
- private final long[] mRejectCount;
- private final long[] mAccessDuration;
+ private @Nullable long[] mAccessCount;
+ private @Nullable long[] mRejectCount;
+ private @Nullable long[] mAccessDuration;
- /**
- * @hide
- */
- public HistoricalOpEntry(int op) {
+ /** @hide */
+ public HistoricalOp(int op) {
mOp = op;
mAccessCount = new long[_NUM_UID_STATE];
mRejectCount = new long[_NUM_UID_STATE];
mAccessDuration = new long[_NUM_UID_STATE];
}
- HistoricalOpEntry(@NonNull Parcel parcel) {
+ private HistoricalOp(@NonNull HistoricalOp other) {
+ mOp = other.mOp;
+ if (other.mAccessCount != null) {
+ System.arraycopy(other.mAccessCount, 0, getOrCreateAccessCount(),
+ 0, other.mAccessCount.length);
+ }
+ if (other.mRejectCount != null) {
+ System.arraycopy(other.mRejectCount, 0, getOrCreateRejectCount(),
+ 0, other.mRejectCount.length);
+ }
+ if (other.mAccessDuration != null) {
+ System.arraycopy(other.mAccessDuration, 0, getOrCreateAccessDuration(),
+ 0, other.mAccessDuration.length);
+ }
+ }
+
+ private HistoricalOp(@NonNull Parcel parcel) {
mOp = parcel.readInt();
mAccessCount = parcel.createLongArray();
mRejectCount = parcel.createLongArray();
mAccessDuration = parcel.createLongArray();
}
- /**
- * @hide
- */
- public void addEntry(@UidState int uidState, long accessCount,
- long rejectCount, long accessDuration) {
- mAccessCount[uidState] = accessCount;
- mRejectCount[uidState] = rejectCount;
- mAccessDuration[uidState] = accessDuration;
+ private void filter(double scaleFactor) {
+ scale(mAccessCount, scaleFactor);
+ scale(mRejectCount, scaleFactor);
+ scale(mAccessDuration, scaleFactor);
+ }
+
+ private boolean isEmpty() {
+ return !hasData(mAccessCount)
+ && !hasData(mRejectCount)
+ && !hasData(mAccessDuration);
+ }
+
+ private boolean hasData(@NonNull long[] array) {
+ for (long value : array) {
+ if (value != 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private @Nullable HistoricalOp splice(double fractionToRemove) {
+ HistoricalOp splice = null;
+ if (mAccessCount != null) {
+ for (int i = 0; i < _NUM_UID_STATE; i++) {
+ final long spliceAccessCount = Math.round(
+ mAccessCount[i] * fractionToRemove);
+ if (spliceAccessCount > 0) {
+ if (splice == null) {
+ splice = new HistoricalOp(mOp);
+ }
+ splice.getOrCreateAccessCount()[i] = spliceAccessCount;
+ mAccessCount[i] -= spliceAccessCount;
+ }
+ }
+ }
+
+ if (mRejectCount != null) {
+ for (int i = 0; i < _NUM_UID_STATE; i++) {
+ final long spliceRejectCount = Math.round(
+ mRejectCount[i] * fractionToRemove);
+
+ if (spliceRejectCount > 0) {
+ if (splice == null) {
+ splice = new HistoricalOp(mOp);
+ }
+ splice.getOrCreateRejectCount()[i] = spliceRejectCount;
+ mRejectCount[i] -= spliceRejectCount;
+ }
+ }
+ }
+
+ if (mAccessDuration != null) {
+ for (int i = 0; i < _NUM_UID_STATE; i++) {
+ final long spliceAccessDuration = Math.round(
+ mAccessDuration[i] * fractionToRemove);
+ if (spliceAccessDuration > 0) {
+ if (splice == null) {
+ splice = new HistoricalOp(mOp);
+ }
+ splice.getOrCreateAccessDuration()[i] = spliceAccessDuration;
+ mAccessDuration[i] -= spliceAccessDuration;
+ }
+ }
+ }
+ return splice;
+ }
+
+ private void merge(@NonNull HistoricalOp other) {
+ if (other.mAccessCount != null) {
+ for (int i = 0; i < _NUM_UID_STATE; i++) {
+ getOrCreateAccessCount()[i] += other.mAccessCount[i];
+ }
+ }
+ if (other.mRejectCount != null) {
+ for (int i = 0; i < _NUM_UID_STATE; i++) {
+ getOrCreateRejectCount()[i] += other.mRejectCount[i];
+ }
+ }
+ if (other.mAccessDuration != null) {
+ for (int i = 0; i < _NUM_UID_STATE; i++) {
+ getOrCreateAccessDuration()[i] += other.mAccessDuration[i];
+ }
+ }
+ }
+
+ private void increaseAccessCount(@UidState int uidState, long increment) {
+ getOrCreateAccessCount()[uidState] += increment;
+ }
+
+ private void increaseRejectCount(@UidState int uidState, long increment) {
+ getOrCreateRejectCount()[uidState] += increment;
+ }
+
+ private void increaseAccessDuration(@UidState int uidState, long increment) {
+ getOrCreateAccessDuration()[uidState] += increment;
}
/**
@@ -2257,10 +3197,15 @@
*
* @return The op name.
*/
- public @NonNull String getOp() {
+ public @NonNull String getOpName() {
return sOpToString[mOp];
}
+ /** @hide */
+ public int getOpCode() {
+ return mOp;
+ }
+
/**
* Gets the number times the op was accessed (performed) in the foreground.
*
@@ -2270,6 +3215,9 @@
* @see #getAccessCount(int)
*/
public long getForegroundAccessCount() {
+ if (mAccessCount == null) {
+ return 0;
+ }
return sum(mAccessCount, UID_STATE_PERSISTENT, UID_STATE_LAST_NON_RESTRICTED + 1);
}
@@ -2282,6 +3230,9 @@
* @see #getAccessCount(int)
*/
public long getBackgroundAccessCount() {
+ if (mAccessCount == null) {
+ return 0;
+ }
return sum(mAccessCount, UID_STATE_LAST_NON_RESTRICTED + 1, _NUM_UID_STATE);
}
@@ -2299,6 +3250,9 @@
* @see #getBackgroundAccessCount()
*/
public long getAccessCount(@UidState int uidState) {
+ if (mAccessCount == null) {
+ return 0;
+ }
return mAccessCount[uidState];
}
@@ -2311,6 +3265,9 @@
* @see #getRejectCount(int)
*/
public long getForegroundRejectCount() {
+ if (mRejectCount == null) {
+ return 0;
+ }
return sum(mRejectCount, UID_STATE_PERSISTENT, UID_STATE_LAST_NON_RESTRICTED + 1);
}
@@ -2323,6 +3280,9 @@
* @see #getRejectCount(int)
*/
public long getBackgroundRejectCount() {
+ if (mRejectCount == null) {
+ return 0;
+ }
return sum(mRejectCount, UID_STATE_LAST_NON_RESTRICTED + 1, _NUM_UID_STATE);
}
@@ -2340,6 +3300,9 @@
* @see #getBackgroundRejectCount()
*/
public long getRejectCount(@UidState int uidState) {
+ if (mRejectCount == null) {
+ return 0;
+ }
return mRejectCount[uidState];
}
@@ -2352,6 +3315,9 @@
* @see #getAccessDuration(int)
*/
public long getForegroundAccessDuration() {
+ if (mAccessDuration == null) {
+ return 0;
+ }
return sum(mAccessDuration, UID_STATE_PERSISTENT, UID_STATE_LAST_NON_RESTRICTED + 1);
}
@@ -2364,6 +3330,9 @@
* @see #getAccessDuration(int)
*/
public long getBackgroundAccessDuration() {
+ if (mAccessDuration == null) {
+ return 0;
+ }
return sum(mAccessDuration, UID_STATE_LAST_NON_RESTRICTED + 1, _NUM_UID_STATE);
}
@@ -2381,6 +3350,9 @@
* @see #getBackgroundAccessDuration()
*/
public long getAccessDuration(@UidState int uidState) {
+ if (mAccessDuration == null) {
+ return 0;
+ }
return mAccessDuration[uidState];
}
@@ -2397,34 +3369,29 @@
parcel.writeLongArray(mAccessDuration);
}
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- }
- if (other == null || getClass() != other.getClass()) {
- return false;
- }
- final HistoricalOpEntry otherInstance = (HistoricalOpEntry) other;
- if (mOp != otherInstance.mOp) {
- return false;
- }
- if (!Arrays.equals(mAccessCount, otherInstance.mAccessCount)) {
- return false;
- }
- if (!Arrays.equals(mRejectCount, otherInstance.mRejectCount)) {
- return false;
- }
- return Arrays.equals(mAccessDuration, otherInstance.mAccessDuration);
+ private void accept(@NonNull HistoricalOpsVisitor visitor) {
+ visitor.visitHistoricalOp(this);
}
- @Override
- public int hashCode() {
- int result = mOp;
- result = 31 * result + Arrays.hashCode(mAccessCount);
- result = 31 * result + Arrays.hashCode(mRejectCount);
- result = 31 * result + Arrays.hashCode(mAccessDuration);
- return result;
+ private @NonNull long[] getOrCreateAccessCount() {
+ if (mAccessCount == null) {
+ mAccessCount = new long[_NUM_UID_STATE];
+ }
+ return mAccessCount;
+ }
+
+ private @NonNull long[] getOrCreateRejectCount() {
+ if (mRejectCount == null) {
+ mRejectCount = new long[_NUM_UID_STATE];
+ }
+ return mRejectCount;
+ }
+
+ private @NonNull long[] getOrCreateAccessDuration() {
+ if (mAccessDuration == null) {
+ mAccessDuration = new long[_NUM_UID_STATE];
+ }
+ return mAccessDuration;
}
/**
@@ -2444,17 +3411,62 @@
return totalCount;
}
- public static final Creator<HistoricalOpEntry> CREATOR = new Creator<HistoricalOpEntry>() {
+ /**
+ * Multiplies the entries in the array with the passed in scale factor and
+ * rounds the result at up 0.5 boundary.
+ *
+ * @param data The data to scale.
+ * @param scaleFactor The scale factor.
+ */
+ private static void scale(@NonNull long[] data, double scaleFactor) {
+ if (data != null) {
+ for (int i = 0; i < _NUM_UID_STATE; i++) {
+ data[i] = (long) HistoricalOps.round((double) data[i] * scaleFactor);
+ }
+ }
+ }
+
+ public static final Creator<HistoricalOp> CREATOR = new Creator<HistoricalOp>() {
@Override
- public @NonNull HistoricalOpEntry createFromParcel(@NonNull Parcel source) {
- return new HistoricalOpEntry(source);
+ public @NonNull HistoricalOp createFromParcel(@NonNull Parcel source) {
+ return new HistoricalOp(source);
}
@Override
- public @NonNull HistoricalOpEntry[] newArray(int size) {
- return new HistoricalOpEntry[size];
+ public @NonNull HistoricalOp[] newArray(int size) {
+ return new HistoricalOp[size];
}
};
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ final HistoricalOp other = (HistoricalOp) obj;
+ if (mOp != other.mOp) {
+ return false;
+ }
+ if (!Arrays.equals(mAccessCount, other.mAccessCount)) {
+ return false;
+ }
+ if (!Arrays.equals(mRejectCount, other.mRejectCount)) {
+ return false;
+ }
+ return Arrays.equals(mAccessDuration, other.mAccessDuration);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = mOp;
+ result = 31 * result + Arrays.hashCode(mAccessCount);
+ result = 31 * result + Arrays.hashCode(mRejectCount);
+ result = 31 * result + Arrays.hashCode(mAccessDuration);
+ return result;
+ }
}
/**
@@ -2520,6 +3532,24 @@
* @param ops The set of operations you are interested in, or null if you want all of them.
* @hide
*/
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
+ public @NonNull List<AppOpsManager.PackageOps> getPackagesForOps(@Nullable String[] ops) {
+ final int opCount = ops.length;
+ final int[] opCodes = new int[opCount];
+ for (int i = 0; i < opCount; i++) {
+ opCodes[i] = sOpStrToOp.get(ops[i]);
+ }
+ final List<AppOpsManager.PackageOps> result = getPackagesForOps(opCodes);
+ return (result != null) ? result : Collections.emptyList();
+ }
+
+ /**
+ * Retrieve current operation state for all applications.
+ *
+ * @param ops The set of operations you are interested in, or null if you want all of them.
+ * @hide
+ */
@RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
@UnsupportedAppUsage
public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
@@ -2536,11 +3566,17 @@
* @param uid The uid of the application of interest.
* @param packageName The name of the application of interest.
* @param ops The set of operations you are interested in, or null if you want all of them.
+ *
+ * @deprecated The int op codes are not stable and you should use the string based op
+ * names which are stable and namespaced. Use
+ * {@link #getOpsForPackage(int, String, String...)})}.
+ *
* @hide
*/
+ @Deprecated
@SystemApi
@RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
- public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) {
+ public List<PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) {
try {
return mService.getOpsForPackage(uid, packageName, ops);
} catch (RemoteException e) {
@@ -2549,7 +3585,49 @@
}
/**
- * Retrieve historical app op stats for a package.
+ * Retrieve current operation state for one application. The UID and the
+ * package must match.
+ *
+ * @param uid The uid of the application of interest.
+ * @param packageName The name of the application of interest.
+ * @param ops The set of operations you are interested in, or null if you want all of them.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
+ public @NonNull List<AppOpsManager.PackageOps> getOpsForPackage(int uid,
+ @NonNull String packageName, @Nullable String... ops) {
+ int[] opCodes = null;
+ if (ops != null) {
+ opCodes = new int[ops.length];
+ for (int i = 0; i < ops.length; i++) {
+ opCodes[i] = strOpToOp(ops[i]);
+ }
+ }
+ try {
+ final List<PackageOps> result = mService.getOpsForPackage(uid, packageName, opCodes);
+ if (result == null) {
+ return Collections.emptyList();
+ }
+ return result;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Retrieve historical app op stats for a period.
+ *
+ * <p>Historical data can be obtained
+ * for a specific package by specifying the <code>packageName</code> argument,
+ * for a specific UID if specifying the <code>uid</code> argument, for a
+ * specific package in a UID by specifying the <code>packageName</code>
+ * and the <code>uid</code> arguments, for all packages by passing
+ * {@link android.os.Process#INVALID_UID} and <code>null</code> for the
+ * <code>uid</code> and <code>packageName</code> arguments, respectively.
+ * Similarly, you can specify the <code>opNames</code> argument to get
+ * data only for these ops or <code>null</code> for all ops.
*
* @param uid The UID to query for.
* @param packageName The package to query for.
@@ -2558,10 +3636,12 @@
* negative.
* @param endTimeMillis The end of the interval in milliseconds since
* epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be after
- * {@code beginTimeMillis}.
+ * {@code beginTimeMillis}. Pass {@link Long#MAX_VALUE} to get the most recent
+ * history including ops that happen while this call is in flight.
* @param opNames The ops to query for. Pass {@code null} for all ops.
- *
- * @return The historical ops or {@code null} if there are no ops for this package.
+ * @param executor Executor on which to run the callback. If <code>null</code>
+ * the callback is executed on the default executor running on the main thread.
+ * @param callback Callback on which to deliver the result.
*
* @throws IllegalArgumentException If any of the argument contracts is violated.
*
@@ -2570,47 +3650,78 @@
@TestApi
@SystemApi
@RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
- public @Nullable HistoricalPackageOps getHistoricalPackagesOps(
- int uid, @NonNull String packageName, @Nullable String[] opNames,
- long beginTimeMillis, long endTimeMillis) {
+ public void getHistoricalOps(int uid, @Nullable String packageName,
+ @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+ @NonNull Executor executor, @NonNull Consumer<HistoricalOps> callback) {
+ Preconditions.checkNotNull(executor, "executor cannot be null");
+ Preconditions.checkNotNull(callback, "callback cannot be null");
try {
- return mService.getHistoricalPackagesOps(uid, packageName, opNames,
- beginTimeMillis, endTimeMillis);
+ mService.getHistoricalOps(uid, packageName, opNames, beginTimeMillis, endTimeMillis,
+ new RemoteCallback((result) -> {
+ final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.accept(ops));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Retrieve historical app op stats for all packages.
+ * Retrieve historical app op stats for a period.
*
+ * <p>Historical data can be obtained
+ * for a specific package by specifying the <code>packageName</code> argument,
+ * for a specific UID if specifying the <code>uid</code> argument, for a
+ * specific package in a UID by specifying the <code>packageName</code>
+ * and the <code>uid</code> arguments, for all packages by passing
+ * {@link android.os.Process#INVALID_UID} and <code>null</code> for the
+ * <code>uid</code> and <code>packageName</code> arguments, respectively.
+ * Similarly, you can specify the <code>opNames</code> argument to get
+ * data only for these ops or <code>null</code> for all ops.
+ * <p>
+ * This method queries only the on disk state and the returned ops are raw,
+ * which is their times are relative to the history start as opposed to the
+ * epoch start.
+ *
+ * @param uid The UID to query for.
+ * @param packageName The package to query for.
* @param beginTimeMillis The beginning of the interval in milliseconds since
- * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be non
- * negative.
+ * history start. History time grows as one goes into the past.
* @param endTimeMillis The end of the interval in milliseconds since
- * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be after
+ * history start. History time grows as one goes into the past. Must be after
* {@code beginTimeMillis}.
* @param opNames The ops to query for. Pass {@code null} for all ops.
- *
- * @return The historical ops or an empty list if there are no ops for any package.
+ * @param executor Executor on which to run the callback. If <code>null</code>
+ * the callback is executed on the default executor running on the main thread.
+ * @param callback Callback on which to deliver the result.
*
* @throws IllegalArgumentException If any of the argument contracts is violated.
*
* @hide
*/
@TestApi
- @SystemApi
@RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
- public @NonNull List<HistoricalPackageOps> getAllHistoricPackagesOps(
- @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis) {
+ public void getHistoricalOpsFromDiskRaw(int uid, @Nullable String packageName,
+ @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+ @Nullable Executor executor, @NonNull Consumer<HistoricalOps> callback) {
+ Preconditions.checkNotNull(executor, "executor cannot be null");
+ Preconditions.checkNotNull(callback, "callback cannot be null");
try {
- @SuppressWarnings("unchecked")
- final ParceledListSlice<HistoricalPackageOps> payload =
- mService.getAllHistoricalPackagesOps(opNames, beginTimeMillis, endTimeMillis);
- if (payload != null) {
- return payload.getList();
- }
- return Collections.emptyList();
+ mService.getHistoricalOpsFromDiskRaw(uid, packageName, opNames, beginTimeMillis,
+ endTimeMillis, new RemoteCallback((result) -> {
+ final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.accept(ops));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2627,7 +3738,7 @@
* @hide
*/
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
- public void setUidMode(int code, int uid, int mode) {
+ public void setUidMode(int code, int uid, @Mode int mode) {
try {
mService.setUidMode(code, uid, mode);
} catch (RemoteException e) {
@@ -2648,7 +3759,7 @@
@SystemApi
@TestApi
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
- public void setUidMode(String appOp, int uid, int mode) {
+ public void setUidMode(String appOp, int uid, @Mode int mode) {
try {
mService.setUidMode(AppOpsManager.strOpToOp(appOp), uid, mode);
} catch (RemoteException e) {
@@ -2680,7 +3791,7 @@
/** @hide */
@TestApi
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
- public void setMode(int code, int uid, String packageName, int mode) {
+ public void setMode(int code, int uid, String packageName, @Mode int mode) {
try {
mService.setMode(code, uid, packageName, mode);
} catch (RemoteException e) {
@@ -2701,7 +3812,7 @@
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
- public void setMode(String op, int uid, String packageName, int mode) {
+ public void setMode(String op, int uid, String packageName, @Mode int mode) {
try {
mService.setMode(strOpToOp(op), uid, packageName, mode);
} catch (RemoteException e) {
@@ -2722,7 +3833,7 @@
*/
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
@UnsupportedAppUsage
- public void setRestriction(int code, @AttributeUsage int usage, int mode,
+ public void setRestriction(int code, @AttributeUsage int usage, @Mode int mode,
String[] exceptionPackages) {
try {
final int uid = Binder.getCallingUid();
@@ -3507,6 +4618,104 @@
}
/**
+ * Configures the app ops persistence for testing.
+ *
+ * @param mode The mode in which the historical registry operates.
+ * @param baseSnapshotInterval The base interval on which we would be persisting a snapshot of
+ * the historical data. The history is recursive where every subsequent step encompasses
+ * {@code compressionStep} longer interval with {@code compressionStep} distance between
+ * snapshots.
+ * @param compressionStep The compression step in every iteration.
+ *
+ * @see #HISTORICAL_MODE_DISABLED
+ * @see #HISTORICAL_MODE_ENABLED_ACTIVE
+ * @see #HISTORICAL_MODE_ENABLED_PASSIVE
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(Manifest.permission.MANAGE_APPOPS)
+ public void setHistoryParameters(@HistoricalMode int mode, long baseSnapshotInterval,
+ int compressionStep) {
+ try {
+ mService.setHistoryParameters(mode, baseSnapshotInterval, compressionStep);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Offsets the history by the given duration.
+ *
+ * @param offsetMillis The offset duration.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(Manifest.permission.MANAGE_APPOPS)
+ public void offsetHistory(long offsetMillis) {
+ try {
+ mService.offsetHistory(offsetMillis);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Adds ops to the history directly. This could be useful for testing especially
+ * when the historical registry operates in {@link #HISTORICAL_MODE_ENABLED_PASSIVE}
+ * mode.
+ *
+ * @param ops The ops to add to the history.
+ *
+ * @see #setHistoryParameters(int, long, int)
+ * @see #HISTORICAL_MODE_ENABLED_PASSIVE
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(Manifest.permission.MANAGE_APPOPS)
+ public void addHistoricalOps(@NonNull HistoricalOps ops) {
+ try {
+ mService.addHistoricalOps(ops);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Resets the app ops persistence for testing.
+ *
+ * @see #setHistoryParameters(int, long, int)
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(Manifest.permission.MANAGE_APPOPS)
+ public void resetHistoryParameters() {
+ try {
+ mService.resetHistoryParameters();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Clears all app ops history.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(Manifest.permission.MANAGE_APPOPS)
+ public void clearHistory() {
+ try {
+ mService.clearHistory();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns all supported operation names.
* @hide
*/
@@ -3538,4 +4747,64 @@
}
return time;
}
+
+ /** @hide */
+ public static String uidStateToString(@UidState int uidState) {
+ switch (uidState) {
+ case UID_STATE_PERSISTENT: {
+ return "UID_STATE_PERSISTENT";
+ }
+ case UID_STATE_TOP: {
+ return "UID_STATE_TOP";
+ }
+ case UID_STATE_FOREGROUND_SERVICE: {
+ return "UID_STATE_FOREGROUND_SERVICE";
+ }
+ case UID_STATE_FOREGROUND: {
+ return "UID_STATE_FOREGROUND";
+ }
+ case UID_STATE_BACKGROUND: {
+ return "UID_STATE_BACKGROUND";
+ }
+ case UID_STATE_CACHED: {
+ return "UID_STATE_CACHED";
+ }
+ default: {
+ return "UNKNOWN";
+ }
+ }
+ }
+
+ /** @hide */
+ public static int parseHistoricalMode(@NonNull String mode) {
+ switch (mode) {
+ case "HISTORICAL_MODE_ENABLED_ACTIVE": {
+ return HISTORICAL_MODE_ENABLED_ACTIVE;
+ }
+ case "HISTORICAL_MODE_ENABLED_PASSIVE": {
+ return HISTORICAL_MODE_ENABLED_PASSIVE;
+ }
+ default: {
+ return HISTORICAL_MODE_DISABLED;
+ }
+ }
+ }
+
+ /** @hide */
+ public static String historicalModeToString(@HistoricalMode int mode) {
+ switch (mode) {
+ case HISTORICAL_MODE_DISABLED: {
+ return "HISTORICAL_MODE_DISABLED";
+ }
+ case HISTORICAL_MODE_ENABLED_ACTIVE: {
+ return "HISTORICAL_MODE_ENABLED_ACTIVE";
+ }
+ case HISTORICAL_MODE_ENABLED_PASSIVE: {
+ return "HISTORICAL_MODE_ENABLED_PASSIVE";
+ }
+ default: {
+ return "UNKNOWN";
+ }
+ }
+ }
}
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index b5295d1..07dbb6b 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -124,6 +124,10 @@
/** Restart the activity after it was stopped. */
public abstract void performRestartActivity(IBinder token, boolean start);
+ /** Set pending activity configuration in case it will be updated by other transaction item. */
+ public abstract void updatePendingActivityConfiguration(IBinder activityToken,
+ Configuration overrideConfig);
+
/** Deliver activity (override) configuration change. */
public abstract void handleActivityConfigurationChanged(IBinder activityToken,
Configuration overrideConfig, int displayId);
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 9ddf4bd..d827f6c 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -21,8 +21,11 @@
import android.app.ContextImpl.ServiceInitializationState;
import android.app.admin.DevicePolicyManager;
import android.app.admin.IDevicePolicyManager;
+import android.app.contentsuggestions.ContentSuggestionsManager;
+import android.app.contentsuggestions.IContentSuggestionsManager;
import android.app.job.IJobScheduler;
import android.app.job.JobScheduler;
+import android.app.prediction.AppPredictionManager;
import android.app.role.RoleManager;
import android.app.slice.SliceManager;
import android.app.timedetector.TimeDetector;
@@ -95,8 +98,10 @@
import android.net.EthernetManager;
import android.net.IConnectivityManager;
import android.net.IEthernetManager;
+import android.net.IIpMemoryStore;
import android.net.IIpSecService;
import android.net.INetworkPolicyManager;
+import android.net.IpMemoryStore;
import android.net.IpSecManager;
import android.net.NetworkPolicyManager;
import android.net.NetworkScoreManager;
@@ -120,6 +125,7 @@
import android.nfc.NfcManager;
import android.os.BatteryManager;
import android.os.BatteryStats;
+import android.os.BugreportManager;
import android.os.Build;
import android.os.DeviceIdleManager;
import android.os.DropBoxManager;
@@ -127,6 +133,7 @@
import android.os.IBatteryPropertiesRegistrar;
import android.os.IBinder;
import android.os.IDeviceIdleController;
+import android.os.IDumpstate;
import android.os.IHardwarePropertiesManager;
import android.os.IPowerManager;
import android.os.IRecoverySystem;
@@ -321,10 +328,21 @@
registerService(Context.NETWORK_STACK_SERVICE, NetworkStack.class,
new StaticServiceFetcher<NetworkStack>() {
- @Override
- public NetworkStack createService() {
- return new NetworkStack();
- }});
+ @Override
+ public NetworkStack createService() {
+ return new NetworkStack();
+ }});
+
+ registerService(Context.IP_MEMORY_STORE_SERVICE, IpMemoryStore.class,
+ new CachedServiceFetcher<IpMemoryStore>() {
+ @Override
+ public IpMemoryStore createService(final ContextImpl ctx)
+ throws ServiceNotFoundException {
+ IBinder b = ServiceManager.getServiceOrThrow(
+ Context.IP_MEMORY_STORE_SERVICE);
+ IIpMemoryStore service = IIpMemoryStore.Stub.asInterface(b);
+ return new IpMemoryStore(ctx, service);
+ }});
registerService(Context.IPSEC_SERVICE, IpSecManager.class,
new CachedServiceFetcher<IpSecManager>() {
@@ -1069,6 +1087,16 @@
return new IncidentManager(ctx);
}});
+ registerService(Context.BUGREPORT_SERVICE, BugreportManager.class,
+ new CachedServiceFetcher<BugreportManager>() {
+ @Override
+ public BugreportManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ IBinder b = ServiceManager.getServiceOrThrow(Context.BUGREPORT_SERVICE);
+ return new BugreportManager(ctx.getOuterContext(),
+ IDumpstate.Stub.asInterface(b));
+ }});
+
registerService(Context.AUTOFILL_MANAGER_SERVICE, AutofillManager.class,
new CachedServiceFetcher<AutofillManager>() {
@Override
@@ -1095,6 +1123,29 @@
return null;
}});
+ registerService(Context.APP_PREDICTION_SERVICE, AppPredictionManager.class,
+ new CachedServiceFetcher<AppPredictionManager>() {
+ @Override
+ public AppPredictionManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ return new AppPredictionManager(ctx);
+ }
+ });
+
+ registerService(Context.CONTENT_SUGGESTIONS_SERVICE,
+ ContentSuggestionsManager.class,
+ new CachedServiceFetcher<ContentSuggestionsManager>() {
+ @Override
+ public ContentSuggestionsManager createService(ContextImpl ctx) {
+ // No throw as this is an optional service
+ IBinder b = ServiceManager.getService(
+ Context.CONTENT_SUGGESTIONS_SERVICE);
+ IContentSuggestionsManager service =
+ IContentSuggestionsManager.Stub.asInterface(b);
+ return new ContentSuggestionsManager(service);
+ }
+ });
+
registerService(Context.VR_SERVICE, VrManager.class, new CachedServiceFetcher<VrManager>() {
@Override
public VrManager createService(ContextImpl ctx) throws ServiceNotFoundException {
diff --git a/core/java/android/app/contentsuggestions/ClassificationsRequest.aidl b/core/java/android/app/contentsuggestions/ClassificationsRequest.aidl
new file mode 100644
index 0000000..a66413b
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ClassificationsRequest.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.contentsuggestions;
+
+parcelable ClassificationsRequest;
diff --git a/core/java/android/app/contentsuggestions/ClassificationsRequest.java b/core/java/android/app/contentsuggestions/ClassificationsRequest.java
new file mode 100644
index 0000000..3f71518
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ClassificationsRequest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class ClassificationsRequest implements Parcelable {
+ @NonNull
+ private final List<ContentSelection> mSelections;
+ @Nullable
+ private final Bundle mExtras;
+
+ private ClassificationsRequest(@NonNull List<ContentSelection> selections,
+ @Nullable Bundle extras) {
+ mSelections = selections;
+ mExtras = extras;
+ }
+
+ /**
+ * Return request selections.
+ */
+ public List<ContentSelection> getSelections() {
+ return mSelections;
+ }
+
+ /**
+ * Return the request extras.
+ */
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeTypedList(mSelections);
+ dest.writeBundle(mExtras);
+ }
+
+ public static final Creator<ClassificationsRequest> CREATOR =
+ new Creator<ClassificationsRequest>() {
+ @Override
+ public ClassificationsRequest createFromParcel(Parcel source) {
+ return new ClassificationsRequest(
+ source.createTypedArrayList(ContentSelection.CREATOR),
+ source.readBundle());
+ }
+
+ @Override
+ public ClassificationsRequest[] newArray(int size) {
+ return new ClassificationsRequest[size];
+ }
+ };
+
+ /**
+ * A builder for classifications request events.
+ * @hide
+ */
+ @SystemApi
+ public static final class Builder {
+
+ private final List<ContentSelection> mSelections;
+ private Bundle mExtras;
+
+ public Builder(@NonNull List<ContentSelection> selections) {
+ mSelections = selections;
+ }
+
+ /**
+ * Sets the request extras.
+ */
+ public Builder setExtras(@NonNull Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
+ /**
+ * Builds a new request instance.
+ */
+ public ClassificationsRequest build() {
+ return new ClassificationsRequest(mSelections, mExtras);
+ }
+ }
+}
diff --git a/core/java/android/app/contentsuggestions/ContentClassification.aidl b/core/java/android/app/contentsuggestions/ContentClassification.aidl
new file mode 100644
index 0000000..f67b2c8
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ContentClassification.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.contentsuggestions;
+
+parcelable ContentClassification;
diff --git a/core/java/android/app/contentsuggestions/ContentClassification.java b/core/java/android/app/contentsuggestions/ContentClassification.java
new file mode 100644
index 0000000..f18520f
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ContentClassification.java
@@ -0,0 +1,79 @@
+/*
+ * 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.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class ContentClassification implements Parcelable {
+ @NonNull
+ private final String mClassificationId;
+ @NonNull
+ private final Bundle mExtras;
+
+ public ContentClassification(@NonNull String classificationId, @NonNull Bundle extras) {
+ mClassificationId = classificationId;
+ mExtras = extras;
+ }
+
+ /**
+ * Return the classification id.
+ */
+ public String getId() {
+ return mClassificationId;
+ }
+
+ /**
+ * Return the classification extras.
+ */
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mClassificationId);
+ dest.writeBundle(mExtras);
+ }
+
+ public static final Creator<ContentClassification> CREATOR =
+ new Creator<ContentClassification>() {
+ @Override
+ public ContentClassification createFromParcel(Parcel source) {
+ return new ContentClassification(
+ source.readString(),
+ source.readBundle());
+ }
+
+ @Override
+ public ContentClassification[] newArray(int size) {
+ return new ContentClassification[size];
+ }
+ };
+}
diff --git a/core/java/android/app/contentsuggestions/ContentSelection.aidl b/core/java/android/app/contentsuggestions/ContentSelection.aidl
new file mode 100644
index 0000000..e626d69
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ContentSelection.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.contentsuggestions;
+
+parcelable ContentSelection;
diff --git a/core/java/android/app/contentsuggestions/ContentSelection.java b/core/java/android/app/contentsuggestions/ContentSelection.java
new file mode 100644
index 0000000..a8917f7
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ContentSelection.java
@@ -0,0 +1,79 @@
+/*
+ * 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.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class ContentSelection implements Parcelable {
+ @NonNull
+ private final String mSelectionId;
+ @NonNull
+ private final Bundle mExtras;
+
+ public ContentSelection(@NonNull String selectionId, @NonNull Bundle extras) {
+ mSelectionId = selectionId;
+ mExtras = extras;
+ }
+
+ /**
+ * Return the selection id.
+ */
+ public String getId() {
+ return mSelectionId;
+ }
+
+ /**
+ * Return the selection extras.
+ */
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mSelectionId);
+ dest.writeBundle(mExtras);
+ }
+
+ public static final Creator<ContentSelection> CREATOR =
+ new Creator<ContentSelection>() {
+ @Override
+ public ContentSelection createFromParcel(Parcel source) {
+ return new ContentSelection(
+ source.readString(),
+ source.readBundle());
+ }
+
+ @Override
+ public ContentSelection[] newArray(int size) {
+ return new ContentSelection[size];
+ }
+ };
+}
diff --git a/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java b/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
new file mode 100644
index 0000000..b4d8977
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
@@ -0,0 +1,230 @@
+/*
+ * 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.contentsuggestions;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * When provided with content from an app, can suggest selections and classifications of that
+ * content.
+ *
+ * <p>The content is mainly a snapshot of a running task, the selections will be text and image
+ * selections with that image content. These mSelections can then be classified to find actions and
+ * entities on those selections.
+ *
+ * <p>Only accessible to blessed components such as Overview.
+ *
+ * @hide
+ */
+@SystemApi
+public final class ContentSuggestionsManager {
+ private static final String TAG = ContentSuggestionsManager.class.getSimpleName();
+
+ @Nullable
+ private final IContentSuggestionsManager mService;
+
+ /** @hide */
+ public ContentSuggestionsManager(@Nullable IContentSuggestionsManager service) {
+ mService = service;
+ }
+
+ /**
+ * Hints to the system that a new context image for the provided task should be sent to the
+ * system content suggestions service.
+ *
+ * @param taskId of the task to snapshot.
+ * @param imageContextRequestExtras sent with with request to provide implementation specific
+ * extra information.
+ */
+ public void provideContextImage(int taskId, @NonNull Bundle imageContextRequestExtras) {
+ if (mService == null) {
+ Log.e(TAG, "provideContextImage called, but no ContentSuggestionsManager configured");
+ return;
+ }
+
+ try {
+ mService.provideContextImage(taskId, imageContextRequestExtras);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Suggest content selections, based on the provided task id and optional
+ * location on screen provided in the request. Called after provideContextImage().
+ * The result can be passed to
+ * {@link #classifyContentSelections(ClassificationsRequest, Executor, ClassificationsCallback)}
+ * to classify actions and entities on these selections.
+ *
+ * @param request containing the task and point location.
+ * @param callbackExecutor to execute the provided callback on.
+ * @param callback to receive the selections.
+ */
+ public void suggestContentSelections(
+ @NonNull SelectionsRequest request,
+ @NonNull @CallbackExecutor Executor callbackExecutor,
+ @NonNull SelectionsCallback callback) {
+ if (mService == null) {
+ Log.e(TAG,
+ "suggestContentSelections called, but no ContentSuggestionsManager configured");
+ return;
+ }
+
+ try {
+ mService.suggestContentSelections(
+ request, new SelectionsCallbackWrapper(callback, callbackExecutor));
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Classify actions and entities in content selections, as returned from
+ * suggestContentSelections. Note these selections may be modified by the
+ * caller before being passed here.
+ *
+ * @param request containing the selections to classify.
+ * @param callbackExecutor to execute the provided callback on.
+ * @param callback to receive the classifications.
+ */
+ public void classifyContentSelections(
+ @NonNull ClassificationsRequest request,
+ @NonNull @CallbackExecutor Executor callbackExecutor,
+ @NonNull ClassificationsCallback callback) {
+ if (mService == null) {
+ Log.e(TAG, "classifyContentSelections called, "
+ + "but no ContentSuggestionsManager configured");
+ return;
+ }
+
+ try {
+ mService.classifyContentSelections(
+ request, new ClassificationsCallbackWrapper(callback, callbackExecutor));
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Report telemetry for interaction with suggestions / classifications.
+ *
+ * @param requestId the id for the associated interaction
+ * @param interaction to report back to the system content suggestions service.
+ */
+ public void notifyInteraction(@NonNull String requestId, @NonNull Bundle interaction) {
+ if (mService == null) {
+ Log.e(TAG, "notifyInteraction called, but no ContentSuggestionsManager configured");
+ return;
+ }
+
+ try {
+ mService.notifyInteraction(requestId, interaction);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Callback to receive content selections from
+ * {@link #suggestContentSelections(SelectionsRequest, Executor, SelectionsCallback)}.
+ */
+ public interface SelectionsCallback {
+ /**
+ * Async callback called when the content suggestions service has selections available.
+ * These can be modified and sent back to the manager for classification. The contents of
+ * the selection is implementation dependent.
+ *
+ * @param statusCode as defined by the implementation of content suggestions service.
+ * @param selections not {@code null}, but can be size {@code 0}.
+ */
+ void onContentSelectionsAvailable(
+ int statusCode, @NonNull List<ContentSelection> selections);
+ }
+
+ /**
+ * Callback to receive classifications from
+ * {@link #classifyContentSelections(ClassificationsRequest, Executor, ClassificationsCallback)}
+ */
+ public interface ClassificationsCallback {
+ /**
+ * Async callback called when the content suggestions service has classified selections. The
+ * contents of the classification is implementation dependent.
+ *
+ * @param statusCode as defined by the implementation of content suggestions service.
+ * @param classifications not {@code null}, but can be size {@code 0}.
+ */
+ void onContentClassificationsAvailable(int statusCode,
+ @NonNull List<ContentClassification> classifications);
+ }
+
+ private static class SelectionsCallbackWrapper extends ISelectionsCallback.Stub {
+ private final SelectionsCallback mCallback;
+ private final Executor mExecutor;
+
+ SelectionsCallbackWrapper(
+ @NonNull SelectionsCallback callback, @NonNull Executor executor) {
+ mCallback = callback;
+ mExecutor = executor;
+ }
+
+ @Override
+ public void onContentSelectionsAvailable(
+ int statusCode, List<ContentSelection> selections) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() ->
+ mCallback.onContentSelectionsAvailable(statusCode, selections));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
+ private static final class ClassificationsCallbackWrapper extends
+ IClassificationsCallback.Stub {
+ private final ClassificationsCallback mCallback;
+ private final Executor mExecutor;
+
+ ClassificationsCallbackWrapper(@NonNull ClassificationsCallback callback,
+ @NonNull Executor executor) {
+ mCallback = callback;
+ mExecutor = executor;
+ }
+
+ @Override
+ public void onContentClassificationsAvailable(
+ int statusCode, List<ContentClassification> classifications) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() ->
+ mCallback.onContentClassificationsAvailable(statusCode, classifications));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+}
diff --git a/core/java/android/app/contentsuggestions/IClassificationsCallback.aidl b/core/java/android/app/contentsuggestions/IClassificationsCallback.aidl
new file mode 100644
index 0000000..69f5d55
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/IClassificationsCallback.aidl
@@ -0,0 +1,25 @@
+/**
+ * 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.contentsuggestions;
+
+import android.app.contentsuggestions.ContentClassification;
+
+/** @hide */
+oneway interface IClassificationsCallback {
+ void onContentClassificationsAvailable(
+ int statusCode, in List<ContentClassification> classifications);
+}
diff --git a/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl b/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl
new file mode 100644
index 0000000..24f5ad8
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl
@@ -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 android.app.contentsuggestions;
+
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.os.Bundle;
+
+/** @hide */
+oneway interface IContentSuggestionsManager {
+ void provideContextImage(
+ int taskId,
+ in Bundle imageContextRequestExtras);
+ void suggestContentSelections(
+ in SelectionsRequest request,
+ in ISelectionsCallback callback);
+ void classifyContentSelections(
+ in ClassificationsRequest request,
+ in IClassificationsCallback callback);
+ void notifyInteraction(in String requestId, in Bundle interaction);
+}
diff --git a/core/java/android/app/contentsuggestions/ISelectionsCallback.aidl b/core/java/android/app/contentsuggestions/ISelectionsCallback.aidl
new file mode 100644
index 0000000..1952583
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ISelectionsCallback.aidl
@@ -0,0 +1,25 @@
+/**
+ * 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.contentsuggestions;
+
+import android.app.contentsuggestions.ContentSelection;
+import android.os.Bundle;
+
+/** @hide */
+oneway interface ISelectionsCallback {
+ void onContentSelectionsAvailable(int statusCode, in List<ContentSelection> selections);
+}
diff --git a/core/java/android/app/contentsuggestions/SelectionsRequest.aidl b/core/java/android/app/contentsuggestions/SelectionsRequest.aidl
new file mode 100644
index 0000000..f5ce7c3
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/SelectionsRequest.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.contentsuggestions;
+
+parcelable SelectionsRequest;
diff --git a/core/java/android/app/contentsuggestions/SelectionsRequest.java b/core/java/android/app/contentsuggestions/SelectionsRequest.java
new file mode 100644
index 0000000..16f3e6b
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/SelectionsRequest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.graphics.Point;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class SelectionsRequest implements Parcelable {
+ private final int mTaskId;
+ @Nullable
+ private final Point mInterestPoint;
+ @Nullable
+ private final Bundle mExtras;
+
+ private SelectionsRequest(int taskId, @Nullable Point interestPoint, @Nullable Bundle extras) {
+ mTaskId = taskId;
+ mInterestPoint = interestPoint;
+ mExtras = extras;
+ }
+
+ /**
+ * Return the request task id.
+ */
+ public int getTaskId() {
+ return mTaskId;
+ }
+
+ /**
+ * Return the request point of interest.
+ */
+ public Point getInterestPoint() {
+ return mInterestPoint;
+ }
+
+ /**
+ * Return the request extras.
+ */
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mTaskId);
+ dest.writeTypedObject(mInterestPoint, flags);
+ dest.writeBundle(mExtras);
+ }
+
+ public static final Creator<SelectionsRequest> CREATOR =
+ new Creator<SelectionsRequest>() {
+ @Override
+ public SelectionsRequest createFromParcel(Parcel source) {
+ return new SelectionsRequest(
+ source.readInt(), source.readTypedObject(Point.CREATOR), source.readBundle());
+ }
+
+ @Override
+ public SelectionsRequest[] newArray(int size) {
+ return new SelectionsRequest[size];
+ }
+ };
+
+ /**
+ * A builder for selections requests events.
+ * @hide
+ */
+ @SystemApi
+ public static final class Builder {
+
+ private final int mTaskId;
+ private Point mInterestPoint;
+ private Bundle mExtras;
+
+ public Builder(int taskId) {
+ mTaskId = taskId;
+ }
+
+ /**
+ * Sets the request extras.
+ */
+ public Builder setExtras(@NonNull Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
+ /**
+ * Sets the request interest point.
+ */
+ public Builder setInterestPoint(@NonNull Point interestPoint) {
+ mInterestPoint = interestPoint;
+ return this;
+ }
+
+ /**
+ * Builds a new request instance.
+ */
+ public SelectionsRequest build() {
+ return new SelectionsRequest(mTaskId, mInterestPoint, mExtras);
+ }
+ }
+}
diff --git a/core/java/android/app/prediction/AppPredictionContext.aidl b/core/java/android/app/prediction/AppPredictionContext.aidl
new file mode 100644
index 0000000..5767bf4
--- /dev/null
+++ b/core/java/android/app/prediction/AppPredictionContext.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.prediction;
+
+parcelable AppPredictionContext;
diff --git a/core/java/android/app/prediction/AppPredictionContext.java b/core/java/android/app/prediction/AppPredictionContext.java
new file mode 100644
index 0000000..87ccb66
--- /dev/null
+++ b/core/java/android/app/prediction/AppPredictionContext.java
@@ -0,0 +1,158 @@
+/*
+ * 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.prediction;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * TODO(b/111701043): Add java docs
+ *
+ * @hide
+ */
+@SystemApi
+public final class AppPredictionContext implements Parcelable {
+
+ private final int mPredictedTargetCount;
+ @NonNull
+ private final String mUiSurface;
+ @NonNull
+ private final String mPackageName;
+ @Nullable
+ private final Bundle mExtras;
+
+ private AppPredictionContext(@NonNull String uiSurface, int numPredictedTargets,
+ @NonNull String packageName, @Nullable Bundle extras) {
+ mUiSurface = uiSurface;
+ mPredictedTargetCount = numPredictedTargets;
+ mPackageName = packageName;
+ mExtras = extras;
+ }
+
+ private AppPredictionContext(Parcel parcel) {
+ mUiSurface = parcel.readString();
+ mPredictedTargetCount = parcel.readInt();
+ mPackageName = parcel.readString();
+ mExtras = parcel.readBundle();
+ }
+
+ public String getUiSurface() {
+ return mUiSurface;
+ }
+
+ public int getPredictedTargetCount() {
+ return mPredictedTargetCount;
+ }
+
+ @NonNull
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ @Nullable
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mUiSurface);
+ dest.writeInt(mPredictedTargetCount);
+ dest.writeString(mPackageName);
+ dest.writeBundle(mExtras);
+ }
+
+ /**
+ * @see Parcelable.Creator
+ */
+ public static final Parcelable.Creator<AppPredictionContext> CREATOR =
+ new Parcelable.Creator<AppPredictionContext>() {
+ public AppPredictionContext createFromParcel(Parcel parcel) {
+ return new AppPredictionContext(parcel);
+ }
+
+ public AppPredictionContext[] newArray(int size) {
+ return new AppPredictionContext[size];
+ }
+ };
+
+ /**
+ * A builder for app prediction contexts.
+ * @hide
+ */
+ @SystemApi
+ public static final class Builder {
+
+ @NonNull
+ private final String mPackageName;
+
+ private int mPredictedTargetCount;
+ @Nullable
+ private String mUiSurface;
+ @Nullable
+ private Bundle mExtras;
+
+ /**
+ * @hide
+ */
+ public Builder(@NonNull Context context) {
+ mPackageName = context.getPackageName();
+ }
+
+
+ /**
+ * Sets the number of prediction targets as a hint.
+ */
+ public Builder setPredictedTargetCount(int predictedTargetCount) {
+ mPredictedTargetCount = predictedTargetCount;
+ return this;
+ }
+
+ /**
+ * Sets the UI surface.
+ */
+ public Builder setUiSurface(@Nullable String uiSurface) {
+ mUiSurface = uiSurface;
+ return this;
+ }
+
+ /**
+ * Sets the extras.
+ */
+ public Builder setExtras(@Nullable Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
+ /**
+ * Builds a new context instance.
+ */
+ public AppPredictionContext build() {
+ return new AppPredictionContext(mUiSurface, mPredictedTargetCount, mPackageName,
+ mExtras);
+ }
+ }
+}
diff --git a/core/java/android/app/prediction/AppPredictionManager.java b/core/java/android/app/prediction/AppPredictionManager.java
new file mode 100644
index 0000000..f8578d4
--- /dev/null
+++ b/core/java/android/app/prediction/AppPredictionManager.java
@@ -0,0 +1,47 @@
+/*
+ * 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.prediction;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.content.Context;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * TODO (b/111701043) : Add java doc
+ * @hide
+ */
+@SystemApi
+public final class AppPredictionManager {
+
+ private final Context mContext;
+
+ /**
+ * @hide
+ */
+ public AppPredictionManager(Context context) {
+ mContext = Preconditions.checkNotNull(context);
+ }
+
+ /**
+ * Creates a new app prediction session.
+ */
+ public AppPredictor createAppPredictionSession(
+ @NonNull AppPredictionContext predictionContext) {
+ return new AppPredictor(mContext, predictionContext);
+ }
+}
diff --git a/core/java/android/app/prediction/AppPredictionSessionId.aidl b/core/java/android/app/prediction/AppPredictionSessionId.aidl
new file mode 100644
index 0000000..e829526
--- /dev/null
+++ b/core/java/android/app/prediction/AppPredictionSessionId.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.prediction;
+
+parcelable AppPredictionSessionId;
diff --git a/core/java/android/app/prediction/AppPredictionSessionId.java b/core/java/android/app/prediction/AppPredictionSessionId.java
new file mode 100644
index 0000000..1d7308e
--- /dev/null
+++ b/core/java/android/app/prediction/AppPredictionSessionId.java
@@ -0,0 +1,86 @@
+/*
+ * 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.prediction;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * TODO (b/111701043) : Add java doc
+ *
+ * @hide
+ */
+@SystemApi
+public final class AppPredictionSessionId implements Parcelable {
+
+ private final String mId;
+
+ /**
+ * @hide
+ */
+ public AppPredictionSessionId(@NonNull String id) {
+ mId = id;
+ }
+
+ private AppPredictionSessionId(Parcel p) {
+ mId = p.readString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!getClass().equals(o != null ? o.getClass() : null)) return false;
+
+ AppPredictionSessionId other = (AppPredictionSessionId) o;
+ return mId.equals(other.mId);
+ }
+
+ @Override
+ public @NonNull String toString() {
+ return mId;
+ }
+
+ @Override
+ public int hashCode() {
+ // Ensure that the id has a consistent hash
+ return mId.hashCode();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mId);
+ }
+
+ /**
+ * @see Parcelable.Creator
+ */
+ public static final Parcelable.Creator<AppPredictionSessionId> CREATOR =
+ new Parcelable.Creator<AppPredictionSessionId>() {
+ public AppPredictionSessionId createFromParcel(Parcel parcel) {
+ return new AppPredictionSessionId(parcel);
+ }
+
+ public AppPredictionSessionId[] newArray(int size) {
+ return new AppPredictionSessionId[size];
+ }
+ };
+}
diff --git a/core/java/android/app/prediction/AppPredictor.java b/core/java/android/app/prediction/AppPredictor.java
new file mode 100644
index 0000000..2ddbd08
--- /dev/null
+++ b/core/java/android/app/prediction/AppPredictor.java
@@ -0,0 +1,257 @@
+/*
+ * 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.prediction;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.prediction.IPredictionCallback.Stub;
+import android.content.Context;
+import android.content.pm.ParceledListSlice;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import dalvik.system.CloseGuard;
+
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
+
+/**
+ * TODO (b/111701043) : Add java doc
+ *
+ * <p>
+ * Usage: <pre> {@code
+ *
+ * class MyActivity {
+ * private AppPredictor mClient
+ *
+ * void onCreate() {
+ * mClient = new AppPredictor(...)
+ * }
+ *
+ * void onStart() {
+ * mClient.requestPredictionUpdate();
+ * }
+ *
+ * void onDestroy() {
+ * mClient.close();
+ * }
+ *
+ * }</pre>
+ *
+ * @hide
+ */
+@SystemApi
+public final class AppPredictor {
+
+ private static final String TAG = AppPredictor.class.getSimpleName();
+
+
+ private final IPredictionManager mPredictionManager;
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+ private final AtomicBoolean mIsClosed = new AtomicBoolean(false);
+
+ private final AppPredictionSessionId mSessionId;
+ private final ArrayMap<Callback, CallbackWrapper> mRegisteredCallbacks = new ArrayMap<>();
+
+ /**
+ * Creates a new Prediction client.
+ * <p>
+ * The caller should call {@link AppPredictor#destroy()} to dispose the client once it
+ * no longer used.
+ *
+ * @param predictionContext The prediction context
+ */
+ AppPredictor(@NonNull Context context, @NonNull AppPredictionContext predictionContext) {
+ IBinder b = ServiceManager.getService(Context.APP_PREDICTION_SERVICE);
+ mPredictionManager = IPredictionManager.Stub.asInterface(b);
+ mSessionId = new AppPredictionSessionId(
+ context.getPackageName() + ":" + UUID.randomUUID().toString());
+ try {
+ mPredictionManager.createPredictionSession(predictionContext, mSessionId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to create predictor", e);
+ return;
+ }
+
+ mCloseGuard.open("close");
+ }
+
+ /**
+ * Notifies the prediction service of an app target event.
+ */
+ public void notifyAppTargetEvent(@NonNull AppTargetEvent event) {
+ try {
+ mPredictionManager.notifyAppTargetEvent(mSessionId, event);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to notify app target event", e);
+ }
+ }
+
+ /**
+ * Notifies the prediction service when the targets in a launch location are shown to the user.
+ */
+ public void notifyLocationShown(@NonNull String launchLocation,
+ @NonNull List<AppTargetId> targetIds) {
+ try {
+ mPredictionManager.notifyLocationShown(mSessionId, launchLocation,
+ new ParceledListSlice<>(targetIds));
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to notify location shown event", e);
+ }
+ }
+
+ /**
+ * Requests the prediction service provide continuous updates of App predictions via the
+ * provided callback, until the given callback is unregistered.
+ *
+ * @see Callback#onTargetsAvailable(List)
+ */
+ public void registerPredictionUpdates(@NonNull @CallbackExecutor Executor callbackExecutor,
+ @NonNull AppPredictor.Callback callback) {
+ if (mRegisteredCallbacks.containsKey(callback)) {
+ // Skip if this callback is already registered
+ return;
+ }
+ try {
+ final CallbackWrapper callbackWrapper = new CallbackWrapper(callbackExecutor,
+ callback::onTargetsAvailable);
+ mPredictionManager.registerPredictionUpdates(mSessionId, callbackWrapper);
+ mRegisteredCallbacks.put(callback, callbackWrapper);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to register for prediction updates", e);
+ }
+ }
+
+ /**
+ * Requests the prediction service to stop providing continuous updates to the provided
+ * callback until the callback is re-registered.
+ */
+ public void unregisterPredictionUpdates(@NonNull AppPredictor.Callback callback) {
+ if (!mRegisteredCallbacks.containsKey(callback)) {
+ // Skip if this callback was never registered
+ return;
+ }
+ try {
+ final CallbackWrapper callbackWrapper = mRegisteredCallbacks.remove(callback);
+ mPredictionManager.unregisterPredictionUpdates(mSessionId, callbackWrapper);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to unregister for prediction updates", e);
+ }
+ }
+
+ /**
+ * Requests the prediction service to dispatch a new set of App predictions via the provided
+ * callback.
+ *
+ * @see Callback#onTargetsAvailable(List)
+ */
+ public void requestPredictionUpdate() {
+ try {
+ mPredictionManager.requestPredictionUpdate(mSessionId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to request prediction update", e);
+ }
+ }
+
+ /**
+ * Returns a new list of AppTargets sorted based on prediction rank or {@code null} if the
+ * ranker is not available.
+ */
+ @Nullable
+ public void sortTargets(@NonNull List<AppTarget> targets,
+ @NonNull Executor callbackExecutor, @NonNull Consumer<List<AppTarget>> callback) {
+ try {
+ mPredictionManager.sortAppTargets(mSessionId, new ParceledListSlice(targets),
+ new CallbackWrapper(callbackExecutor, callback));
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to sort targets", e);
+ }
+ }
+
+ /**
+ * Destroys the client and unregisters the callback. Any method on this class after this call
+ * with throw {@link IllegalStateException}.
+ *
+ * TODO(b/111701043): Add state check in other methods.
+ */
+ public void destroy() {
+ if (!mIsClosed.getAndSet(true)) {
+ mCloseGuard.close();
+
+ // Do destroy;
+ try {
+ mPredictionManager.onDestroyPredictionSession(mSessionId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to notify app target event", e);
+ }
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+ destroy();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /**
+ * Callback for receiving prediction updates.
+ */
+ public interface Callback {
+
+ /**
+ * Called when a new set of predicted app targets are available.
+ * @param targets Sorted list of predicted targets
+ */
+ void onTargetsAvailable(@NonNull List<AppTarget> targets);
+ }
+
+ static class CallbackWrapper extends Stub {
+
+ private final Consumer<List<AppTarget>> mCallback;
+ private final Executor mExecutor;
+
+ CallbackWrapper(@NonNull Executor callbackExecutor,
+ @NonNull Consumer<List<AppTarget>> callback) {
+ mCallback = callback;
+ mExecutor = callbackExecutor;
+ }
+
+ @Override
+ public void onResult(ParceledListSlice result) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.accept(result.getList()));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+}
diff --git a/core/java/android/app/prediction/AppTarget.aidl b/core/java/android/app/prediction/AppTarget.aidl
new file mode 100644
index 0000000..e4e2bc2
--- /dev/null
+++ b/core/java/android/app/prediction/AppTarget.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.prediction;
+
+parcelable AppTarget;
diff --git a/core/java/android/app/prediction/AppTarget.java b/core/java/android/app/prediction/AppTarget.java
new file mode 100644
index 0000000..99c1c44
--- /dev/null
+++ b/core/java/android/app/prediction/AppTarget.java
@@ -0,0 +1,166 @@
+/*
+ * 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.prediction;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.pm.ShortcutInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * A representation of a launchable target.
+ * @hide
+ */
+@SystemApi
+public final class AppTarget implements Parcelable {
+
+ private final AppTargetId mId;
+ private final String mPackageName;
+ private final String mClassName;
+ private final UserHandle mUser;
+
+ private final ShortcutInfo mShortcutInfo;
+
+ private int mRank;
+
+ /**
+ * @hide
+ */
+ public AppTarget(@NonNull AppTargetId id, @NonNull String packageName,
+ @Nullable String className, @NonNull UserHandle user) {
+ mId = id;
+ mShortcutInfo = null;
+
+ mPackageName = Preconditions.checkNotNull(packageName);
+ mClassName = className;
+ mUser = Preconditions.checkNotNull(user);
+ }
+
+ /**
+ * @hide
+ */
+ public AppTarget(@NonNull AppTargetId id, @NonNull ShortcutInfo shortcutInfo) {
+ mId = id;
+ mShortcutInfo = Preconditions.checkNotNull(shortcutInfo);
+
+ mPackageName = mShortcutInfo.getPackage();
+ mUser = mShortcutInfo.getUserHandle();
+ mClassName = null;
+ }
+
+ private AppTarget(Parcel parcel) {
+ mId = parcel.readTypedObject(AppTargetId.CREATOR);
+ mShortcutInfo = parcel.readTypedObject(ShortcutInfo.CREATOR);
+ if (mShortcutInfo == null) {
+ mPackageName = parcel.readString();
+ mClassName = parcel.readString();
+ mUser = UserHandle.of(parcel.readInt());
+ } else {
+ mPackageName = mShortcutInfo.getPackage();
+ mUser = mShortcutInfo.getUserHandle();
+ mClassName = null;
+ }
+ mRank = parcel.readInt();
+ }
+
+ /**
+ * Returns the target id.
+ */
+ @NonNull
+ public AppTargetId getId() {
+ return mId;
+ }
+
+ /**
+ * Returns the class name for the app target.
+ */
+ @Nullable
+ public String getClassName() {
+ return mClassName;
+ }
+
+ /**
+ * Returns the package name for the app target.
+ */
+ @NonNull
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ /**
+ * Returns the user for the app target.
+ */
+ @NonNull
+ public UserHandle getUser() {
+ return mUser;
+ }
+
+ /**
+ * Returns the shortcut info for the target.
+ */
+ @Nullable
+ public ShortcutInfo getShortcutInfo() {
+ return mShortcutInfo;
+ }
+
+ /**
+ * Sets the rank of the for the target.
+ * @hide
+ */
+ public void setRank(int rank) {
+ mRank = rank;
+ }
+
+ public int getRank() {
+ return mRank;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeTypedObject(mId, flags);
+ dest.writeTypedObject(mShortcutInfo, flags);
+ if (mShortcutInfo == null) {
+ dest.writeString(mPackageName);
+ dest.writeString(mClassName);
+ dest.writeInt(mUser.getIdentifier());
+ }
+ dest.writeInt(mRank);
+ }
+
+ /**
+ * @see Parcelable.Creator
+ */
+ public static final Parcelable.Creator<AppTarget> CREATOR =
+ new Parcelable.Creator<AppTarget>() {
+ public AppTarget createFromParcel(Parcel parcel) {
+ return new AppTarget(parcel);
+ }
+
+ public AppTarget[] newArray(int size) {
+ return new AppTarget[size];
+ }
+ };
+}
diff --git a/core/java/android/app/prediction/AppTargetEvent.aidl b/core/java/android/app/prediction/AppTargetEvent.aidl
new file mode 100644
index 0000000..ebed2da
--- /dev/null
+++ b/core/java/android/app/prediction/AppTargetEvent.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.prediction;
+
+parcelable AppTargetEvent;
diff --git a/core/java/android/app/prediction/AppTargetEvent.java b/core/java/android/app/prediction/AppTargetEvent.java
new file mode 100644
index 0000000..18317e1
--- /dev/null
+++ b/core/java/android/app/prediction/AppTargetEvent.java
@@ -0,0 +1,154 @@
+/*
+ * 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.prediction;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A representation of an app target event.
+ * @hide
+ */
+@SystemApi
+public final class AppTargetEvent implements Parcelable {
+
+ /**
+ * @hide
+ */
+ @IntDef({ACTION_LAUNCH, ACTION_DISMISS, ACTION_PIN})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ActionType {}
+
+ /**
+ * Event type constant indicating an app target has been launched.
+ */
+ public static final int ACTION_LAUNCH = 1;
+
+ /**
+ * Event type constant indicating an app target has been dismissed.
+ */
+ public static final int ACTION_DISMISS = 2;
+
+ /**
+ * Event type constant indicating an app target has been pinned.
+ */
+ public static final int ACTION_PIN = 3;
+
+ private final AppTarget mTarget;
+ private final String mLocation;
+ private final int mAction;
+
+ private AppTargetEvent(@Nullable AppTarget target, @Nullable String location,
+ @ActionType int actionType) {
+ mTarget = target;
+ mLocation = location;
+ mAction = actionType;
+ }
+
+ private AppTargetEvent(Parcel parcel) {
+ mTarget = parcel.readParcelable(null);
+ mLocation = parcel.readString();
+ mAction = parcel.readInt();
+ }
+
+ /**
+ * Returns the app target.
+ */
+ @Nullable
+ public AppTarget getTarget() {
+ return mTarget;
+ }
+
+ /**
+ * Returns the launch location.
+ */
+ @NonNull
+ public String getLaunchLocation() {
+ return mLocation;
+ }
+
+ /**
+ * Returns the action type.
+ */
+ @NonNull
+ public int getAction() {
+ return mAction;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mTarget, 0);
+ dest.writeString(mLocation);
+ dest.writeInt(mAction);
+ }
+
+ /**
+ * @see Creator
+ */
+ public static final Creator<AppTargetEvent> CREATOR =
+ new Creator<AppTargetEvent>() {
+ public AppTargetEvent createFromParcel(Parcel parcel) {
+ return new AppTargetEvent(parcel);
+ }
+
+ public AppTargetEvent[] newArray(int size) {
+ return new AppTargetEvent[size];
+ }
+ };
+
+ /**
+ * A builder for app target events.
+ * @hide
+ */
+ @SystemApi
+ public static final class Builder {
+ private AppTarget mTarget;
+ private String mLocation;
+ private @ActionType int mAction;
+
+ public Builder(@Nullable AppTarget target, @ActionType int actionType) {
+ mTarget = target;
+ mAction = actionType;
+ }
+
+ /**
+ * Sets the launch location.
+ */
+ public Builder setLaunchLocation(String location) {
+ mLocation = location;
+ return this;
+ }
+
+ /**
+ * Builds a new event instance.
+ */
+ public AppTargetEvent build() {
+ return new AppTargetEvent(mTarget, mLocation, mAction);
+ }
+ }
+}
diff --git a/core/java/android/app/prediction/AppTargetId.aidl b/core/java/android/app/prediction/AppTargetId.aidl
new file mode 100644
index 0000000..bf69eea
--- /dev/null
+++ b/core/java/android/app/prediction/AppTargetId.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.prediction;
+
+parcelable AppTargetId;
diff --git a/core/java/android/app/prediction/AppTargetId.java b/core/java/android/app/prediction/AppTargetId.java
new file mode 100644
index 0000000..0b8fb47
--- /dev/null
+++ b/core/java/android/app/prediction/AppTargetId.java
@@ -0,0 +1,90 @@
+/*
+ * 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.prediction;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * The id for a prediction target.
+ * @hide
+ */
+@SystemApi
+public final class AppTargetId implements Parcelable {
+
+ @NonNull
+ private final String mId;
+
+ /**
+ * @hide
+ */
+ public AppTargetId(@NonNull String id) {
+ mId = id;
+ }
+
+ private AppTargetId(Parcel parcel) {
+ mId = parcel.readString();
+ }
+
+ /**
+ * Returns the id.
+ * @hide
+ */
+ @NonNull
+ public String getId() {
+ return mId;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!getClass().equals(o != null ? o.getClass() : null)) return false;
+
+ AppTargetId other = (AppTargetId) o;
+ return mId.equals(other.mId);
+ }
+
+ @Override
+ public int hashCode() {
+ // Ensure that the id has a consistent hash
+ return mId.hashCode();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mId);
+ }
+
+ /**
+ * @see Creator
+ */
+ public static final Creator<AppTargetId> CREATOR =
+ new Creator<AppTargetId>() {
+ public AppTargetId createFromParcel(Parcel parcel) {
+ return new AppTargetId(parcel);
+ }
+
+ public AppTargetId[] newArray(int size) {
+ return new AppTargetId[size];
+ }
+ };
+}
diff --git a/core/java/android/app/prediction/IPredictionCallback.aidl b/core/java/android/app/prediction/IPredictionCallback.aidl
new file mode 100644
index 0000000..f6f241e
--- /dev/null
+++ b/core/java/android/app/prediction/IPredictionCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.prediction;
+
+import android.content.pm.ParceledListSlice;
+
+/**
+ * @hide
+ */
+oneway interface IPredictionCallback {
+
+ void onResult(in ParceledListSlice result);
+}
diff --git a/core/java/android/app/prediction/IPredictionManager.aidl b/core/java/android/app/prediction/IPredictionManager.aidl
new file mode 100644
index 0000000..114a1ff
--- /dev/null
+++ b/core/java/android/app/prediction/IPredictionManager.aidl
@@ -0,0 +1,51 @@
+/*
+ * 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.prediction;
+
+import android.app.prediction.AppTarget;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.AppPredictionContext;
+import android.app.prediction.AppPredictionSessionId;
+import android.app.prediction.IPredictionCallback;
+import android.content.pm.ParceledListSlice;
+
+/**
+ * @hide
+ */
+interface IPredictionManager {
+
+ void createPredictionSession(in AppPredictionContext context,
+ in AppPredictionSessionId sessionId);
+
+ void notifyAppTargetEvent(in AppPredictionSessionId sessionId, in AppTargetEvent event);
+
+ void notifyLocationShown(in AppPredictionSessionId sessionId, in String launchLocation,
+ in ParceledListSlice targetIds);
+
+ void sortAppTargets(in AppPredictionSessionId sessionId, in ParceledListSlice targets,
+ in IPredictionCallback callback);
+
+ void registerPredictionUpdates(in AppPredictionSessionId sessionId,
+ in IPredictionCallback callback);
+
+ void unregisterPredictionUpdates(in AppPredictionSessionId sessionId,
+ in IPredictionCallback callback);
+
+ void requestPredictionUpdate(in AppPredictionSessionId sessionId);
+
+ void onDestroyPredictionSession(in AppPredictionSessionId sessionId);
+}
diff --git a/core/java/android/app/role/IRoleManager.aidl b/core/java/android/app/role/IRoleManager.aidl
index 0c9b41bf..2964fbc 100644
--- a/core/java/android/app/role/IRoleManager.aidl
+++ b/core/java/android/app/role/IRoleManager.aidl
@@ -50,4 +50,6 @@
boolean removeRoleHolderFromController(in String roleName, in String packageName);
List<String> getHeldRolesFromController(in String packageName);
+
+ String getDefaultSmsPackage(int userId);
}
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index d73e73f..27581fc 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -19,6 +19,7 @@
import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -67,57 +68,9 @@
private static final String LOG_TAG = RoleManager.class.getSimpleName();
/**
- * The name of the proxy calling role.
- * <p>
- * A proxy calling app implements the {@link android.telecom.CallRedirectionService} API and
- * provides a means to re-write the phone number for an outgoing call to place the call through
- * a proxy calling service.
- * <p>
- * A single app may fill this role at any one time.
- * @hide
- */
- public static final String ROLE_PROXY_CALLING_APP = "android.app.role.PROXY_CALLING_APP";
-
- /**
- * The name of the call screening and caller id role.
- * <p>
- * A call screening and caller id app implements the
- * {@link android.telecom.CallScreeningService} API.
- * <p>
- * A single app may fill this role at any one time.
- * @hide
- */
- public static final String ROLE_CALL_SCREENING_APP = "android.app.role.CALL_SCREENING_APP";
-
- /**
- * The name of the call companion app role.
- * <p>
- * A call companion app provides no user interface for calls, but will be bound to by Telecom
- * when there are active calls on the device. Companion apps for wearable devices are an
- * acceptable use-case. A call companion app implements the
- * {@link android.telecom.InCallService} API.
- * <p>
- * Multiple apps app may fill this role at any one time.
- * @hide
- */
- public static final String ROLE_CALL_COMPANION_APP = "android.app.role.CALL_COMPANION_APP";
-
- /**
- * The name of the car mode dialer app role.
- * <p>
- * Similar to the {@link #ROLE_DIALER} role, this role determines which app is responsible for
- * showing the user interface for ongoing calls on the device. This app filling this role is
- * only used when the device is in car mode (see
- * {@link android.app.UiModeManager#ACTION_ENTER_CAR_MODE} for more information). An app
- * filling this role must implement the {@link android.telecom.InCallService} API.
- * <p>
- * A single app may fill this role at any one time.
- * @hide
- */
- public static final String ROLE_CAR_MODE_DIALER_APP = "android.app.role.CAR_MODE_DIALER_APP";
-
- /**
* The name of the dialer role.
+ *
+ * @see Intent#ACTION_DIAL
*/
public static final String ROLE_DIALER = "android.app.role.DIALER";
@@ -150,6 +103,75 @@
public static final String ROLE_MUSIC = "android.app.role.MUSIC";
/**
+ * The name of the home role.
+ *
+ * @see Intent#CATEGORY_HOME
+ */
+ public static final String ROLE_HOME = "android.app.role.HOME";
+
+ /**
+ * The name of the emergency role
+ *
+ * @see android.telephony.TelephonyManager#ACTION_EMERGENCY_ASSISTANCE
+ */
+ public static final String ROLE_EMERGENCY = "android.app.role.EMERGENCY";
+
+ /**
+ * The name of the car mode dialer app role.
+ * <p>
+ * Similar to the {@link #ROLE_DIALER dialer} role, this role determines which app is
+ * responsible for showing the user interface for ongoing calls on the device. It is only used
+ * when the device is in car mode.
+ *
+ * @see #ROLE_DIALER
+ * @see android.app.UiModeManager#ACTION_ENTER_CAR_MODE
+ * @see android.telecom.InCallService
+ *
+ * TODO: STOPSHIP: Make name of required roles public API
+ * @hide
+ */
+ public static final String ROLE_CAR_MODE_DIALER_APP = "android.app.role.CAR_MODE_DIALER_APP";
+
+ /**
+ * The name of the proxy calling role.
+ * <p>
+ * A proxy calling app provides a means to re-write the phone number for an outgoing call to
+ * place the call through a proxy calling service.
+ *
+ * @see android.telecom.CallRedirectionService
+ *
+ * TODO: STOPSHIP: Make name of required roles public API
+ * @hide
+ */
+ public static final String ROLE_PROXY_CALLING_APP = "android.app.role.PROXY_CALLING_APP";
+
+ /**
+ * The name of the call screening and caller id role.
+ *
+ * @see android.telecom.CallScreeningService
+ *
+ * TODO: STOPSHIP: Make name of required roles public API
+ * @hide
+ */
+ public static final String ROLE_CALL_SCREENING_APP = "android.app.role.CALL_SCREENING_APP";
+
+ /**
+ * The name of the call companion app role.
+ * <p>
+ * A call companion app provides no user interface for calls, but will be bound to by Telecom
+ * when there are active calls on the device. Companion apps for wearable devices are an
+ * acceptable use-case.
+ * <p>
+ * Multiple apps may hold this role at the same time.
+ *
+ * @see android.telecom.InCallService
+ *
+ * TODO: STOPSHIP: Make name of required roles public API
+ * @hide
+ */
+ public static final String ROLE_CALL_COMPANION_APP = "android.app.role.CALL_COMPANION_APP";
+
+ /**
* The action used to request user approval of a role for an application.
*
* @hide
@@ -592,7 +614,6 @@
}
}
-
/**
* Returns the list of all roles that the given package is currently holding
*
@@ -613,6 +634,22 @@
}
}
+ /**
+ * Allows getting the role holder for {@link #ROLE_SMS} without
+ * {@link Manifest.permission#OBSERVE_ROLE_HOLDERS}, as required by
+ * {@link android.provider.Telephony.Sms#getDefaultSmsPackage(Context)}
+ *
+ * @hide
+ */
+ @Nullable
+ public String getDefaultSmsPackage(@UserIdInt int userId) {
+ try {
+ return mService.getDefaultSmsPackage(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
private static class RoleManagerCallbackDelegate extends IRoleManagerCallback.Stub {
@NonNull
diff --git a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
index a2b7d58..8ee9e53 100644
--- a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
+++ b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
@@ -36,6 +36,11 @@
private Configuration mConfiguration;
@Override
+ public void preExecute(android.app.ClientTransactionHandler client, IBinder token) {
+ client.updatePendingActivityConfiguration(token, mConfiguration);
+ }
+
+ @Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
// TODO(lifecycler): detect if PIP or multi-window mode changed and report it here.
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index eb7be6f..cefc700 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -337,6 +337,15 @@
public static final int BIND_ADJUST_BELOW_PERCEPTIBLE = 0x0100;
/**
+ * @hide Flag for {@link #bindService}: the service being bound to represents a
+ * protected system component, so must have association restrictions applied to it.
+ * That is, a system config must have one or more allow-association tags limiting
+ * which packages it can interact with. If it does not have any such association
+ * restrictions, a default empty set will be created.
+ */
+ public static final int BIND_RESTRICT_ASSOCIATIONS = 0x00200000;
+
+ /**
* @hide Flag for {@link #bindService}: allows binding to a service provided
* by an instant app. Note that the caller may not have access to the instant
* app providing the service which is a violation of the instant app sandbox.
@@ -3093,6 +3102,7 @@
VIBRATOR_SERVICE,
//@hide: STATUS_BAR_SERVICE,
CONNECTIVITY_SERVICE,
+ //@hide: IP_MEMORY_STORE_SERVICE,
IPSEC_SERVICE,
//@hide: UPDATE_LOCK_SERVICE,
//@hide: NETWORKMANAGEMENT_SERVICE,
@@ -3630,6 +3640,14 @@
/**
* Use with {@link #getSystemService(String)} to retrieve a
+ * {@link android.net.IpMemoryStore} to store and read information about
+ * known networks.
+ * @hide
+ */
+ public static final String IP_MEMORY_STORE_SERVICE = "ipmemorystore";
+
+ /**
+ * Use with {@link #getSystemService(String)} to retrieve a
* {@link android.net.IpSecManager} for encrypting Sockets or Networks with
* IPSec.
*
@@ -3975,6 +3993,24 @@
public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture";
/**
+ * Used for getting content selections and classifications for task snapshots.
+ *
+ * @hide
+ * @see #getSystemService(String)
+ */
+ @SystemApi
+ public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
+
+ /**
+ * Official published name of the app prediction service.
+ *
+ * @hide
+ * @see #getSystemService(String)
+ */
+ @SystemApi
+ public static final String APP_PREDICTION_SERVICE = "app_prediction";
+
+ /**
* Use with {@link #getSystemService(String)} to access the
* {@link com.android.server.voiceinteraction.SoundTriggerService}.
*
@@ -4427,6 +4463,16 @@
public static final String STATS_MANAGER = "stats";
/**
+ * Service to capture a bugreport.
+ * @see #getSystemService(String)
+ * @see android.os.BugreportManager
+ * @hide
+ */
+ // TODO: Expose API when the implementation is more complete.
+ // @SystemApi
+ public static final String BUGREPORT_SERVICE = "bugreport";
+
+ /**
* Use with {@link #getSystemService(String)} to retrieve a {@link
* android.content.om.OverlayManager} for managing overlay packages.
*
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index de810e8..e37126b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1953,16 +1953,35 @@
public static final String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME";
/**
+ * Intent extra: The name of a permission group.
+ * <p>
+ * Type: String
+ * </p>
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_PERMISSION_GROUP_NAME =
+ "android.intent.extra.PERMISSION_GROUP_NAME";
+
+ /**
* Activity action: Launch UI to review app uses of permissions.
* <p>
* Input: {@link #EXTRA_PERMISSION_NAME} specifies the permission name
- * that will be displayed by the launched UI.
+ * that will be displayed by the launched UI. Do not pass both this and
+ * {@link #EXTRA_PERMISSION_GROUP_NAME} .
+ * </p>
+ * <p>
+ * Input: {@link #EXTRA_PERMISSION_GROUP_NAME} specifies the permission group name
+ * that will be displayed by the launched UI. Do not pass both this and
+ * {@link #EXTRA_PERMISSION_NAME}.
* </p>
* <p>
* Output: Nothing.
* </p>
*
* @see #EXTRA_PERMISSION_NAME
+ * @see #EXTRA_PERMISSION_GROUP_NAME
*
* @hide
*/
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 2978058..576466f 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1866,7 +1866,15 @@
return (privateFlags & ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE) != 0;
}
- /** @hide */
+ /**
+ * Check whether the application is encryption aware.
+ *
+ * @see #isDirectBootAware()
+ * @see #isPartiallyDirectBootAware()
+ *
+ * @hide
+ */
+ @SystemApi
public boolean isEncryptionAware() {
return isDirectBootAware() || isPartiallyDirectBootAware();
}
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index be6ed51..74dd08f 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -29,8 +29,11 @@
import android.annotation.UnsupportedAppUsage;
import android.os.BaseBundle;
+import android.os.Debug;
import android.os.PersistableBundle;
import android.util.ArraySet;
+import android.util.DebugUtils;
+import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
@@ -43,6 +46,9 @@
* @hide
*/
public class PackageUserState {
+ private static final boolean DEBUG = false;
+ private static final String LOG_TAG = "PackageUserState";
+
public long ceDataInode;
public boolean installed;
public boolean stopped;
@@ -132,12 +138,12 @@
final boolean isSystemApp = componentInfo.applicationInfo.isSystemApp();
final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0;
if (!isAvailable(flags)
- && !(isSystemApp && matchUninstalled)) return false;
- if (!isEnabled(componentInfo, flags)) return false;
+ && !(isSystemApp && matchUninstalled)) return reportIfDebug(false, flags);
+ if (!isEnabled(componentInfo, flags)) return reportIfDebug(false, flags);
if ((flags & MATCH_SYSTEM_ONLY) != 0) {
if (!isSystemApp) {
- return false;
+ return reportIfDebug(false, flags);
}
}
@@ -145,7 +151,16 @@
&& !componentInfo.directBootAware;
final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)
&& componentInfo.directBootAware;
- return matchesUnaware || matchesAware;
+ return reportIfDebug(matchesUnaware || matchesAware, flags);
+ }
+
+ private boolean reportIfDebug(boolean result, int flags) {
+ if (DEBUG && !result) {
+ Slog.i(LOG_TAG, "No match!; flags: "
+ + DebugUtils.flagsToString(PackageManager.class, "MATCH_", flags) + " "
+ + Debug.getCaller());
+ }
+ return result;
}
/**
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index a8c3b88..6e519c1 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -475,6 +475,14 @@
final List<ResolveInfo> resolveInfos = queryIntentServices(userId);
for (ResolveInfo resolveInfo : resolveInfos) {
try {
+ // if this package is not one of those changedUids, we don't need to scan it,
+ // since nothing in it changed, so save a call to parseServiceInfo, which
+ // can cause a large amount of the package apk to be loaded into memory.
+ // if this is the initial scan, changedUids will be null, and containsUid will
+ // trivially return true, and will call parseServiceInfo
+ if (!containsUid(changedUids, resolveInfo.serviceInfo.applicationInfo.uid)) {
+ continue;
+ }
ServiceInfo<V> info = parseServiceInfo(resolveInfo);
if (info == null) {
Log.w(TAG, "Unable to load service info " + resolveInfo.toString());
diff --git a/core/java/android/hardware/display/ColorDisplayManager.java b/core/java/android/hardware/display/ColorDisplayManager.java
index dd782ec..0cf2d18 100644
--- a/core/java/android/hardware/display/ColorDisplayManager.java
+++ b/core/java/android/hardware/display/ColorDisplayManager.java
@@ -16,7 +16,9 @@
package android.hardware.display;
+import android.Manifest;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
import android.os.IBinder;
@@ -31,6 +33,7 @@
*
* @hide
*/
+@SystemApi
@SystemService(Context.COLOR_DISPLAY_SERVICE)
public final class ColorDisplayManager {
@@ -48,13 +51,29 @@
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
+ @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
public boolean isDeviceColorManaged() {
return mManager.isDeviceColorManaged();
}
/**
+ * Set the level of color saturation to apply to the display.
+ *
+ * @param saturationLevel 0-100 (inclusive), where 100 is full saturation
+ * @return whether the saturation level change was applied successfully
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
+ public boolean setSaturationLevel(int saturationLevel) {
+ return mManager.setSaturationLevel(saturationLevel);
+ }
+
+ /**
* Returns {@code true} if Night Display is supported by the device.
+ *
+ * @hide
*/
public static boolean isNightDisplayAvailable(Context context) {
return context.getResources().getBoolean(R.bool.config_nightDisplayAvailable);
@@ -62,6 +81,8 @@
/**
* Returns {@code true} if display white balance is supported by the device.
+ *
+ * @hide
*/
public static boolean isDisplayWhiteBalanceAvailable(Context context) {
return context.getResources().getBoolean(R.bool.config_displayWhiteBalanceAvailable);
@@ -99,5 +120,13 @@
throw e.rethrowFromSystemServer();
}
}
+
+ boolean setSaturationLevel(int saturationLevel) {
+ try {
+ return mCdm.setSaturationLevel(saturationLevel);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 82e765d..44b653c 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -563,11 +563,16 @@
* 0 produces a grayscale image, 1 is normal.
*
* @hide
+ * @deprecated use {@link ColorDisplayManager#setSaturationLevel(int)}.
*/
@SystemApi
@RequiresPermission(Manifest.permission.CONTROL_DISPLAY_SATURATION)
public void setSaturationLevel(float level) {
- mGlobal.setSaturationLevel(level);
+ if (level < 0f || level > 1f) {
+ throw new IllegalArgumentException("Saturation level must be between 0 and 1");
+ }
+ final ColorDisplayManager cdm = mContext.getSystemService(ColorDisplayManager.class);
+ cdm.setSaturationLevel(Math.round(level * 100f));
}
/**
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 7304ab4..cda8498 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -394,17 +394,6 @@
}
}
- /**
- * Set the level of color saturation to apply to the display.
- */
- public void setSaturationLevel(float level) {
- try {
- mDm.setSaturationLevel(level);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
- }
-
public VirtualDisplay createVirtualDisplay(Context context, MediaProjection projection,
String name, int width, int height, int densityDpi, Surface surface, int flags,
VirtualDisplay.Callback callback, Handler handler, String uniqueId) {
diff --git a/core/java/android/hardware/display/IColorDisplayManager.aidl b/core/java/android/hardware/display/IColorDisplayManager.aidl
index f786589..81b82c6 100644
--- a/core/java/android/hardware/display/IColorDisplayManager.aidl
+++ b/core/java/android/hardware/display/IColorDisplayManager.aidl
@@ -19,4 +19,6 @@
/** @hide */
interface IColorDisplayManager {
boolean isDeviceColorManaged();
+
+ boolean setSaturationLevel(int saturationLevel);
}
\ No newline at end of file
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index b575997..2d81cdf 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -66,9 +66,6 @@
// Requires CONFIGURE_DISPLAY_COLOR_MODE
void requestColorMode(int displayId, int colorMode);
- // Requires CONTROL_DISPLAY_SATURATION
- void setSaturationLevel(float level);
-
// Requires CAPTURE_VIDEO_OUTPUT, CAPTURE_SECURE_VIDEO_OUTPUT, or an appropriate
// MediaProjection token for certain combinations of flags.
int createVirtualDisplay(in IVirtualDisplayCallback callback,
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 1630b06..c9a7830 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -163,8 +163,8 @@
mAuthenticationCallback = callback;
mCryptoObject = crypto;
long sessionId = crypto != null ? crypto.getOpId() : 0;
- mService.authenticate(mToken, sessionId, mServiceReceiver, flags,
- mContext.getOpPackageName());
+ mService.authenticate(mToken, sessionId, mContext.getUserId(), mServiceReceiver,
+ flags, mContext.getOpPackageName());
} catch (RemoteException e) {
Log.w(TAG, "Remote exception while authenticating: ", e);
if (callback != null) {
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index a1c88f8..f67760a 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -27,7 +27,7 @@
*/
interface IFaceService {
// Authenticate the given sessionId with a face
- void authenticate(IBinder token, long sessionId,
+ void authenticate(IBinder token, long sessionId, int userid,
IFaceServiceReceiver receiver, int flags, String opPackageName);
// This method prepares the service to start authenticating, but doesn't start authentication.
diff --git a/core/java/android/net/IIpMemoryStore.aidl b/core/java/android/net/IIpMemoryStore.aidl
new file mode 100644
index 0000000..6f88dec
--- /dev/null
+++ b/core/java/android/net/IIpMemoryStore.aidl
@@ -0,0 +1,113 @@
+/*
+ * 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.net;
+
+import android.net.ipmemorystore.Blob;
+import android.net.ipmemorystore.NetworkAttributesParcelable;
+import android.net.ipmemorystore.IOnBlobRetrievedListener;
+import android.net.ipmemorystore.IOnL2KeyResponseListener;
+import android.net.ipmemorystore.IOnNetworkAttributesRetrieved;
+import android.net.ipmemorystore.IOnSameNetworkResponseListener;
+import android.net.ipmemorystore.IOnStatusListener;
+
+/** {@hide} */
+oneway interface IIpMemoryStore {
+ /**
+ * Store network attributes for a given L2 key.
+ * If L2Key is null, choose automatically from the attributes ; passing null is equivalent to
+ * calling findL2Key with the attributes and storing in the returned value.
+ *
+ * @param l2Key The L2 key for the L2 network. Clients that don't know or care about the L2
+ * key and only care about grouping can pass a unique ID here like the ones
+ * generated by {@code java.util.UUID.randomUUID()}, but keep in mind the low
+ * relevance of such a network will lead to it being evicted soon if it's not
+ * refreshed. Use findL2Key to try and find a similar L2Key to these attributes.
+ * @param attributes The attributes for this network.
+ * @param listener A listener that will be invoked to inform of the completion of this call,
+ * or null if the client is not interested in learning about success/failure.
+ * @return (through the listener) The L2 key. This is useful if the L2 key was not specified.
+ * If the call failed, the L2 key will be null.
+ */
+ void storeNetworkAttributes(String l2Key, in NetworkAttributesParcelable attributes,
+ IOnStatusListener listener);
+
+ /**
+ * Store a binary blob associated with an L2 key and a name.
+ *
+ * @param l2Key The L2 key for this network.
+ * @param clientId The ID of the client.
+ * @param name The name of this data.
+ * @param data The data to store.
+ * @param listener A listener to inform of the completion of this call, or null if the client
+ * is not interested in learning about success/failure.
+ * @return (through the listener) A status to indicate success or failure.
+ */
+ void storeBlob(String l2Key, String clientId, String name, in Blob data,
+ IOnStatusListener listener);
+
+ /**
+ * Returns the best L2 key associated with the attributes.
+ *
+ * This will find a record that would be in the same group as the passed attributes. This is
+ * useful to choose the key for storing a sample or private data when the L2 key is not known.
+ * If multiple records are group-close to these attributes, the closest match is returned.
+ * If multiple records have the same closeness, the one with the smaller (unicode codepoint
+ * order) L2 key is returned.
+ * If no record matches these attributes, null is returned.
+ *
+ * @param attributes The attributes of the network to find.
+ * @param listener The listener that will be invoked to return the answer.
+ * @return (through the listener) The L2 key if one matched, or null.
+ */
+ void findL2Key(in NetworkAttributesParcelable attributes, IOnL2KeyResponseListener listener);
+
+ /**
+ * Returns whether, to the best of the store's ability to tell, the two specified L2 keys point
+ * to the same L3 network. Group-closeness is used to determine this.
+ *
+ * @param l2Key1 The key for the first network.
+ * @param l2Key2 The key for the second network.
+ * @param listener The listener that will be invoked to return the answer.
+ * @return (through the listener) A SameL3NetworkResponse containing the answer and confidence.
+ */
+ void isSameNetwork(String l2Key1, String l2Key2, IOnSameNetworkResponseListener listener);
+
+ /**
+ * Retrieve the network attributes for a key.
+ * If no record is present for this key, this will return null attributes.
+ *
+ * @param l2Key The key of the network to query.
+ * @param listener The listener that will be invoked to return the answer.
+ * @return (through the listener) The network attributes and the L2 key associated with
+ * the query.
+ */
+ void retrieveNetworkAttributes(String l2Key, IOnNetworkAttributesRetrieved listener);
+
+ /**
+ * Retrieve previously stored private data.
+ * If no data was stored for this L2 key and name this will return null.
+ *
+ * @param l2Key The L2 key.
+ * @param clientId The id of the client that stored this data.
+ * @param name The name of the data.
+ * @param listener The listener that will be invoked to return the answer.
+ * @return (through the listener) The private data (or null), with the L2 key
+ * and the name of the data associated with the query.
+ */
+ void retrieveBlob(String l2Key, String clientId, String name,
+ IOnBlobRetrievedListener listener);
+}
diff --git a/core/java/android/net/IpMemoryStore.java b/core/java/android/net/IpMemoryStore.java
new file mode 100644
index 0000000..b35f097
--- /dev/null
+++ b/core/java/android/net/IpMemoryStore.java
@@ -0,0 +1,174 @@
+/*
+ * 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.net;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.net.ipmemorystore.Blob;
+import android.net.ipmemorystore.IOnBlobRetrievedListener;
+import android.net.ipmemorystore.IOnL2KeyResponseListener;
+import android.net.ipmemorystore.IOnNetworkAttributesRetrieved;
+import android.net.ipmemorystore.IOnSameNetworkResponseListener;
+import android.net.ipmemorystore.IOnStatusListener;
+import android.net.ipmemorystore.NetworkAttributes;
+import android.os.RemoteException;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * The interface for system components to access the IP memory store.
+ * @see com.android.server.net.ipmemorystore.IpMemoryStoreService
+ * @hide
+ */
+@SystemService(Context.IP_MEMORY_STORE_SERVICE)
+public class IpMemoryStore {
+ @NonNull final Context mContext;
+ @NonNull final IIpMemoryStore mService;
+
+ public IpMemoryStore(@NonNull final Context context, @NonNull final IIpMemoryStore service) {
+ mContext = Preconditions.checkNotNull(context, "missing context");
+ mService = Preconditions.checkNotNull(service, "missing IIpMemoryStore");
+ }
+
+ /**
+ * Store network attributes for a given L2 key.
+ * If L2Key is null, choose automatically from the attributes ; passing null is equivalent to
+ * calling findL2Key with the attributes and storing in the returned value.
+ *
+ * @param l2Key The L2 key for the L2 network. Clients that don't know or care about the L2
+ * key and only care about grouping can pass a unique ID here like the ones
+ * generated by {@code java.util.UUID.randomUUID()}, but keep in mind the low
+ * relevance of such a network will lead to it being evicted soon if it's not
+ * refreshed. Use findL2Key to try and find a similar L2Key to these attributes.
+ * @param attributes The attributes for this network.
+ * @param listener A listener that will be invoked to inform of the completion of this call,
+ * or null if the client is not interested in learning about success/failure.
+ * Through the listener, returns the L2 key. This is useful if the L2 key was not specified.
+ * If the call failed, the L2 key will be null.
+ */
+ public void storeNetworkAttributes(@NonNull final String l2Key,
+ @NonNull final NetworkAttributes attributes,
+ @Nullable final IOnStatusListener listener) {
+ try {
+ mService.storeNetworkAttributes(l2Key, attributes.toParcelable(), listener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Store a binary blob associated with an L2 key and a name.
+ *
+ * @param l2Key The L2 key for this network.
+ * @param clientId The ID of the client.
+ * @param name The name of this data.
+ * @param data The data to store.
+ * @param listener A listener to inform of the completion of this call, or null if the client
+ * is not interested in learning about success/failure.
+ * Through the listener, returns a status to indicate success or failure.
+ */
+ public void storeBlob(@NonNull final String l2Key, @NonNull final String clientId,
+ @NonNull final String name, @NonNull final Blob data,
+ @Nullable final IOnStatusListener listener) {
+ try {
+ mService.storeBlob(l2Key, clientId, name, data, listener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the best L2 key associated with the attributes.
+ *
+ * This will find a record that would be in the same group as the passed attributes. This is
+ * useful to choose the key for storing a sample or private data when the L2 key is not known.
+ * If multiple records are group-close to these attributes, the closest match is returned.
+ * If multiple records have the same closeness, the one with the smaller (unicode codepoint
+ * order) L2 key is returned.
+ * If no record matches these attributes, null is returned.
+ *
+ * @param attributes The attributes of the network to find.
+ * @param listener The listener that will be invoked to return the answer.
+ * Through the listener, returns the L2 key if one matched, or null.
+ */
+ public void findL2Key(@NonNull final NetworkAttributes attributes,
+ @NonNull final IOnL2KeyResponseListener listener) {
+ try {
+ mService.findL2Key(attributes.toParcelable(), listener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns whether, to the best of the store's ability to tell, the two specified L2 keys point
+ * to the same L3 network. Group-closeness is used to determine this.
+ *
+ * @param l2Key1 The key for the first network.
+ * @param l2Key2 The key for the second network.
+ * @param listener The listener that will be invoked to return the answer.
+ * Through the listener, a SameL3NetworkResponse containing the answer and confidence.
+ */
+ public void isSameNetwork(@NonNull final String l2Key1, @NonNull final String l2Key2,
+ @NonNull final IOnSameNetworkResponseListener listener) {
+ try {
+ mService.isSameNetwork(l2Key1, l2Key2, listener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Retrieve the network attributes for a key.
+ * If no record is present for this key, this will return null attributes.
+ *
+ * @param l2Key The key of the network to query.
+ * @param listener The listener that will be invoked to return the answer.
+ * Through the listener, returns the network attributes and the L2 key associated with
+ * the query.
+ */
+ public void retrieveNetworkAttributes(@NonNull final String l2Key,
+ @NonNull final IOnNetworkAttributesRetrieved listener) {
+ try {
+ mService.retrieveNetworkAttributes(l2Key, listener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Retrieve previously stored private data.
+ * If no data was stored for this L2 key and name this will return null.
+ *
+ * @param l2Key The L2 key.
+ * @param clientId The id of the client that stored this data.
+ * @param name The name of the data.
+ * @param listener The listener that will be invoked to return the answer.
+ * Through the listener, returns the private data (or null), with the L2 key
+ * and the name of the data associated with the query.
+ */
+ public void retrieveBlob(@NonNull final String l2Key, @NonNull final String clientId,
+ @NonNull final String name, @NonNull final IOnBlobRetrievedListener listener) {
+ try {
+ mService.retrieveBlob(l2Key, clientId, name, listener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+}
diff --git a/core/java/android/net/ipmemorystore/Blob.aidl b/core/java/android/net/ipmemorystore/Blob.aidl
new file mode 100644
index 0000000..9dbef11
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/Blob.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.net.ipmemorystore;
+
+/**
+ * A blob of data opaque to the memory store. The client mutates this at its own risk,
+ * and it is strongly suggested to never do it at all and treat this as immutable.
+ * {@hide}
+ */
+parcelable Blob {
+ byte[] data;
+}
diff --git a/core/java/android/net/ipmemorystore/IOnBlobRetrievedListener.aidl b/core/java/android/net/ipmemorystore/IOnBlobRetrievedListener.aidl
new file mode 100644
index 0000000..4926feb
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/IOnBlobRetrievedListener.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.net.ipmemorystore;
+
+import android.net.ipmemorystore.Blob;
+import android.net.ipmemorystore.StatusParcelable;
+
+/** {@hide} */
+oneway interface IOnBlobRetrievedListener {
+ /**
+ * Private data was retrieved for the L2 key and name specified.
+ * Note this does not return the client ID, as clients are expected to only ever use one ID.
+ */
+ void onBlobRetrieved(in StatusParcelable status, in String l2Key, in String name,
+ in Blob data);
+}
diff --git a/core/java/android/net/ipmemorystore/IOnL2KeyResponseListener.aidl b/core/java/android/net/ipmemorystore/IOnL2KeyResponseListener.aidl
new file mode 100644
index 0000000..dea0cc4
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/IOnL2KeyResponseListener.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.net.ipmemorystore;
+
+import android.net.ipmemorystore.StatusParcelable;
+
+/** {@hide} */
+oneway interface IOnL2KeyResponseListener {
+ /**
+ * The operation completed with the specified L2 key.
+ */
+ void onL2KeyResponse(in StatusParcelable status, in String l2Key);
+}
diff --git a/core/java/android/net/ipmemorystore/IOnNetworkAttributesRetrieved.aidl b/core/java/android/net/ipmemorystore/IOnNetworkAttributesRetrieved.aidl
new file mode 100644
index 0000000..57f59a1
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/IOnNetworkAttributesRetrieved.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.net.ipmemorystore;
+
+import android.net.ipmemorystore.NetworkAttributesParcelable;
+import android.net.ipmemorystore.StatusParcelable;
+
+/** {@hide} */
+oneway interface IOnNetworkAttributesRetrieved {
+ /**
+ * Network attributes were fetched for the specified L2 key. While the L2 key will never
+ * be null, the attributes may be if no data is stored about this L2 key.
+ */
+ void onL2KeyResponse(in StatusParcelable status, in String l2Key,
+ in NetworkAttributesParcelable attributes);
+}
diff --git a/core/java/android/net/ipmemorystore/IOnSameNetworkResponseListener.aidl b/core/java/android/net/ipmemorystore/IOnSameNetworkResponseListener.aidl
new file mode 100644
index 0000000..294bd3b
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/IOnSameNetworkResponseListener.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.net.ipmemorystore;
+
+import android.net.ipmemorystore.SameL3NetworkResponseParcelable;
+import android.net.ipmemorystore.StatusParcelable;
+
+/** {@hide} */
+oneway interface IOnSameNetworkResponseListener {
+ /**
+ * The memory store has come up with the answer to a query that was sent.
+ */
+ void onSameNetworkResponse(in StatusParcelable status,
+ in SameL3NetworkResponseParcelable response);
+}
diff --git a/core/java/android/net/ipmemorystore/IOnStatusListener.aidl b/core/java/android/net/ipmemorystore/IOnStatusListener.aidl
new file mode 100644
index 0000000..5d07504
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/IOnStatusListener.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.net.ipmemorystore;
+
+import android.net.ipmemorystore.StatusParcelable;
+
+/** {@hide} */
+oneway interface IOnStatusListener {
+ /**
+ * The operation has completed with the specified status.
+ */
+ void onComplete(in StatusParcelable status);
+}
diff --git a/core/java/android/net/ipmemorystore/NetworkAttributes.java b/core/java/android/net/ipmemorystore/NetworkAttributes.java
new file mode 100644
index 0000000..d7e5b27
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/NetworkAttributes.java
@@ -0,0 +1,210 @@
+/*
+ * 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.net.ipmemorystore;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A POD object to represent attributes of a single L2 network entry.
+ * @hide
+ */
+public class NetworkAttributes {
+ private static final boolean DBG = true;
+
+ // The v4 address that was assigned to this device the last time it joined this network.
+ // This typically comes from DHCP but could be something else like static configuration.
+ // This does not apply to IPv6.
+ // TODO : add a list of v6 prefixes for the v6 case.
+ @Nullable
+ public final Inet4Address assignedV4Address;
+
+ // Optionally supplied by the client if it has an opinion on L3 network. For example, this
+ // could be a hash of the SSID + security type on WiFi.
+ @Nullable
+ public final String groupHint;
+
+ // The list of DNS server addresses.
+ @Nullable
+ public final List<InetAddress> dnsAddresses;
+
+ // The mtu on this network.
+ @Nullable
+ public final Integer mtu;
+
+ NetworkAttributes(
+ @Nullable final Inet4Address assignedV4Address,
+ @Nullable final String groupHint,
+ @Nullable final List<InetAddress> dnsAddresses,
+ @Nullable final Integer mtu) {
+ if (mtu != null && mtu < 0) throw new IllegalArgumentException("MTU can't be negative");
+ this.assignedV4Address = assignedV4Address;
+ this.groupHint = groupHint;
+ this.dnsAddresses = null == dnsAddresses ? null :
+ Collections.unmodifiableList(new ArrayList<>(dnsAddresses));
+ this.mtu = mtu;
+ }
+
+ @VisibleForTesting
+ public NetworkAttributes(@NonNull final NetworkAttributesParcelable parcelable) {
+ // The call to the other constructor must be the first statement of this constructor,
+ // so everything has to be inline
+ this((Inet4Address) getByAddressOrNull(parcelable.assignedV4Address),
+ parcelable.groupHint,
+ blobArrayToInetAddressList(parcelable.dnsAddresses),
+ parcelable.mtu >= 0 ? parcelable.mtu : null);
+ }
+
+ @Nullable
+ private static InetAddress getByAddressOrNull(@Nullable final byte[] address) {
+ try {
+ return InetAddress.getByAddress(address);
+ } catch (UnknownHostException e) {
+ return null;
+ }
+ }
+
+ @Nullable
+ private static List<InetAddress> blobArrayToInetAddressList(@Nullable final Blob[] blobs) {
+ if (null == blobs) return null;
+ final ArrayList<InetAddress> list = new ArrayList<>(blobs.length);
+ for (final Blob b : blobs) {
+ final InetAddress addr = getByAddressOrNull(b.data);
+ if (null != addr) list.add(addr);
+ }
+ return list;
+ }
+
+ @Nullable
+ private static Blob[] inetAddressListToBlobArray(@Nullable final List<InetAddress> addresses) {
+ if (null == addresses) return null;
+ final ArrayList<Blob> blobs = new ArrayList<>();
+ for (int i = 0; i < addresses.size(); ++i) {
+ final InetAddress addr = addresses.get(i);
+ if (null == addr) continue;
+ final Blob b = new Blob();
+ b.data = addr.getAddress();
+ blobs.add(b);
+ }
+ return blobs.toArray(new Blob[0]);
+ }
+
+ /** Converts this NetworkAttributes to a parcelable object */
+ @NonNull
+ public NetworkAttributesParcelable toParcelable() {
+ final NetworkAttributesParcelable parcelable = new NetworkAttributesParcelable();
+ parcelable.assignedV4Address =
+ (null == assignedV4Address) ? null : assignedV4Address.getAddress();
+ parcelable.groupHint = groupHint;
+ parcelable.dnsAddresses = inetAddressListToBlobArray(dnsAddresses);
+ parcelable.mtu = (null == mtu) ? -1 : mtu;
+ return parcelable;
+ }
+
+ /** @hide */
+ public static class Builder {
+ @Nullable
+ private Inet4Address mAssignedAddress;
+ @Nullable
+ private String mGroupHint;
+ @Nullable
+ private List<InetAddress> mDnsAddresses;
+ @Nullable
+ private Integer mMtu;
+
+ /**
+ * Set the assigned address.
+ * @param assignedV4Address The assigned address.
+ * @return This builder.
+ */
+ public Builder setAssignedV4Address(@Nullable final Inet4Address assignedV4Address) {
+ mAssignedAddress = assignedV4Address;
+ return this;
+ }
+
+ /**
+ * Set the group hint.
+ * @param groupHint The group hint.
+ * @return This builder.
+ */
+ public Builder setGroupHint(@Nullable final String groupHint) {
+ mGroupHint = groupHint;
+ return this;
+ }
+
+ /**
+ * Set the DNS addresses.
+ * @param dnsAddresses The DNS addresses.
+ * @return This builder.
+ */
+ public Builder setDnsAddresses(@Nullable final List<InetAddress> dnsAddresses) {
+ if (DBG && null != dnsAddresses) {
+ // Parceling code crashes if one of the addresses is null, therefore validate
+ // them when running in debug.
+ for (final InetAddress address : dnsAddresses) {
+ if (null == address) throw new IllegalArgumentException("Null DNS address");
+ }
+ }
+ this.mDnsAddresses = dnsAddresses;
+ return this;
+ }
+
+ /**
+ * Set the MTU.
+ * @param mtu The MTU.
+ * @return This builder.
+ */
+ public Builder setMtu(@Nullable final Integer mtu) {
+ if (null != mtu && mtu < 0) throw new IllegalArgumentException("MTU can't be negative");
+ mMtu = mtu;
+ return this;
+ }
+
+ /**
+ * Return the built NetworkAttributes object.
+ * @return The built NetworkAttributes object.
+ */
+ public NetworkAttributes build() {
+ return new NetworkAttributes(mAssignedAddress, mGroupHint, mDnsAddresses, mMtu);
+ }
+ }
+
+ @Override
+ public boolean equals(@Nullable final Object o) {
+ if (!(o instanceof NetworkAttributes)) return false;
+ final NetworkAttributes other = (NetworkAttributes) o;
+ return Objects.equals(assignedV4Address, other.assignedV4Address)
+ && Objects.equals(groupHint, other.groupHint)
+ && Objects.equals(dnsAddresses, other.dnsAddresses)
+ && Objects.equals(mtu, other.mtu);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(assignedV4Address, groupHint, dnsAddresses, mtu);
+ }
+}
diff --git a/core/java/android/net/ipmemorystore/NetworkAttributesParcelable.aidl b/core/java/android/net/ipmemorystore/NetworkAttributesParcelable.aidl
new file mode 100644
index 0000000..0894d72
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/NetworkAttributesParcelable.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.net.ipmemorystore;
+
+// Blob[] is used to represent an array of byte[], as structured AIDL does not support arrays
+// of arrays.
+import android.net.ipmemorystore.Blob;
+
+/**
+ * An object to represent attributes of a single L2 network entry.
+ * See NetworkAttributes.java for a description of each field. The types used in this class
+ * are structured parcelable types instead of the richer types of the NetworkAttributes object,
+ * but they have the same purpose. The NetworkAttributes.java file also contains the code
+ * to convert the richer types to the parcelable types and back.
+ * @hide
+ */
+parcelable NetworkAttributesParcelable {
+ byte[] assignedV4Address;
+ String groupHint;
+ Blob[] dnsAddresses;
+ int mtu;
+}
diff --git a/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java b/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java
new file mode 100644
index 0000000..0cb37e9
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java
@@ -0,0 +1,131 @@
+/*
+ * 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.net.ipmemorystore;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * An object representing the answer to a query whether two given L2 networks represent the
+ * same L3 network. Parcels as a SameL3NetworkResponseParceled object.
+ * @hide
+ */
+public class SameL3NetworkResponse {
+ @IntDef(prefix = "NETWORK_",
+ value = {NETWORK_SAME, NETWORK_DIFFERENT, NETWORK_NEVER_CONNECTED})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface NetworkSameness {}
+
+ /**
+ * Both L2 networks represent the same L3 network.
+ */
+ public static final int NETWORK_SAME = 1;
+
+ /**
+ * The two L2 networks represent a different L3 network.
+ */
+ public static final int NETWORK_DIFFERENT = 2;
+
+ /**
+ * The device has never connected to at least one of these two L2 networks, or data
+ * has been wiped. Therefore the device has never seen the L3 network behind at least
+ * one of these two L2 networks, and can't evaluate whether it's the same as the other.
+ */
+ public static final int NETWORK_NEVER_CONNECTED = 3;
+
+ /**
+ * The first L2 key specified in the query.
+ */
+ @NonNull
+ public final String l2Key1;
+
+ /**
+ * The second L2 key specified in the query.
+ */
+ @NonNull
+ public final String l2Key2;
+
+ /**
+ * A confidence value indicating whether the two L2 networks represent the same L3 network.
+ *
+ * If both L2 networks were known, this value will be between 0.0 and 1.0, with 0.0
+ * representing complete confidence that the given L2 networks represent a different
+ * L3 network, and 1.0 representing complete confidence that the given L2 networks
+ * represent the same L3 network.
+ * If at least one of the L2 networks was not known, this value will be outside of the
+ * 0.0~1.0 range.
+ *
+ * Most apps should not be interested in this, and are encouraged to use the collapsing
+ * {@link #getNetworkSameness()} function below.
+ */
+ public final float confidence;
+
+ /**
+ * @return whether the two L2 networks represent the same L3 network. Either
+ * {@code NETWORK_SAME}, {@code NETWORK_DIFFERENT} or {@code NETWORK_NEVER_CONNECTED}.
+ */
+ @NetworkSameness
+ public final int getNetworkSameness() {
+ if (confidence > 1.0 || confidence < 0.0) return NETWORK_NEVER_CONNECTED;
+ return confidence > 0.5 ? NETWORK_SAME : NETWORK_DIFFERENT;
+ }
+
+ SameL3NetworkResponse(@NonNull final String l2Key1, @NonNull final String l2Key2,
+ final float confidence) {
+ this.l2Key1 = l2Key1;
+ this.l2Key2 = l2Key2;
+ this.confidence = confidence;
+ }
+
+ /** Builds a SameL3NetworkResponse from a parcelable object */
+ @VisibleForTesting
+ public SameL3NetworkResponse(@NonNull final SameL3NetworkResponseParcelable parceled) {
+ this(parceled.l2Key1, parceled.l2Key2, parceled.confidence);
+ }
+
+ /** Converts this SameL3NetworkResponse to a parcelable object */
+ @NonNull
+ public SameL3NetworkResponseParcelable toParcelable() {
+ final SameL3NetworkResponseParcelable parcelable = new SameL3NetworkResponseParcelable();
+ parcelable.l2Key1 = l2Key1;
+ parcelable.l2Key2 = l2Key2;
+ parcelable.confidence = confidence;
+ return parcelable;
+ }
+
+ // Note key1 and key2 have to match each other for this to return true. If
+ // key1 matches o.key2 and the other way around this returns false.
+ @Override
+ public boolean equals(@Nullable final Object o) {
+ if (!(o instanceof SameL3NetworkResponse)) return false;
+ final SameL3NetworkResponse other = (SameL3NetworkResponse) o;
+ return l2Key1.equals(other.l2Key1) && l2Key2.equals(other.l2Key2)
+ && confidence == other.confidence;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(l2Key1, l2Key2, confidence);
+ }
+}
diff --git a/core/java/android/net/ipmemorystore/SameL3NetworkResponseParcelable.aidl b/core/java/android/net/ipmemorystore/SameL3NetworkResponseParcelable.aidl
new file mode 100644
index 0000000..7196699
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/SameL3NetworkResponseParcelable.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.net.ipmemorystore;
+
+/** {@hide} */
+parcelable SameL3NetworkResponseParcelable {
+ String l2Key1;
+ String l2Key2;
+ float confidence;
+}
diff --git a/core/java/android/net/ipmemorystore/Status.java b/core/java/android/net/ipmemorystore/Status.java
new file mode 100644
index 0000000..5b016ec
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/Status.java
@@ -0,0 +1,50 @@
+/*
+ * 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.net.ipmemorystore;
+
+import android.annotation.NonNull;
+
+/**
+ * A parcelable status representing the result of an operation.
+ * Parcels as StatusParceled.
+ * @hide
+ */
+public class Status {
+ public static final int SUCCESS = 0;
+
+ public final int resultCode;
+
+ public Status(final int resultCode) {
+ this.resultCode = resultCode;
+ }
+
+ Status(@NonNull final StatusParcelable parcelable) {
+ this(parcelable.resultCode);
+ }
+
+ /** Converts this Status to a parcelable object */
+ @NonNull
+ public StatusParcelable toParcelable() {
+ final StatusParcelable parcelable = new StatusParcelable();
+ parcelable.resultCode = resultCode;
+ return parcelable;
+ }
+
+ public boolean isSuccess() {
+ return SUCCESS == resultCode;
+ }
+}
diff --git a/core/java/android/net/ipmemorystore/StatusParcelable.aidl b/core/java/android/net/ipmemorystore/StatusParcelable.aidl
new file mode 100644
index 0000000..fb36ef4
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/StatusParcelable.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.net.ipmemorystore;
+
+/** {@hide} */
+parcelable StatusParcelable {
+ int resultCode;
+}
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
new file mode 100644
index 0000000..1343d24
--- /dev/null
+++ b/core/java/android/os/BugreportManager.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.IBinder.DeathRecipient;
+
+import java.io.FileDescriptor;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Class that provides a privileged API to capture and consume bugreports.
+ *
+ * @hide
+ */
+// TODO: Expose API when the implementation is more complete.
+// @SystemApi
+@SystemService(Context.BUGREPORT_SERVICE)
+public class BugreportManager {
+ private final Context mContext;
+ private final IDumpstate mBinder;
+
+ /** @hide */
+ public BugreportManager(@NonNull Context context, IDumpstate binder) {
+ mContext = context;
+ mBinder = binder;
+ }
+
+ /**
+ * An interface describing the listener for bugreport progress and status.
+ */
+ public interface BugreportListener {
+ /**
+ * Called when there is a progress update.
+ * @param progress the progress in [0.0, 100.0]
+ */
+ void onProgress(float progress);
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "BUGREPORT_ERROR_" }, value = {
+ BUGREPORT_ERROR_INVALID_INPUT,
+ BUGREPORT_ERROR_RUNTIME
+ })
+
+ /** Possible error codes taking a bugreport can encounter */
+ @interface BugreportErrorCode {}
+
+ /** The input options were invalid */
+ int BUGREPORT_ERROR_INVALID_INPUT = 1;
+
+ /** A runtime error occured */
+ int BUGREPORT_ERROR_RUNTIME = 2;
+
+ /**
+ * Called when taking bugreport resulted in an error.
+ *
+ * @param errorCode the error that occurred. Possible values are
+ * {@code BUGREPORT_ERROR_INVALID_INPUT}, {@code BUGREPORT_ERROR_RUNTIME}.
+ */
+ void onError(@BugreportErrorCode int errorCode);
+
+ /**
+ * Called when taking bugreport finishes successfully
+ *
+ * @param durationMs time capturing bugreport took in milliseconds
+ * @param title title for the bugreport; helpful in reminding the user why they took it
+ * @param description detailed description for the bugreport
+ */
+ void onFinished(long durationMs, @NonNull String title,
+ @NonNull String description);
+ }
+
+ /**
+ * Starts a bugreport asynchronously.
+ *
+ * @param bugreportFd file to write the bugreport. This should be opened in write-only,
+ * append mode.
+ * @param screenshotFd file to write the screenshot, if necessary. This should be opened
+ * in write-only, append mode.
+ * @param params options that specify what kind of a bugreport should be taken
+ * @param listener callback for progress and status updates
+ */
+ @RequiresPermission(android.Manifest.permission.DUMP)
+ public void startBugreport(@NonNull FileDescriptor bugreportFd,
+ @Nullable FileDescriptor screenshotFd,
+ @NonNull BugreportParams params, @Nullable BugreportListener listener) {
+ // TODO(b/111441001): Enforce android.Manifest.permission.DUMP if necessary.
+ DumpstateListener dsListener = new DumpstateListener(listener);
+
+ try {
+ mBinder.startBugreport(bugreportFd, screenshotFd, params.getMode(), dsListener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+
+ // TODO(b/111441001) Connect up with BugreportListener methods.
+ private final class DumpstateListener extends IDumpstateListener.Stub
+ implements DeathRecipient {
+ private final BugreportListener mListener;
+
+ DumpstateListener(@Nullable BugreportListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void binderDied() {
+ // TODO(b/111441001): implement
+ }
+
+ @Override
+ public void onProgressUpdated(int progress) throws RemoteException {
+ // TODO(b/111441001): implement
+ }
+
+ @Override
+ public void onMaxProgressUpdated(int maxProgress) throws RemoteException {
+ // TODO(b/111441001): implement
+ }
+
+ @Override
+ public void onSectionComplete(String title, int status, int size, int durationMs)
+ throws RemoteException {
+ // TODO(b/111441001): implement
+ }
+ }
+}
diff --git a/core/java/android/os/BugreportParams.java b/core/java/android/os/BugreportParams.java
new file mode 100644
index 0000000..4e696ae
--- /dev/null
+++ b/core/java/android/os/BugreportParams.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Parameters that specify what kind of bugreport should be taken.
+ *
+ * @hide
+ */
+// TODO: Expose API when the implementation is more complete.
+// @SystemApi
+public final class BugreportParams {
+ private final int mMode;
+
+ public BugreportParams(@BugreportMode int mode) {
+ mMode = mode;
+ }
+
+ public int getMode() {
+ return mMode;
+ }
+
+ /**
+ * Defines acceptable types of bugreports.
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "BUGREPORT_MODE_" }, value = {
+ BUGREPORT_MODE_FULL,
+ BUGREPORT_MODE_INTERACTIVE,
+ BUGREPORT_MODE_REMOTE,
+ BUGREPORT_MODE_WEAR,
+ BUGREPORT_MODE_TELEPHONY,
+ BUGREPORT_MODE_WIFI
+ })
+ public @interface BugreportMode {}
+
+ /**
+ * Options for a bugreport without user interference (and hence causing less
+ * interference to the system), but includes all sections.
+ */
+ public static final int BUGREPORT_MODE_FULL = IDumpstate.BUGREPORT_MODE_FULL;
+
+ /**
+ * Options that allow user to monitor progress and enter additional data; might not
+ * include all sections.
+ */
+ public static final int BUGREPORT_MODE_INTERACTIVE = IDumpstate.BUGREPORT_MODE_INTERACTIVE;
+
+ /**
+ * Options for a bugreport requested remotely by administrator of the Device Owner app,
+ * not the device's user.
+ */
+ public static final int BUGREPORT_MODE_REMOTE = IDumpstate.BUGREPORT_MODE_REMOTE;
+
+ /**
+ * Options for a bugreport on a wearable device.
+ */
+ public static final int BUGREPORT_MODE_WEAR = IDumpstate.BUGREPORT_MODE_WEAR;
+
+ /**
+ * Options for a lightweight version of bugreport that only includes a few, urgent
+ * sections used to report telephony bugs.
+ */
+ public static final int BUGREPORT_MODE_TELEPHONY = IDumpstate.BUGREPORT_MODE_TELEPHONY;
+
+ /**
+ * Options for a lightweight bugreport that only includes a few sections related to
+ * Wifi.
+ */
+ public static final int BUGREPORT_MODE_WIFI = IDumpstate.BUGREPORT_MODE_WIFI;
+}
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index cc6bb12..b9cdcc0 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -899,6 +899,33 @@
}
/**
+ * Flatten an {@link ArrayMap} with string keys containing a particular object
+ * type into the parcel at the current dataPosition() and growing dataCapacity()
+ * if needed. The type of the objects in the array must be one that implements
+ * Parcelable. Only the raw data of the objects is written and not their type,
+ * so you must use the corresponding {@link #createTypedArrayMap(Parcelable.Creator)}
+ *
+ * @param val The map of objects to be written.
+ * @param parcelableFlags The parcelable flags to use.
+ *
+ * @see #createTypedArrayMap(Parcelable.Creator)
+ * @see Parcelable
+ */
+ public <T extends Parcelable> void writeTypedArrayMap(@Nullable ArrayMap<String, T> val,
+ int parcelableFlags) {
+ if (val == null) {
+ writeInt(-1);
+ return;
+ }
+ final int count = val.size();
+ writeInt(count);
+ for (int i = 0; i < count; i++) {
+ writeString(val.keyAt(i));
+ writeTypedObject(val.valueAt(i), parcelableFlags);
+ }
+ }
+
+ /**
* Write an array set to the parcel.
*
* @param val The array set to write.
@@ -1001,7 +1028,7 @@
* values are written using {@link #writeValue} and must follow the
* specification there.
*/
- public final void writeSparseArray(@Nullable SparseArray<Object> val) {
+ public final <T> void writeSparseArray(@Nullable SparseArray<T> val) {
if (val == null) {
writeInt(-1);
return;
@@ -1400,6 +1427,34 @@
}
/**
+ * Flatten a {@link SparseArray} containing a particular object type into the parcel
+ * at the current dataPosition() and growing dataCapacity() if needed. The
+ * type of the objects in the array must be one that implements Parcelable.
+ * Unlike the generic {@link #writeSparseArray(SparseArray)} method, however, only
+ * the raw data of the objects is written and not their type, so you must use the
+ * corresponding {@link #createTypedSparseArray(Parcelable.Creator)}.
+ *
+ * @param val The list of objects to be written.
+ * @param parcelableFlags The parcelable flags to use.
+ *
+ * @see #createTypedSparseArray(Parcelable.Creator)
+ * @see Parcelable
+ */
+ public final <T extends Parcelable> void writeTypedSparseArray(@Nullable SparseArray<T> val,
+ int parcelableFlags) {
+ if (val == null) {
+ writeInt(-1);
+ return;
+ }
+ final int count = val.size();
+ writeInt(count);
+ for (int i = 0; i < count; i++) {
+ writeInt(val.keyAt(i));
+ writeTypedObject(val.valueAt(i), parcelableFlags);
+ }
+ }
+
+ /**
* @hide
*/
public <T extends Parcelable> void writeTypedList(@Nullable List<T> val, int parcelableFlags) {
@@ -2369,7 +2424,7 @@
* Parcelables.
*/
@Nullable
- public final SparseArray readSparseArray(@Nullable ClassLoader loader) {
+ public final <T> SparseArray<T> readSparseArray(@Nullable ClassLoader loader) {
int N = readInt();
if (N < 0) {
return null;
@@ -2466,6 +2521,62 @@
}
/**
+ * Read into a new {@link SparseArray} items containing a particular object type
+ * that were written with {@link #writeTypedSparseArray(SparseArray, int)} at the
+ * current dataPosition(). The list <em>must</em> have previously been written
+ * via {@link #writeTypedSparseArray(SparseArray, int)} with the same object type.
+ *
+ * @param creator The creator to use when for instantiation.
+ *
+ * @return A newly created {@link SparseArray} containing objects with the same data
+ * as those that were previously written.
+ *
+ * @see #writeTypedSparseArray(SparseArray, int)
+ */
+ public final @Nullable <T extends Parcelable> SparseArray<T> createTypedSparseArray(
+ @NonNull Parcelable.Creator<T> creator) {
+ final int count = readInt();
+ if (count < 0) {
+ return null;
+ }
+ final SparseArray<T> array = new SparseArray<>(count);
+ for (int i = 0; i < count; i++) {
+ final int index = readInt();
+ final T value = readTypedObject(creator);
+ array.append(index, value);
+ }
+ return array;
+ }
+
+ /**
+ * Read into a new {@link ArrayMap} with string keys items containing a particular
+ * object type that were written with {@link #writeTypedArrayMap(ArrayMap, int)} at the
+ * current dataPosition(). The list <em>must</em> have previously been written
+ * via {@link #writeTypedArrayMap(ArrayMap, int)} with the same object type.
+ *
+ * @param creator The creator to use when for instantiation.
+ *
+ * @return A newly created {@link ArrayMap} containing objects with the same data
+ * as those that were previously written.
+ *
+ * @see #writeTypedArrayMap(ArrayMap, int)
+ */
+ public final @Nullable <T extends Parcelable> ArrayMap<String, T> createTypedArrayMap(
+ @NonNull Parcelable.Creator<T> creator) {
+ final int count = readInt();
+ if (count < 0) {
+ return null;
+ }
+ final ArrayMap<String, T> map = new ArrayMap<>(count);
+ for (int i = 0; i < count; i++) {
+ final String key = readString();
+ final T value = readTypedObject(creator);
+ map.append(key, value);
+ }
+ return map;
+ }
+
+ /**
* Read and return a new ArrayList containing String objects from
* the parcel that was written with {@link #writeStringList} at the
* current dataPosition(). Returns null if the
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index c3e0489..0942d97 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -1326,7 +1326,7 @@
* @return Battery saver state data.
*
* @hide
- * @see com.android.server.power.BatterySaverPolicy
+ * @see com.android.server.power.batterysaver.BatterySaverPolicy
* @see PowerSaveState
*/
public PowerSaveState getPowerSaveState(@ServiceType int serviceType) {
diff --git a/core/java/android/os/PowerSaveState.java b/core/java/android/os/PowerSaveState.java
index de1128df..4918ad1 100644
--- a/core/java/android/os/PowerSaveState.java
+++ b/core/java/android/os/PowerSaveState.java
@@ -27,7 +27,7 @@
/**
* Whether we should enable battery saver for this service.
*
- * @see com.android.server.power.BatterySaverPolicy
+ * @see com.android.server.power.batterysaver.BatterySaverPolicy
*/
public final boolean batterySaverEnabled;
/**
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index b5aeba0..226d1d0 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -74,10 +74,13 @@
private final String mPackageName;
// The default vibration intensity level for haptic feedback.
@VibrationIntensity
- private final int mDefaultHapticFeedbackIntensity;
+ private int mDefaultHapticFeedbackIntensity;
// The default vibration intensity level for notifications.
@VibrationIntensity
- private final int mDefaultNotificationVibrationIntensity;
+ private int mDefaultNotificationVibrationIntensity;
+ // The default vibration intensity level for ringtones.
+ @VibrationIntensity
+ private int mDefaultRingVibrationIntensity;
/**
* @hide to prevent subclassing from outside of the framework
@@ -85,10 +88,7 @@
public Vibrator() {
mPackageName = ActivityThread.currentPackageName();
final Context ctx = ActivityThread.currentActivityThread().getSystemContext();
- mDefaultHapticFeedbackIntensity = loadDefaultIntensity(ctx,
- com.android.internal.R.integer.config_defaultHapticFeedbackIntensity);
- mDefaultNotificationVibrationIntensity = loadDefaultIntensity(ctx,
- com.android.internal.R.integer.config_defaultNotificationVibrationIntensity);
+ loadVibrationIntensities(ctx);
}
/**
@@ -96,10 +96,16 @@
*/
protected Vibrator(Context context) {
mPackageName = context.getOpPackageName();
+ loadVibrationIntensities(context);
+ }
+
+ private void loadVibrationIntensities(Context context) {
mDefaultHapticFeedbackIntensity = loadDefaultIntensity(context,
com.android.internal.R.integer.config_defaultHapticFeedbackIntensity);
mDefaultNotificationVibrationIntensity = loadDefaultIntensity(context,
com.android.internal.R.integer.config_defaultNotificationVibrationIntensity);
+ mDefaultRingVibrationIntensity = loadDefaultIntensity(context,
+ com.android.internal.R.integer.config_defaultRingVibrationIntensity);
}
private int loadDefaultIntensity(Context ctx, int resId) {
@@ -115,13 +121,20 @@
}
/**
- * Get the default vibration intensity for notifications and ringtones.
+ * Get the default vibration intensity for notifications.
* @hide
*/
public int getDefaultNotificationVibrationIntensity() {
return mDefaultNotificationVibrationIntensity;
}
+ /** Get the default vibration intensity for ringtones.
+ * @hide
+ */
+ public int getDefaultRingVibrationIntensity() {
+ return mDefaultRingVibrationIntensity;
+ }
+
/**
* Check whether the hardware has a vibrator.
*
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index e21a660..d7332ae 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -45,6 +45,7 @@
import android.util.ArrayMap;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
import com.android.internal.infra.AbstractRemoteService;
import com.android.internal.util.Preconditions;
@@ -68,6 +69,12 @@
public final class PermissionControllerManager {
private static final String TAG = PermissionControllerManager.class.getSimpleName();
+ private static final Object sLock = new Object();
+
+ /** App global remote service used by all {@link PermissionControllerManager managers} */
+ @GuardedBy("sLock")
+ private static RemoteService sRemoteService;
+
/**
* The key for retrieving the result from the returned bundle.
*
@@ -140,17 +147,27 @@
}
private final @NonNull Context mContext;
- private final RemoteService mRemoteService;
- /** @hide */
+ /**
+ * Create a new {@link PermissionControllerManager}.
+ *
+ * @param context to create the manager for
+ *
+ * @hide
+ */
public PermissionControllerManager(@NonNull Context context) {
- Intent intent = new Intent(SERVICE_INTERFACE);
- intent.setPackage(context.getPackageManager().getPermissionControllerPackageName());
- ResolveInfo serviceInfo = context.getPackageManager().resolveService(intent, 0);
+ synchronized (sLock) {
+ if (sRemoteService == null) {
+ Intent intent = new Intent(SERVICE_INTERFACE);
+ intent.setPackage(context.getPackageManager().getPermissionControllerPackageName());
+ ResolveInfo serviceInfo = context.getPackageManager().resolveService(intent, 0);
+
+ sRemoteService = new RemoteService(context.getApplicationContext(),
+ serviceInfo.getComponentInfo().getComponentName());
+ }
+ }
mContext = context;
- mRemoteService = new RemoteService(context,
- serviceInfo.getComponentInfo().getComponentName());
}
/**
@@ -182,7 +199,7 @@
+ " required");
}
- mRemoteService.scheduleRequest(new PendingRevokeRuntimePermissionRequest(mRemoteService,
+ sRemoteService.scheduleRequest(new PendingRevokeRuntimePermissionRequest(sRemoteService,
request, doDryRun, reason, mContext.getPackageName(), executor, callback));
}
@@ -201,8 +218,8 @@
checkNotNull(packageName);
checkNotNull(callback);
- mRemoteService.scheduleRequest(new PendingGetAppPermissionRequest(mRemoteService,
- packageName, callback, handler == null ? mRemoteService.getHandler() : handler));
+ sRemoteService.scheduleRequest(new PendingGetAppPermissionRequest(sRemoteService,
+ packageName, callback, handler == null ? sRemoteService.getHandler() : handler));
}
/**
@@ -219,7 +236,7 @@
checkNotNull(packageName);
checkNotNull(permissionName);
- mRemoteService.scheduleAsyncRequest(new PendingRevokeAppPermissionRequest(packageName,
+ sRemoteService.scheduleAsyncRequest(new PendingRevokeAppPermissionRequest(packageName,
permissionName));
}
@@ -241,9 +258,9 @@
checkCollectionElementsNotNull(permissionNames, "permissionNames");
checkNotNull(callback);
- mRemoteService.scheduleRequest(new PendingCountPermissionAppsRequest(mRemoteService,
+ sRemoteService.scheduleRequest(new PendingCountPermissionAppsRequest(sRemoteService,
permissionNames, countOnlyGranted, countSystem, callback,
- handler == null ? mRemoteService.getHandler() : handler));
+ handler == null ? sRemoteService.getHandler() : handler));
}
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 101252b..574ccaf 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3377,6 +3377,22 @@
*/
public static final String NOTIFICATION_VIBRATION_INTENSITY =
"notification_vibration_intensity";
+ /**
+ * The intensity of ringtone vibrations, if configurable.
+ *
+ * Not all devices are capable of changing their vibration intensity; on these devices
+ * there will likely be no difference between the various vibration intensities except for
+ * intensity 0 (off) and the rest.
+ *
+ * <b>Values:</b><br/>
+ * 0 - Vibration is disabled<br/>
+ * 1 - Weak vibrations<br/>
+ * 2 - Medium vibrations<br/>
+ * 3 - Strong vibrations
+ * @hide
+ */
+ public static final String RING_VIBRATION_INTENSITY =
+ "ring_vibration_intensity";
/**
* The intensity of haptic feedback vibrations, if configurable.
@@ -4246,6 +4262,7 @@
ACCELEROMETER_ROTATION,
SHOW_BATTERY_PERCENT,
NOTIFICATION_VIBRATION_INTENSITY,
+ RING_VIBRATION_INTENSITY,
HAPTIC_FEEDBACK_INTENSITY,
DISPLAY_COLOR_MODE,
ALARM_ALERT,
@@ -4397,6 +4414,7 @@
VALIDATORS.put(MUTE_STREAMS_AFFECTED, MUTE_STREAMS_AFFECTED_VALIDATOR);
VALIDATORS.put(VIBRATE_ON, VIBRATE_ON_VALIDATOR);
VALIDATORS.put(NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
+ VALIDATORS.put(RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
VALIDATORS.put(HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
VALIDATORS.put(RINGTONE, RINGTONE_VALIDATOR);
VALIDATORS.put(NOTIFICATION_SOUND, NOTIFICATION_SOUND_VALIDATOR);
@@ -5998,6 +6016,15 @@
"lock_screen_allow_remote_input";
/**
+ * Indicates which clock face to show on lock screen and AOD.
+ * @hide
+ */
+ public static final String LOCK_SCREEN_CUSTOM_CLOCK_FACE = "lock_screen_custom_clock_face";
+
+ private static final Validator LOCK_SCREEN_CUSTOM_CLOCK_FACE_VALIDATOR =
+ ANY_STRING_VALIDATOR;
+
+ /**
* Set by the system to track if the user needs to see the call to action for
* the lockscreen notification policy.
* @hide
@@ -8441,6 +8468,7 @@
HUSH_GESTURE_USED,
IN_CALL_NOTIFICATION_ENABLED,
LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+ LOCK_SCREEN_CUSTOM_CLOCK_FACE,
LOCK_SCREEN_SHOW_NOTIFICATIONS,
ZEN_DURATION,
SHOW_ZEN_UPGRADE_NOTIFICATION,
@@ -8619,6 +8647,7 @@
VALIDATORS.put(ASSIST_GESTURE_SETUP_COMPLETE, BOOLEAN_VALIDATOR);
VALIDATORS.put(NOTIFICATION_NEW_INTERRUPTION_MODEL, BOOLEAN_VALIDATOR);
VALIDATORS.put(TRUST_AGENTS_EXTEND_UNLOCK, TRUST_AGENTS_EXTEND_UNLOCK_VALIDATOR);
+ VALIDATORS.put(LOCK_SCREEN_CUSTOM_CLOCK_FACE, LOCK_SCREEN_CUSTOM_CLOCK_FACE_VALIDATOR);
VALIDATORS.put(LOCK_SCREEN_WHEN_TRUST_LOST, LOCK_SCREEN_WHEN_TRUST_LOST_VALIDATOR);
}
@@ -9340,8 +9369,7 @@
"hdmi_control_auto_wakeup_enabled";
/**
- * Whether TV or Audio System will also turn off other CEC devices when it goes to standby
- * mode.
+ * Whether TV will also turn off other CEC devices when it goes to standby mode.
* (0 = false, 1 = true)
*
* @hide
@@ -9350,15 +9378,6 @@
"hdmi_control_auto_device_off_enabled";
/**
- * Whether Audio System will also turn off TV when it goes to standby mode.
- * (0 = false, 1 = true)
- *
- * @hide
- */
- public static final String HDMI_CONTROL_AUTO_TV_OFF_ENABLED =
- "hdmi_control_auto_tv_off_enabled";
-
- /**
* If <b>true</b>, enables out-of-the-box execution for priv apps.
* Default: false
* Values: 0 = false, 1 = true
@@ -11189,14 +11208,14 @@
* quick_doze_enabled (boolean)
* </pre>
* @hide
- * @see com.android.server.power.BatterySaverPolicy
+ * @see com.android.server.power.batterysaver.BatterySaverPolicy
*/
public static final String BATTERY_SAVER_CONSTANTS = "battery_saver_constants";
/**
* Battery Saver device specific settings
* This is encoded as a key=value list, separated by commas.
- * See {@link com.android.server.power.BatterySaverPolicy} for the details.
+ * See {@link com.android.server.power.batterysaver.BatterySaverPolicy} for the details.
*
* @hide
*/
@@ -13937,6 +13956,53 @@
*/
public static final String NATIVE_FLAGS_HEALTH_CHECK_ENABLED =
"native_flags_health_check_enabled";
+
+ /**
+ * Parameter for {@link #APPOP_HISTORY_PARAMETERS} that controls the mode
+ * in which the historical registry operates.
+ *
+ * @hide
+ */
+ public static final String APPOP_HISTORY_MODE = "mode";
+
+ /**
+ * Parameter for {@link #APPOP_HISTORY_PARAMETERS} that controls how long
+ * is the interval between snapshots in the base case i.e. the most recent
+ * part of the history.
+ *
+ * @hide
+ */
+ public static final String APPOP_HISTORY_BASE_INTERVAL_MILLIS = "baseIntervalMillis";
+
+ /**
+ * Parameter for {@link #APPOP_HISTORY_PARAMETERS} that controls the base
+ * for the logarithmic step when building app op history.
+ *
+ * @hide
+ */
+ public static final String APPOP_HISTORY_INTERVAL_MULTIPLIER = "intervalMultiplier";
+
+ /**
+ * Appop history parameters. These parameters are represented by
+ * a comma-delimited key-value list.
+ *
+ * The following strings are supported as keys:
+ * <pre>
+ * mode (int)
+ * baseIntervalMillis (long)
+ * intervalMultiplier (int)
+ * </pre>
+ *
+ * Ex: "enabled=true,baseIntervalMillis=1000,intervalMultiplier=10"
+ *
+ * @see #APPOP_HISTORY_MODE
+ * @see #APPOP_HISTORY_BASE_INTERVAL_MILLIS
+ * @see #APPOP_HISTORY_INTERVAL_MULTIPLIER
+ *
+ * @hide
+ */
+ public static final String APPOP_HISTORY_PARAMETERS =
+ "appop_history_parameters";
}
/**
diff --git a/core/java/android/service/appprediction/AppPredictionService.java b/core/java/android/service/appprediction/AppPredictionService.java
new file mode 100644
index 0000000..b77405a
--- /dev/null
+++ b/core/java/android/service/appprediction/AppPredictionService.java
@@ -0,0 +1,322 @@
+/*
+ * 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.service.appprediction;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.CallSuper;
+import android.annotation.MainThread;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.app.prediction.AppPredictionContext;
+import android.app.prediction.AppPredictionSessionId;
+import android.app.prediction.AppTarget;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.AppTargetId;
+import android.app.prediction.IPredictionCallback;
+import android.content.Intent;
+import android.content.pm.ParceledListSlice;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.service.appprediction.IPredictionService.Stub;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * TODO(b/111701043): Add java docs
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class AppPredictionService extends Service {
+
+ private static final String TAG = "AppPredictionService";
+
+ /**
+ * The {@link Intent} that must be declared as handled by the service.
+ * TODO(b/111701043): Add any docs about permissions the service must hold
+ *
+ * @hide
+ */
+ public static final String SERVICE_INTERFACE =
+ "android.service.appprediction.AppPredictionService";
+
+ private final ArrayMap<AppPredictionSessionId, ArrayList<CallbackWrapper>> mSessionCallbacks =
+ new ArrayMap<>();
+ private Handler mHandler;
+
+ private final IPredictionService mInterface = new Stub() {
+
+ @Override
+ public void onCreatePredictionSession(AppPredictionContext context,
+ AppPredictionSessionId sessionId) {
+ mHandler.sendMessage(
+ obtainMessage(AppPredictionService::doCreatePredictionSession,
+ AppPredictionService.this, context, sessionId));
+ }
+
+ @Override
+ public void notifyAppTargetEvent(AppPredictionSessionId sessionId, AppTargetEvent event) {
+ mHandler.sendMessage(
+ obtainMessage(AppPredictionService::onAppTargetEvent,
+ AppPredictionService.this, sessionId, event));
+ }
+
+ @Override
+ public void notifyLocationShown(AppPredictionSessionId sessionId, String launchLocation,
+ ParceledListSlice targetIds) {
+ mHandler.sendMessage(
+ obtainMessage(AppPredictionService::onLocationShown, AppPredictionService.this,
+ sessionId, launchLocation, targetIds.getList()));
+ }
+
+ @Override
+ public void sortAppTargets(AppPredictionSessionId sessionId, ParceledListSlice targets,
+ IPredictionCallback callback) {
+ mHandler.sendMessage(
+ obtainMessage(AppPredictionService::onSortAppTargets,
+ AppPredictionService.this, sessionId, targets.getList(), null,
+ new CallbackWrapper(callback)));
+ }
+
+ @Override
+ public void registerPredictionUpdates(AppPredictionSessionId sessionId,
+ IPredictionCallback callback) {
+ mHandler.sendMessage(
+ obtainMessage(AppPredictionService::doRegisterPredictionUpdates,
+ AppPredictionService.this, sessionId, callback));
+ }
+
+ @Override
+ public void unregisterPredictionUpdates(AppPredictionSessionId sessionId,
+ IPredictionCallback callback) {
+ mHandler.sendMessage(
+ obtainMessage(AppPredictionService::doUnregisterPredictionUpdates,
+ AppPredictionService.this, sessionId, callback));
+ }
+
+ @Override
+ public void requestPredictionUpdate(AppPredictionSessionId sessionId) {
+ mHandler.sendMessage(
+ obtainMessage(AppPredictionService::doRequestPredictionUpdate,
+ AppPredictionService.this, sessionId));
+ }
+
+ @Override
+ public void onDestroyPredictionSession(AppPredictionSessionId sessionId) {
+ mHandler.sendMessage(
+ obtainMessage(AppPredictionService::doDestroyPredictionSession,
+ AppPredictionService.this, sessionId));
+ }
+ };
+
+ @CallSuper
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mHandler = new Handler(Looper.getMainLooper(), null, true);
+ }
+
+ @Override
+ public final IBinder onBind(Intent intent) {
+ return mInterface.asBinder();
+ }
+
+ /**
+ * Called by a client app to indicate a target launch
+ */
+ @MainThread
+ public abstract void onAppTargetEvent(@NonNull AppPredictionSessionId sessionId,
+ @NonNull AppTargetEvent event);
+
+ /**
+ * Called by a client app to indication a particular location has been shown to the user.
+ */
+ @MainThread
+ public abstract void onLocationShown(@NonNull AppPredictionSessionId sessionId,
+ @NonNull String launchLocation, @NonNull List<AppTargetId> targetIds);
+
+ private void doCreatePredictionSession(@NonNull AppPredictionContext context,
+ @NonNull AppPredictionSessionId sessionId) {
+ mSessionCallbacks.put(sessionId, new ArrayList<>());
+ onCreatePredictionSession(context, sessionId);
+ }
+
+ /**
+ * Creates a new interaction session.
+ *
+ * @param context interaction context
+ * @param sessionId the session's Id
+ */
+ public void onCreatePredictionSession(@NonNull AppPredictionContext context,
+ @NonNull AppPredictionSessionId sessionId) {}
+
+ /**
+ * Called by the client app to request sorting of targets based on prediction rank.
+ * TODO(b/111701043): Implement CancellationSignal so caller can cancel a long running request
+ */
+ @MainThread
+ public abstract void onSortAppTargets(@NonNull AppPredictionSessionId sessionId,
+ @NonNull List<AppTarget> targets, @NonNull CancellationSignal cancellationSignal,
+ @NonNull Consumer<List<AppTarget>> callback);
+
+ private void doRegisterPredictionUpdates(@NonNull AppPredictionSessionId sessionId,
+ @NonNull IPredictionCallback callback) {
+ final ArrayList<CallbackWrapper> callbacks = mSessionCallbacks.get(sessionId);
+ if (callbacks == null) {
+ Slog.e(TAG, "Failed to register for updates for unknown session: " + sessionId);
+ return;
+ }
+
+ final CallbackWrapper wrapper = findCallbackWrapper(callbacks, callback);
+ if (wrapper == null) {
+ callbacks.add(new CallbackWrapper(callback));
+ if (callbacks.size() == 1) {
+ onStartPredictionUpdates();
+ }
+ }
+ }
+
+ /**
+ * Called when any continuous prediction callback is registered.
+ */
+ @MainThread
+ public void onStartPredictionUpdates() {}
+
+ private void doUnregisterPredictionUpdates(@NonNull AppPredictionSessionId sessionId,
+ @NonNull IPredictionCallback callback) {
+ final ArrayList<CallbackWrapper> callbacks = mSessionCallbacks.get(sessionId);
+ if (callbacks == null) {
+ Slog.e(TAG, "Failed to unregister for updates for unknown session: " + sessionId);
+ return;
+ }
+
+ final CallbackWrapper wrapper = findCallbackWrapper(callbacks, callback);
+ if (wrapper != null) {
+ callbacks.remove(wrapper);
+ if (callbacks.isEmpty()) {
+ onStopPredictionUpdates();
+ }
+ }
+ }
+
+ /**
+ * Called when there are no longer any continuous prediction callbacks registered.
+ */
+ @MainThread
+ public void onStopPredictionUpdates() {}
+
+ private void doRequestPredictionUpdate(@NonNull AppPredictionSessionId sessionId) {
+ final ArrayList<CallbackWrapper> callbacks = mSessionCallbacks.get(sessionId);
+ if (callbacks != null && !callbacks.isEmpty()) {
+ onRequestPredictionUpdate(sessionId);
+ }
+ }
+
+ /**
+ * Called by the client app to request target predictions. This method is only called if there
+ * are one or more prediction callbacks registered.
+ * TODO(b/111701043): Add java docs
+ *
+ * @see #updatePredictions(AppPredictionSessionId, List)
+ */
+ @MainThread
+ public abstract void onRequestPredictionUpdate(@NonNull AppPredictionSessionId sessionId);
+
+ private void doDestroyPredictionSession(@NonNull AppPredictionSessionId sessionId) {
+ mSessionCallbacks.remove(sessionId);
+ onDestroyPredictionSession(sessionId);
+ }
+
+ /**
+ * Destroys the interaction session.
+ *
+ * @param sessionId the id of the session to destroy
+ */
+ @MainThread
+ public void onDestroyPredictionSession(@NonNull AppPredictionSessionId sessionId) {}
+
+ /**
+ * Used by the prediction factory to send back results the client app. The can be called
+ * in response to {@link #onRequestPredictionUpdate(AppPredictionSessionId)} or proactively as
+ * a result of changes in predictions.
+ */
+ public final void updatePredictions(@NonNull AppPredictionSessionId sessionId,
+ @NonNull List<AppTarget> targets) {
+ List<CallbackWrapper> callbacks = mSessionCallbacks.get(sessionId);
+ if (callbacks != null) {
+ for (CallbackWrapper callback : callbacks) {
+ callback.accept(targets);
+ }
+ }
+ }
+
+ /**
+ * Finds the callback wrapper for the given callback.
+ */
+ private CallbackWrapper findCallbackWrapper(ArrayList<CallbackWrapper> callbacks,
+ IPredictionCallback callback) {
+ for (int i = callbacks.size() - 1; i >= 0; i--) {
+ if (callbacks.get(i).isCallback(callback)) {
+ return callbacks.get(i);
+ }
+ }
+ return null;
+ }
+
+ private static final class CallbackWrapper implements Consumer<List<AppTarget>>,
+ IBinder.DeathRecipient {
+
+ private IPredictionCallback mCallback;
+
+ CallbackWrapper(IPredictionCallback callback) {
+ mCallback = callback;
+ try {
+ mCallback.asBinder().linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to link to death: " + e);
+ }
+ }
+
+ public boolean isCallback(@NonNull IPredictionCallback callback) {
+ return mCallback.equals(callback);
+ }
+
+ @Override
+ public void accept(List<AppTarget> ts) {
+ try {
+ if (mCallback != null) {
+ mCallback.onResult(new ParceledListSlice(ts));
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error sending result:" + e);
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ mCallback = null;
+ }
+ }
+}
diff --git a/core/java/android/service/appprediction/IPredictionService.aidl b/core/java/android/service/appprediction/IPredictionService.aidl
new file mode 100644
index 0000000..3a6d166
--- /dev/null
+++ b/core/java/android/service/appprediction/IPredictionService.aidl
@@ -0,0 +1,53 @@
+/*
+ * 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.service.appprediction;
+
+import android.app.prediction.AppTarget;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.AppPredictionContext;
+import android.app.prediction.AppPredictionSessionId;
+import android.app.prediction.IPredictionCallback;
+import android.content.pm.ParceledListSlice;
+
+/**
+ * Interface from the system to a prediction service.
+ *
+ * @hide
+ */
+oneway interface IPredictionService {
+
+ void onCreatePredictionSession(in AppPredictionContext context,
+ in AppPredictionSessionId sessionId);
+
+ void notifyAppTargetEvent(in AppPredictionSessionId sessionId, in AppTargetEvent event);
+
+ void notifyLocationShown(in AppPredictionSessionId sessionId, in String launchLocation,
+ in ParceledListSlice targetIds);
+
+ void sortAppTargets(in AppPredictionSessionId sessionId, in ParceledListSlice targets,
+ in IPredictionCallback callback);
+
+ void registerPredictionUpdates(in AppPredictionSessionId sessionId,
+ in IPredictionCallback callback);
+
+ void unregisterPredictionUpdates(in AppPredictionSessionId sessionId,
+ in IPredictionCallback callback);
+
+ void requestPredictionUpdate(in AppPredictionSessionId sessionId);
+
+ void onDestroyPredictionSession(in AppPredictionSessionId sessionId);
+}
diff --git a/core/java/android/service/contentsuggestions/ContentSuggestionsService.java b/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
new file mode 100644
index 0000000..0da8039
--- /dev/null
+++ b/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
@@ -0,0 +1,154 @@
+/*
+ * 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.service.contentsuggestions;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.ContentSuggestionsManager;
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.GraphicBuffer;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Slog;
+
+/**
+ * @hide
+ */
+@SystemApi
+public abstract class ContentSuggestionsService extends Service {
+
+ private static final String TAG = ContentSuggestionsService.class.getSimpleName();
+
+ private Handler mHandler;
+
+ /**
+ * The action for the intent used to define the content suggestions service.
+ */
+ public static final String SERVICE_INTERFACE =
+ "android.service.contentsuggestions.ContentSuggestionsService";
+
+ private final IContentSuggestionsService mInterface = new IContentSuggestionsService.Stub() {
+ @Override
+ public void provideContextImage(int taskId, GraphicBuffer contextImage,
+ Bundle imageContextRequestExtras) {
+ mHandler.sendMessage(
+ obtainMessage(ContentSuggestionsService::processContextImage,
+ ContentSuggestionsService.this, taskId,
+ Bitmap.createHardwareBitmap(contextImage),
+ imageContextRequestExtras));
+ }
+
+ @Override
+ public void suggestContentSelections(SelectionsRequest request,
+ ISelectionsCallback callback) {
+ mHandler.sendMessage(obtainMessage(ContentSuggestionsService::suggestContentSelections,
+ ContentSuggestionsService.this, request, wrapSelectionsCallback(callback)));
+
+ }
+
+ @Override
+ public void classifyContentSelections(ClassificationsRequest request,
+ IClassificationsCallback callback) {
+ mHandler.sendMessage(obtainMessage(ContentSuggestionsService::classifyContentSelections,
+ ContentSuggestionsService.this, request, wrapClassificationCallback(callback)));
+ }
+
+ @Override
+ public void notifyInteraction(String requestId, Bundle interaction) {
+ mHandler.sendMessage(
+ obtainMessage(ContentSuggestionsService::notifyInteraction,
+ ContentSuggestionsService.this, requestId, interaction));
+ }
+ };
+
+ @CallSuper
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mHandler = new Handler(Looper.getMainLooper(), null, true);
+ }
+
+ /** @hide */
+ @Override
+ public final IBinder onBind(Intent intent) {
+ if (SERVICE_INTERFACE.equals(intent.getAction())) {
+ return mInterface.asBinder();
+ }
+ Log.w(TAG, "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + ": " + intent);
+ return null;
+ }
+
+ /**
+ * Called by the system to provide the snapshot for the task associated with the given
+ * {@param taskId}.
+ */
+ public abstract void processContextImage(
+ int taskId, @Nullable Bitmap contextImage, @NonNull Bundle extras);
+
+ /**
+ * Called by a client app to make a request for content selections.
+ */
+ public abstract void suggestContentSelections(@NonNull SelectionsRequest request,
+ @NonNull ContentSuggestionsManager.SelectionsCallback callback);
+
+ /**
+ * Called by a client app to classify the provided content selections.
+ */
+ public abstract void classifyContentSelections(@NonNull ClassificationsRequest request,
+ @NonNull ContentSuggestionsManager.ClassificationsCallback callback);
+
+ /**
+ * Called by a client app to report an interaction.
+ */
+ public abstract void notifyInteraction(@NonNull String requestId, @NonNull Bundle interaction);
+
+ private ContentSuggestionsManager.SelectionsCallback wrapSelectionsCallback(
+ ISelectionsCallback callback) {
+ return (statusCode, selections) -> {
+ try {
+ callback.onContentSelectionsAvailable(statusCode, selections);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error sending result: " + e);
+ }
+ };
+ }
+
+ private ContentSuggestionsManager.ClassificationsCallback wrapClassificationCallback(
+ IClassificationsCallback callback) {
+ return ((statusCode, classifications) -> {
+ try {
+ callback.onContentClassificationsAvailable(statusCode, classifications);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error sending result: " + e);
+ }
+ });
+ }
+}
diff --git a/core/java/android/service/contentsuggestions/IContentSuggestionsService.aidl b/core/java/android/service/contentsuggestions/IContentSuggestionsService.aidl
new file mode 100644
index 0000000..1926478
--- /dev/null
+++ b/core/java/android/service/contentsuggestions/IContentSuggestionsService.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.service.contentsuggestions;
+
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.graphics.GraphicBuffer;
+import android.os.Bundle;
+
+/**
+ * Interface from the system to an implementation of a content suggestions service.
+ *
+ * @hide
+ */
+oneway interface IContentSuggestionsService {
+ void provideContextImage(
+ int taskId,
+ in GraphicBuffer contextImage,
+ in Bundle imageContextRequestExtras);
+ void suggestContentSelections(
+ in SelectionsRequest request,
+ in ISelectionsCallback callback);
+ void classifyContentSelections(
+ in ClassificationsRequest request,
+ in IClassificationsCallback callback);
+ void notifyInteraction(in String requestId, in Bundle interaction);
+}
diff --git a/core/java/android/util/DebugUtils.java b/core/java/android/util/DebugUtils.java
index af73a16..265b0d3 100644
--- a/core/java/android/util/DebugUtils.java
+++ b/core/java/android/util/DebugUtils.java
@@ -18,6 +18,7 @@
import android.annotation.UnsupportedAppUsage;
import android.os.Build;
+
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
@@ -250,7 +251,7 @@
if (value == 0 && flagsWasZero) {
return constNameWithoutPrefix(prefix, field);
}
- if ((flags & value) != 0) {
+ if ((flags & value) == value) {
flags &= ~value;
res.append(constNameWithoutPrefix(prefix, field)).append('|');
}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 8b97e0e..0edcb3d 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -22,7 +22,9 @@
import android.text.TextUtils;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
/**
* Util class to get feature flag information.
@@ -37,8 +39,11 @@
public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
public static final String SAFETY_HUB = "settings_safety_hub";
public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
+ public static final String AOD_IMAGEWALLPAPER_ENABLED = "settings_aod_imagewallpaper_enabled";
private static final Map<String, String> DEFAULT_FLAGS;
+ private static final Set<String> OBSERVABLE_FLAGS;
+
static {
DEFAULT_FLAGS = new HashMap<>();
DEFAULT_FLAGS.put("settings_audio_switcher", "true");
@@ -54,6 +59,10 @@
DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
DEFAULT_FLAGS.put(SAFETY_HUB, "false");
DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false");
+ DEFAULT_FLAGS.put(AOD_IMAGEWALLPAPER_ENABLED, "false");
+
+ OBSERVABLE_FLAGS = new HashSet<>();
+ OBSERVABLE_FLAGS.add(AOD_IMAGEWALLPAPER_ENABLED);
}
/**
@@ -90,6 +99,16 @@
*/
public static void setEnabled(Context context, String feature, boolean enabled) {
SystemProperties.set(FFLAG_OVERRIDE_PREFIX + feature, enabled ? "true" : "false");
+
+ // Also update Settings.Global if needed so that we can observe it via observer.
+ if (OBSERVABLE_FLAGS.contains(feature)) {
+ setObservableFlag(context, feature, enabled);
+ }
+ }
+
+ private static void setObservableFlag(Context context, String feature, boolean enabled) {
+ Settings.Global.putString(
+ context.getContentResolver(), feature, enabled ? "true" : "false");
}
/**
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index acad5d7..ff5120d 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -58,7 +58,7 @@
/**
* SurfaceControl
- * @hide
+ * @hide
*/
public class SurfaceControl implements Parcelable {
private static final String TAG = "SurfaceControl";
@@ -186,6 +186,7 @@
/**
* Surface creation flag: Surface is created hidden
+ * @hide
*/
@UnsupportedAppUsage
public static final int HIDDEN = 0x00000004;
@@ -196,7 +197,7 @@
* from another process. In particular, screenshots and VNC servers will
* be disabled, but other measures can take place, for instance the
* surface might not be hardware accelerated.
- *
+ * @hide
*/
public static final int SECURE = 0x00000080;
@@ -220,7 +221,7 @@
* pixel.
* <p>
* In some rare situations, a non pre-multiplied surface is preferable.
- *
+ * @hide
*/
public static final int NON_PREMULTIPLIED = 0x00000100;
@@ -240,6 +241,7 @@
* </ul>
* If the underlying buffer lacks an alpha channel, the OPAQUE flag is effectively
* set automatically.
+ * @hide
*/
public static final int OPAQUE = 0x00000400;
@@ -248,6 +250,7 @@
* external display sink. If a hardware-protected path is not available,
* then this surface will not be displayed on the external sink.
*
+ * @hide
*/
public static final int PROTECTED_APP = 0x00000800;
@@ -255,6 +258,7 @@
/**
* Surface creation flag: Window represents a cursor glyph.
+ * @hide
*/
public static final int CURSOR_WINDOW = 0x00002000;
@@ -262,6 +266,7 @@
* Surface creation flag: Creates a normal surface.
* This is the default.
*
+ * @hide
*/
public static final int FX_SURFACE_NORMAL = 0x00000000;
@@ -271,6 +276,7 @@
* in {@link #setAlpha}. It is an error to lock a Dim surface, since it
* doesn't have a backing store.
*
+ * @hide
*/
public static final int FX_SURFACE_DIM = 0x00020000;
@@ -278,12 +284,14 @@
* Surface creation flag: Creates a container surface.
* This surface will have no buffers and will only be used
* as a container for other surfaces, or for its InputInfo.
+ * @hide
*/
public static final int FX_SURFACE_CONTAINER = 0x00080000;
/**
* Mask used for FX values above.
*
+ * @hide
*/
public static final int FX_SURFACE_MASK = 0x000F0000;
@@ -309,12 +317,14 @@
/**
* Built-in physical display id: Main display.
* Use only with {@link SurfaceControl#getBuiltInDisplay(int)}.
+ * @hide
*/
public static final int BUILT_IN_DISPLAY_ID_MAIN = 0;
/**
* Built-in physical display id: Attached HDMI display.
* Use only with {@link SurfaceControl#getBuiltInDisplay(int)}.
+ * @hide
*/
public static final int BUILT_IN_DISPLAY_ID_HDMI = 1;
@@ -323,30 +333,35 @@
/**
* Display power mode off: used while blanking the screen.
* Use only with {@link SurfaceControl#setDisplayPowerMode}.
+ * @hide
*/
public static final int POWER_MODE_OFF = 0;
/**
* Display power mode doze: used while putting the screen into low power mode.
* Use only with {@link SurfaceControl#setDisplayPowerMode}.
+ * @hide
*/
public static final int POWER_MODE_DOZE = 1;
/**
* Display power mode normal: used while unblanking the screen.
* Use only with {@link SurfaceControl#setDisplayPowerMode}.
+ * @hide
*/
public static final int POWER_MODE_NORMAL = 2;
/**
* Display power mode doze: used while putting the screen into a suspended
* low power mode. Use only with {@link SurfaceControl#setDisplayPowerMode}.
+ * @hide
*/
public static final int POWER_MODE_DOZE_SUSPEND = 3;
/**
* Display power mode on: used while putting the screen into a suspended
* full power mode. Use only with {@link SurfaceControl#setDisplayPowerMode}.
+ * @hide
*/
public static final int POWER_MODE_ON_SUSPEND = 4;
@@ -366,6 +381,9 @@
mNativeObject = nativeObject;
}
+ /**
+ * @hide
+ */
public void copyFrom(SurfaceControl other) {
mName = other.mName;
mWidth = other.mWidth;
@@ -375,6 +393,7 @@
/**
* Builder class for {@link SurfaceControl} objects.
+ * @hide
*/
public static class Builder {
private SurfaceSession mSession;
@@ -391,6 +410,7 @@
* Begin building a SurfaceControl with a given {@link SurfaceSession}.
*
* @param session The {@link SurfaceSession} with which to eventually construct the surface.
+ * @hide
*/
public Builder(SurfaceSession session) {
mSession = session;
@@ -398,6 +418,7 @@
/**
* Construct a new {@link SurfaceControl} with the set parameters.
+ * @hide
*/
public SurfaceControl build() {
if (mWidth < 0 || mHeight < 0) {
@@ -416,6 +437,7 @@
* Set a debugging-name for the SurfaceControl.
*
* @param name A name to identify the Surface in debugging.
+ * @hide
*/
public Builder setName(String name) {
mName = name;
@@ -427,6 +449,7 @@
*
* @param width The buffer width in pixels.
* @param height The buffer height in pixels.
+ * @hide
*/
public Builder setBufferSize(int width, int height) {
if (width < 0 || height < 0) {
@@ -441,6 +464,7 @@
/**
* Set the pixel format of the controlled surface's buffers, using constants from
* {@link android.graphics.PixelFormat}.
+ * @hide
*/
public Builder setFormat(@PixelFormat.Format int format) {
mFormat = format;
@@ -454,6 +478,7 @@
* not be displayed.
*
* @param protectedContent Whether to require a protected sink.
+ * @hide
*/
public Builder setProtected(boolean protectedContent) {
if (protectedContent) {
@@ -469,6 +494,7 @@
* will prevent the surfaces content from being copied by another process. In
* particular screenshots and VNC servers will be disabled. This is however
* not a complete prevention of readback as {@link #setProtected}.
+ * @hide
*/
public Builder setSecure(boolean secure) {
if (secure) {
@@ -501,6 +527,7 @@
* If the underlying buffer lacks an alpha channel, it is as if setOpaque(true)
* were set automatically.
* @param opaque Whether the Surface is OPAQUE.
+ * @hide
*/
public Builder setOpaque(boolean opaque) {
if (opaque) {
@@ -519,6 +546,7 @@
* of the parent.
*
* @param parent The parent control.
+ * @hide
*/
public Builder setParent(SurfaceControl parent) {
mParent = parent;
@@ -534,6 +562,7 @@
*
* @param windowType A window-type
* @param ownerUid UID of the window owner.
+ * @hide
*/
public Builder setMetadata(int windowType, int ownerUid) {
if (UserHandle.getAppId(Process.myUid()) != Process.SYSTEM_UID) {
@@ -552,6 +581,7 @@
* solid color (that is, solid before plane alpha). Currently that color is black.
*
* @param isColorLayer Whether to create a color layer.
+ * @hide
*/
public Builder setColorLayer(boolean isColorLayer) {
if (isColorLayer) {
@@ -573,6 +603,7 @@
* as a parent of renderable layers.
*
* @param isContainerLayer Whether to create a container layer.
+ * @hide
*/
public Builder setContainerLayer(boolean isContainerLayer) {
if (isContainerLayer) {
@@ -592,6 +623,7 @@
*
* TODO: Finish conversion to individual builder methods?
* @param flags The combined flags
+ * @hide
*/
public Builder setFlags(int flags) {
mFlags = flags;
@@ -660,9 +692,11 @@
mCloseGuard.open("release");
}
- // This is a transfer constructor, useful for transferring a live SurfaceControl native
- // object to another Java wrapper which could have some different behavior, e.g.
- // event logging.
+ /** This is a transfer constructor, useful for transferring a live SurfaceControl native
+ * object to another Java wrapper which could have some different behavior, e.g.
+ * event logging.
+ * @hide
+ */
public SurfaceControl(SurfaceControl other) {
mName = other.mName;
mWidth = other.mWidth;
@@ -678,10 +712,16 @@
mCloseGuard.open("release");
}
+ /**
+ * @hide
+ */
public SurfaceControl() {
mCloseGuard.open("release");
}
+ /**
+ * @hide
+ */
public void readFromParcel(Parcel in) {
if (in == null) {
throw new IllegalArgumentException("source must not be null");
@@ -698,11 +738,17 @@
assignNativeObject(object);
}
+ /**
+ * @hide
+ */
@Override
public int describeContents() {
return 0;
}
+ /**
+ * @hide
+ */
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mName);
@@ -735,6 +781,9 @@
proto.end(token);
}
+ /**
+ * @hide
+ */
public static final Creator<SurfaceControl> CREATOR
= new Creator<SurfaceControl>() {
public SurfaceControl createFromParcel(Parcel in) {
@@ -746,6 +795,9 @@
}
};
+ /**
+ * @hide
+ */
@Override
protected void finalize() throws Throwable {
try {
@@ -764,6 +816,7 @@
* Release the local reference to the server-side surface.
* Always call release() when you're done with a Surface.
* This will make the surface invalid.
+ * @hide
*/
public void release() {
if (mNativeObject != 0) {
@@ -777,6 +830,7 @@
* Free all server-side state associated with this surface and
* release this object's reference. This method can only be
* called from the process that created the service.
+ * @hide
*/
public void destroy() {
if (mNativeObject != 0) {
@@ -788,6 +842,7 @@
/**
* Disconnect any client still connected to the surface.
+ * @hide
*/
public void disconnect() {
if (mNativeObject != 0) {
@@ -800,6 +855,9 @@
"mNativeObject is null. Have you called release() already?");
}
+ /**
+ * @hide
+ */
public boolean isValid() {
return mNativeObject != 0;
}
@@ -809,7 +867,9 @@
* needs to be inside open/closeTransaction block
*/
- /** start a transaction */
+ /** start a transaction
+ * @hide
+ */
@UnsupportedAppUsage
public static void openTransaction() {
synchronized (SurfaceControl.class) {
@@ -838,6 +898,7 @@
* This clears the supplied transaction in an identical fashion to {@link Transaction#merge}.
* <p>
* This is a utility for interop with legacy-code and will go away with the Global Transaction.
+ * @hide
*/
@Deprecated
public static void mergeToGlobalTransaction(Transaction t) {
@@ -846,46 +907,69 @@
}
}
- /** end a transaction */
+ /** end a transaction
+ * @hide
+ */
@UnsupportedAppUsage
public static void closeTransaction() {
closeTransaction(false);
}
+ /**
+ * @hide
+ */
public static void closeTransactionSync() {
closeTransaction(true);
}
+ /**
+ * @hide
+ */
public void deferTransactionUntil(IBinder handle, long frame) {
synchronized(SurfaceControl.class) {
sGlobalTransaction.deferTransactionUntil(this, handle, frame);
}
}
+ /**
+ * @hide
+ */
public void deferTransactionUntil(Surface barrier, long frame) {
synchronized(SurfaceControl.class) {
sGlobalTransaction.deferTransactionUntilSurface(this, barrier, frame);
}
}
+ /**
+ * @hide
+ */
public void reparentChildren(IBinder newParentHandle) {
synchronized(SurfaceControl.class) {
sGlobalTransaction.reparentChildren(this, newParentHandle);
}
}
+ /**
+ * @hide
+ */
public void reparent(IBinder newParentHandle) {
synchronized(SurfaceControl.class) {
sGlobalTransaction.reparent(this, newParentHandle);
}
}
+ /**
+ * @hide
+ */
public void detachChildren() {
synchronized(SurfaceControl.class) {
sGlobalTransaction.detachChildren(this);
}
}
+ /**
+ * @hide
+ */
public void setOverrideScalingMode(int scalingMode) {
checkNotReleased();
synchronized(SurfaceControl.class) {
@@ -893,16 +977,25 @@
}
}
+ /**
+ * @hide
+ */
public IBinder getHandle() {
return nativeGetHandle(mNativeObject);
}
+ /**
+ * @hide
+ */
public static void setAnimationTransaction() {
synchronized (SurfaceControl.class) {
sGlobalTransaction.setAnimationTransaction();
}
}
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public void setLayer(int zorder) {
checkNotReleased();
@@ -911,6 +1004,9 @@
}
}
+ /**
+ * @hide
+ */
public void setRelativeLayer(SurfaceControl relativeTo, int zorder) {
checkNotReleased();
synchronized(SurfaceControl.class) {
@@ -918,6 +1014,9 @@
}
}
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public void setPosition(float x, float y) {
checkNotReleased();
@@ -926,6 +1025,9 @@
}
}
+ /**
+ * @hide
+ */
public void setGeometryAppliesWithResize() {
checkNotReleased();
synchronized(SurfaceControl.class) {
@@ -933,6 +1035,9 @@
}
}
+ /**
+ * @hide
+ */
public void setBufferSize(int w, int h) {
checkNotReleased();
synchronized(SurfaceControl.class) {
@@ -940,6 +1045,9 @@
}
}
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public void hide() {
checkNotReleased();
@@ -948,6 +1056,9 @@
}
}
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public void show() {
checkNotReleased();
@@ -956,6 +1067,9 @@
}
}
+ /**
+ * @hide
+ */
public void setTransparentRegionHint(Region region) {
checkNotReleased();
synchronized(SurfaceControl.class) {
@@ -963,24 +1077,39 @@
}
}
+ /**
+ * @hide
+ */
public boolean clearContentFrameStats() {
checkNotReleased();
return nativeClearContentFrameStats(mNativeObject);
}
+ /**
+ * @hide
+ */
public boolean getContentFrameStats(WindowContentFrameStats outStats) {
checkNotReleased();
return nativeGetContentFrameStats(mNativeObject, outStats);
}
+ /**
+ * @hide
+ */
public static boolean clearAnimationFrameStats() {
return nativeClearAnimationFrameStats();
}
+ /**
+ * @hide
+ */
public static boolean getAnimationFrameStats(WindowAnimationFrameStats outStats) {
return nativeGetAnimationFrameStats(outStats);
}
+ /**
+ * @hide
+ */
public void setAlpha(float alpha) {
checkNotReleased();
synchronized(SurfaceControl.class) {
@@ -988,6 +1117,9 @@
}
}
+ /**
+ * @hide
+ */
public void setColor(@Size(3) float[] color) {
checkNotReleased();
synchronized (SurfaceControl.class) {
@@ -995,6 +1127,9 @@
}
}
+ /**
+ * @hide
+ */
public void setMatrix(float dsdx, float dtdx, float dtdy, float dsdy) {
checkNotReleased();
synchronized(SurfaceControl.class) {
@@ -1007,6 +1142,7 @@
*
* @param matrix The matrix to apply.
* @param float9 An array of 9 floats to be used to extract the values from the matrix.
+ * @hide
*/
public void setMatrix(Matrix matrix, float[] float9) {
checkNotReleased();
@@ -1022,6 +1158,7 @@
* Sets the color transform for the Surface.
* @param matrix A float array with 9 values represents a 3x3 transform matrix
* @param translation A float array with 3 values represents a translation vector
+ * @hide
*/
public void setColorTransform(@Size(9) float[] matrix, @Size(3) float[] translation) {
checkNotReleased();
@@ -1037,6 +1174,7 @@
* constrained by the size of its parent bounds.
*
* @param crop Bounds of the crop to apply.
+ * @hide
*/
public void setWindowCrop(Rect crop) {
checkNotReleased();
@@ -1050,6 +1188,7 @@
*
* @param width width of crop rect
* @param height height of crop rect
+ * @hide
*/
public void setWindowCrop(int width, int height) {
checkNotReleased();
@@ -1062,6 +1201,7 @@
* Sets the corner radius of a {@link SurfaceControl}.
*
* @param cornerRadius Corner radius in pixels.
+ * @hide
*/
public void setCornerRadius(float cornerRadius) {
checkNotReleased();
@@ -1070,6 +1210,9 @@
}
}
+ /**
+ * @hide
+ */
public void setLayerStack(int layerStack) {
checkNotReleased();
synchronized(SurfaceControl.class) {
@@ -1077,6 +1220,9 @@
}
}
+ /**
+ * @hide
+ */
public void setOpaque(boolean isOpaque) {
checkNotReleased();
@@ -1085,6 +1231,9 @@
}
}
+ /**
+ * @hide
+ */
public void setSecure(boolean isSecure) {
checkNotReleased();
@@ -1093,18 +1242,27 @@
}
}
+ /**
+ * @hide
+ */
public int getWidth() {
synchronized (mSizeLock) {
return mWidth;
}
}
+ /**
+ * @hide
+ */
public int getHeight() {
synchronized (mSizeLock) {
return mHeight;
}
}
+ /**
+ * @hide
+ */
@Override
public String toString() {
return "Surface(name=" + mName + ")/@0x" +
@@ -1120,38 +1278,85 @@
* Describes the properties of a physical display known to surface flinger.
*/
public static final class PhysicalDisplayInfo {
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public int width;
+
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public int height;
+
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public float refreshRate;
+
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public float density;
+
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public float xDpi;
+
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public float yDpi;
+
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public boolean secure;
+
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public long appVsyncOffsetNanos;
+
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public long presentationDeadlineNanos;
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public PhysicalDisplayInfo() {
}
+ /**
+ * @hide
+ */
public PhysicalDisplayInfo(PhysicalDisplayInfo other) {
copyFrom(other);
}
+ /**
+ * @hide
+ */
@Override
public boolean equals(Object o) {
return o instanceof PhysicalDisplayInfo && equals((PhysicalDisplayInfo)o);
}
+ /**
+ * @hide
+ */
public boolean equals(PhysicalDisplayInfo other) {
return other != null
&& width == other.width
@@ -1165,11 +1370,17 @@
&& presentationDeadlineNanos == other.presentationDeadlineNanos;
}
+ /**
+ * @hide
+ */
@Override
public int hashCode() {
return 0; // don't care
}
+ /**
+ * @hide
+ */
public void copyFrom(PhysicalDisplayInfo other) {
width = other.width;
height = other.height;
@@ -1182,7 +1393,9 @@
presentationDeadlineNanos = other.presentationDeadlineNanos;
}
- // For debugging purposes
+ /**
+ * @hide
+ */
@Override
public String toString() {
return "PhysicalDisplayInfo{" + width + " x " + height + ", " + refreshRate + " fps, "
@@ -1192,6 +1405,9 @@
}
}
+ /**
+ * @hide
+ */
public static void setDisplayPowerMode(IBinder displayToken, int mode) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
@@ -1199,6 +1415,9 @@
nativeSetDisplayPowerMode(displayToken, mode);
}
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public static SurfaceControl.PhysicalDisplayInfo[] getDisplayConfigs(IBinder displayToken) {
if (displayToken == null) {
@@ -1207,6 +1426,9 @@
return nativeGetDisplayConfigs(displayToken);
}
+ /**
+ * @hide
+ */
public static int getActiveConfig(IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
@@ -1253,6 +1475,9 @@
}
+ /**
+ * @hide
+ */
public static boolean setActiveConfig(IBinder displayToken, int id) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
@@ -1260,6 +1485,9 @@
return nativeSetActiveConfig(displayToken, id);
}
+ /**
+ * @hide
+ */
public static int[] getDisplayColorModes(IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
@@ -1267,6 +1495,9 @@
return nativeGetDisplayColorModes(displayToken);
}
+ /**
+ * @hide
+ */
public static int getActiveColorMode(IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
@@ -1274,6 +1505,9 @@
return nativeGetActiveColorMode(displayToken);
}
+ /**
+ * @hide
+ */
public static boolean setActiveColorMode(IBinder displayToken, int colorMode) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
@@ -1281,6 +1515,9 @@
return nativeSetActiveColorMode(displayToken, colorMode);
}
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public static void setDisplayProjection(IBinder displayToken,
int orientation, Rect layerStackRect, Rect displayRect) {
@@ -1290,6 +1527,9 @@
}
}
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public static void setDisplayLayerStack(IBinder displayToken, int layerStack) {
synchronized (SurfaceControl.class) {
@@ -1297,6 +1537,9 @@
}
}
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public static void setDisplaySurface(IBinder displayToken, Surface surface) {
synchronized (SurfaceControl.class) {
@@ -1304,12 +1547,18 @@
}
}
+ /**
+ * @hide
+ */
public static void setDisplaySize(IBinder displayToken, int width, int height) {
synchronized (SurfaceControl.class) {
sGlobalTransaction.setDisplaySize(displayToken, width, height);
}
}
+ /**
+ * @hide
+ */
public static Display.HdrCapabilities getHdrCapabilities(IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
@@ -1317,6 +1566,9 @@
return nativeGetHdrCapabilities(displayToken);
}
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public static IBinder createDisplay(String name, boolean secure) {
if (name == null) {
@@ -1325,6 +1577,9 @@
return nativeCreateDisplay(name, secure);
}
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public static void destroyDisplay(IBinder displayToken) {
if (displayToken == null) {
@@ -1333,6 +1588,9 @@
nativeDestroyDisplay(displayToken);
}
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public static IBinder getBuiltInDisplay(int builtInDisplayId) {
return nativeGetBuiltInDisplay(builtInDisplayId);
@@ -1340,6 +1598,7 @@
/**
* @see SurfaceControl#screenshot(IBinder, Surface, Rect, int, int, boolean, int)
+ * @hide
*/
public static void screenshot(IBinder display, Surface consumer) {
screenshot(display, consumer, new Rect(), 0, 0, false, 0);
@@ -1350,6 +1609,7 @@
*
* @param consumer The {@link Surface} to take the screenshot into.
* @see SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)
+ * @hide
*/
public static void screenshot(IBinder display, Surface consumer, Rect sourceCrop, int width,
int height, boolean useIdentityTransform, int rotation) {
@@ -1368,6 +1628,7 @@
/**
* @see SurfaceControl#screenshot(Rect, int, int, boolean, int)}
+ * @hide
*/
@UnsupportedAppUsage
public static Bitmap screenshot(Rect sourceCrop, int width, int height, int rotation) {
@@ -1385,6 +1646,7 @@
* {@link SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)}.
*
* @see SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)}
+ * @hide
*/
@UnsupportedAppUsage
public static Bitmap screenshot(Rect sourceCrop, int width, int height,
@@ -1428,6 +1690,7 @@
* this is useful for returning screenshots that are independent of
* device orientation.
* @return Returns a GraphicBuffer that contains the captured content.
+ * @hide
*/
public static GraphicBuffer screenshotToBuffer(IBinder display, Rect sourceCrop, int width,
int height, boolean useIdentityTransform, int rotation) {
@@ -1459,12 +1722,16 @@
* screen will be scaled up/down.
*
* @return Returns a GraphicBuffer that contains the layer capture.
+ * @hide
*/
public static GraphicBuffer captureLayers(IBinder layerHandleToken, Rect sourceCrop,
float frameScale) {
return nativeCaptureLayers(layerHandleToken, sourceCrop, frameScale);
}
+ /**
+ * @hide
+ */
public static class Transaction implements Closeable {
public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
Transaction.class.getClassLoader(),
@@ -1474,6 +1741,9 @@
private final ArrayMap<SurfaceControl, Point> mResizedSurfaces = new ArrayMap<>();
Runnable mFreeNativeResources;
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public Transaction() {
mNativeObject = nativeCreateTransaction();
@@ -1484,6 +1754,7 @@
/**
* Apply the transaction, clearing it's state, and making it usable
* as a new transaction.
+ * @hide
*/
@UnsupportedAppUsage
public void apply() {
@@ -1493,6 +1764,7 @@
/**
* Close the transaction, if the transaction was not already applied this will cancel the
* transaction.
+ * @hide
*/
@Override
public void close() {
@@ -1502,6 +1774,7 @@
/**
* Jankier version of apply. Avoid use (b/28068298).
+ * @hide
*/
public void apply(boolean sync) {
applyResizedSurfaces();
@@ -1520,6 +1793,9 @@
mResizedSurfaces.clear();
}
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public Transaction show(SurfaceControl sc) {
sc.checkNotReleased();
@@ -1527,6 +1803,9 @@
return this;
}
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public Transaction hide(SurfaceControl sc) {
sc.checkNotReleased();
@@ -1534,6 +1813,9 @@
return this;
}
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public Transaction setPosition(SurfaceControl sc, float x, float y) {
sc.checkNotReleased();
@@ -1541,6 +1823,9 @@
return this;
}
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public Transaction setBufferSize(SurfaceControl sc, int w, int h) {
sc.checkNotReleased();
@@ -1549,6 +1834,9 @@
return this;
}
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public Transaction setLayer(SurfaceControl sc, int z) {
sc.checkNotReleased();
@@ -1556,6 +1844,9 @@
return this;
}
+ /**
+ * @hide
+ */
public Transaction setRelativeLayer(SurfaceControl sc, SurfaceControl relativeTo, int z) {
sc.checkNotReleased();
nativeSetRelativeLayer(mNativeObject, sc.mNativeObject,
@@ -1563,6 +1854,9 @@
return this;
}
+ /**
+ * @hide
+ */
public Transaction setTransparentRegionHint(SurfaceControl sc, Region transparentRegion) {
sc.checkNotReleased();
nativeSetTransparentRegionHint(mNativeObject,
@@ -1570,6 +1864,9 @@
return this;
}
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public Transaction setAlpha(SurfaceControl sc, float alpha) {
sc.checkNotReleased();
@@ -1577,6 +1874,9 @@
return this;
}
+ /**
+ * @hide
+ */
public Transaction setInputWindowInfo(SurfaceControl sc, InputWindowHandle handle) {
sc.checkNotReleased();
nativeSetInputWindowInfo(mNativeObject, sc.mNativeObject, handle);
@@ -1592,12 +1892,16 @@
* @param fromToken The token of a window that currently has touch focus.
* @param toToken The token of the window that should receive touch focus in
* place of the first.
+ * @hide
*/
public Transaction transferTouchFocus(IBinder fromToken, IBinder toToken) {
nativeTransferTouchFocus(mNativeObject, fromToken, toToken);
return this;
}
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public Transaction setMatrix(SurfaceControl sc,
float dsdx, float dtdx, float dtdy, float dsdy) {
@@ -1607,6 +1911,9 @@
return this;
}
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public Transaction setMatrix(SurfaceControl sc, Matrix matrix, float[] float9) {
matrix.getValues(float9);
@@ -1620,6 +1927,7 @@
* Sets the color transform for the Surface.
* @param matrix A float array with 9 values represents a 3x3 transform matrix
* @param translation A float array with 3 values represents a translation vector
+ * @hide
*/
public Transaction setColorTransform(SurfaceControl sc, @Size(9) float[] matrix,
@Size(3) float[] translation) {
@@ -1628,6 +1936,9 @@
return this;
}
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public Transaction setWindowCrop(SurfaceControl sc, Rect crop) {
sc.checkNotReleased();
@@ -1641,6 +1952,9 @@
return this;
}
+ /**
+ * @hide
+ */
public Transaction setWindowCrop(SurfaceControl sc, int width, int height) {
sc.checkNotReleased();
nativeSetWindowCrop(mNativeObject, sc.mNativeObject, 0, 0, width, height);
@@ -1652,6 +1966,7 @@
* @param sc SurfaceControl
* @param cornerRadius Corner radius in pixels.
* @return Itself.
+ * @hide
*/
@UnsupportedAppUsage
public Transaction setCornerRadius(SurfaceControl sc, float cornerRadius) {
@@ -1662,6 +1977,9 @@
}
@UnsupportedAppUsage
+ /**
+ * @hide
+ */
public Transaction setLayerStack(SurfaceControl sc, int layerStack) {
sc.checkNotReleased();
nativeSetLayerStack(mNativeObject, sc.mNativeObject, layerStack);
@@ -1669,6 +1987,9 @@
}
@UnsupportedAppUsage
+ /**
+ * @hide
+ */
public Transaction deferTransactionUntil(SurfaceControl sc, IBinder handle,
long frameNumber) {
if (frameNumber < 0) {
@@ -1680,6 +2001,9 @@
}
@UnsupportedAppUsage
+ /**
+ * @hide
+ */
public Transaction deferTransactionUntilSurface(SurfaceControl sc, Surface barrierSurface,
long frameNumber) {
if (frameNumber < 0) {
@@ -1691,13 +2015,18 @@
return this;
}
+ /**
+ * @hide
+ */
public Transaction reparentChildren(SurfaceControl sc, IBinder newParentHandle) {
sc.checkNotReleased();
nativeReparentChildren(mNativeObject, sc.mNativeObject, newParentHandle);
return this;
}
- /** Re-parents a specific child layer to a new parent */
+ /** Re-parents a specific child layer to a new parent
+ * @hide
+ */
public Transaction reparent(SurfaceControl sc, IBinder newParentHandle) {
sc.checkNotReleased();
nativeReparent(mNativeObject, sc.mNativeObject,
@@ -1705,12 +2034,18 @@
return this;
}
+ /**
+ * @hide
+ */
public Transaction detachChildren(SurfaceControl sc) {
sc.checkNotReleased();
nativeSeverChildren(mNativeObject, sc.mNativeObject);
return this;
}
+ /**
+ * @hide
+ */
public Transaction setOverrideScalingMode(SurfaceControl sc, int overrideScalingMode) {
sc.checkNotReleased();
nativeSetOverrideScalingMode(mNativeObject, sc.mNativeObject,
@@ -1721,6 +2056,7 @@
/**
* Sets a color for the Surface.
* @param color A float array with three values to represent r, g, b in range [0..1]
+ * @hide
*/
@UnsupportedAppUsage
public Transaction setColor(SurfaceControl sc, @Size(3) float[] color) {
@@ -1735,6 +2071,7 @@
* arrives. As transform matrix and size are already frozen in this fashion,
* this enables totally freezing the surface until the resize has completed
* (at which point the geometry influencing aspects of this transaction will then occur)
+ * @hide
*/
public Transaction setGeometryAppliesWithResize(SurfaceControl sc) {
sc.checkNotReleased();
@@ -1745,6 +2082,7 @@
/**
* Sets the security of the surface. Setting the flag is equivalent to creating the
* Surface with the {@link #SECURE} flag.
+ * @hide
*/
public Transaction setSecure(SurfaceControl sc, boolean isSecure) {
sc.checkNotReleased();
@@ -1759,6 +2097,7 @@
/**
* Sets the opacity of the surface. Setting the flag is equivalent to creating the
* Surface with the {@link #OPAQUE} flag.
+ * @hide
*/
public Transaction setOpaque(SurfaceControl sc, boolean isOpaque) {
sc.checkNotReleased();
@@ -1770,6 +2109,9 @@
return this;
}
+ /**
+ * @hide
+ */
public Transaction setDisplaySurface(IBinder displayToken, Surface surface) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
@@ -1785,6 +2127,9 @@
return this;
}
+ /**
+ * @hide
+ */
public Transaction setDisplayLayerStack(IBinder displayToken, int layerStack) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
@@ -1793,6 +2138,9 @@
return this;
}
+ /**
+ * @hide
+ */
public Transaction setDisplayProjection(IBinder displayToken,
int orientation, Rect layerStackRect, Rect displayRect) {
if (displayToken == null) {
@@ -1810,6 +2158,9 @@
return this;
}
+ /**
+ * @hide
+ */
public Transaction setDisplaySize(IBinder displayToken, int width, int height) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
@@ -1822,7 +2173,9 @@
return this;
}
- /** flag the transaction as an animation */
+ /** flag the transaction as an animation
+ * @hide
+ */
public Transaction setAnimationTransaction() {
nativeSetAnimationTransaction(mNativeObject);
return this;
@@ -1835,6 +2188,7 @@
* order not to miss frame deadlines.
* <p>
* Corresponds to setting ISurfaceComposer::eEarlyWakeup
+ * @hide
*/
public Transaction setEarlyWakeup() {
nativeSetEarlyWakeup(mNativeObject);
@@ -1844,6 +2198,7 @@
/**
* Merge the other transaction into this transaction, clearing the
* other transaction as if it had been applied.
+ * @hide
*/
public Transaction merge(Transaction other) {
mResizedSurfaces.putAll(other.mResizedSurfaces);
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index d7c8aed..793c315 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -43,6 +43,7 @@
import android.text.style.URLSpan;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
import android.util.LongArray;
import android.util.Pools.SynchronizedPool;
import android.view.TouchDelegate;
@@ -91,6 +92,8 @@
private static final boolean DEBUG = false;
+ private static final String TAG = "AccessibilityNodeInfo";
+
/** @hide */
public static final int UNDEFINED_CONNECTION_ID = -1;
@@ -990,6 +993,7 @@
* <strong>Note:</strong> Cannot be called from an
* {@link android.accessibilityservice.AccessibilityService}.
* This class is made immutable before being delivered to an AccessibilityService.
+ * Note that a view cannot be made its own child.
* </p>
*
* @param child The child.
@@ -1037,6 +1041,7 @@
* hierarchy for accessibility purposes. This enables custom views that draw complex
* content to report them selves as a tree of virtual views, thus conveying their
* logical structure.
+ * Note that a view cannot be made its own child.
* </p>
*
* @param root The root of the virtual subtree.
@@ -1054,6 +1059,11 @@
final int rootAccessibilityViewId =
(root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
+ if (childNodeId == mSourceNodeId) {
+ Log.e(TAG, "Rejecting attempt to make a View its own child");
+ return;
+ }
+
// If we're checking uniqueness and the ID already exists, abort.
if (checked && mChildNodeIds.indexOf(childNodeId) >= 0) {
return;
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index 95a346f..c630177 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -794,7 +794,7 @@
* @deprecated All window animations are running with detached wallpaper.
*/
public boolean getDetachWallpaper() {
- return false;
+ return true;
}
/**
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index e59bee4..c4ab91f 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -17,8 +17,10 @@
package com.android.internal.app;
import android.app.AppOpsManager;
+import android.app.AppOpsManager;
import android.content.pm.ParceledListSlice;
import android.os.Bundle;
+import android.os.RemoteCallback;
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsActiveCallback;
import com.android.internal.app.IAppOpsNotedCallback;
@@ -42,10 +44,15 @@
int checkPackage(int uid, String packageName);
List<AppOpsManager.PackageOps> getPackagesForOps(in int[] ops);
List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops);
- ParceledListSlice getAllHistoricalPackagesOps(in String[] ops,
- long beginTimeMillis, long endTimeMillis);
- AppOpsManager.HistoricalPackageOps getHistoricalPackagesOps(int uid, String packageName,
- in String[] ops, long beginTimeMillis, long endTimeMillis);
+ void getHistoricalOps(int uid, String packageName, in String[] ops, long beginTimeMillis,
+ long endTimeMillis, in RemoteCallback callback);
+ void getHistoricalOpsFromDiskRaw(int uid, String packageName, in String[] ops,
+ long beginTimeMillis, long endTimeMillis, in RemoteCallback callback);
+ void offsetHistory(long duration);
+ void setHistoryParameters(int mode, long baseSnapshotInterval, int compressionStep);
+ void addHistoricalOps(in AppOpsManager.HistoricalOps ops);
+ void resetHistoryParameters();
+ void clearHistory();
List<AppOpsManager.PackageOps> getUidOps(int uid, in int[] ops);
void setUidMode(int code, int uid, int mode);
void setMode(int code, int uid, String packageName, int mode);
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index c94c64a..e8ac223 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -39,6 +39,7 @@
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
+import java.util.ArrayList;
/**
* Base class representing a remote service.
@@ -93,6 +94,9 @@
// Used just for debugging purposes (on dump)
private long mNextUnbind;
+ /** Requests that have been scheduled, but that are not finished yet */
+ private final ArrayList<PendingRequest<S, I>> mUnfinishedRequests = new ArrayList<>();
+
/**
* Callback called when the service dies.
*
@@ -229,6 +233,8 @@
.append(mComponentName.flattenToString()).println();
pw.append(prefix).append(tab).append("destroyed=")
.append(String.valueOf(mDestroyed)).println();
+ pw.append(prefix).append(tab).append("numUnfinishedRequests=")
+ .append(String.valueOf(mUnfinishedRequests.size()));
final boolean bound = handleIsBound();
pw.append(prefix).append(tab).append("bound=")
.append(String.valueOf(bound));
@@ -257,23 +263,37 @@
* <p>This request must be responded by the service somehow (typically using a callback),
* othewise it will trigger a {@link PendingRequest#onTimeout(AbstractRemoteService)} if the
* service doesn't respond.
- *
- * <p><b>NOTE: </b>this request is responsible for calling {@link #scheduleUnbind()}.
*/
protected void scheduleRequest(@NonNull PendingRequest<S, I> pendingRequest) {
- cancelScheduledUnbind();
mHandler.sendMessage(obtainMessage(
AbstractRemoteService::handlePendingRequest, this, pendingRequest));
}
/**
+ * Marks a pendingRequest as finished.
+ *
+ * @param finshedRequest The request that is finished
+ */
+ void finishRequest(@NonNull PendingRequest<S, I> finshedRequest) {
+ mHandler.sendMessage(
+ obtainMessage(AbstractRemoteService::handleFinishRequest, this, finshedRequest));
+ }
+
+ private void handleFinishRequest(@NonNull PendingRequest<S, I> finshedRequest) {
+ mUnfinishedRequests.remove(finshedRequest);
+
+ if (mUnfinishedRequests.isEmpty()) {
+ scheduleUnbind();
+ }
+ }
+
+ /**
* Schedules an async request.
*
* <p>This request is not expecting a callback from the service, hence it's represented by
* a simple {@link Runnable}.
*/
protected void scheduleAsyncRequest(@NonNull AsyncRequest<I> request) {
- scheduleUnbind();
// TODO(b/117779333): fix generics below
@SuppressWarnings({"unchecked", "rawtypes"})
final MyAsyncPendingRequest<S, I> asyncRequest = new MyAsyncPendingRequest(this, request);
@@ -341,6 +361,10 @@
handleEnsureBound();
} else {
if (mVerbose) Slog.v(mTag, "handlePendingRequest(): " + pendingRequest);
+
+ mUnfinishedRequests.add(pendingRequest);
+ cancelScheduledUnbind();
+
pendingRequest.run();
if (pendingRequest.isFinal()) {
mCompleted = true;
@@ -504,6 +528,12 @@
}
mCompleted = true;
}
+
+ S service = mWeakService.get();
+ if (service != null) {
+ service.finishRequest(this);
+ }
+
mServiceHandler.removeCallbacks(mTimeoutTrigger);
return true;
}
diff --git a/core/java/com/android/internal/os/AtomicDirectory.java b/core/java/com/android/internal/os/AtomicDirectory.java
new file mode 100644
index 0000000..f24d12e
--- /dev/null
+++ b/core/java/com/android/internal/os/AtomicDirectory.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.FileUtils;
+import android.util.ArrayMap;
+
+import com.android.internal.util.Preconditions;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * Helper class for performing atomic operations on a directory, by creating a
+ * backup directory until a write has successfully completed.
+ * <p>
+ * Atomic directory guarantees directory integrity by ensuring that a directory has
+ * been completely written and sync'd to disk before removing its backup.
+ * As long as the backup directory exists, the original directory is considered
+ * to be invalid (leftover from a previous attempt to write).
+ * <p>
+ * Atomic directory does not confer any file locking semantics. Do not use this
+ * class when the directory may be accessed or modified concurrently
+ * by multiple threads or processes. The caller is responsible for ensuring
+ * appropriate mutual exclusion invariants whenever it accesses the directory.
+ * <p>
+ * To ensure atomicity you must always use this class to interact with the
+ * backing directory when checking existence, making changes, and deleting.
+ */
+public final class AtomicDirectory {
+ private final @NonNull ArrayMap<File, FileOutputStream> mOpenFiles = new ArrayMap<>();
+ private final @NonNull File mBaseDirectory;
+ private final @NonNull File mBackupDirectory;
+
+ private int mBaseDirectoryFd = -1;
+ private int mBackupDirectoryFd = -1;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param baseDirectory The base directory to treat atomically.
+ */
+ public AtomicDirectory(@NonNull File baseDirectory) {
+ Preconditions.checkNotNull(baseDirectory, "baseDirectory cannot be null");
+ mBaseDirectory = baseDirectory;
+ mBackupDirectory = new File(baseDirectory.getPath() + "_bak");
+ }
+
+ /**
+ * Gets the backup directory if present. This could be useful if you are
+ * writing new state to the dir but need to access the last persisted state
+ * at the same time. This means that this call is useful in between
+ * {@link #startWrite()} and {@link #finishWrite()} or {@link #failWrite()}.
+ * You should not modify the content returned by this method.
+ *
+ * @see #startRead()
+ */
+ public @Nullable File getBackupDirectory() {
+ return mBackupDirectory;
+ }
+
+ /**
+ * Starts reading this directory. After calling this method you should
+ * not make any changes to its contents.
+ *
+ * @throws IOException If an error occurs.
+ *
+ * @see #finishRead()
+ * @see #startWrite()
+ */
+ public @NonNull File startRead() throws IOException {
+ restore();
+ return getOrCreateBaseDirectory();
+ }
+
+ /**
+ * Finishes reading this directory.
+ *
+ * @see #startRead()
+ * @see #startWrite()
+ */
+ public void finishRead() {
+ mBaseDirectoryFd = -1;
+ mBackupDirectoryFd = -1;
+ }
+
+ /**
+ * Starts editing this directory. After calling this method you should
+ * add content to the directory only via the APIs on this class. To open a
+ * file for writing in this directory you should use {@link #openWrite(File)}
+ * and to close the file {@link #closeWrite(FileOutputStream)}. Once all
+ * content has been written and all files closed you should commit via a
+ * call to {@link #finishWrite()} or discard via a call to {@link #failWrite()}.
+ *
+ * @throws IOException If an error occurs.
+ *
+ * @see #startRead()
+ * @see #openWrite(File)
+ * @see #finishWrite()
+ * @see #failWrite()
+ */
+ public @NonNull File startWrite() throws IOException {
+ backup();
+ return getOrCreateBaseDirectory();
+ }
+
+ /**
+ * Opens a file in this directory for writing.
+ *
+ * @param file The file to open. Must be a file in the base directory.
+ * @return An input stream for reading.
+ *
+ * @throws IOException If an I/O error occurs.
+ *
+ * @see #closeWrite(FileOutputStream)
+ */
+ public @NonNull FileOutputStream openWrite(@NonNull File file) throws IOException {
+ if (file.isDirectory() || !file.getParentFile().equals(getOrCreateBaseDirectory())) {
+ throw new IllegalArgumentException("Must be a file in " + getOrCreateBaseDirectory());
+ }
+ final FileOutputStream destination = new FileOutputStream(file);
+ if (mOpenFiles.put(file, destination) != null) {
+ throw new IllegalArgumentException("Already open file" + file.getCanonicalPath());
+ }
+ return destination;
+ }
+
+ /**
+ * Closes a previously opened file.
+ *
+ * @param destination The stream to the file returned by {@link #openWrite(File)}.
+ *
+ * @see #openWrite(File)
+ */
+ public void closeWrite(@NonNull FileOutputStream destination) {
+ final int indexOfValue = mOpenFiles.indexOfValue(destination);
+ if (mOpenFiles.removeAt(indexOfValue) == null) {
+ throw new IllegalArgumentException("Unknown file stream " + destination);
+ }
+ FileUtils.sync(destination);
+ try {
+ destination.close();
+ } catch (IOException ignored) {}
+ }
+
+ public void failWrite(@NonNull FileOutputStream destination) {
+ final int indexOfValue = mOpenFiles.indexOfValue(destination);
+ if (indexOfValue >= 0) {
+ mOpenFiles.removeAt(indexOfValue);
+ }
+ }
+
+ /**
+ * Finishes the edit and commits all changes.
+ *
+ * @see #startWrite()
+ *
+ * @throws IllegalStateException is some files are not closed.
+ */
+ public void finishWrite() {
+ throwIfSomeFilesOpen();
+ fsyncDirectoryFd(mBaseDirectoryFd);
+ deleteDirectory(mBackupDirectory);
+ fsyncDirectoryFd(mBackupDirectoryFd);
+ mBaseDirectoryFd = -1;
+ mBackupDirectoryFd = -1;
+ }
+
+ /**
+ * Finishes the edit and discards all changes.
+ *
+ * @see #startWrite()
+ */
+ public void failWrite() {
+ throwIfSomeFilesOpen();
+ try{
+ restore();
+ } catch (IOException ignored) {}
+ mBaseDirectoryFd = -1;
+ mBackupDirectoryFd = -1;
+ }
+
+ /**
+ * @return Whether this directory exists.
+ */
+ public boolean exists() {
+ return mBaseDirectory.exists() || mBackupDirectory.exists();
+ }
+
+ /**
+ * Deletes this directory.
+ */
+ public void delete() {
+ if (mBaseDirectory.exists()) {
+ deleteDirectory(mBaseDirectory);
+ fsyncDirectoryFd(mBaseDirectoryFd);
+ }
+ if (mBackupDirectory.exists()) {
+ deleteDirectory(mBackupDirectory);
+ fsyncDirectoryFd(mBackupDirectoryFd);
+ }
+ }
+
+ private @NonNull File getOrCreateBaseDirectory() throws IOException {
+ if (!mBaseDirectory.exists()) {
+ if (!mBaseDirectory.mkdirs()) {
+ throw new IOException("Couldn't create directory " + mBaseDirectory);
+ }
+ FileUtils.setPermissions(mBaseDirectory.getPath(),
+ FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH,
+ -1, -1);
+ }
+ if (mBaseDirectoryFd < 0) {
+ mBaseDirectoryFd = getDirectoryFd(mBaseDirectory.getCanonicalPath());
+ }
+ return mBaseDirectory;
+ }
+
+ private void throwIfSomeFilesOpen() {
+ if (!mOpenFiles.isEmpty()) {
+ throw new IllegalStateException("Unclosed files: "
+ + Arrays.toString(mOpenFiles.keySet().toArray()));
+ }
+ }
+
+ private void backup() throws IOException {
+ if (!mBaseDirectory.exists()) {
+ return;
+ }
+ if (mBaseDirectoryFd < 0) {
+ mBaseDirectoryFd = getDirectoryFd(mBaseDirectory.getCanonicalPath());
+ }
+ if (mBackupDirectory.exists()) {
+ deleteDirectory(mBackupDirectory);
+ }
+ if (!mBaseDirectory.renameTo(mBackupDirectory)) {
+ throw new IOException("Couldn't backup " + mBaseDirectory
+ + " to " + mBackupDirectory);
+ }
+ mBackupDirectoryFd = mBaseDirectoryFd;
+ mBaseDirectoryFd = -1;
+ fsyncDirectoryFd(mBackupDirectoryFd);
+ }
+
+ private void restore() throws IOException {
+ if (!mBackupDirectory.exists()) {
+ return;
+ }
+ if (mBackupDirectoryFd == -1) {
+ mBackupDirectoryFd = getDirectoryFd(mBackupDirectory.getCanonicalPath());
+ }
+ if (mBaseDirectory.exists()) {
+ deleteDirectory(mBaseDirectory);
+ }
+ if (!mBackupDirectory.renameTo(mBaseDirectory)) {
+ throw new IOException("Couldn't restore " + mBackupDirectory
+ + " to " + mBaseDirectory);
+ }
+ mBaseDirectoryFd = mBackupDirectoryFd;
+ mBackupDirectoryFd = -1;
+ fsyncDirectoryFd(mBaseDirectoryFd);
+ }
+
+ private static void deleteDirectory(@NonNull File file) {
+ final File[] children = file.listFiles();
+ if (children != null) {
+ for (File child : children) {
+ deleteDirectory(child);
+ }
+ }
+ file.delete();
+ }
+
+ private static native int getDirectoryFd(String path);
+ private static native void fsyncDirectoryFd(int fd);
+}
diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java
index 470533f2..605df04 100644
--- a/core/java/com/android/internal/util/CollectionUtils.java
+++ b/core/java/com/android/internal/util/CollectionUtils.java
@@ -330,4 +330,18 @@
public static @NonNull <T> List<T> defeatNullable(@Nullable List<T> val) {
return (val != null) ? val : Collections.emptyList();
}
+
+ /**
+ * @return the first element if not empty/null, null otherwise
+ */
+ public static @Nullable <T> T firstOrNull(@Nullable List<T> cur) {
+ return isEmpty(cur) ? null : cur.get(0);
+ }
+
+ /**
+ * @return list of single given element if it's not null, empty list otherwise
+ */
+ public static @NonNull <T> List<T> singletonOrEmpty(@Nullable T item) {
+ return item == null ? Collections.emptyList() : Collections.singletonList(item);
+ }
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index dc6a73a..088e13f 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -41,7 +41,7 @@
"com_google_android_gles_jni_EGLImpl.cpp",
"com_google_android_gles_jni_GLImpl.cpp", // TODO: .arm
"android_app_Activity.cpp",
- "android_app_ActivityThread.cpp",
+ "android_app_ActivityThread.cpp",
"android_app_NativeActivity.cpp",
"android_app_admin_SecurityLog.cpp",
"android_opengl_EGL14.cpp",
@@ -202,6 +202,7 @@
"android_animation_PropertyValuesHolder.cpp",
"android_security_Scrypt.cpp",
"com_android_internal_net_NetworkStatsFactory.cpp",
+ "com_android_internal_os_AtomicDirectory.cpp",
"com_android_internal_os_ClassLoaderFactory.cpp",
"com_android_internal_os_FuseAppLoop.cpp",
"com_android_internal_os_Zygote.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 687b105..1092222 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -218,6 +218,7 @@
extern int register_android_security_Scrypt(JNIEnv *env);
extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env);
+extern int register_com_android_internal_os_AtomicDirectory(JNIEnv *env);
extern int register_com_android_internal_os_ClassLoaderFactory(JNIEnv* env);
extern int register_com_android_internal_os_FuseAppLoop(JNIEnv* env);
extern int register_com_android_internal_os_Zygote(JNIEnv *env);
@@ -1495,6 +1496,7 @@
REG_JNI(register_android_security_Scrypt),
REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
REG_JNI(register_com_android_internal_net_NetworkStatsFactory),
+ REG_JNI(register_com_android_internal_os_AtomicDirectory),
REG_JNI(register_com_android_internal_os_FuseAppLoop),
};
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index 163b86b..42e3942 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -329,7 +329,7 @@
return NULL;
}
- LOG(INFO) << "HwBinder: Starting thread pool for " << serviceName << "::" << ifaceName;
+ LOG(INFO) << "HwBinder: Starting thread pool for getting: " << ifaceName << "/" << serviceName;
::android::hardware::ProcessState::self()->startThreadPool();
return JHwRemoteBinder::NewObject(env, service);
diff --git a/core/jni/com_android_internal_os_AtomicDirectory.cpp b/core/jni/com_android_internal_os_AtomicDirectory.cpp
new file mode 100644
index 0000000..50b2288
--- /dev/null
+++ b/core/jni/com_android_internal_os_AtomicDirectory.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <nativehelper/ScopedUtfChars.h>
+#include "jni.h"
+
+#include "core_jni_helpers.h"
+
+namespace android {
+
+static jint com_android_internal_os_AtomicDirectory_getDirectoryFd(JNIEnv* env,
+ jobject /*clazz*/, jstring path) {
+ ScopedUtfChars path8(env, path);
+ if (path8.c_str() == NULL) {
+ ALOGE("Invalid path: %s", path8.c_str());
+ return -1;
+ }
+ int fd;
+ if ((fd = TEMP_FAILURE_RETRY(open(path8.c_str(), O_DIRECTORY | O_RDONLY))) == -1) {
+ ALOGE("Cannot open directory %s, error: %s\n", path8.c_str(), strerror(errno));
+ return -1;
+ }
+ return fd;
+}
+
+static void com_android_internal_os_AtomicDirectory_fsyncDirectoryFd(JNIEnv* env,
+ jobject /*clazz*/, jint fd) {
+ if (TEMP_FAILURE_RETRY(fsync(fd)) == -1) {
+ ALOGE("Cannot fsync directory %d, error: %s\n", fd, strerror(errno));
+ }
+}
+
+/*
+ * JNI registration.
+ */
+static const JNINativeMethod gRegisterMethods[] = {
+ /* name, signature, funcPtr */
+ { "fsyncDirectoryFd",
+ "(I)V",
+ (void*) com_android_internal_os_AtomicDirectory_fsyncDirectoryFd
+ },
+ { "getDirectoryFd",
+ "(Ljava/lang/String;)I",
+ (void*) com_android_internal_os_AtomicDirectory_getDirectoryFd
+ },
+};
+
+int register_com_android_internal_os_AtomicDirectory(JNIEnv* env) {
+ return RegisterMethodsOrDie(env, "com/android/internal/os/AtomicDirectory",
+ gRegisterMethods, NELEM(gRegisterMethods));
+}
+
+}; // namespace android
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index a00fde9..cc5aa20 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -1018,7 +1018,9 @@
optional SettingProto zram_enabled = 139 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto app_ops_constants = 148 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
// Please insert fields in alphabetical order and group them into messages
// if possible (to avoid reaching the method limit).
- // Next tag = 148;
+ // Next tag = 149;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 449a7b3..8b85a28 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4254,6 +4254,16 @@
<permission android:name="android.permission.MANAGE_CONTENT_CAPTURE"
android:protectionLevel="signature" />
+ <!-- @SystemApi Allows an application to manage the content suggestions service.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.MANAGE_CONTENT_SUGGESTIONS"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to manage the app predictions service.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.MANAGE_APP_PREDICTIONS"
+ android:protectionLevel="signature" />
+
<!-- Allows an app to set the theme overlay in /vendor/overlay
being used.
@hide <p>Not for use by third-party applications.</p> -->
@@ -4334,6 +4344,11 @@
<permission android:name="android.permission.BIND_SMS_APP_SERVICE"
android:protectionLevel="signature" />
+ <!-- @hide Permission that allows configuring appops.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MANAGE_APPOPS"
+ android:protectionLevel="signature" />
+
<!-- @hide Permission that allows background clipboard access.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 3f23da6..c4616c5 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Maak oop met"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Maak oop met %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Maak oop"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Gee toegang tot oop <xliff:g id="HOST">%1$s</xliff:g>-skakels met"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Gee toegang tot oop <xliff:g id="HOST">%1$s</xliff:g>-skakels met <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Verleen toegang"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Redigeer met"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redigeer met %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Wysig"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Aanvaar oproep?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Altyd"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Net een keer"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Instellings"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s steun nie werkprofiel nie"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Kleurkorreksie"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Toeganklikheidskortpad het <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aangeskakel"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Toeganklikheidskortpad het <xliff:g id="SERVICE_NAME">%1$s</xliff:g> afgeskakel"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Gebruik weer toeganklikheidskortpad om die huidige toeganklikheidskenmerk te begin"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Druk en hou albei volumesleutels drie sekondes lank om <xliff:g id="SERVICE_NAME">%1$s</xliff:g> te gebruik"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Kies \'n kenmerk om te gebruik wanneer jy op die Toeganklikheid-knoppie tik:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Raak en hou die Toeganklikheid-knoppie om kenmerke te verander."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Vergroting"</string>
@@ -1975,5 +1979,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofoon"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"wys tans bo-oor ander programme op jou skerm"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Roetinemodus-inligtingkennisgewing"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Battery kan afloop voordat dit normaalweg gelaai word"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Batterybespaarder is geaktiveer om batterylewe te verleng"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Laai tans"</string>
</resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index ca1aabd..25c23b2 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"ክፈት በ"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"ክፈት በ%1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"ክፈት"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"የ<xliff:g id="HOST">%1$s</xliff:g> አገናኞችን በዚህ ለመክፈት መዳረሻ ይስጡ፦"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"የ<xliff:g id="HOST">%1$s</xliff:g> አገናኞችን በ<xliff:g id="APPLICATION">%2$s</xliff:g> ለመክፈት መዳረሻ ይስጡ"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"መዳረሻ ስጥ"</string>
<string name="whichEditApplication" msgid="144727838241402655">"ያርትዑ በ"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"ያርትዑ በ%1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"ያርትዑ"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"ጥሪ ተቀበል?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"ዘወትር"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"አንዴ ብቻ"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ቅንብሮች"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s የስራ መገለጫ አይደግፍም"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ጡባዊ ተኮ"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ቴሌቪዥን"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"የቀለም ማስተካከያ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"የተደራሽነት አቋራጭ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ን አብርቶታል"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"የተደራሽነት አቋራጭ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ን አጥፍቶታል"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"አሁን ያለውን የተደራሽነት ባህሪ ለመጀመር እንደገና የተደራሽነት አቋራጭን ይጠቀሙ"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ን ለመጠቀም ለሦስት ሰከንዶች ሁለቱንም የድምፅ ቁልፎች ተጭነው ይያዙ"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"የተደራሽነት አዝራርን መታ በሚያደርጉበት ጊዜ ጥቅም ላይ የሚውለውን ባህሪ ይምረጡ፦"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ባህሪያትን ለመለወጥ የተደራሽነት አዝራሩን ይንኩ እና ይያዙት።"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ማጉላት"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"ካሜራ"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"ማይክሮፎን"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"በማያዎ ላይ በሌሎች መተግበሪያዎች ላይ በማሳየት ላይ"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"በመጫን ላይ"</string>
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 4557563..25902bb 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1208,6 +1208,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"فتح باستخدام"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"فتح باستخدام %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"فتح"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"منح إمكانية الوصول لفتح روابط <xliff:g id="HOST">%1$s</xliff:g> باستخدام"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"منح إمكانية الوصول لفتح روابط <xliff:g id="HOST">%1$s</xliff:g> باستخدام <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"منح إذن الوصول"</string>
<string name="whichEditApplication" msgid="144727838241402655">"تعديل باستخدام"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"تعديل باستخدام %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"تعديل"</string>
@@ -1658,6 +1661,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"هل تريد قبول المكالمة؟"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"دومًا"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"مرة واحدة فقط"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"الإعدادات"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"لا يدعم %1$s الملفات الشخصية للعمل"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"الجهاز اللوحي"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"التلفزيون"</string>
@@ -1741,7 +1745,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"تصحيح الألوان"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"شغَّل اختصار إمكانية الوصول خدمة <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"أوقف اختصار إمكانية الوصول خدمة <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"استخدِم اختصار إمكانية الوصول لبدء ميزة إمكانية الوصول الحالية."</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"اضغط مع الاستمرار على مفتاحي مستوى الصوت لمدة 3 ثوانٍ لاستخدام <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"يمكنك اختيار إحدى الميزات لاستخدامها عند النقر على زر إمكانية الوصول:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"لتغيير الميزات، يمكنك لمس زر \"إمكانية الوصول\" مع الاستمرار."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"التكبير"</string>
@@ -2115,5 +2119,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"كاميرا"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"ميكروفون"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"العرض فوق التطبيقات الأخرى على شاشتك"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"إشعار معلومات \"وضع سلسلة الإجراءات\""</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"قد تنفد طاقة البطارية قبل الشحن المعتاد"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"تم تفعيل \"توفير شحن البطارية\" لإطالة عمرها."</string>
<string name="car_loading_profile" msgid="3545132581795684027">"جارٍ التحميل"</string>
</resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index a4f950a..12d9677 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"ইয়াৰ জৰিয়তে খোলক"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$sৰ জৰিয়তে খোলক"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"খোলক"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ইয়াৰ দ্বাৰা <xliff:g id="HOST">%1$s</xliff:g> লিংক খুলিবলৈ এক্সেছ দিয়ক"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g>ৰ দ্বাৰা <xliff:g id="HOST">%1$s</xliff:g> লিংক খুলিবলৈ এক্সেছ দিয়ক"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"এক্সেছ দিয়ক"</string>
<string name="whichEditApplication" msgid="144727838241402655">"ইয়াৰ দ্বাৰা সম্পাদনা কৰক"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sৰদ্বাৰা সম্পাদনা কৰক"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"সম্পাদনা কৰক"</string>
@@ -1257,7 +1260,7 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"নেটৱৰ্কত ছাইন ইন কৰক"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8938267198124654938">"ৱাই-ফাইত ইন্টাৰনেট নাই"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"ৱাই-ফাইত ইণ্টাৰনেট নাই"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"অধিক বিকল্পৰ বাবে টিপক"</string>
<string name="wifi_softap_config_change" msgid="8475911871165857607">"আপোনাৰ হটস্পট ছেটিংসমূহত কৰা সালসলনি"</string>
<string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"আপোনাৰ হটস্পটৰ বেণ্ড সলনি কৰা হ’ল।"</string>
@@ -1567,6 +1570,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"কল স্বীকাৰ কৰিবনে?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"সদায়"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"মাত্ৰ এবাৰ"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ছেটিংসমূহ"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$sএ কৰ্মস্থানৰ প্ৰ\'ফাইল সমৰ্থন নকৰে।"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"টেবলেট"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"টিভি"</string>
@@ -1646,7 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"ৰং শুধৰণী"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"দিব্যাংগসকলৰ সুবিধাৰ শ্বৰ্টকাটটোৱে <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ক অন কৰিছে"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"দিব্যাংগসকলৰ সুবিধাৰ শ্বৰ্টকাটটোৱে <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ক অফ কৰিছে"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"বর্তমানৰ সাধ্য সুবিধাসমূহৰ আৰম্ভ কৰিবলৈ সাধ্য সুবিধাসমূহৰ শ্বৰ্টকাট পুনৰ ব্যৱহাৰ কৰক"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ব্যৱহাৰ কৰিবলৈ দুয়োটা ভলিউম বুটাম তিনি ছেকেণ্ডৰ বাবে হেঁচি ৰাখক"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"আপুনি দিব্যাংগসকলৰ সুবিধাৰ বুটামটো টিপিলে ব্যৱহাৰ কৰিবলগীয়া কোনো সুবিধা বাছক:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"সুবিধাসমূহ সলনি কৰিবলৈ দিব্যাংগসকলৰ সুবিধাৰ বুটামটো স্পৰ্শ কৰি থাকক।"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"বিবৰ্ধন"</string>
@@ -1976,5 +1980,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"কেমেৰা"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"মাইক্ৰ\'ফ\'ন"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"স্ক্ৰীণত অইন এপৰ ওপৰত দেখুৱাওক"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"ল’ড হৈ আছে"</string>
</resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 076ea8d..1bcce98 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Bununla açın"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ilə açın"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Açın"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Bu tətbiqlə <xliff:g id="HOST">%1$s</xliff:g> linklərini açmağa icazə verin:"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> ilə <xliff:g id="HOST">%1$s</xliff:g> linklərini açmağa icazə verin"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"İcazə verin"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Bununla düzəliş edin:"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ilə düzəliş edin"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Redaktə edin"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Zəngi qəbul edək?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Həmişə"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Sadəcə bir dəfə"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ayarlar"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s iş profilini dəstəkləmir"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Planşet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Rəng korreksiyası"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Əlçatımlıq Qısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> xidmətini aktiv etdi"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Əlçatımlıq Qısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> xidmətini deaktiv etdi"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Cari əlçatımlılıq funksiyasını yenidən başlatmaq üçün Əlçatımlılıq Qısayolundan istifadə edin"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> istifadə etmək üçün hər iki səs düyməsini üç saniyə basıb saxlayın"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Əlçatımlılıq düyməsinə kliklədikdə istifadə etmək üçün funksiya seçin:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Funksiyaları dəyişmək üçün Əlçatımlılıq düyməsinə basıb saxlayın."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Böyütmə"</string>
@@ -1975,5 +1979,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"ekrandakı digər tətbiqlərdə göstərin"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Rejim üçün məlumat bildirişi"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Batareya həmişəki vaxtdan əvvəl bitə bilər"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Enerjiyə Qənaət rejimi batareya istifadəsinin müddətini artırmaq üçün aktiv edilir"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Yüklənir"</string>
</resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 0a94acf..57ee03d 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1148,6 +1148,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Otvorite pomoću"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otvorite pomoću aplikacije %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otvori"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Dozvolite da se linkovi <xliff:g id="HOST">%1$s</xliff:g> otvaraju pomoću"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Dozvolite da <xliff:g id="APPLICATION">%2$s</xliff:g> otvara linikove <xliff:g id="HOST">%1$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Dozvoli pristup"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Izmenite pomoću"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Izmenite pomoću aplikacije %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Izmeni"</string>
@@ -1589,6 +1592,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Želite li da prihvatite poziv?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Uvek"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Samo jednom"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Podešavanja"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne podržava poslovni profil"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1669,7 +1673,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Korekcija boja"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Prečica za pristupačnost je uključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Prečica za pristupačnost je isključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Upotrebite ponovo prečicu za pristupačnost da biste pokrenuli aktuelnu funkciju pristupačnosti"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Pritisnite i zadržite oba tastera za jačinu zvuka tri sekunde da biste koristili <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Izaberite funkciju koja će se koristiti kada dodirnete dugme za pristupačnost:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Pritisnite i zadržite dugme za pristupačnost da biste menjali funkcije."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Uvećanje"</string>
@@ -2010,5 +2014,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"prikazuje se na ekranu dok koristite druge aplikacije"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Obaveštenje o informacijama Rutinskog režima"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Baterija će se možda isprazniti pre uobičajenog punjenja"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Ušteda baterije je aktivirana da bi se produžilo trajanje baterije"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Učitava se"</string>
</resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index cfe076d..77de542 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -79,7 +79,7 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Налады ідэнтыфікатару АВН па змаўчанні: не абмяжавана. Наступны выклік: не абмежавана"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Служба не прадастаўляецца."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Вы не можаце змяніць налады ідэнтыфікатара абанента, якi тэлефануе."</string>
- <string name="RestrictedOnDataTitle" msgid="5221736429761078014">"Мабільны інтэрнэт недаступны"</string>
+ <string name="RestrictedOnDataTitle" msgid="5221736429761078014">"Мабільная перадача даных недаступная"</string>
<string name="RestrictedOnEmergencyTitle" msgid="6855466023161191166">"Экстранныя выклікі недаступныя"</string>
<string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"Няма сэрвісу галасавых выклікаў"</string>
<string name="RestrictedOnAllVoiceTitle" msgid="8037246983606545202">"Галасавыя або экстранныя выклікі недаступныя"</string>
@@ -435,7 +435,7 @@
<string name="permdesc_accessBackgroundLocation" msgid="1096394429579210251">"Акрамя доступу да прыкладнага ці дакладнага месцазнаходжання праграма можа мець доступ да вызначэння геалакацыі ў фонавым рэжыме працы. На гэта патрабуецца дазвол."</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"змяняць налады аудыё"</string>
<string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Дазваляе прыкладанням змяняць глабальныя налады гуку, такія як моц і тое, што дынамік выкарыстоўваецца для выхаду."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"запісваць аўдыё"</string>
+ <string name="permlab_recordAudio" msgid="3876049771427466323">"запіс аўдыя"</string>
<string name="permdesc_recordAudio" msgid="4245930455135321433">"Гэта праграма можа у любы час запісваць аўдыя, выкарыстоўваючы мікрафон."</string>
<string name="permlab_sim_communication" msgid="2935852302216852065">"адпраўляць каманды на SIM-карту"</string>
<string name="permdesc_sim_communication" msgid="5725159654279639498">"Дазваляе праграме адпраўляць каманды SIM-карце. Гэта вельмі небяспечна."</string>
@@ -1168,6 +1168,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Адкрыць з дапамогай"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Адкрыць з дапамогай %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Адкрыць"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Адкрываць спасылкі на сэрвіс <xliff:g id="HOST">%1$s</xliff:g> з дапамогай"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Адкрываць спасылкі на сэрвіс <xliff:g id="HOST">%1$s</xliff:g> з дапамогай праграмы \"<xliff:g id="APPLICATION">%2$s</xliff:g>\""</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Даць доступ"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Рэдагаваць з дапамогай"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Рэдагаваць з дапамогай %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Рэдагаваць"</string>
@@ -1612,6 +1615,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Прыняць выклік?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Заўсёды"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Толькі адзін раз"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Налады"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не падтрымлівае працоўны профіль"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Планшэт"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ТБ"</string>
@@ -1693,7 +1697,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Карэкцыя колеру"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> быў уключаны з дапамогай камбінацыі хуткага доступу для спецыяльных магчымасцей"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> быў адключаны з дапамогай камбінацыі хуткага доступу для спецыяльных магчымасцей"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Каб запусціць функцыю спецыяльных магчымасцей, паўторна скарыстайце ярлык спецыяльных магчымасцей"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Каб карыстацца сэрвісам \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\", націсніце і ўтрымлівайце на працягу трох секунд абедзве клавішы гучнасці"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Выберыце функцыю для выкарыстання пры націску кнопкі \"Спецыяльныя магчымасці\":"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Каб змяняць функцыі, краніце і ўтрымлівайце кнопку \"Спецыяльныя магчымасці\"."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Павелічэнне"</string>
@@ -2045,5 +2049,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Мікрафон"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"паказваецца паверх іншых праграм на экране"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Загрузка"</string>
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 8897bac..a360eae 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Отваряне чрез"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Отваряне чрез %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Отваряне"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Предоставяне на достъп за отваряне на връзките от <xliff:g id="HOST">%1$s</xliff:g> с(ъс)"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Предоставяне на достъп за отваряне на връзките от <xliff:g id="HOST">%1$s</xliff:g> с(ъс) <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Даване на достъп"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Редактиране чрез"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Редактиране чрез %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Редактиране"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Да се приеме ли обаждането?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Винаги"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Само веднъж"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Настройки"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не поддържа служебен потребителски профил"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Таблет"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Телевизор"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Коригиране на цветовете"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Прекият път за достъпност включи <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Прекият път за достъпност изключи <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Използвайте отново прекия път към функцията за достъпност, за да стартирате текущата"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"За да използвате <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, натиснете двата бутона за силата на звука и ги задръжте за 3 секунди"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Изберете функция, която да използвате, когато докоснете бутона за достъпност:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"За да промените функции, докоснете и задръжте бутона за достъпност."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ниво на мащаба"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Микрофон"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"се показва върху други приложения на екрана"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Зарежда се"</string>
</resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 26a3ba0..ea53d19 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"এর মাধ্যমে খুলুন"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s দিয়ে খুলুন"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"খুলুন"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ব্যবহার করে <xliff:g id="HOST">%1$s</xliff:g> লিঙ্ক খুলতে অ্যাক্সেস দিন"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> ব্যবহার করে <xliff:g id="HOST">%1$s</xliff:g> লিঙ্ক খুলতে অ্যাক্সেস দিন"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"অ্যাক্সেস দিন"</string>
<string name="whichEditApplication" msgid="144727838241402655">"এর মাধ্যমে সম্পাদনা করুন"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s দিয়ে সম্পাদনা করুন"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"সম্পাদনা করুন"</string>
@@ -1567,6 +1570,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"কল গ্রহণ করবেন?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"সবসময়"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"শুধু একবার"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"সেটিংস"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s কর্মস্থলের প্রোফাইল সমর্থন করে না।"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ট্যাবলেট"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"টিভি"</string>
@@ -1646,7 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"রঙ সংশোধন"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"অ্যাক্সেসযোগ্যতা শর্টকাট <xliff:g id="SERVICE_NAME">%1$s</xliff:g> কে চালু করেছে"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"অ্যাক্সেসযোগ্যতা শর্টকাট <xliff:g id="SERVICE_NAME">%1$s</xliff:g> কে বন্ধ করেছে"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"বর্তমান অ্যাক্সেসিবিলিটি বৈশিষ্ট্য শুরু করার জন্য অ্যাক্সেসিবিলিটি শর্টকাটটি আবার ব্যবহার করুন"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ব্যবহার করতে ভলিউম কী বোতাম ৩ সেকেন্ডের জন্য চেপে ধরে রাখুন"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"অ্যাক্সেসযোগ্যতা বোতামের সাহায্যে যে বৈশিষ্ট্যটি নিয়ন্ত্রণ করতে চান, সেটি বেছে নিন:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"বৈশিষ্ট্যগুলি পরিবর্তন করতে অ্যাক্সেসযোগ্যতা বোতামটি ট্যাপ করে ধরে রাখুন।"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"বড় করে দেখা"</string>
@@ -1976,5 +1980,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"ক্যামেরা"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"মাইক্রোফোন"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"স্ক্রিনে অন্যান্য অ্যাপের উপরে দেখানো হচ্ছে"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"লোড হচ্ছে"</string>
</resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index e336cd0..a3d2ac3 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1148,6 +1148,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Otvori koristeći"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otvori koristeći %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otvori"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Dozvolite pristup za otvaranje linkova hosta <xliff:g id="HOST">%1$s</xliff:g> pomoću"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Dozvolite pristup za otvaranje linkova hosta <xliff:g id="HOST">%1$s</xliff:g> pomoću aplikacije <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Dozvoli pristup"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Uredi koristeći"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Uredi koristeći %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Uredi"</string>
@@ -1591,6 +1594,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Prihvatiti poziv?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Uvijek"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Samo ovaj put"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Postavke"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne podržava poslovni profil"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1671,7 +1675,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Ispravka boja"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Prečica za pristupačnost je uključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Prečica za pristupačnost je isključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Ponovo koristite Prečicu za pristupačnost da započnete trenutnu funkciju pristupačnosti"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Pritisnite obje tipke za podešavanje jačine zvuka i držite ih pritisnutim tri sekunde da koristite uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Odaberite funkciju koja će se koristiti kada dodirnete dugme Pristupačnost:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Da promijenite funkcije, dodirnite i držite dugme Pristupačnost."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Uvećanje"</string>
@@ -2012,5 +2016,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"prikazivanje preko drugih aplikacija na ekranu"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Obavještenje za informacije Rutinskog načina"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Moguće je da će se baterija isprazniti prije uobičajenog punjenja"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Ušteda baterije je aktivirana da bi se produžio vijek trajanja baterije"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Učitavanje"</string>
</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 35c223b..1b1335d 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Obre amb"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Obre amb %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Obre"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Dona accés per obrir enllaços de <xliff:g id="HOST">%1$s</xliff:g> amb"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Dona accés per obrir enllaços de <xliff:g id="HOST">%1$s</xliff:g> amb <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Dona accés"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Edita amb"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edita amb %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edita"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Vols acceptar la trucada?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Només una vegada"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configuració"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s no admet perfils professionals."</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tauleta"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televisor"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Correcció del color"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"La drecera d\'accessibilitat ha activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"La drecera d\'accessibilitat ha desactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Torna a utilitzar la drecera d\'accessibilitat per iniciar la funció d\'accessibilitat actual"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Mantén premudes les dues tecles de volum durant 3 segons per fer servir <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Tria la funció que s\'utilitzarà quan toquis el botó Accessibilitat:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Per canviar les funcions, toca i mantén premut el botó Accessibilitat."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliació"</string>
@@ -1975,5 +1979,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Càmera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Micròfon"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"es mostra sobre altres aplicacions a la pantalla"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notificació d\'informació del mode de rutina"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"És possible que la bateria s\'esgoti abans de la càrrega habitual"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"S\'ha activat l\'estalvi de bateria per allargar-ne la durada"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"S\'està carregant"</string>
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 0061ca7..6a65be3 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1168,6 +1168,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Otevřít v aplikaci"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otevřít v aplikaci %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otevřít"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Udělte přístup k otevírání odkazů <xliff:g id="HOST">%1$s</xliff:g> pomocí aplikace"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Udělte přístup k otevírání odkazů <xliff:g id="HOST">%1$s</xliff:g> pomocí aplikace <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Udělit přístup"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Upravit v aplikaci"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Upravit v aplikaci %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Upravit"</string>
@@ -1612,6 +1615,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Přijmout hovor?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Vždy"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Pouze jednou"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Nastavení"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s pracovní profily nepodporuje."</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televize"</string>
@@ -1693,7 +1697,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Oprava barev"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Zkratka přístupnosti zapnula službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Zkratka přístupnosti vypnula službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Znovu použijte zkratku přístupnosti, čímž spustíte aktuální funkci pro usnadnění přístupu"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Chcete-li používat službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, tři sekundy podržte stisknutá obě tlačítka hlasitosti"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Určete, jakou funkci aktivujete klepnutím na tlačítko Přístupnost:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Chcete-li vybrat jinou funkci, podržte tlačítko Přístupnost."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Zvětšení"</string>
@@ -2045,5 +2049,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Fotoaparát"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"zobrazení přes ostatní aplikace na obrazovce"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Informační oznámení režimu sledu činností"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Baterie se možná vybije před obvyklým časem nabití"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Byl aktivován spořič baterie za účelem prodloužení výdrže"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Načítání"</string>
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 2795efe..ae50f32 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -87,7 +87,7 @@
<string name="NetworkPreferenceSwitchSummary" msgid="509327194863482733">"Prøv at skifte dit foretrukne netværk. Tryk for skifte."</string>
<string name="EmergencyCallWarningTitle" msgid="813380189532491336">"Det er ikke muligt at foretage nødopkald"</string>
<string name="EmergencyCallWarningSummary" msgid="1899692069750260619">"Det er ikke muligt at foretage nødopkald via Wi‑Fi"</string>
- <string name="notification_channel_network_alert" msgid="4427736684338074967">"Underretninger"</string>
+ <string name="notification_channel_network_alert" msgid="4427736684338074967">"Notifikationer"</string>
<string name="notification_channel_call_forward" msgid="2419697808481833249">"Viderestilling af opkald"</string>
<string name="notification_channel_emergency_callback" msgid="6686166232265733921">"Nødtilbagekaldstilstand"</string>
<string name="notification_channel_mobile_data_status" msgid="4575131690860945836">"Status for mobildata"</string>
@@ -187,7 +187,7 @@
<string name="work_profile_deleted_description_dpm_wipe" msgid="8823792115612348820">"Din arbejdsprofil er ikke længere tilgængelig på denne enhed"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="8986903510053359694">"For mange mislykkede adgangskodeforsøg"</string>
<string name="network_logging_notification_title" msgid="6399790108123704477">"Dette er en administreret enhed"</string>
- <string name="network_logging_notification_text" msgid="7930089249949354026">"Din organisation administrerer denne enhed og kan overvåge netværkstrafik. Tryk for at se oplysninger."</string>
+ <string name="network_logging_notification_text" msgid="7930089249949354026">"Din organisation administrerer denne enhed og kan overvåge netværkstrafik. Tryk for at se info."</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Enheden slettes"</string>
<string name="factory_reset_message" msgid="9024647691106150160">"Administrationsappen kan ikke bruges. Enheden vil nu blive ryddet. \n\nKontakt din organisations administrator, hvis du har spørgsmål."</string>
<string name="printing_disabled_by" msgid="8936832919072486965">"Udskrivning er deaktiveret af <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -249,7 +249,7 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Taleassistent"</string>
<string name="global_action_lockdown" msgid="1099326950891078929">"Lukning"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_hidden_text" msgid="6351207030447943784">"Ny underretning"</string>
+ <string name="notification_hidden_text" msgid="6351207030447943784">"Ny notifikation"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"Virtuelt tastatur"</string>
<string name="notification_channel_physical_keyboard" msgid="7297661826966861459">"Fysisk tastatur"</string>
<string name="notification_channel_security" msgid="7345516133431326347">"Sikkerhed"</string>
@@ -262,22 +262,22 @@
<string name="notification_channel_network_available" msgid="4531717914138179517">"Tilgængeligt netværk"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN-status"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Enhedsadministration"</string>
- <string name="notification_channel_alerts" msgid="4496839309318519037">"Underretninger"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Notifikationer"</string>
<string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demo til udstilling i butik"</string>
<string name="notification_channel_usb" msgid="9006850475328924681">"USB-forbindelse"</string>
<string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Appen kører"</string>
<string name="notification_channel_foreground_service" msgid="3931987440602669158">"Apps, der bruger batteri"</string>
<string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> bruger batteri"</string>
<string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> apps bruger batteri"</string>
- <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Tryk for at se oplysninger om batteri- og dataforbrug"</string>
+ <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Tryk for at se info om batteri- og dataforbrug"</string>
<string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
<string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
<string name="user_owner_label" msgid="8836124313744349203">"Skift til personlig profil"</string>
<string name="managed_profile_label" msgid="8947929265267690522">"Skift til arbejdsprofil"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakter"</string>
- <string name="permgroupdesc_contacts" msgid="6951499528303668046">"have adgang til dine kontaktpersoner"</string>
- <string name="permgrouprequest_contacts" msgid="6032805601881764300">"Vil du give <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> adgang til dine kontaktpersoner?"</string>
+ <string name="permgroupdesc_contacts" msgid="6951499528303668046">"have adgang til dine kontakter"</string>
+ <string name="permgrouprequest_contacts" msgid="6032805601881764300">"Vil du give <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> adgang til dine kontakter?"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Placering"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"få adgang til enhedens placering"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Vil du give <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> adgang til enhedens placering?"</string>
@@ -393,11 +393,11 @@
<string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"Tillader, at appen kan sende klæbende udsendelser, der forbliver tilbage, når udsendelsen er slut. Overdreven brug kan gøre din tablet langsom eller ustabil ved at tvinge den til at bruge for meget hukommelse."</string>
<string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"Giver appen lov til at sende klæbende udsendelser, som ikke forsvinder, når udsendelsen er slut. Overdreven brug kan gøre fjernsynet langsomt eller ustabilt ved at få det til at bruge for meget hukommelse."</string>
<string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Tillader, at appen kan sende klæbende udsendelser, der forbliver tilbage, når udsendelsen er slut. Overdreven brug kan gøre din telefon langsom eller ustabil ved at tvinge den til at bruge for meget hukommelse."</string>
- <string name="permlab_readContacts" msgid="8348481131899886131">"læse dine kontaktpersoner"</string>
+ <string name="permlab_readContacts" msgid="8348481131899886131">"læse dine kontakter"</string>
<string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Tillader, at appen kan læse data om de kontakter, der er gemt på din tablet, f.eks. hvor ofte du har ringet til, sendt mail til eller på anden måde kommunikeret med bestemte personer. Med denne tilladelse kan apps gemme dine kontaktdata, og skadelige apps kan dele kontaktdata uden din viden."</string>
<string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Giver appen lov til at læse data om dine kontakter, der er gemt på dit tv, herunder hvor ofte du har ringet, mailet eller på andre måder kommunikeret med bestemte personer. Denne tilladelse gør det muligt for apps at gemme dine kontaktoplysninger, og ondsindede apps kan dele kontaktoplysninger uden din viden."</string>
<string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Tillader, at appen kan læse data om de kontakter, der er gemt på din telefon, f.eks. hvor ofte du har ringet til, sendt mail til eller på anden måde kommunikeret med bestemte personer. Med denne tilladelse kan apps gemme dine kontaktdata, og skadelige apps kan dele kontaktdata uden din viden."</string>
- <string name="permlab_writeContacts" msgid="5107492086416793544">"ændre dine kontaktpersoner"</string>
+ <string name="permlab_writeContacts" msgid="5107492086416793544">"ændre dine kontakter"</string>
<string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Tillader, at appen kan ændre data om de kontakter, der er gemt på din tablet, f.eks. hvor ofte du har ringet til dem, sendt dem en mail eller på anden måde kommunikeret med bestemte kontakter. Med denne tilladelse kan apps slette kontaktoplysninger."</string>
<string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"Giver appen lov til at ændre data om dine kontakter, der er gemt på dit tv, herunder hvor ofte du har ringet, mailet eller på anden måde kommunikeret med bestemte kontakter. Denne tilladelse gør det muligt for apps at slette kontaktoplysninger."</string>
<string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Tillader, at appen kan ændre data om de kontakter, der er gemt på din telefon, f.eks. hvor ofte du har ringet til dem, sendt en mail til dem eller på anden måde kommunikeret med bestemte kontakter. Med denne tilladelse kan apps slette kontaktoplysninger."</string>
@@ -624,10 +624,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Tillader, at appen kan administrere netværkspolitikker og definere appspecifikke regler."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"skift afregning af netværksbrug"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Tillader, at appen kan ændre den måde, som netværksforbrug udregnes på i forhold til apps. Anvendes ikke af normale apps."</string>
- <string name="permlab_accessNotifications" msgid="7673416487873432268">"adgang til underretninger"</string>
- <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillader, at appen kan hente, undersøge og rydde underretninger, f.eks. dem, der er sendt af andre apps."</string>
- <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"forpligte sig til en underretningslyttertjeneste"</string>
- <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Tillader brugeren at forpligte sig til en underretningslyttertjenestes grænseflade på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"adgang til notifikationer"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillader, at appen kan hente, undersøge og rydde notifikationer, f.eks. dem, der er sendt af andre apps."</string>
+ <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"forpligte sig til en notifikationslyttertjeneste"</string>
+ <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Tillader brugeren at forpligte sig til en notifikationslyttertjenestes grænseflade på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
<string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"oprette binding til en tjeneste til formidling af betingelser"</string>
<string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Tillader, at brugeren opretter en binding til det øverste niveau af grænsefladen i en tjeneste til formidling af betingelser. Dette bør aldrig være nødvendigt for almindelige apps."</string>
<string name="permlab_bindDreamService" msgid="4153646965978563462">"fastlås til en drømmetjeneste"</string>
@@ -1098,7 +1098,7 @@
<string name="sms" msgid="4560537514610063430">"Send besked"</string>
<string name="sms_desc" msgid="7526588350969638809">"Send en besked til det valgte telefonnummer"</string>
<string name="add_contact" msgid="7867066569670597203">"Tilføj"</string>
- <string name="add_contact_desc" msgid="4830217847004590345">"Føj til kontaktpersoner"</string>
+ <string name="add_contact_desc" msgid="4830217847004590345">"Føj til kontakter"</string>
<string name="view_calendar" msgid="979609872939597838">"Se"</string>
<string name="view_calendar_desc" msgid="5828320291870344584">"Se det valgte tidspunkt i kalenderen"</string>
<string name="add_calendar_event" msgid="1953664627192056206">"Planlæg"</string>
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Åbn med"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Åbn med %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Åbn"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Giv adgang til at åbne <xliff:g id="HOST">%1$s</xliff:g>-link med"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Giv adgang til at åbne <xliff:g id="HOST">%1$s</xliff:g>-links med <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Giv adgang"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Rediger med"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Rediger med %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Rediger"</string>
@@ -1214,19 +1217,19 @@
<string name="volume_call" msgid="3941680041282788711">"Lydstyrke for opkald"</string>
<string name="volume_bluetooth_call" msgid="2002891926351151534">"Lydstyrke for Bluetooth under opkald"</string>
<string name="volume_alarm" msgid="1985191616042689100">"Lydstyrke for alarm"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Lydstyrke for underretninger"</string>
+ <string name="volume_notification" msgid="2422265656744276715">"Lydstyrke for notifikationer"</string>
<string name="volume_unknown" msgid="1400219669770445902">"Lydstyrke"</string>
<string name="volume_icon_description_bluetooth" msgid="6538894177255964340">"Lydstyrke for bluetooth"</string>
<string name="volume_icon_description_ringer" msgid="3326003847006162496">"Lydstyrke for ringetone"</string>
<string name="volume_icon_description_incall" msgid="8890073218154543397">"Lydstyrke for opkald"</string>
<string name="volume_icon_description_media" msgid="4217311719665194215">"Lydstyrke for medier"</string>
- <string name="volume_icon_description_notification" msgid="7044986546477282274">"Lydstyrke for underretninger"</string>
+ <string name="volume_icon_description_notification" msgid="7044986546477282274">"Lydstyrke for notifikationer"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Standardringetone"</string>
<string name="ringtone_default_with_actual" msgid="1767304850491060581">"Standard (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Ingen"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Ringetoner"</string>
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarmlyde"</string>
- <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Underretningslyde"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Notifikationslyde"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"Ukendt"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="one">Tilgængelige Wi-Fi-netværk</item>
@@ -1436,10 +1439,10 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Hjælpefunktioner"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Baggrund"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Skift baggrund"</string>
- <string name="notification_listener_binding_label" msgid="2014162835481906429">"Underretningslytter"</string>
+ <string name="notification_listener_binding_label" msgid="2014162835481906429">"Notifikationslytter"</string>
<string name="vr_listener_binding_label" msgid="4316591939343607306">"VR-lyttefunktion"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Tjeneste til formidling af betingelser"</string>
- <string name="notification_ranker_binding_label" msgid="774540592299064747">"Tjeneste til rangering af underretninger"</string>
+ <string name="notification_ranker_binding_label" msgid="774540592299064747">"Tjeneste til rangering af notifikationer"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN er aktiveret."</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN aktiveres af <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"Tryk for at administrere netværket."</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Vil du besvare opkaldet?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Altid"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Kun én gang"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Indstillinger"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s understøtter ikke arbejdsprofil"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Tv"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Korriger farve"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Genvejen til hjælpefunktioner aktiverede <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Genvejen til hjælpefunktioner deaktiverede <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Brug Genvej til hjælpefunktioner for at starte den aktuelle hjælpefunktion"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Hold begge lydstyrkeknapper nede i tre sekunder for at bruge <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Vælg, hvilken funktion du vil bruge, når du trykker på knappen Hjælpefunktioner:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Tryk på knappen Hjælpefunktioner, og hold fingeren nede for at skifte funktioner."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Forstørrelse"</string>
@@ -1858,7 +1862,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> valgt</item>
</plurals>
<string name="default_notification_channel_label" msgid="5929663562028088222">"Uden kategori"</string>
- <string name="importance_from_user" msgid="7318955817386549931">"Du angiver, hvor vigtige disse underretninger er."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Du angiver, hvor vigtige disse notifikationer er."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Dette er vigtigt på grund af de personer, det handler om."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Vil du give <xliff:g id="APP">%1$s</xliff:g> tilladelse til at oprette en ny bruger med <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Vil du give <xliff:g id="APP">%1$s</xliff:g> tilladelse til at oprette en ny bruger med <xliff:g id="ACCOUNT">%2$s</xliff:g> (der findes allerede en bruger med denne konto)?"</string>
@@ -1873,7 +1877,7 @@
<string name="app_suspended_default_message" msgid="123166680425711887">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> er ikke tilgængelig lige nu. Dette administreres af <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="1131804827776778187">"Få flere oplysninger"</string>
<string name="work_mode_off_title" msgid="1118691887588435530">"Skal arbejdsprofilen slås til?"</string>
- <string name="work_mode_off_message" msgid="5130856710614337649">"Dine arbejdsapps, underretninger, data og andre funktioner til din arbejdsprofil deaktiveres"</string>
+ <string name="work_mode_off_message" msgid="5130856710614337649">"Dine arbejdsapps, notifikationer, data og andre funktioner til din arbejdsprofil deaktiveres"</string>
<string name="work_mode_turn_on" msgid="2062544985670564875">"Slå til"</string>
<string name="deprecated_target_sdk_message" msgid="1449696506742572767">"Denne app er lavet til en ældre version af Android og fungerer muligvis ikke korrekt. Prøv at søge efter opdateringer, eller kontakt udvikleren."</string>
<string name="deprecated_target_sdk_app_store" msgid="5032340500368495077">"Søg efter opdatering"</string>
@@ -1962,11 +1966,11 @@
<string name="harmful_app_warning_title" msgid="8982527462829423432">"Der er registreret en skadelig app"</string>
<string name="slices_permission_request" msgid="8484943441501672932">"<xliff:g id="APP_0">%1$s</xliff:g> anmoder om tilladelse til at vise eksempler fra <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7867478911006447565">"Rediger"</string>
- <string name="volume_dialog_ringer_guidance_vibrate" msgid="8902050240801159042">"Telefonen vil vibrere ved opkald og underretninger"</string>
- <string name="volume_dialog_ringer_guidance_silent" msgid="2128975224280276122">"Der afspilles ikke lyd ved opkald og underretninger"</string>
+ <string name="volume_dialog_ringer_guidance_vibrate" msgid="8902050240801159042">"Telefonen vil vibrere ved opkald og notifikationer"</string>
+ <string name="volume_dialog_ringer_guidance_silent" msgid="2128975224280276122">"Der afspilles ikke lyd ved opkald og notifikationer"</string>
<string name="notification_channel_system_changes" msgid="5072715579030948646">"Systemændringer"</string>
<string name="notification_channel_do_not_disturb" msgid="6766940333105743037">"Forstyr ikke"</string>
- <string name="zen_upgrade_notification_visd_title" msgid="3288313883409759733">"Nyhed! Forstyr ikke skjuler underretninger"</string>
+ <string name="zen_upgrade_notification_visd_title" msgid="3288313883409759733">"Nyhed! Forstyr ikke skjuler notifikationer"</string>
<string name="zen_upgrade_notification_visd_content" msgid="5533674060311631165">"Tryk for at få flere oplysninger og foretage ændringer."</string>
<string name="zen_upgrade_notification_title" msgid="3799603322910377294">"Tilstanden Forstyr ikke blev ændret"</string>
<string name="zen_upgrade_notification_content" msgid="1794994264692424562">"Tryk for at se, hvad der er blokeret."</string>
@@ -1975,5 +1979,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"vises over andre apps på din skærm"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notifikation med oplysninger om rutinetilstand"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Enheden løber muligvis tør for batteri, inden du normalt oplader den"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Batterisparefunktion er aktiveret for at forlænge batteritiden"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Indlæser"</string>
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 6087438..895eaa1 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Öffnen mit"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Mit %1$s öffnen"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Öffnen"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Zugriff zum Öffnen von <xliff:g id="HOST">%1$s</xliff:g>-Links erlauben"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Zugriff zum Öffnen von <xliff:g id="HOST">%1$s</xliff:g>-Links mit <xliff:g id="APPLICATION">%2$s</xliff:g> erlauben"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Zugriff erlauben"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Bearbeiten mit"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Mit %1$s bearbeiten"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Bearbeiten"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Anruf annehmen?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Immer"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Nur diesmal"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Einstellungen"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Das Arbeitsprofil wird von %1$s nicht unterstützt."</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Farbkorrektur"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> wurde durch die Bedienungshilfenverknüpfung aktiviert"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> wurde durch die Bedienungshilfenverknüpfung deaktiviert"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Verwende noch einmal die Verknüpfung für Bedienungshilfen, um die aktuelle Bedienungshilfe zu starten."</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Halten Sie beide Lautstärketasten drei Sekunden lang gedrückt, um <xliff:g id="SERVICE_NAME">%1$s</xliff:g> zu verwenden"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Wähle eine Funktion aus, die verwendet wird, wenn du auf die Schaltfläche für die Bedienungshilfen tippst:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Um die Funktionen zu ändern, halte die Schaltfläche für die Bedienungshilfen gedrückt."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Vergrößerung"</string>
@@ -1975,5 +1979,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"wird über anderen Apps auf dem Bildschirm angezeigt"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Infomitteilung zum Ablaufmodus"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Dein Akku könnte vor der gewöhnlichen Ladezeit leer sein"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Energiesparmodus aktiviert, um die Akkulaufzeit zu verlängern"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Wird geladen"</string>
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index f899309..441435b 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Άνοιγμα με"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Άνοιγμα με %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Άνοιγμα"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Παραχώρηση πρόσβασης για το άνοιγμα συνδέσμων <xliff:g id="HOST">%1$s</xliff:g> με"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Παραχώρηση πρόσβασης για το άνοιγμα συνδέσμων <xliff:g id="HOST">%1$s</xliff:g> με την εφαρμογή <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Παροχή πρόσβασης"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Επεξεργασία με"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Επεξεργασία με %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Επεξεργασία"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Αποδοχή κλήσης;"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Πάντα"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Μόνο μία φορά"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ρυθμίσεις"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Το προφίλ εργασίας δεν υποστηρίζεται από %1$s"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Τηλεόραση"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Διόρθωση χρωμάτων"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Η συντόμευση προσβασιμότητας ενεργοποίησε την υπηρεσία <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Η συντόμευση προσβασιμότητας απενεργοποίησε την υπηρεσία <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Χρησιμοποιήστε τη Συντόμευση προσβασιμότητας ξανά, για να ξεκινήσετε την τρέχουσα λειτουργία προσβασιμότητας"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Πατήστε παρατεταμένα και τα δύο κουμπιά έντασης ήχου για τρία δευτερόλεπτα, ώστε να χρησιμοποιήσετε την υπηρεσία <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Επιλέξτε μια λειτουργία που θα χρησιμοποιείται κατά το πάτημα του κουμπιού \"Προσβασιμότητα\"."</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Για να αλλάξετε λειτουργίες, αγγίξτε παρατεταμένα το κουμπί \"Προσβασιμότητα\"."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Μεγιστοποίηση"</string>
@@ -1975,5 +1979,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Κάμερα"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Μικρόφωνο"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"εμφανίζεται πάνω σε άλλες εφαρμογές στην οθόνη σας"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Ειδοποίηση πληροφοριών λειτουργίας Ρουτίνας"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Η μπαταρία μπορεί να εξαντληθεί πριν από τη συνηθισμένη φόρτιση"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Η Εξοικονόμηση μπαταρίας ενεργοποιήθηκε για την επέκταση της διάρκειας ζωής της μπαταρίας"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Φόρτωση"</string>
</resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 7288a80..8b49cf1 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Open with"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Open with %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Open"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Give access"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Edit with"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edit"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Settings"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s doesn\'t support work profile"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Colour Correction"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use Accessibility Shortcut again to start the current accessibility feature"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choose a feature to use when you tap the Accessibility button:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"To change features, touch & hold the Accessibility button."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Magnification"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Camera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microphone"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"displaying over other apps on your screen"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Loading"</string>
</resources>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 0481755..888bc26 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Open with"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Open with %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Open"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Give access"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Edit with"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edit"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Settings"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s doesn\'t support work profile"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Colour Correction"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use Accessibility Shortcut again to start the current accessibility feature"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choose a feature to use when you tap the Accessibility button:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"To change features, touch & hold the Accessibility button."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Magnification"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Camera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microphone"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"displaying over other apps on your screen"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Loading"</string>
</resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 7288a80..8b49cf1 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Open with"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Open with %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Open"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Give access"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Edit with"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edit"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Settings"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s doesn\'t support work profile"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Colour Correction"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use Accessibility Shortcut again to start the current accessibility feature"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choose a feature to use when you tap the Accessibility button:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"To change features, touch & hold the Accessibility button."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Magnification"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Camera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microphone"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"displaying over other apps on your screen"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Loading"</string>
</resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 7288a80..8b49cf1 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Open with"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Open with %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Open"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Give access"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Edit with"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edit"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Settings"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s doesn\'t support work profile"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Colour Correction"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use Accessibility Shortcut again to start the current accessibility feature"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choose a feature to use when you tap the Accessibility button:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"To change features, touch & hold the Accessibility button."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Magnification"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Camera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microphone"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"displaying over other apps on your screen"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Loading"</string>
</resources>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 5d3b466..b4f1156d0 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1126,6 +1126,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Open with"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Open with %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Open"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Give access"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Edit with"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edit"</string>
@@ -1564,6 +1567,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Settings"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s doesn\'t support work profile"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1643,7 +1647,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Color Correction"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use Accessibility Shortcut again to start the current accessibility feature"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choose a feature to use when you tap the Accessibility button:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"To change features, touch & hold the Accessibility button."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Magnification"</string>
@@ -1973,5 +1977,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Camera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microphone"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"displaying over other apps on your screen"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Routine Mode info notification"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Battery may run out before usual charge"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Battery Saver activated to extend battery life"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Loading"</string>
</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index d369da5..e821fca 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Abrir con"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir con %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Otorgar acceso para abrir vínculos de <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Otorgar acceso para abrir vínculos de <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Otorgar acceso"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Editar con"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar con %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Editar"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"¿Aceptar la llamada?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Siempre"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Solo una vez"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configuración"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s no admite perfiles de trabajo."</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Corrección de color"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"El acceso directo de accesibilidad activó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"El acceso directo de accesibilidad desactivó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Vuelve a usar el acceso directo de accesibilidad para iniciar la función de accesibilidad actual"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Mantén presionadas ambas teclas de volumen durante tres segundos para usar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Elige una función para usar cuando presionas el botón Accesibilidad:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para cambiar funciones, mantén presionado el botón Accesibilidad."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliación"</string>
@@ -1975,5 +1979,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Cámara"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Micrófono"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"se superpone a otras apps en tu pantalla"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notificación de información del modo de Rutinas"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Es posible que la batería se agote antes de la carga habitual"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Se activó el Ahorro de batería para extender la duración de la batería"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Cargando"</string>
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 9174248..3f93565 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Abrir con"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir con %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Permitir acceso para abrir enlaces de <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Permitir acceso para abrir enlaces de <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Permitir acceso"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Editar con"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar con %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Cambiar"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"¿Aceptar la llamada?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Siempre"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Solo una vez"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ajustes"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s no admite perfiles de trabajo"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Corrección de color"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"El acceso directo a accesibilidad ha activado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"El acceso directo a accesibilidad ha desactivado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Usa de nuevo la combinación de teclas de accesibilidad para iniciar la función de accesibilidad actual"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Para utilizar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, mantén pulsadas ambas teclas de volumen durante 3 segundos"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Selecciona la función que se utilizará cuando toques el botón Accesibilidad:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para cambiar las funciones, mantén pulsado el botón Accesibilidad."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliar"</string>
@@ -1975,5 +1979,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Cámara"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Micrófono"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"se muestra sobre otras aplicaciones que haya en la pantalla"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notificación sobre el modo rutina"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Es posible que te quedes sin batería antes de lo habitual"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Se ha activado el ahorro de batería para aumentar la duración de la batería"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Cargando"</string>
</resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index f20b35f..466ead0 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Avamine:"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Avamine rakendusega %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ava"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Juurdepääsu andmine, et avada üksuse <xliff:g id="HOST">%1$s</xliff:g> lingid"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Juurdepääsu andmine, et avada üksuse <xliff:g id="HOST">%1$s</xliff:g> lingid rakendusega <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Juudep. andmine"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Muutmine:"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Muutmine rakendusega %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Muuda"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Kas vastata kõnele?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Alati"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Ainult üks kord"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Seaded"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ei toeta tööprofiili"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tahvelarvuti"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Teler"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Värviparandus"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Juurdepääsetavuse otsetee lülitas teenuse <xliff:g id="SERVICE_NAME">%1$s</xliff:g> sisse"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Juurdepääsetavuse otsetee lülitas teenuse <xliff:g id="SERVICE_NAME">%1$s</xliff:g> välja"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Praeguse juurdepääsufunktsiooni käivitamiseks kasutage juurdpääsetavuse otseteed uuesti"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Teenuse <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kasutamiseks hoidke kolm sekundit all mõlemat helitugevuse klahvi"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Valige, millist funktsiooni kasutada, kui vajutate nuppu Juurdepääsetavus:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Funktsioonide muutmiseks puudutage pikalt nuppu Juurdepääsetavus."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Suurendus"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Kaamera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"teie ekraanil muude rakenduste peal kuvamine"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Laadimine"</string>
</resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 153eeae..c478bab 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Ireki honekin:"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Irekin %1$s aplikazioarekin"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ireki"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Eman <xliff:g id="HOST">%1$s</xliff:g> estekak irekitzeko baimena aplikazio honi:"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Eman <xliff:g id="APPLICATION">%2$s</xliff:g> aplikazioari <xliff:g id="HOST">%1$s</xliff:g> irekitzeko baimena"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Eman sarbidea"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Editatu honekin:"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editatu %1$s aplikazioarekin"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Editatu"</string>
@@ -1567,6 +1570,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Deia onartu nahi duzu?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Beti"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Behin soilik"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ezarpenak"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s abiarazleak ez du laneko profil hau onartzen"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tableta"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Telebista"</string>
@@ -1646,7 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Koloreen zuzenketa"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Erabilerraztasun-lasterbideak <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktibatu du"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Erabilerraztasun-lasterbideak <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desaktibatu du"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Uneko erabilerraztasun-eginbidea abiarazteko, erabili erabilerraztasun-lasterbidea berriro"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> erabiltzeko, eduki sakatuta bolumen-tekla biak hiru segundoz"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Aukeratu zein eginbide erabili nahi duzun Erabilerraztasuna botoia sakatzean:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Eginbideak aldatzeko, eduki sakatuta Erabilerraztasuna botoia."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Lupa"</string>
@@ -1976,5 +1980,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofonoa"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"pantailako beste aplikazioen gainean bistaratzen"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Ohitura moduaren informazio-jakinarazpena"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Baliteke bateria ohi baino lehenago agortzea"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Bateria-aurrezlea aktibatuta dago bateriaren iraupena luzatzeko"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Kargatzen"</string>
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 76845c8..c38f1d2 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"باز کردن با"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"باز کردن با %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"باز کردن"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ارائه دسترسی برای باز کردن پیوندهای <xliff:g id="HOST">%1$s</xliff:g> با"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"ارائه دسترسی برای باز کردن پیوندهای <xliff:g id="HOST">%1$s</xliff:g> با<xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ارائه دسترسی"</string>
<string name="whichEditApplication" msgid="144727838241402655">"ویرایش با"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"ویرایش با %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"ویرایش"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"تماس را میپذیرید؟"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"همیشه"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"فقط این بار"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"تنظیمات"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s از نمایه کاری پشتیبانی نمیکند"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"رایانهٔ لوحی"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"تلویزیون"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"تصحیح رنگ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"«میانبر دسترسپذیری» <xliff:g id="SERVICE_NAME">%1$s</xliff:g> را روشن کرد"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"«میانبر دسترسپذیری» <xliff:g id="SERVICE_NAME">%1$s</xliff:g> را خاموش کرد"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"برای راهاندازی ویژگی دسترسپذیری کنونی، دوباره از «میانبر دسترسپذیری» استفاده کنید"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"برای استفاده از <xliff:g id="SERVICE_NAME">%1$s</xliff:g>، هر دو کلید صدا را فشار دهید و سه ثانیه نگه دارید"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"قابلیتی را انتخاب کنید که هنگام ضربه زدن روی دکمه «دسترسپذیری» استفاده میشود:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"برای تغییر دادن قابلیتها، دکمه «دسترسپذیری» را لمس کنید و نگهدارید."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"درشتنمایی"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"دوربین"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"میکروفون"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"نمایش روی برنامههای دیگر در صفحهنمایش"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"درحال بارگیری"</string>
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 16c96cc..ac6d8dc 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Avaa sovelluksessa"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Avaa sovelluksessa %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Avaa"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Salli linkkien (<xliff:g id="HOST">%1$s</xliff:g>) avaaminen:"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Salli linkkien (<xliff:g id="HOST">%1$s</xliff:g>) avaaminen: <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Salli"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Muokkaa sovelluksessa"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Muokkaa sovelluksessa %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Muokkaa"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Vastataanko puheluun?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Aina"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Vain kerran"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Asetukset"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ei tue työprofiilia"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tabletti"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televisio"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Värinkorjaus"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> otettiin käyttöön esteettömyystilan pikanäppäimellä."</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> poistettiin käytöstä esteettömyystilan pikanäppäimellä."</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Valitse esteettömyystilan oikopolku uudelleen käynnistääksesi esteettömyysominaisuuden"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Voit käyttää palvelua <xliff:g id="SERVICE_NAME">%1$s</xliff:g> painamalla molempia äänenvoimakkuuspainikkeita kolmen sekunnin ajan"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Valitse toiminto, jonka Esteettömyys-painike aktivoi:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Jos haluat muokata ominaisuuksia, kosketa Esteettömyys-painiketta pitkään."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Suurennus"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofoni"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"näkyy näytöllä muiden sovellusten päällä"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Ladataan"</string>
</resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 6fb1f12..8383078 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Ouvrir avec"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Ouvrir avec %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ouvrir"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Accorder l\'accès pour ouvrir les liens de <xliff:g id="HOST">%1$s</xliff:g> avec"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Accorder l\'accès pour ouvrir les liens de <xliff:g id="HOST">%1$s</xliff:g> avec <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Accorder l\'accès"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Modifier avec"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Modifier avec %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Modifier"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Prendre l\'appel?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Toujours"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Une seule fois"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Paramètres"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne prend pas en charge le profil professionnel"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablette"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Télévision"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Correction des couleurs"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Le raccourci d\'accessibilité a activé la fonction <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Le raccourci d\'accessibilité a désactivé la fonction <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Utilisez à nouveau le raccourci d\'accessibilité pour démarrer la fonctionnalité d\'accessibilité actuelle"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Maintenez enfoncées les deux touches de volume pendant trois secondes pour utiliser <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choisissez une fonctionnalité à utiliser lorsque vous touchez le bouton d\'accessibilité :"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Pour changer des fonctionnalités, maintenez le doigt sur le bouton d\'accessibilité."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Zoom"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Appareil photo"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microphone"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"superpose du contenu par-dessus d\'autres applications à l\'écran"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Chargement en cours…"</string>
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index fa8c7f0..3e87d88 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Ouvrir avec"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Ouvrir avec %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ouvrir"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Autoriser l\'ouverture des liens <xliff:g id="HOST">%1$s</xliff:g> avec"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Autoriser l\'ouverture des liens <xliff:g id="HOST">%1$s</xliff:g> avec <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Accorder l\'accès"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Modifier avec"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Modifier avec %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Modifier"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Prendre l\'appel ?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Toujours"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Une seule fois"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Paramètres"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s n\'est pas compatible avec le profil professionnel."</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablette"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Téléviseur"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Correction des couleurs"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Le raccourci d\'accessibilité a activé <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Le raccourci d\'accessibilité a désactivé <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Utilisez à nouveau le raccourci d\'accessibilité pour démarrer la fonctionnalité d\'accessibilité actuelle"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Appuyez de manière prolongée sur les deux touches de volume pendant trois secondes pour utiliser <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choisissez une fonctionnalité à utiliser lorsque vous appuyez sur le bouton d\'accessibilité :"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Pour changer des fonctionnalités, appuyez de manière prolongée sur le bouton d\'accessibilité."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Agrandissement"</string>
@@ -1975,5 +1979,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Caméra"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Micro"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"se superpose aux autres applications sur l\'écran"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notification d\'information du mode Routine"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Vous risquez d\'être à court de batterie plus tôt que prévu"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Économiseur de batterie activé pour prolonger l\'autonomie"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Chargement…"</string>
</resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 2c9b09d..1e78401 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -32,7 +32,7 @@
<string name="unknownName" msgid="6867811765370350269">"Descoñecido"</string>
<string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Correo de voz"</string>
<string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Problema de conexión ou código MMI non válido."</string>
+ <string name="mmiError" msgid="5154499457739052907">"Problema de conexión ou código MMI non-válido."</string>
<string name="mmiFdnError" msgid="5224398216385316471">"A operación está restrinxida a números de marcación fixa."</string>
<string name="mmiErrorWhileRoaming" msgid="762488890299284230">"Non se pode cambiar a configuración do desvío de chamadas desde o teléfono mentres estás en itinerancia."</string>
<string name="serviceEnabled" msgid="8147278346414714315">"Activouse o servizo."</string>
@@ -150,7 +150,7 @@
<string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: non desviada"</string>
<string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: non reenviada"</string>
<string name="fcComplete" msgid="3118848230966886575">"Código de función completo"</string>
- <string name="fcError" msgid="3327560126588500777">"Problema de conexión ou código de función non válido"</string>
+ <string name="fcError" msgid="3327560126588500777">"Problema de conexión ou código de función non-válido"</string>
<string name="httpErrorOk" msgid="1191919378083472204">"Aceptar"</string>
<string name="httpError" msgid="7956392511146698522">"Produciuse un erro na rede."</string>
<string name="httpErrorLookup" msgid="4711687456111963163">"Non se puido atopar o URL."</string>
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Abrir con"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir con %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Conceder acceso para abrir ligazóns de <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Conceder acceso para abrir ligazóns de <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Conceder acceso"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Editar con"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar con %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Editar"</string>
@@ -1567,6 +1570,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Aceptar chamada?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Só unha vez"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configuración"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s non admite o perfil de traballo"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tableta"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televisión"</string>
@@ -1646,7 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Corrección de cor"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O atallo de accesibilidade activou <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"O atallo de accesibilidade desactivou <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Para iniciar a función de accesibilidade actual, utiliza de novo o atallo de accesibilidade"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Mantén premidas as teclas do volume durante tres segudos para usar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Escolle que función queres utilizar cando toques o botón Accesibilidade:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para cambiar as funcións, mantén premido o botón Accesibilidade."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliación"</string>
@@ -1976,5 +1980,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Cámara"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Micrófono"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"mostrando outras aplicacións na pantalla"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Cargando"</string>
</resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index da8a6e5..958183d 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"આની સાથે ખોલો"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s સાથે ખોલો"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"ખોલો"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"આના વડે <xliff:g id="HOST">%1$s</xliff:g>ની લિંક ખોલવા માટે ઍક્સેસ આપો"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> વડે <xliff:g id="HOST">%1$s</xliff:g>ની લિંક ખોલવા માટે ઍક્સેસ આપો"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ઍક્સેસ આપો"</string>
<string name="whichEditApplication" msgid="144727838241402655">"આનાથી સંપાદિત કરો"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s સાથે સંપાદિત કરો"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"સંપાદિત કરો"</string>
@@ -1567,6 +1570,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"કૉલ સ્વીકારીએ?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"હંમેશા"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"ફક્ત એક વાર"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"સેટિંગ"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s કાર્ય પ્રોફાઇલનું સમર્થન કરતું નથી"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ટેબ્લેટ"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1646,7 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"રંગ સુધારણા"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ઍક્સેસિબિલિટી શૉર્ટકટે <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ચાલુ કરી"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ઍક્સેસિબિલિટી શૉર્ટકટે <xliff:g id="SERVICE_NAME">%1$s</xliff:g> બંધ કરી"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"વર્તમાન ઍક્સેસિબિલિટી સુવિધાને શરૂ કરવા માટે ફરીથી ઍક્સેસિબિલિટી શૉર્ટકટનો ઉપયોગ કરો"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>નો ઉપયોગ કરવા માટે બન્ને વૉલ્યૂમ કીને ત્રણ સેકન્ડ સુધી દબાવી રાખો"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"જ્યારે તમે ઍક્સેસિબિલિટી બટન પર ટૅપ કરો, ત્યારે ઉપયોગ કરવાની સુવિધા પસંદ કરો:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"સુવિધાઓ બદલવા માટે, ઍક્સેસિબિલિટી બટન દબાવી રાખો."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"વિસ્તૃતીકરણ"</string>
@@ -1976,5 +1980,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"કૅમેરા"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"માઇક્રોફોન"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"આ તમારી સ્ક્રીન પર અન્ય ઍપની ઉપર દેખાશે"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"લોડિંગ"</string>
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 4349c09..6a247af 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"इसमें खोलें"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s में खोलें"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"खोलें"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"इससे <xliff:g id="HOST">%1$s</xliff:g> लिंक खोलने का एक्सेस दें"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> से <xliff:g id="HOST">%1$s</xliff:g> लिंक खोलने का एक्सेस दें"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"एक्सेस दें"</string>
<string name="whichEditApplication" msgid="144727838241402655">"इसके ज़रिये बदलाव करें"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s की मदद से बदलाव करें"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"बदलाव करें"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"कॉल स्वीकार करें?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"हमेशा"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"केवल एक बार"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"सेटिंग"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s कार्य प्रोफ़ाइल का समर्थन नहीं करता"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"टैबलेट"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"टीवी"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"रंग में सुधार करने की सुविधा"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"सुलभता शॉर्टकट ने <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को चालू किया"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"सुलभता शॉर्टकट ने <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को बंद किया"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"मौजूदा सुलभता सुविधा शुरू करने के लिए \'सुलभता शॉर्टकट\' का फिर से इस्तेमाल करें"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> इस्तेमाल करने के लिए आवाज़ वाले दोनों बटन तीन सेकंड तक दबाकर रखें"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"सुलभता बटन पर टैप करते समय इस्तेमाल की जाने वाली सुविधा चुनें:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"सुविधाओं में बदलाव करने के लिए, सुलभता बटन को दबाकर रखें."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"बड़ा करना"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"कैमरा"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"माइक्रोफ़ोन"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"आपकी स्क्रीन पर, इस्तेमाल हो रहे दूसरे ऐप्लिकेशन के ऊपर दिखाया जा रहा है"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"प्राेफ़ाइल लोड हो रही है"</string>
</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 2747521..92fdbba 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1148,6 +1148,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Otvaranje pomoću aplikacije"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otvaranje pomoću aplikacije %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otvori"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Omogućite pristup za otvaranje <xliff:g id="HOST">%1$s</xliff:g> veza pomoću aplikacije"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Omogućite pristup za otvaranje <xliff:g id="HOST">%1$s</xliff:g> veza pomoću aplikacije <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Omogući pristup"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Uređivanje pomoću aplikacije"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Uređivanje pomoću aplikacije %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Uredi"</string>
@@ -1589,6 +1592,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Prihvatiti poziv?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Uvijek"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Samo jednom"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Postavke"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne podržava radni profil"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tabletno računalo"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televizor"</string>
@@ -1669,7 +1673,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Korekcija boje"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Prečac pristupačnosti uključio je uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Prečac pristupačnosti isključio je uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Ponovo upotrijebite prečac pristupačnosti da biste pokrenuli trenutačnu značajku pristupačnosti"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Pritisnite i zadržite tipke za glasnoću na tri sekunde da biste koristili uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Odaberite značajku koju ćete upotrebljavati kada dodirnete gumb Pristupačnost:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Da biste promijenili značajke, dodirnite i zadržite gumb Pristupačnost."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Povećavanje"</string>
@@ -2010,5 +2014,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Fotoaparat"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"prikazuje se preko drugih aplikacija na zaslonu"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Učitavanje"</string>
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 10538f4..c04d4fe 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Megnyitás a következővel:"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Megnyitás a következővel: %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Megnyitás"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Engedély megadása, hogy a(z) <xliff:g id="HOST">%1$s</xliff:g> linkek a következő alkalmazásban nyíljanak meg:"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Engedély megadása, hogy a(z) <xliff:g id="HOST">%1$s</xliff:g> linkek a következő alkalmazásban nyíljanak meg: <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Engedély adása"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Szerkesztés a következővel:"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Szerkesztés a következővel: %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Szerkesztés"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Fogadja a hívást?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Mindig"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Csak egyszer"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Beállítások"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"A(z) %1$s nem támogatja a munkaprofilokat."</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Táblagép"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Színkorrekció"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"A Kisegítő lehetőségek gyorsparancsa bekapcsolta a következő szolgáltatást: <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"A Kisegítő lehetőségek gyorsparancsa kikapcsolta a következő szolgáltatást: <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Használja újból a Kisegítő lehetőségek gyorsparancsát az aktuális kisegítő lehetőségek elindításához"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"A(z) <xliff:g id="SERVICE_NAME">%1$s</xliff:g> használatához tartsa lenyomva három másodpercig a két hangerőgombot"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Válassza ki a Kisegítő lehetőségek gombra koppintáskor használni kívánt funkciót:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"A funkciók módosításához tartsa lenyomva a Kisegítő lehetőségek gombot."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Nagyítás"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"megjelenítés a képernyőn lévő egyéb alkalmazások előtt"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Betöltés"</string>
</resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index fbb5f4b..84280ac 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Բացել հետևյալ ծրագրով՝"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Բացել ծրագրով՝ %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Բացել"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Թույլատրեք, որ <xliff:g id="HOST">%1$s</xliff:g> տիրույթը հղումները բացվեն հետևյալ հավելվածում՝"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Թույլատրեք, որ <xliff:g id="HOST">%1$s</xliff:g> տիրույթի հղումները բացվեն <xliff:g id="APPLICATION">%2$s</xliff:g> հավելվածում"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Թույլատրել"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Խմբագրել հետևյալ ծրագրով՝"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Խմբագրել հետևյալով՝ %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Փոփոխել"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Ընդունե՞լ զանգը:"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Միշտ"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Միայն մեկ անգամ"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Կարգավորումներ"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s-ը չի աջակցում աշխատանքային պրոֆիլներ"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Գրասալիկ"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Հեռուստացույց"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Գունաշտկում"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Մատչելիության դյուրանցումն միացրել է <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ծառայությունը"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Մատչելիության դյուրանցումն անջատել է <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ծառայությունը"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Հատուկ գործառույթների դյուրանցումը գործարկելու համար նորից օգտագործեք համապատասխան դյուրանցումը"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"«<xliff:g id="SERVICE_NAME">%1$s</xliff:g>» ծառայությունն օգտագործելու համար սեղմեք և 3 վայրկյան պահեք ձայնի ուժգնության երկու կոճակները"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Ընտրեք որևէ գործառույթ, որը կօգտագործվի Հատուկ գործառույթներ կոճակին հպելու դեպքում՝"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Գործառույթները փոխելու համար հպեք և պահեք Հատուկ գործառույթներ կոճակը։"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Խոշորացում"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Տեսախցիկ"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Խոսափող"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"ցուցադրվում է մյուս հավելվածների վերևում"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Բեռնում"</string>
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 3c6e347..905d3f2 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Buka dengan"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Buka dengan %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Buka"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Berikan akses untuk membuka link <xliff:g id="HOST">%1$s</xliff:g> dengan"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Berikan akses untuk membuka link <xliff:g id="HOST">%1$s</xliff:g> dengan <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Berikan akses"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Edit dengan"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit dengan %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edit"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Terima panggilan?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Selalu"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Hanya sekali"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Setelan"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s tidak mendukung profil kerja"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Koreksi Warna"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pintasan Aksesibilitas mengaktifkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pintasan Aksesibilitas menonaktifkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Gunakan Pintasan Aksesibilitas lagi untuk memulai fitur aksesibilitas saat ini"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Tekan dan tahan kedua tombol volume selama tiga detik untuk menggunakan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Pilih fitur yang akan digunakan saat menge-tap tombol Aksesibilitas:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Untuk mengubah fitur, sentuh & tahan tombol Aksesibilitas."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Pembesaran"</string>
@@ -1975,5 +1979,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"ditampilkan di atas aplikasi lain di layar"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notifikasi info Mode Rutinitas"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Baterai mungkin habis sebelum pengisian daya biasanya"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Penghemat Baterai diaktifkan untuk memperpanjang masa pakai baterai"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Memuat"</string>
</resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index f638ff8..432fc7e 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Opna með"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Opna með %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Opna"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Veita aðgang til að opna <xliff:g id="HOST">%1$s</xliff:g> tengla með"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Veita aðgang til að opna <xliff:g id="HOST">%1$s</xliff:g> tengla með <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Veita aðgang"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Breyta með"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Breyta með %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Breyta"</string>
@@ -1567,6 +1570,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Samþykkja símtal?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Alltaf"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Bara einu sinni"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Stillingar"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s styður ekki vinnusnið"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Spjaldtölva"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Sjónvarp"</string>
@@ -1646,7 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Litaleiðrétting"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Flýtileið aðgengisstillingar kveikti á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Flýtileið aðgengisstillingar slökkti á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Notaðu flýtileið aðgengisstillingar aftur til að opna aðgengiseiginleika"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Haltu báðum hljóðstyrkstökkunum inni í þrjár sekúndur til að nota <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Veldu eiginleika sem á að nota þegar ýtt er á aðgengishnappinn:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Haltu fingri á aðgengishnappinum til að breyta eiginleikum."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Stækkun"</string>
@@ -1976,5 +1980,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Myndavél"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Hljóðnemi"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"birt yfir öðrum forritum á skjánum"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Upplýsingatilkynning aðgerðastillingar"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Rafhlaðan kann að tæmast áður en hún kemst í hleðslu"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Kveikt á rafhlöðusparnaði til að lengja endingu rafhlöðunnar"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Hleður"</string>
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index c9c8f0c..d76049d 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Apri con"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Apri con %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Apri"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Dai l\'accesso per aprire i link di <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Dai l\'accesso per aprire i link di <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Fornisci accesso"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Modifica con"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Modifica con %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Modifica"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Accettare la chiamata?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Solo una volta"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Impostazioni"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s non supporta il profilo di lavoro"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Correzione del colore"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"La scorciatoia Accessibilità ha attivato <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"La scorciatoia Accessibilità ha disattivato <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Usa di nuovo la scorciatoia Accessibilità per avviare l\'attuale funzione di accessibilità"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Tieni premuti entrambi i tasti del volume per tre secondi per utilizzare <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Scegli una funzione da usare quando tocchi il pulsante Accessibilità:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Per cambiare le funzioni, tocca e tieni premuto il pulsante Accessibilità."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ingrandimento"</string>
@@ -1975,5 +1979,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Fotocamera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microfono"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"si sovrappone ad altre app sullo schermo"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notifica di informazioni sulla modalità Routine"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"La batteria potrebbe esaurirsi prima della ricarica abituale"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Risparmio energetico attivo per far durare di più la batteria"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Caricamento"</string>
</resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 26f6988f..df9631e 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1168,6 +1168,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"פתח באמצעות"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"פתח באמצעות %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"פתח"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"הענקת גישה לפתיחת קישורים של <xliff:g id="HOST">%1$s</xliff:g> באמצעות"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"הענקת גישה לפתיחת קישורים של <xliff:g id="HOST">%1$s</xliff:g> באמצעות <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"הענקת גישה"</string>
<string name="whichEditApplication" msgid="144727838241402655">"ערוך באמצעות"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"ערוך באמצעות %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"עריכה"</string>
@@ -1612,6 +1615,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"האם לקבל את השיחה?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"תמיד"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"רק פעם אחת"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"הגדרות"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s אינו תומך בפרופיל עבודה"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"טאבלט"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"טלוויזיה"</string>
@@ -1693,7 +1697,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"תיקון צבעים"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> הופעל על-ידי קיצור הדרך לנגישות"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> הושבת על-ידי קיצור הדרך לנגישות"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"יש להשתמש שוב במקש הקיצור לנגישות כדי להפעיל את תכונת הנגישות הנוכחית"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"יש ללחוץ לחיצה ארוכה על שני לחצני עוצמת הקול למשך שלוש שניות כדי להשתמש בשירות <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"בחר תכונה שתופעל כשתלחץ על הלחצן \'נגישות\':"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"כדי להחליף תכונה, גע בלחצן \'נגישות\' והחזק אותו."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"הגדלה"</string>
@@ -2045,5 +2049,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"מצלמה"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"מיקרופון"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"תצוגה מעל אפליקציות אחרות במסך"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"בטעינה"</string>
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 45587cb..991ef13 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"アプリで開く"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$sで開く"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"開く"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"<xliff:g id="HOST">%1$s</xliff:g> のリンクを開くには、アクセス権を付与してください"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> で <xliff:g id="HOST">%1$s</xliff:g> のリンクを開くには、アクセス権を付与してください"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"アクセス権を付与"</string>
<string name="whichEditApplication" msgid="144727838241402655">"編集に使用"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sで編集"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"編集"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"通話を受けますか?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"常時"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"1回のみ"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"設定"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$sは仕事用プロファイルをサポートしていません"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"タブレット"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"テレビ"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"色補正"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ユーザー補助機能のショートカットにより <xliff:g id="SERVICE_NAME">%1$s</xliff:g> は ON になっています"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ユーザー補助機能のショートカットにより <xliff:g id="SERVICE_NAME">%1$s</xliff:g> は OFF になっています"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"現在のユーザー補助機能を開始するには、ユーザー補助機能のショートカットをもう一度使用してください"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> を使用するには、音量大と音量小の両方のボタンを 3 秒間長押ししてください"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"[ユーザー補助] ボタンをタップした場合に使用する機能を選択してください。"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"機能を変更するには、[ユーザー補助] ボタンを押し続けてください。"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"拡大"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"カメラ"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"マイク"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"画面の他のアプリの上に重ねて表示"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"読み込んでいます"</string>
</resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 07df9fc..cfce254 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"გახსნა აპით"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s-ით გახსნა"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"გახსნა"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"<xliff:g id="HOST">%1$s</xliff:g> ბმულების შემდეგი აპით გახსნის წვდომის მინიჭება:"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="HOST">%1$s</xliff:g> ბმულების <xliff:g id="APPLICATION">%2$s</xliff:g>-ით გახსნის წვდომის მინიჭება"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"წვდომის მინიჭება"</string>
<string name="whichEditApplication" msgid="144727838241402655">"რედაქტირება აპით:"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"რედაქტირება %1$s-ით"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"რედაქტირება"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"უპასუხებთ ზარს?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"ყოველთვის"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"მხოლოდ ერთხელ"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"პარამეტრები"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s მხარს არ უჭერს სამუშაო პროფილს"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ტაბლეტი"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ტელევიზია"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"ფერთა კორექცია"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"მარტივი წვდომის მალსახმობმა ჩართო <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"მარტივი წვდომის მალსახმობმა გამორთო <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"მარტივი წვდომის ამჟამინდელი ფუნქციის გასაშვებად გამოიყენეთ მარტივი წვდომის მალსახმობი"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> რომ გამოიყენოთ, დააჭირეთ ხმის ორივე ღილაკზე 3 წამის განმავლობაში"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"აირჩიეთ მარტივი წვდომის ღილაკზე შეხებისას გამოსაყენებელი ფუნქცია:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ფუნქციების შესაცვლელად ხანგრძლივად შეეხეთ მარტივი წვდომის ღილაკს."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"გადიდება"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"კამერა"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"მიკროფონი"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"სხვა აპების გადაფარვით ჩანს თქვენს ეკრანზე"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"იტვირთება"</string>
</resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index c622094..fb70fa9 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Басқаша ашу"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s қолданбасымен ашу"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ашу"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"<xliff:g id="HOST">%1$s</xliff:g> сілтемелерін келесі қолданбамен ашу үшін рұқсат беру:"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="HOST">%1$s</xliff:g> сілтемелерін <xliff:g id="APPLICATION">%2$s</xliff:g> қолданбасымен ашу үшін рұқсат беру"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Рұқсат беру"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Келесімен өңдеу"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s көмегімен өңдеу"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Өңдеу"</string>
@@ -1567,6 +1570,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Қоңырауды қабылдау?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Үнемі"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Бір рет қана"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Параметрлер"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s жұмыс профилін қолдамайды"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Планшет"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ТД"</string>
@@ -1646,7 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Түсті түзету"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Арнайы мүмкіндіктер таңбашасы <xliff:g id="SERVICE_NAME">%1$s</xliff:g> қызметін қосты"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Арнайы мүмкіндіктер таңбашасы <xliff:g id="SERVICE_NAME">%1$s</xliff:g> қызметін өшірді"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Арнайы мүмкіндіктер функциясын іске қосу үшін оның таңбашасын пайдаланыңыз"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> қызметін пайдалану үшін дыбыс деңгейін реттейтін екі түймені де 3 секунд басып тұрыңыз"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"\"Арнайы мүмкіндіктер\" түймесін түрткенде пайдаланатын мүмкіндікті таңдаңыз:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Мүмкіндіктерді өзгерту үшін \"Арнайы мүмкіндіктер\" түймесін түртіп, ұстап тұрыңыз."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ұлғайту"</string>
@@ -1976,5 +1980,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Микрофон"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"экранда басқа қолданбалардың үстінен көрсету"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Жүктелуде"</string>
</resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index ccc243d..9cc64ab 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1130,6 +1130,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"បើកជាមួយ"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"បើកជាមួយ %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"បើក"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ផ្ដល់សិទ្ធិចូលប្រើ ដើម្បីបើកតំណ <xliff:g id="HOST">%1$s</xliff:g> តាមរយៈ"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"ផ្ដល់សិទ្ធិចូលប្រើ ដើម្បីបើកតំណ <xliff:g id="HOST">%1$s</xliff:g> តាមរយៈ <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ផ្តល់សិទ្ធិចូលប្រើ"</string>
<string name="whichEditApplication" msgid="144727838241402655">"កែសម្រួលជាមួយ"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"កែសម្រួលជាមួយ %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"កែសម្រួល"</string>
@@ -1568,6 +1571,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"ទទួលការហៅ?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"ជានិច្ច"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"តែម្ដង"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ការកំណត់"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s មិនគាំទ្រប្រវត្តិរូបការងារ"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"កុំព្យូទ័របន្ទះ"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ទូរទស្សន៍"</string>
@@ -1647,7 +1651,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"ការកែពណ៌"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ផ្លូវកាត់ភាពងាយស្រួលបានបើក <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ផ្លូវកាត់ភាពងាយស្រួលបានបិទ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ប្រើផ្លូវកាត់ភាពងាយស្រួលម្ដងទៀត ដើម្បីចាប់ផ្ដើមមុខងារភាពងាយប្រើបច្ចុប្បន្ន"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"ចុចគ្រាប់ចុចកម្រិតសំឡេងទាំងពីរឱ្យជាប់រយៈពេលបីវិនាទី ដើម្បីប្រើ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ជ្រើសរើសមុខងារដែលត្រូវប្រើ នៅពេលដែលអ្នកចុចប៊ូតុងភាពងាយស្រួល៖"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ដើម្បីផ្លាស់ប្តូរមុខងារ សូមចុចប៊ូតុងភាពងាយស្រួលឲ្យជាប់។"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ការពង្រីក"</string>
@@ -1977,5 +1981,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"កាមេរ៉ា"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"មីក្រូហ្វូន"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"កំពុងបង្ហាញពីលើកម្មវិធីផ្សេងទៀតនៅលើអេក្រង់របស់អ្នក"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"កំពុងផ្ទុក"</string>
</resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 835070a..d6cde26 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"ಇದರ ಮೂಲಕ ತೆರೆಯಿರಿ"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ಜೊತೆಗೆ ತೆರೆಯಿರಿ"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"ತೆರೆ"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ಮೂಲಕ <xliff:g id="HOST">%1$s</xliff:g> ಲಿಂಕ್ಗಳನ್ನು ತೆರೆಯಲು ಪ್ರವೇಶವನ್ನು ನೀಡಿ"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> ಮೂಲಕ <xliff:g id="HOST">%1$s</xliff:g> ಲಿಂಕ್ಗಳನ್ನು ತೆರೆಯಲು ಪ್ರವೇಶವನ್ನು ನೀಡಿ"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ಪ್ರವೇಶ ಅನುಮತಿಸಿ"</string>
<string name="whichEditApplication" msgid="144727838241402655">"ಇವರ ಜೊತೆಗೆ ಎಡಿಟ್ ಮಾಡಿ"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ಜೊತೆಗೆ ಎಡಿಟ್ ಮಾಡಿ"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"ಎಡಿಟ್"</string>
@@ -1567,6 +1570,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"ಕರೆ ಸ್ವೀಕರಿಸುವುದೇ?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"ಯಾವಾಗಲೂ"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"ಒಮ್ಮೆ ಮಾತ್ರ"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ಟ್ಯಾಬ್ಲೆಟ್"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ಟಿವಿ"</string>
@@ -1646,7 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"ಬಣ್ಣ ತಿದ್ದುಪಡಿ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್ಕಟ್, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಆನ್ ಮಾಡಿದೆ"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್ಕಟ್, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಆಫ್ ಮಾಡಿದೆ"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ಪ್ರಸ್ತುತ ಪ್ರವೇಶದ ವೈಶಿಷ್ಟ್ಯವನ್ನು ಪ್ರಾರಂಭಿಸಲು ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್ಕಟ್ ಅನ್ನು ಪುನಃ ಬಳಸಿ"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಬಳಸಲು ಎರಡೂ ಧ್ವನಿ ಕೀಗಳನ್ನು ಮೂರು ಸೆಕೆಂಡ್ಗಳ ಕಾಲ ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ನೀವು ಪ್ರವೇಶಿಸುವಿಕೆ ಬಟನ್ ಟ್ಯಾಪ್ ಮಾಡಿದಾಗ ಬಳಸುವುದಕ್ಕಾಗಿ ವೈಶಿಷ್ಟ್ಯವನ್ನು ಆರಿಸಿ:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಬದಲಾಯಿಸಲು, ಪ್ರವೇಶಿಸುವಿಕೆ ಬಟನ್ ಒತ್ತಿಹಿಡಿದುಕೊಳ್ಳಿ."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ಹಿಗ್ಗಿಸುವಿಕೆ"</string>
@@ -1976,5 +1980,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"ಕ್ಯಾಮರಾ"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"ಮೈಕ್ರೋಫೋನ್"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ನಲ್ಲಿ ಇತರ ಅಪ್ಲಿಕೇಶನ್ಗಳ ಮೂಲಕ ಪ್ರದರ್ಶಿಸಲಾಗುತ್ತಿದೆ"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"ಲೋಡ್ ಆಗುತ್ತಿದೆ"</string>
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 8886815..05ab555 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"연결 프로그램"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s(으)로 열기"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"열기"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"다음으로 <xliff:g id="HOST">%1$s</xliff:g> 링크를 열려면 액세스 권한 부여"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g>(으)로 <xliff:g id="HOST">%1$s</xliff:g> 링크를 열려면 액세스 권한 부여"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"권한 부여"</string>
<string name="whichEditApplication" msgid="144727838241402655">"편집 프로그램:"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s(으)로 수정"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"수정"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"통화를 수락하시겠습니까?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"항상"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"한 번만"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"설정"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s에서 직장 프로필을 지원하지 않습니다."</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"태블릿"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"색상 보정"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"접근성 단축키로 인해 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>이(가) 사용 설정되었습니다."</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"접근성 단축키로 인해 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>이(가) 사용 중지되었습니다."</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"현재 접근성 기능을 시작하려면 접근성 단축키를 다시 사용하세요"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> 서비스를 사용하려면 두 볼륨 키를 3초 동안 길게 누르세요"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"접근성 버튼을 탭할 때 사용할 기능을 선택하세요."</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"기능을 변경하려면 접근성 버튼을 길게 터치하세요."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"확대"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"카메라"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"마이크"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"화면에서 다른 앱 위에 표시"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"로드 중"</string>
</resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index de49741..88f0ef2 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Төмөнкү менен ачуу"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s менен ачуу"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ачуу"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Төмөнкү колдонмо менен <xliff:g id="HOST">%1$s</xliff:g> шилтемелерин ачууга уруксат берүү"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> колдонмосу менен <xliff:g id="HOST">%1$s</xliff:g> шилтемелерин ачууга уруксат берүү"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Мүмкүнчүлүк берүү"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Төмөнкү менен түзөтүү"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s менен түзөтүү"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Түзөтүү"</string>
@@ -1568,6 +1571,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Чалуу кабыл алынсынбы?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Дайыма"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Бир жолу гана"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Жөндөөлөр"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s жумуш профилин колдоого албайт"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Планшет"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Сыналгы"</string>
@@ -1647,7 +1651,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Түсүн тууралоо"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Атайын мүмкүнчүлүктөр кыска жолу <xliff:g id="SERVICE_NAME">%1$s</xliff:g> кызматын күйгүздү"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Атайын мүмкүнчүлүктөр кыска жолу <xliff:g id="SERVICE_NAME">%1$s</xliff:g> кызматын өчүрдү"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Учурдагы атайын мүмкүнчүлүктөр функциясын иштетүү үчүн кыска жолду кайра колдонуңуз"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> кызматын колдонуу үчүн үнүн чоңойтуп/кичирейтүү баскычтарын үч секунд коё бербей басып туруңуз"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Атайын мүмкүнчүлүктөр баскычын таптаганыңызда иштетиле турган функцияны тандаңыз:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Функцияларды өзгөртүү үчүн Атайын мүмкүнчүлүктөр баскычын басып, кармап туруңуз."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Чоңойтуу"</string>
@@ -1977,5 +1981,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Микрофон"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"экрандагы башка терезелердин үстүнөн көрсөтүлүүдө"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Жүктөлүүдө"</string>
</resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 9356302..7a5ab96 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"ເປີດໂດຍໃຊ້"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"ເປີດໂດຍໃຊ້ %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"ເປີດ"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ໃຫ້ສິດອະນຸຍາດເພື່ອເປີດລິ້ງ <xliff:g id="HOST">%1$s</xliff:g> ດ້ວຍ"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"ໃຫ້ສິດອະນຸຍາດເພື່ອເປີດລິ້ງ <xliff:g id="HOST">%1$s</xliff:g> ດ້ວຍ <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ໃຫ້ສິດອະນຸຍາດ"</string>
<string name="whichEditApplication" msgid="144727838241402655">"ແກ້ໄຂໃນ"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"ແກ້ໄຂໃນ %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"ແກ້ໄຂ"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"ຮັບການໂທບໍ່?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"ທຸກຄັ້ງ"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"ຄັ້ງດຽວ"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ການຕັ້ງຄ່າ"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ບໍ່ຮອງຮັບໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຂອງທ່ານ"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ແທັບເລັດ"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ໂທລະພາບ"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"ການແກ້ໄຂຄ່າສີ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ໃຊ້ປຸ່ມລັດການຊ່ວຍເຂົ້າເຖິງອີກເທື່ອໜຶ່ງເພື່ອຊອກຫາຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງໃນປັດຈຸບັນ"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"ກົດປຸ່ມສຽງທັງສອງພ້ອມກັນຄ້າງໄວ້ສາມວິນາທີເພື່ອໃຊ້ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ເລືອກຄຸນສົມບັດທີ່ຈະໃຊ້ເມື່ອທ່ານແຕະປຸ່ມການຊ່ວຍເຂົ້າເຖິງ:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ເພື່ອປ່ຽນຄຸນສົມບັດ, ໃຫ້ແຕະປຸ່ມການຊ່ວຍເຂົ້າເຖິງຄ້າງໄວ້."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ການຂະຫຍາຍ"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"ກ້ອງ"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"ໄມໂຄຣໂຟນ"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"ສະແດງຜົນບັງແອັບອື່ນຢູ່ໜ້າຈໍຂອງທ່ານ"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"ກຳລັງໂຫລດ"</string>
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 8870ebb..90ed406 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1168,6 +1168,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Atidaryti naudojant"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Atidaryti naudojant %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Atidaryti"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Suteikite prieigą atidaryti <xliff:g id="HOST">%1$s</xliff:g> nuorodas naudojant"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Suteikite prieigą atidaryti <xliff:g id="HOST">%1$s</xliff:g> nuorodas naudojant „<xliff:g id="APPLICATION">%2$s</xliff:g>“"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Suteikti prieigą"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Redaguoti naudojant"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redaguoti naudojant %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Redaguoti"</string>
@@ -1612,6 +1615,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Priimti skambutį?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Visada"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Tik kartą"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Nustatymai"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s nepalaiko darbo profilio"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Planšetinis kompiuteris"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1693,7 +1697,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Spalvų taisymas"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pritaikymo neįgaliesiems sparčiuoju klavišu buvo įjungta „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pritaikymo neįgaliesiems sparčiuoju klavišu buvo išjungta „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Norėdami įjungti dabartinę pritaikymo neįgaliesiems funkciją, dar kartą naudokite spartųjį pritaikymo neįgaliesiems klavišą"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Jei norite naudoti „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“, paspauskite abu garsumo klavišus ir palaikykite tris sekundes"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Pasirinkite funkciją, kuri bus naudojama, kai paliesite pritaikymo neįgaliesiems mygtuką:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Jei norite pakeisti funkcijas, palieskite ir palaikykite pritaikymo neįgaliesiems mygtuką."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Didinimas"</string>
@@ -2045,5 +2049,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Fotoaparatas"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofonas"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"rodo virš kitų programų jūsų ekrane"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Įkeliama"</string>
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 5a1432b..e58b462 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1148,6 +1148,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Atvērt, izmantojot"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Atvērt, izmantojot %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Atvērt"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Piekļuves piešķiršana, lai atvērtu <xliff:g id="HOST">%1$s</xliff:g> saites lietojumprogrammā"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Piekļuves piešķiršana, lai atvērtu <xliff:g id="HOST">%1$s</xliff:g> saites lietojumprogrammā <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Atļaut piekļuvi"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Rediģēt, izmantojot"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Rediģēt, izmantojot %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Rediģēt"</string>
@@ -1589,6 +1592,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Vai atbildēt uz zvanu?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Vienmēr"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Tikai vienreiz"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Iestatījumi"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Programma %1$s neatbalsta darba profilus"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Planšetdators"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1669,7 +1673,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Krāsu korekcija"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pieejamības saīsne aktivizēja lietotni <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pieejamības saīsne deaktivizēja lietotni <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Lai sāktu izmantot pašreizējo pieejamības funkciju, vēlreiz izmantojiet pieejamības saīsni."</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Lai izmantotu pakalpojumu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, nospiediet abus skaļuma taustiņus un turiet tos trīs sekundes."</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Izvēlieties funkciju, ko izmantot, kad pieskaraties pogai Pieejamība."</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Lai mainītu funkcijas, pieskarieties pogai Pieejamība un turiet to."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Palielinājums"</string>
@@ -2010,5 +2014,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofons"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"rāda pāri citām lietotnēm jūsu ekrānā"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Ielāde"</string>
</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 769ac43..8bede29 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Отвори со"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Отвори со %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Отвори"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Дајте пристап да се отвораат линкови на <xliff:g id="HOST">%1$s</xliff:g> со"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Дајте пристап да се отвораат линкови на <xliff:g id="HOST">%1$s</xliff:g> со <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Дозволи пристап"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Измени со"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Измени со %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Измени"</string>
@@ -1569,6 +1572,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Прифати повик?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Секогаш"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Само еднаш"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Поставки"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не поддржува работен профил"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Таблет"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Телевизор"</string>
@@ -1648,7 +1652,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Корекција на бои"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Кратенката за пристапност ја вклучи <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Кратенката за пристапност ја исклучи <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Повторно употребете ја кратенката за пристапност за да ја стартувате тековната функција за пристапност"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Притиснете ги и задржете ги двете копчиња за јачина на звукот во траење од три секунди за да користите <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Изберете функција за користење кога ќе го допрете копчето за „Пристапност“."</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"За променување функции, допрете го и задржете го копчето за „Пристапност“."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Зголемување"</string>
@@ -1978,5 +1982,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Микрофон"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"се прикажува преку други апликации на вашиот екран"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Известување за информации за режимот за рутини"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Батеријата може да се потроши пред вообичаеното време за полнење"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Активиран е „Штедачот на батерија“ за да се продолжи траењето на батеријата"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Се вчитува"</string>
</resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 620718d..190341b 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"ഇത് ഉപയോഗിച്ച് തുറക്കുക"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ഉപയോഗിച്ച് തുറക്കുക"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"തുറക്കുക"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ഇനിപ്പറയുന്നത് ഉപയോഗിച്ച്, <xliff:g id="HOST">%1$s</xliff:g> ലിങ്കുകൾ തുറക്കാൻ ആക്സസ് നൽകുക"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> ഉപയോഗിച്ച്, <xliff:g id="HOST">%1$s</xliff:g> ലിങ്കുകൾ തുറക്കാൻ ആക്സസ് നൽകുക"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ആക്സസ് നൽകുക"</string>
<string name="whichEditApplication" msgid="144727838241402655">"ഇത് ഉപയോഗിച്ച് എഡിറ്റുചെയ്യുക"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ഉപയോഗിച്ച് എഡിറ്റുചെയ്യുക"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"എഡിറ്റുചെയ്യുക"</string>
@@ -1567,6 +1570,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"കോൾ സ്വീകരിക്കണോ?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"എല്ലായ്പ്പോഴും"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"ഒരിക്കൽ മാത്രം"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ക്രമീകരണം"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s, ഔദ്യോഗിക പ്രൊഫൈലിനെ പിന്തുണയ്ക്കുന്നില്ല"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ടാബ്ലെറ്റ്"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ടിവി"</string>
@@ -1646,7 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"വർണ്ണം ക്രമീകരിക്കൽ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ഉപയോഗസഹായിക്കുള്ള കുറുക്കുവഴി <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഓൺ ചെയ്തിരിക്കുന്നു"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ഉപയോഗസഹായിക്കുള്ള കുറുക്കുവഴി <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഓഫ് ചെയ്തിരിക്കുന്നു"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"നിലവിലെ ഉപയോഗസഹായി ഫീച്ചർ ആരംഭിക്കാൻ വീണ്ടും ഉപയോഗസഹായി കുറുക്കുവഴി ഉപയോഗിക്കുക"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഉപയോഗിക്കാൻ, രണ്ട് വോളിയം കീകളും മൂന്ന് സെക്കൻഡ് അമർത്തിപ്പിടിക്കുക"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"നിങ്ങൾ ഉപയോഗസഹായി ബട്ടൺ ടാപ്പുചെയ്യുമ്പോൾ ഉപയോഗിക്കുന്നതിന് ഒരു ഫീച്ചർ തിരഞ്ഞെടുക്കുക:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ഫീച്ചറുകൾ മാറ്റുന്നതിന് ഉപയോഗസഹായി ബട്ടൺ സ്പർശിച്ചുപിടിക്കുക."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"മാഗ്നിഫിക്കേഷൻ"</string>
@@ -1976,5 +1980,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"ക്യാമറ"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"മൈക്രോഫോൺ"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"നിങ്ങളുടെ സ്ക്രീനിലെ മറ്റ് ആപ്പുകൾക്ക് മുകളിൽ പ്രദർശിപ്പിക്കുന്നു"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"ലോഡ് ചെയ്യുന്നു"</string>
</resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index c0b23fc..f22974d 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Нээх"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ашиглан нээх"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Нээх"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"<xliff:g id="HOST">%1$s</xliff:g>-н холбоосыг дараахаар нээх хандалт өгөх"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="HOST">%1$s</xliff:g>-н холбоосыг <xliff:g id="APPLICATION">%2$s</xliff:g>-р нээх хандалт өгөх"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Хандалт өгөх"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Засварлах"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ашиглан засварлах"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Засах"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Дуудлагыг зөвшөөрөх үү?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Байнга"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Нэг удаа"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Тохиргоо"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ажлын профайлыг дэмждэггүй"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Таблет"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Tелевиз"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Өнгөний засвар"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Хүртээмжийн товчлол <xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г асаасан"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Хүртээмжийн товчлол <xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г унтраасан"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Одоогийн хүртээмжит онцлогийг эхлүүлэхийн тулд нэвтрэлтийн товчлолыг ашиглах"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г ашиглахын тулд дууны түвшнийг ихэсгэх, багасгах түлхүүрийг 3 секундийн турш зэрэг дарна уу"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Хүртээмжийн товчлуурыг товших үедээ ашиглах онцлогийг сонгоно уу:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Онцлогийг өөрчлөхийн тулд Хүртээмжийн товчлуурыг дараад хүлээнэ үү."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Томруулах"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Камер"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Микрофон"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"таны дэлгэцэд бусад аппын дээр харуулж байна"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Ачаалж байна"</string>
</resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index f3d6b4b..1792887 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"यासह उघडा"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s सह उघडा"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"उघडा"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"सह <xliff:g id="HOST">%1$s</xliff:g> लिंक उघडण्याचा अॅक्सेस द्या"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> सह <xliff:g id="HOST">%1$s</xliff:g> लिंक उघडण्याचा अॅक्सेस द्या"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"अॅक्सेस द्या"</string>
<string name="whichEditApplication" msgid="144727838241402655">"सह संपादित करा"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s सह संपादित करा"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"संपादित करा"</string>
@@ -1567,6 +1570,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"कॉल स्वीकारायचा?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"नेहमी"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"फक्त एकदाच"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"सेटिंग्ज"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s कार्य प्रोफाईलचे समर्थन करीत नाही"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"टॅबलेट"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"टीव्ही"</string>
@@ -1646,7 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"रंग सुधारणा"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"प्रवेशयोग्यता शॉर्टकटने <xliff:g id="SERVICE_NAME">%1$s</xliff:g> चालू केली"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"प्रवेशयोग्यता शॉर्टकटने <xliff:g id="SERVICE_NAME">%1$s</xliff:g> बंद केली"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"सध्याचे अॅक्सेसिबिलिटी वैशिष्ट्य पुन्हा सुरू करण्यासाठी अॅक्सेसिबिलिटी शॉर्टकट वापरा"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> वापरण्यासाठी दोन्ही व्हॉल्युम की तीन सेकंद दाबा आणि धरून ठेवा"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"तुम्ही प्रवेशयोग्यता बटण दाबल्यावर वापरण्यासाठी वैशिष्ट्य निवडा:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"वैशिष्ट्ये बदलण्यासाठी, प्रवेशयोग्यता बटणाला स्पर्श करा आणि धरून ठेवा."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"मोठे करणे"</string>
@@ -1976,5 +1980,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"कॅमेरा"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"मायक्रोफोन"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"तुमच्या स्क्रीनवर इतर अॅप्सवर डिस्प्ले करत आहे"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"लोड होत आहे"</string>
</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 0eb022a..1055ca6 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Buka dengan"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Buka dengan %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Buka"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Berikan akses untuk membuka pautan <xliff:g id="HOST">%1$s</xliff:g> dengan"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Berikan akses untuk membuka pautan <xliff:g id="HOST">%1$s</xliff:g> dengan <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Berikan akses"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Edit dengan"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit dengan %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edit"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Terima panggilan?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Sentiasa"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Hanya sekali"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Tetapan"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s tidak menyokong profil kerja"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Pembetulan Warna"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pintasan kebolehaksesan menghidupkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pintasan Kebolehaksesan mematikan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Gunakan Pintasan Kebolehaksesan sekali lagi untuk memulakan ciri kebolehaksesan semasa"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Tekan dan tahan kedua-dua kekunci kelantangan selama tiga saat untuk menggunakan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Pilih ciri yang hendak digunakan apabila anda mengetik butang Kebolehaksesan:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Untuk menukar ciri, sentuh & tahan butang Kebolehaksesan."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Pembesaran"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"dipaparkan di atas apl lain pada skrin anda"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Memuatkan"</string>
</resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 1c5f0c7..651affc 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"...ဖြင့် ဖွင့်မည်"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ဖြင့် ဖွင့်မည်"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"ဖွင့်ပါ"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"<xliff:g id="HOST">%1$s</xliff:g> လင့်ခ်များကို အောက်ပါဖြင့် ဖွင့်ခွင့်ပေးပါ-"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="HOST">%1$s</xliff:g> လင့်ခ်များကို <xliff:g id="APPLICATION">%2$s</xliff:g> ဖြင့် ဖွင့်ခွင့်ပေးပါ"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ဖွင့်ခွင့်ပေးရန်"</string>
<string name="whichEditApplication" msgid="144727838241402655">"...နှင့် တည်းဖြတ်ရန်"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s နှင့် တည်းဖြတ်ရန်"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"တည်းဖြတ်ပါ"</string>
@@ -1567,6 +1570,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"ဖုန်းခေါ်ဆိုမှုကို လက်ခံမလား?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"အမြဲတမ်း"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"တစ်ခါတည်း"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ဆက်တင်များ"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s က အလုပ်ပရိုဖိုင်ကို မပံ့ပိုးပါ။"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"တက်ဘလက်"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"တီဗွီ"</string>
@@ -1646,7 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"အရောင်ပြင်ဆင်ခြင်း"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"အများသုံးစွဲနိုင်မှု ဖြတ်လမ်းလင့်ခ်သည် <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ကို ဖွင့်လိုက်ပါသည်"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"အများသုံးစွဲနိုင်မှု ဖြတ်လမ်းလင့်ခ်သည် <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ကို ပိတ်လိုက်ပါသည်"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"လက်ရှိ အသုံးလွယ်ရေး ဝန်ဆောင်မှုကို စတင်ရန် အသုံးလွယ်ရေး ဖြတ်လမ်းလင့်ခ်ကို သုံးပါ"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ကို သုံးရန် အသံအတိုးအလျှော့ ခလုတ်နှစ်ခုလုံးကို သုံးစက္ကန့်ကြာ ဖိထားပါ"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"အများသုံးစွဲနိုင်မှု ခလုတ်ကို တို့သည့်အခါ အသုံးပြုမည့် ဝန်ဆောင်မှုကို ရွေးချယ်ပါ−"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ဝန်ဆောင်မှုများကို ပြောင်းလဲရန် အများသုံးစွဲနိုင်မှု ခလုတ်ကို တို့၍ ထိထားပါ။"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ချဲ့ခြင်း"</string>
@@ -1976,5 +1980,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"ကင်မရာ"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"မိုက်ခရိုဖုန်း"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"သင့်မျက်နှာပြင်ပေါ်ရှိ အခြားအက်ပ်များပေါ်တွင် ပြသခြင်း"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"ပုံမှန်မုဒ်အတွက် အချက်အလက်ပြသည့် အကြောင်းကြားချက်"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"ပုံမှန်အားသွင်းမှုမပြုလုပ်မီ ဘက်ထရီကုန်သွားနိုင်သည်"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"ဘက်ထရီသက်တမ်းကို တိုးမြှင့်ရန် \'ဘက်ထရီအားထိန်း\' စတင်ပြီးပါပြီ"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"တင်နေသည်"</string>
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 233b98a..1f70767 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Åpne med"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Åpne med %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Åpne"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Gi tilgang til å åpne <xliff:g id="HOST">%1$s</xliff:g>-linker med"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Gi tilgang til å åpne <xliff:g id="HOST">%1$s</xliff:g>-linker med <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Gi tilgang"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Rediger med"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Rediger med %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Endre"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Vil du besvare anropet?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Alltid"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Bare én gang"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Innstillinger"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s støtter ikke arbeidsprofiler"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Nettbrett"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Google TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Fargekorrigering"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Snarveien for tilgjengelighet slo på <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Snarveien for tilgjengelighet slo av <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Bruk tilgjengelighetssnarveien igjen for å starte den nåværende tilgjengelighetsfunksjonen"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Trykk og hold inne begge volumtastene i tre sekunder for å bruke <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Velg en funksjon du vil bruke når du trykker på Tilgjengelighet-knappen:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"For å endre funksjoner, trykk på og hold inne Tilgjengelighet-knappen."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Forstørring"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"vises over andre apper på skjermen"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Laster inn"</string>
</resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 0b2362a..d278fbe 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1132,6 +1132,9 @@
<!-- no translation found for whichViewApplicationNamed (2286418824011249620) -->
<skip />
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"खोल्नुहोस्"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"निम्नमार्फत <xliff:g id="HOST">%1$s</xliff:g>का लिंकहरू खोल्न पहुँच दिनुहोस्"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g>मार्फत <xliff:g id="HOST">%1$s</xliff:g>का लिंकहरू खोल्न पहुँच दिनुहोस्"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"पहुँच दिनुहोस्"</string>
<string name="whichEditApplication" msgid="144727838241402655">"सँग सम्पादन गर्नुहोस्"</string>
<!-- String.format failed for translation -->
<!-- no translation found for whichEditApplicationNamed (1775815530156447790) -->
@@ -1572,6 +1575,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"कल स्वीकार गर्नुहुन्छ?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"सधैँ"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"एक पटक मात्र"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"सेटिङहरू"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s कार्य प्रोफाइल समर्थन गर्दैन"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ट्याब्लेट"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1651,7 +1655,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"रङ सच्याउने सुविधा"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"पहुँचको सर्टकटले <xliff:g id="SERVICE_NAME">%1$s</xliff:g> लाई सक्रिय पार्यो"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"पहुँचको सर्टकटले <xliff:g id="SERVICE_NAME">%1$s</xliff:g> लाई निष्क्रिय पार्यो"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"हालको पहुँचसम्बन्धी सुविधा प्रयोग गर्न फेरि पहुँचसम्बन्धी सर्टकट प्रयोग गर्नुहोस्"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> प्रयोग गर्न दुवै भोल्युम कुञ्जीहरूलाई तीन सेकेन्डसम्म थिचिराख्नुहोस्"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"तपाईंले पहुँच सम्बन्धी बटनलाई ट्याप गर्दा प्रयोग गर्नुपर्ने सुविधा रोज्नुहोस्:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"सुविधाहरूलाई बदल्न, पहुँच सम्बन्धी बटनलाई छोएर थिची राख्नुहोस्।"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"म्याग्निफिकेसन"</string>
@@ -1981,5 +1985,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"क्यामेरा"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"माइक्रोफोन"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"तपाईंको स्क्रिनका अन्य अनुप्रयोगहरूमा प्रदर्शन गरिँदै छ"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"लोड गर्दै"</string>
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 996b700..752fbc2 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Openen met"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Openen met %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Openen"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Toegang verlenen om links naar <xliff:g id="HOST">%1$s</xliff:g> te openen met"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Toegang verlenen om links naar <xliff:g id="HOST">%1$s</xliff:g> te openen met <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Toegang geven"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Bewerken met"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Bewerken met %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Bewerken"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Gesprek accepteren?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Altijd"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Één keer"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Instellingen"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ondersteunt werkprofielen niet"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Tv"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Kleurcorrectie"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"\'Snelle link voor toegankelijkheid\' heeft <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ingeschakeld"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"\'Snelle link voor toegankelijkheid\' heeft <xliff:g id="SERVICE_NAME">%1$s</xliff:g> uitgeschakeld"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Gebruik de snelkoppeling voor toegankelijkheid nogmaals om de huidige toegankelijkheidsfunctie te starten"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Houd beide volumetoetsen drie seconden ingedrukt om <xliff:g id="SERVICE_NAME">%1$s</xliff:g> te gebruiken"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Kies een functie om te gebruiken wanneer je op de knop Toegankelijkheid tikt:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Als je functies wilt wijzigen, tik je op de knop Toegankelijkheid en houd je deze vast."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Vergroting"</string>
@@ -1975,5 +1979,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Camera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microfoon"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"wordt weergegeven vóór andere apps op je scherm"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Informatiemelding voor routinemodus"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"De batterij raakt mogelijk leeg voordat deze normaal gesproken wordt opgeladen"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Batterijbesparing is geactiveerd om de batterijduur te verlengen"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Laden"</string>
</resources>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 27b7d5d..f2c0f62 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"ସହିତ ଖୋଲନ୍ତୁ"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ସହିତ ଖୋଲନ୍ତୁ"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"ଖୋଲନ୍ତୁ"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ଏହା ସହିତ ଲିଙ୍କ ଥିବା <xliff:g id="HOST">%1$s</xliff:g> ଖୋଲିବା ପାଇଁ ଆକ୍ସେସ୍ ଦିଅନ୍ତୁ"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> ସହିତ ଲିଙ୍କ ଥିବା <xliff:g id="HOST">%1$s</xliff:g> ଖୋଲିବା ପାଇଁ ଆକ୍ସେସ୍ ଦିଅନ୍ତୁ"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ଆକ୍ସେସ୍ ଦିଅନ୍ତୁ"</string>
<string name="whichEditApplication" msgid="144727838241402655">"ସହିତ ଏଡିଟ୍ କରନ୍ତୁ"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sରେ ସଂଶୋଧନ କରନ୍ତୁ"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"ଏଡିଟ୍ କରନ୍ତୁ"</string>
@@ -1567,6 +1570,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"କଲ୍ ସ୍ୱୀକାର କରିବେ?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"ସର୍ବଦା"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"ଥରେ ମାତ୍ର"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ସେଟିଂସ୍"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ୱର୍କ ପ୍ରୋଫାଇଲ୍କୁ ସପୋର୍ଟ କରୁନାହିଁ"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ଟାବଲେଟ୍"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1646,7 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"ରଙ୍ଗ ସଂଶୋଧନ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ଆକ୍ସେସିବିଲିଟୀ ଶର୍ଟକଟ୍ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ଅନ୍ କରାଯାଇଛି"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ଆକ୍ସେସିବିଲିଟୀ ଶର୍ଟକଟ୍ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ଅଫ୍ କରାଯାଇଛି"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ବର୍ତ୍ତମାନର ଆକ୍ସେସିବିଲିଟୀ ବୈଶିଷ୍ଟ୍ୟ ଆରମ୍ଭ କରିବାକୁ ପୁଣି ଆକ୍ସେସିବିଲିଟୀ ସର୍ଟ୍କର୍ଟ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ବ୍ୟବହାର କରିବାକୁ ତିନି ସେକେଣ୍ଡ ପାଇଁ ଉଭୟ ଭଲ୍ୟୁମ୍ କୀ ଦବାଇ ଧରି ରଖନ୍ତୁ"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ଆପଣ ଆକ୍ସେସବିଲିଟି ବଟନ୍ ଟାପ୍ କରିବା ବେଳେ ଏକ ବୈଶିଷ୍ଟ୍ୟ ବ୍ୟବହାର କରିବାକୁ ବାଛନ୍ତୁ:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ବୈଶିଷ୍ଟ୍ୟ ବଦଳାଇବାକୁ, ଆକ୍ସେସବିଲିଟି ବଟନ୍ ସ୍ପର୍ଶ କରନ୍ତୁ ଓ ଧରିରଖନ୍ତୁ।"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ମ୍ୟାଗ୍ନିଫିକେସନ୍"</string>
@@ -1976,5 +1980,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"କ୍ୟାମେରା"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"ମାଇକ୍ରୋଫୋନ୍"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"ଆପଣଙ୍କ ସ୍କ୍ରୀନ୍ ଉପରେ ଥିବା ଅନ୍ୟ ଆପ୍ ଉପରେ ଦେଖାଦେବ"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"ଲୋଡ୍ ହେଉଛି"</string>
</resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index eacf006..266b226 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"ਨਾਲ ਖੋਲ੍ਹੋ"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ਨਾਲ ਖੋਲ੍ਹੋ"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"ਖੋਲ੍ਹੋ"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ਇਸ ਨਾਲ <xliff:g id="HOST">%1$s</xliff:g> ਲਿੰਕਾਂ ਨੂੰ ਖੋਲ੍ਹਣ ਦੀ ਪਹੁੰਚ ਦਿਓ"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> ਨਾਲ <xliff:g id="HOST">%1$s</xliff:g> ਲਿੰਕਾਂ ਨੂੰ ਖੋਲ੍ਹਣ ਦੀ ਪਹੁੰਚ ਦਿਓ"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ਪਹੁੰਚ ਦਿਓ"</string>
<string name="whichEditApplication" msgid="144727838241402655">"ਇਸ ਨਾਲ ਸੰਪਾਦਨ ਕਰੋ"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ਨਾਲ ਸੰਪਾਦਨ ਕਰੋ"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"ਸੰਪਾਦਨ ਕਰੋ"</string>
@@ -1567,6 +1570,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"ਕੀ ਕਾਲ ਸਵੀਕਾਰ ਕਰਨੀ ਹੈ?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"ਹਮੇਸ਼ਾਂ"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"ਕੇਵਲ ਇੱਕ ਵਾਰ"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ਸੈਟਿੰਗਾਂ"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ਟੈਬਲੈੱਟ"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1646,7 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"ਰੰਗ ਸੁਧਾਈ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ ਨੇ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਚਾਲੂ ਕੀਤਾ"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ ਨੇ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਬੰਦ ਕੀਤਾ"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ਮੌਜੂਦਾ ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਲਈ \'ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ\' ਦੀ ਦੁਬਾਰਾ ਵਰਤੋਂ ਕਰੋ"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਦੋਵੇਂ ਅਵਾਜ਼ ਕੁੰਜੀਆਂ ਨੂੰ 3 ਸਕਿੰਟਾਂ ਲਈ ਦਬਾਈ ਰੱਖੋ"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ਤੁਹਾਡੇ ਵੱਲੋਂ ਪਹੁੰਚਯੋਗਤਾ ਬਟਨ ਨੂੰ ਟੈਪ ਕੀਤੇ ਜਾਣ \'ਤੇ ਵਰਤਣ ਲਈ ਕੋਈ ਵਿਸ਼ੇਸ਼ਤਾ ਚੁਣੋ:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬਦਲਣ ਲਈ, ਪਹੁੰਚਯੋਗਤਾ ਬਟਨ ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾਈ ਰੱਖੋ।"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ਵੱਡਦਰਸ਼ੀਕਰਨ"</string>
@@ -1976,5 +1980,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"ਕੈਮਰਾ"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ \'ਤੇ ਹੋਰਾਂ ਐਪਾਂ ਉੱਪਰ ਦਿਖਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index b2bb7b0..a86d5a6 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1168,6 +1168,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Otwórz w aplikacji"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otwórz w aplikacji %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otwórz"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Przyznaj uprawnienia do otwierania linków z <xliff:g id="HOST">%1$s</xliff:g> w:"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Przyznaj uprawnienia do otwierania linków z <xliff:g id="HOST">%1$s</xliff:g> w aplikacji <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Udziel uprawnień"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Edytuj w aplikacji"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edytuj w aplikacji %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edytuj"</string>
@@ -1612,6 +1615,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Odebrać połączenie?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Zawsze"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Tylko raz"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ustawienia"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s nie obsługuje profilu do pracy"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Telewizor"</string>
@@ -1693,7 +1697,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Korekcja kolorów"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Skrót ułatwień dostępu wyłączył usługę <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Skrót ułatwień dostępu wyłączył usługę <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Użyj ponownie skrótu ułatwień dostępu, by uruchomić bieżące ułatwienie dostępu"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Naciśnij i przytrzymaj oba przyciski głośności przez trzy sekundy, by użyć usługi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Wybierz funkcję używaną po kliknięciu przycisku ułatwień dostępu."</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Aby zmienić funkcje, kliknij i przytrzymaj przycisk ułatwień dostępu."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Powiększenie"</string>
@@ -2045,5 +2049,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Aparat"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"wyświetla się nad innymi aplikacjami na ekranie"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Powiadomienie z informacją o trybie rutynowym"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Bateria może się wyczerpać przed zwykłą porą ładowania"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Włączono Oszczędzanie baterii, by wydłużyć czas pracy na baterii"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Ładuję"</string>
</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index b1a1d39..44f8478 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Abrir com"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir com %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Conceder acesso para abrir links de <xliff:g id="HOST">%1$s</xliff:g> com"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Conceder acesso para abrir links de <xliff:g id="HOST">%1$s</xliff:g> com o app <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Conceder acesso"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Editar com"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar com %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Editar"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Aceitar chamada?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Só uma vez"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configurações"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s não aceita perfis de trabalho"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Correção de cor"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O atalho de acessibilidade ativou o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"O atalho de acessibilidade desativou o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use o atalho de acessibilidade novamente para iniciar o recurso de acessibilidade atual"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Toque nos dois botões de volume e os mantenha pressionados por três segundo para usar o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Escolha um recurso a ser usado ao tocar no botão Acessibilidade:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para alterar os recursos, mantenha o botão Acessibilidade pressionado."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliação"</string>
@@ -1975,5 +1979,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Câmera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microfone"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"exibindo sobre outros apps na sua tela"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notificação de informação do modo rotina"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"A bateria pode acabar antes da recarga normal"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"A \"Economia de bateria\" foi ativada para aumentar a duração da carga"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Carregando"</string>
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index ec4cf8c..f7ffa1d 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Abrir com"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir com %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Conceda acesso para abrir links de <xliff:g id="HOST">%1$s</xliff:g> com"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Conceda acesso para abrir links de <xliff:g id="HOST">%1$s</xliff:g> com a aplicação <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Conceder acesso"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Editar com"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar com %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Editar"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Aceitar chamada?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Apenas uma vez"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Definições"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s não suporta o perfil de trabalho"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Correção da cor"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O Atalho de acessibilidade ativou o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"O Atalho de acessibilidade desativou o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Utilize novamente o atalho de acessibilidade para iniciar a funcionalidade de acessibilidade atual."</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Prima sem soltar as teclas de volume durante três segundos para utilizar o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Escolha uma funcionalidade para utilizar quando tocar no botão Acessibilidade:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para alterar as funcionalidades, toque sem soltar no botão Acessibilidade."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliação"</string>
@@ -1975,5 +1979,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Câmara"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microfone"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"sobrepõe-se a outras aplicações no ecrã"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notificação de informações do Modo rotina"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Pode ficar sem bateria antes do carregamento habitual"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Poupança de bateria ativada para prolongar a duração da bateria"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"A carregar…"</string>
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index b1a1d39..44f8478 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Abrir com"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir com %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Conceder acesso para abrir links de <xliff:g id="HOST">%1$s</xliff:g> com"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Conceder acesso para abrir links de <xliff:g id="HOST">%1$s</xliff:g> com o app <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Conceder acesso"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Editar com"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar com %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Editar"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Aceitar chamada?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Só uma vez"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configurações"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s não aceita perfis de trabalho"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Correção de cor"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O atalho de acessibilidade ativou o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"O atalho de acessibilidade desativou o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use o atalho de acessibilidade novamente para iniciar o recurso de acessibilidade atual"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Toque nos dois botões de volume e os mantenha pressionados por três segundo para usar o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Escolha um recurso a ser usado ao tocar no botão Acessibilidade:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para alterar os recursos, mantenha o botão Acessibilidade pressionado."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliação"</string>
@@ -1975,5 +1979,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Câmera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microfone"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"exibindo sobre outros apps na sua tela"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notificação de informação do modo rotina"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"A bateria pode acabar antes da recarga normal"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"A \"Economia de bateria\" foi ativada para aumentar a duração da carga"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Carregando"</string>
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 5b36b9a..f3303c4 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1148,6 +1148,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Deschideți cu"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Deschideți cu %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Deschideți"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Permiteți accesul pentru a deschide linkurile <xliff:g id="HOST">%1$s</xliff:g> cu"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Permiteți accesul pentru a deschide linkurile <xliff:g id="HOST">%1$s</xliff:g> cu <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Permiteți accesul"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Editați cu"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editați cu %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Editați"</string>
@@ -1589,6 +1592,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Acceptați apelul?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Întotdeauna"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Numai o dată"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Setări"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s nu acceptă profilul de serviciu"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tabletă"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1669,7 +1673,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Corecția culorii"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Comanda rapidă de accesibilitate a activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Comanda rapidă de accesibilitate a dezactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Folosiți din nou comanda rapidă Accesibilitate pentru a porni funcția de accesibilitate prezentă"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Apăsați ambele butoane de volum timp de trei secunde pentru a folosi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Alegeți o funcție pe care să o folosiți când atingeți butonul Accesibilitate:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Pentru a schimba funcțiile, atingeți lung butonul Accesibilitate."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Mărire"</string>
@@ -2010,5 +2014,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Cameră foto"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microfon"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"se afișează peste alte aplicații de pe ecran"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Se încarcă"</string>
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index ac7908c..fde1c5d 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1168,6 +1168,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Открыть с помощью приложения:"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Открыть с помощью приложения \"%1$s\""</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Открыть"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Предоставьте доступ, чтобы открывать ссылки <xliff:g id="HOST">%1$s</xliff:g> в приложении"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Предоставьте доступ, чтобы открывать ссылки <xliff:g id="HOST">%1$s</xliff:g> в приложении <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Открыть доступ"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Редактировать с помощью приложения:"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Редактировать с помощью приложения \"%1$s\""</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Изменить"</string>
@@ -1612,6 +1615,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Ответить?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Всегда"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Только сейчас"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Настройки"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не поддерживает рабочие профили"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Планшетный ПК"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Телевизор"</string>
@@ -1693,7 +1697,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Коррекция цвета"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Сервис <xliff:g id="SERVICE_NAME">%1$s</xliff:g> включен"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Сервис <xliff:g id="SERVICE_NAME">%1$s</xliff:g> отключен"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Чтобы активировать выбранные специальные возможности, воспользуйтесь быстрым включением ещё раз"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Чтобы использовать сервис \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\", нажмите и удерживайте обе клавиши громкости в течение трех секунд."</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Выберите функцию, которая запускается при нажатии кнопки специальных возможностей:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Чтобы изменить функцию, удерживайте кнопку специальных возможностей."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Увеличение"</string>
@@ -2045,5 +2049,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Микрофон"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"показ поверх других окон"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Загрузка"</string>
</resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 6486f3a..baa0387 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1130,6 +1130,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"සමඟ විවෘත කරන්න"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s සමඟ විවෘත කරන්න"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"විවෘත කරන්න"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"මේවා මඟින් <xliff:g id="HOST">%1$s</xliff:g> සබැඳි විවෘත කිරීමට ප්රවේශය දෙන්න"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> මඟින් <xliff:g id="HOST">%1$s</xliff:g> සබැඳි විවෘත කිරීමට ප්රවේශය දෙන්න"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ප්රවේශය දෙන්න"</string>
<string name="whichEditApplication" msgid="144727838241402655">"සමඟ සංස්කරණය කරන්න"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s සමඟ සංස්කරණය කරන්න"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"සංස්කරණය"</string>
@@ -1568,6 +1571,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"ඇමතුම පිළිගන්නවාද?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"සැම විටම"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"එක් වාරයයි"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"සැකසීම්"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s කාර්යාල පැතිකඩ සඳහා සහාය ලබනොදේ."</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ටැබ්ලට්ය"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"රූපවාහිනී"</string>
@@ -1647,7 +1651,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"වර්ණ නිවැරදි කිරීම"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ප්රවේශ්යතා කෙටි මග <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ක්රියාත්මක කරන ලදී"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ප්රවේශ්යතා කෙටි මග <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ක්රියාවිරහිත කරන ලදී"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"වර්තමාන ප්රවේශ්යතා විශේෂංගය ආරම්භ කිරීම සඳහා ප්රවේශ්යතා කෙටි මග භාවිතා කරන්න"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> භාවිත කිරීමට හඬ පරිමා යතුරු දෙකම තත්පර තුනකට ඔබාගෙන සිටින්න"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ඔබ ප්රවේශ්යතා බොත්තම තට්ටු කරන විට භාවිතා කිරීමට අංගයක් තෝරාගන්න:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"අංග වෙනස් කිරීමට ප්රවේශ්යතා බොත්තම ස්පර්ශ කර අල්ලා ගෙන සිටින්න."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"විශාලනය"</string>
@@ -1977,5 +1981,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"කැමරාව"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"මයික්රෆෝනය"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"ඔබගේ තිරය මත වෙනත් යෙදුම්වලට උඩින් සංදර්ශනය කරමින්"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"දිනචරියා ප්රකාර තතු දැනුම්දීම"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"බැටරිය සුපුරුදු ආරෝපණයට පෙර ඉවර විය හැක"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"බැටරි සුරැකුම බැටරි ආයු කාලය දීර්ඝ කිරීමට සක්රිය කෙරිණි"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"පූරණය කරමින්"</string>
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 66d6ef6..2942537 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1168,6 +1168,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Otvoriť v aplikácii"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otvoriť v aplikácii %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otvoriť"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Udeľte prístup na otváranie odkazov <xliff:g id="HOST">%1$s</xliff:g> pomocou aplikácie"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Udeľte prístup na otváranie odkazov <xliff:g id="HOST">%1$s</xliff:g> pomocou aplikácie <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Udeliť prístup"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Upraviť pomocou"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Upraviť v aplikácii %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Upraviť"</string>
@@ -1612,6 +1615,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Prijať hovor?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Vždy"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Len raz"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Nastavenia"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Spúšťač %1$s nepodporuje pracovné profily"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televízor"</string>
@@ -1693,7 +1697,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Úprava farieb"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Skratka dostupnosti zapla službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Skratka dostupnosti vypla službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Znova použite skratku dostupnosti, čím sprístupníte aktuálnu funkciu dostupnosti"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Ak chcete používať službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, pridržte tri sekundy oba klávesy hlasitosti"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Klepnutím na tlačidlo dostupnosti vyberte požadovanú funkciu:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Ak chcete zmeniť funkcie, klepnite na tlačidlo dostupnosti a podržte ho"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Priblíženie"</string>
@@ -2045,5 +2049,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Fotoaparát"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofón"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"sa zobrazuje cez ďalšie aplikácie na obrazovke"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Načítava sa"</string>
</resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index dcaa4f5..d3f0872 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1168,6 +1168,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Odpiranje z aplikacijo"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Odpiranje z aplikacijo %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Odpiranje"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Omogočanje dostopa za odpiranje povezav <xliff:g id="HOST">%1$s</xliff:g> z aplikacijo"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Omogočanje dostopa za odpiranje povezav <xliff:g id="HOST">%1$s</xliff:g> z aplikacijo <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Omogoči dostop"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Urejanje z aplikacijo"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Urejanje z aplikacijo %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Urejanje"</string>
@@ -1612,6 +1615,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Ali želite sprejeti klic?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Vedno"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Samo tokrat"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Nastavitve"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne podpira delovnega profila"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablični računalnik"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televizor"</string>
@@ -1693,7 +1697,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Popravljanje barv"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Bližnjica funkcij za ljudi s posebnimi potrebami je vklopila <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Bližnjica funkcij za ljudi s posebnimi potrebami je izklopila <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Če želite zagnati trenutno funkcijo za ljudi s posebnimi potrebami, znova uporabite bližnjico funkcij za ljudi s posebnimi potrebami"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Za uporabo storitve <xliff:g id="SERVICE_NAME">%1$s</xliff:g> pritisnite obe tipki za glasnost in ju pridržite tri sekunde"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Izberite funkcijo, ki jo želite uporabljati, ko se dotaknete gumba »Dostopnost«:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Če želite spremeniti funkcije, se dotaknite gumba »Dostopnost« in ga pridržite."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Povečava"</string>
@@ -2045,5 +2049,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Fotoaparat"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"prekriva druge aplikacije na zaslonu"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Nalaganje"</string>
</resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 413ff8a..89afb1a 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Hap me"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Hap me %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Hap"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Jep qasje për të hapur lidhjet e <xliff:g id="HOST">%1$s</xliff:g> me"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Jep qasje për të hapur lidhjet e <xliff:g id="HOST">%1$s</xliff:g> me <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Jep qasje"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Redakto me"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redakto me %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Redakto"</string>
@@ -1567,6 +1570,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Dëshiron ta pranosh telefonatën?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Gjithmonë"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Vetëm një herë"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Cilësimet"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s nuk e mbështet profilin e punës"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televizori"</string>
@@ -1646,7 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Korrigjimi i ngjyrës"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Shkurtorja e qasshmërisë e aktivizoi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Shkurtorja e qasshmërisë e çaktivizoi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Përdor përsëri \"Shkurtoren e qasshmërisë\" për të nisur funksionin aktual të qasshmërisë"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Shtyp dhe mbaj shtypur të dy butonat e volumit për tre sekonda për të përdorur <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Zgjidh një funksion për ta përdorur kur troket butonin e \"Qasshmërisë\":"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Për të ndryshuar funksionet, prek dhe mbaj butonin e \"Qasshmërisë\"."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Zmadhimi"</string>
@@ -1976,5 +1980,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofoni"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"po shfaqet mbi aplikacionet e tjera në ekranin tënd"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Njoftimi i informacionit të \"Modalitetit rutinë\""</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Bateria mund të mbarojë përpara ngarkimit të zakonshëm"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"\"Kursyesi i baterisë\" u aktivizua për të zgjatur jetëgjatësinë e baterisë"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Po ngarkohet"</string>
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 8f8fe0e..19f88cf 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1148,6 +1148,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Отворите помоћу"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Отворите помоћу апликације %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Отвори"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Дозволите да се линкови <xliff:g id="HOST">%1$s</xliff:g> отварају помоћу"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Дозволите да <xliff:g id="APPLICATION">%2$s</xliff:g> отвара линикове <xliff:g id="HOST">%1$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Дозволи приступ"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Измените помоћу"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Измените помоћу апликације %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Измени"</string>
@@ -1589,6 +1592,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Желите ли да прихватите позив?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Увек"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Само једном"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Подешавања"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не подржава пословни профил"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Таблет"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ТВ"</string>
@@ -1669,7 +1673,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Корекција боја"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Пречица за приступачност је укључила услугу <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Пречица за приступачност је искључила услугу <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Употребите поново пречицу за приступачност да бисте покренули актуелну функцију приступачности"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Притисните и задржите оба тастера за јачину звука три секунде да бисте користили <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Изаберите функцију која ће се користити када додирнете дугме за приступачност:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Притисните и задржите дугме за приступачност да бисте мењали функције."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Увећање"</string>
@@ -2010,5 +2014,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Микрофон"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"приказује се на екрану док користите друге апликације"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Обавештење о информацијама Рутинског режима"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Батерија ће се можда испразнити пре уобичајеног пуњења"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Уштеда батерије је активирана да би се продужило трајање батерије"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Учитава се"</string>
</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index cd5580d..fcae364 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Öppna med"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Öppna med %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Öppna"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Tillåt att länkar från <xliff:g id="HOST">%1$s</xliff:g> öppnas med"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Tillåt att länkar från <xliff:g id="HOST">%1$s</xliff:g> öppnas med <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Ge åtkomst"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Redigera med"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redigera med %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Redigera"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Vill du ta emot samtal?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Alltid"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Bara en gång"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Inställningar"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s har inte stöd för arbetsprofil"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Surfplatta"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Färgkorrigering"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktiverades av Aktivera tillgänglighet snabbt"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> inaktiverades av Aktivera tillgänglighet snabbt"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Använd Aktivera tillgänglighet snabbt en gång till om du vill aktivera tillgänglighetsfunktionen i fråga"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Tryck och håll båda volymknapparna i tre sekunder för att använda <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Välj en funktion som ska användas när du trycker på tillgänglighetsknappen:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Tryck länge på tillgänglighetsknappen för att ändra funktioner."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Förstoring"</string>
@@ -1975,5 +1979,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"visar över andra appar på mobilen"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Avisering om rutinläge"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Batteriet kan ta slut innan du brukar ladda det"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Batterisparläget har aktiverats för att utöka batteritiden"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Läser in"</string>
</resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index bc3e4ad..be7c301 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Fungua ukitumia"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Fungua ukitumia %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Fungua"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Ipe <xliff:g id="HOST">%1$s</xliff:g> ruhusa ya kufungua viungo kwa kutumia"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Ipe <xliff:g id="HOST">%1$s</xliff:g> ruhusa ya kufungua viungo kwa kutumia <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Idhinisha ufikiaji"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Badilisha kwa"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Badilisha kwa %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Badilisha"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Kubali simu?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Kila mara"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Mara moja tu"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Mipangilio"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s haitumii wasifu wa kazini"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Kompyuta kibao"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Runinga"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Usahihishaji wa rangi"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Njia ya mkato ya zana za walio na matatizo ya kuona au kusikia imewasha <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Njia ya mkato ya zana za walio na matatizo ya kuona au kusikia imezima <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Tumia njia ya Mkato wa Zana za walio na matatizo ya kuona au kusikia tena ili kuanzisha kipengele kilichopo cha walio na matatizo ya kuona au kusikia"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Bonyeza na ushikilie vitufe vyote viwili vya sauti kwa sekunde tatu ili utumie <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Chagua kipengele utakachotumia, ukigonga Kitufe cha zana za walio na matatizo ya kuona au kusikia."</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Ili kubadilisha vipengele, gusa na ushikile Kitufe cha zana za walio na matatizo ya kuona au kusikia."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ukuzaji"</string>
@@ -1975,5 +1979,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Maikrofoni"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"inachomoza kwenye programu zingine katika skrini yako"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Arifa ya maelezo ya Hali ya Kawaida"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Huenda betri itakwisha chaji mapema"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Imewasha Kiokoa Betri ili kurefusha muda wa matumizi ya betri"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Inapakia"</string>
</resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 22da7b0..117f071 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"இதன்மூலம் திற"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s மூலம் திற"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"திற"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"மூலம் <xliff:g id="HOST">%1$s</xliff:g> இணைப்புகளைத் திறப்பதற்கான அணுகலை வழங்குதல்"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> மூலம் <xliff:g id="HOST">%1$s</xliff:g> இணைப்புகளைத் திறப்பதற்கான அணுகலை வழங்குதல்"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"அணுகலை வழங்கு"</string>
<string name="whichEditApplication" msgid="144727838241402655">"இதன் மூலம் திருத்து"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s மூலம் திருத்து"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"மாற்று"</string>
@@ -1567,6 +1570,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"அழைப்பை ஏற்கவா?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"எப்போதும்"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"இப்போது மட்டும்"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"அமைப்புகள்"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s பணி சுயவிவரத்தை ஆதரிக்காது"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"டேப்லெட்"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"டிவி"</string>
@@ -1646,7 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"வண்ணத் திருத்தம்"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"அணுகல்தன்மைக் குறுக்குவழியானது <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ஐ இயக்கியது"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"அணுகல்தன்மைக் குறுக்குவழியானது <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ஐ முடக்கியது"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"தற்போதுள்ள அணுகல்தன்மை அம்சத்தை மீண்டும் தொடங்க ’அணுகல்தன்மை ஷார்ட்கட்டைப்’ பயன்படுத்தவும்"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ஐப் பயன்படுத்த 3 விநாடிகளுக்கு இரண்டு ஒலியளவு பட்டன்களையும் அழுத்திப் பிடிக்கவும்"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"அணுகல்தன்மைப் பொத்தானைத் தட்டி, பயன்படுத்துவதற்கான அம்சத்தைத் தேர்ந்தெடுக்கவும்:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"அம்சங்களை மாற்ற, அணுகல்தன்மைப் பொத்தானைத் தொட்டுப் பிடித்திருக்கவும்."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"பெரிதாக்கல்"</string>
@@ -1976,5 +1980,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"கேமரா"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"மைக்ரோஃபோன்"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"உங்கள் திரையில் உள்ள பிற பயன்பாடுகளின் மேல் காட்டுகிறது"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"வழக்கமான பேட்டரி சேமிப்பானுக்கான விவர அறிவிப்பு"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"வழக்கமாகச் சார்ஜ் செய்வதற்கு முன்பே பேட்டரி தீர்ந்துபோகக்கூடும்"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"பேட்டரி நிலையை நீட்டிக்க பேட்டரி சேமிப்பான் இயக்கப்பட்டுள்ளது"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"ஏற்றுகிறது"</string>
</resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 1cc0274..654585d 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"దీనితో తెరువు"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$sతో తెరువు"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"తెరువు"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"<xliff:g id="HOST">%1$s</xliff:g> లింక్లను తెరవడానికి యాక్సెస్ ఇవ్వండి"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g>తో <xliff:g id="HOST">%1$s</xliff:g> లింక్లను తెరవడానికి యాక్సెస్ ఇవ్వండి"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"యాక్సెస్ ఇవ్వండి"</string>
<string name="whichEditApplication" msgid="144727838241402655">"దీనితో సవరించు"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sతో సవరించు"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"సవరించు"</string>
@@ -1567,6 +1570,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"కాల్ను ఆమోదించాలా?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"ఎల్లప్పుడూ"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"ఒకసారి"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"సెట్టింగ్లు"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s కార్యాలయ ప్రొఫైల్కు మద్దతు ఇవ్వదు"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"టాబ్లెట్"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"టీవీ"</string>
@@ -1646,7 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"రంగు సవరణ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"యాక్సెస్ సామర్థ్య షార్ట్కట్ ద్వారా <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆన్ చేయబడింది"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"యాక్సెస్ సామర్థ్య షార్ట్కట్ ద్వారా <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆఫ్ చేయబడింది"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ప్రస్తుత యాక్సెస్ సౌలభ్య ఫీచర్ను ఉపయోగించడానికి యాక్సెసిబిలిటీ షార్ట్కట్ను మళ్లీ ప్రారంభించండి"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ని ఉపయోగించడానికి వాల్యూమ్ కీలు రెండింటినీ 3 సెకన్లు నొక్కి ఉంచండి"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"యాక్సెస్ సామర్థ్య బటన్ను మీరు నొక్కినప్పుడు ఉపయోగించాల్సిన ఒక ఫీచర్ను ఎంచుకోండి:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ఫీచర్లను మార్చడానికి, యాక్సెస్ సామర్థ్య బటన్ను నొక్కి & పట్టుకోండి."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"మాగ్నిఫికేషన్"</string>
@@ -1976,5 +1980,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"కెమెరా"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"మైక్రోఫోన్"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"మీ స్క్రీన్పై ఇతర యాప్ల ద్వారా ప్రదర్శించబడుతోంది"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"లోడవుతోంది"</string>
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 2edf57c..ca8f529 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"เปิดด้วย"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"เปิดด้วย %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"เปิด"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ให้สิทธิ์ในการเปิดลิงก์ของ <xliff:g id="HOST">%1$s</xliff:g> โดยใช้"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"ให้สิทธิ์ในการเปิดลิงก์ของ <xliff:g id="HOST">%1$s</xliff:g> โดยใช้ <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ให้สิทธิ์"</string>
<string name="whichEditApplication" msgid="144727838241402655">"แก้ไขด้วย"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"แก้ไขด้วย %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"แก้ไข"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"รับสายหรือไม่"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"ทุกครั้ง"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"เฉพาะครั้งนี้"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"การตั้งค่า"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ไม่สนับสนุนโปรไฟล์งาน"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"แท็บเล็ต"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ทีวี"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"การปรับแก้สี"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ทางลัดการเข้าถึงเปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> แล้ว"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ทางลัดการเข้าถึงปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> แล้ว"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ใช้ทางลัดการช่วยเหลือพิเศษอีกครั้งเพื่อเริ่มฟีเจอร์การช่วยเหลือพิเศษปัจจุบัน"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"กดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มค้างไว้ 3 วินาทีเพื่อใช้ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"เลือกฟีเจอร์ที่จะใช้เมื่อคุณแตะปุ่ม \"การเข้าถึงพิเศษ\":"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"หากต้องการเปลี่ยนฟีเจอร์ ให้แตะปุ่ม \"การเข้าถึงพิเศษ\" ค้างไว้"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"การขยาย"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"กล้อง"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"ไมโครโฟน"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"แสดงทับแอปอื่นๆ บนหน้าจอ"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"กำลังโหลด"</string>
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index f7995f7..31d906f 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Buksan gamit ang"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Buksan gamit ang %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Buksan"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Magbigay ng access para buksan ang mga link ng <xliff:g id="HOST">%1$s</xliff:g> sa"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Magbigay ng access para buksan ang mga link ng <xliff:g id="HOST">%1$s</xliff:g> sa <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Bigyan ng access"</string>
<string name="whichEditApplication" msgid="144727838241402655">"I-edit gamit ang"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"I-edit gamit ang %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"I-edit"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Tanggapin ang tawag?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Palagi"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Isang beses lang"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Mga Setting"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Hindi sinusuportahan ng %1$s ang profile sa trabaho"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Pagwawasto ng Kulay"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Na-on ng Shortcut sa Accessibility ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Na-off ng Shortcut sa Accessibility ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Gamiting muli ang Shortcut sa Pagiging Naa-access para simulan ang kasalukuyang feature ng pagiging naa-access"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Pindutin nang matagal ang parehong volume key sa loob ng tatlong segundo para magamit ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Pumili ng feature na gagamitin kapag na-tap mo ang button ng Pagiging Naa-access:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Upang baguhin ang mga feature, pindutin nang matagal ang button ng Pagiging Naa-access."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Pag-magnify"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Camera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikropono"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"ipinapakita sa ibabaw ng ibang app sa iyong screen"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Naglo-load"</string>
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 761eba6..75b19a9 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Şununla aç:"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ile aç"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Aç"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Şununla <xliff:g id="HOST">%1$s</xliff:g> bağlantılarını açma izni verin"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> uygulamasıyla <xliff:g id="HOST">%1$s</xliff:g> bağlantılarını açma izni verin"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Erişim ver"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Şununla düzenle:"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ile düzenle"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Düzenle"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Çağrı kabul edilsin mi?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Her zaman"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Yalnızca bir defa"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ayarlar"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s, iş profilini desteklemiyor"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Renk Düzeltme"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Erişilebilirlik Kısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini açtı"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Erişilebilirlik Kısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini kapattı"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Geçerli erişilebilirlik özelliğini başlatmak için Erişilebilirlik Kısayolu\'nu tekrar kullanın"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini kullanmak için her iki ses tuşunu basılı tutun"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Erişilebilirlik düğmesine dokunduğunuzda kullanmak üzere bir özellik seçin:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Özellikleri değiştirmek için Erişilebilirlik düğmesine dokunup basılı tutun."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Büyütme"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"ekranınızdaki diğer uygulamaların üzerinde görüntüleniyor"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Yükleniyor"</string>
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index e7e99ae..933d04a 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1168,6 +1168,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Відкрити за допомогою"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Відкрити за допомогою %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Відкрити"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Дозвольте відкривати посилання на сайт <xliff:g id="HOST">%1$s</xliff:g> у додатку"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Дозвольте відкривати посилання на сайт <xliff:g id="HOST">%1$s</xliff:g> у додатку <xliff:g id="APPLICATION">%2$s</xliff:g>."</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Дозволити"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Редагувати за допомогою"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Редагувати за допомогою %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Редагувати"</string>
@@ -1612,6 +1615,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Прийняти виклик?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Завжди"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Лише цього разу"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Налаштування"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не підтримує робочий профіль"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Планшетний ПК"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Телевізор"</string>
@@ -1693,7 +1697,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Корекція кольорів"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Ярлик спеціальних можливостей увімкнув <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Ярлик спеціальних можливостей вимкнув <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Щоб запустити поточну функцію спеціальних можливостей, знову скористайтеся відповідним ярликом"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Щоб скористатися службою <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, утримуйте обидві клавіші гучності впродовж трьох секунд"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Виберіть функцію для кнопки спеціальних можливостей:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Щоб змінити функцію, натисніть і втримуйте кнопку спеціальних можливостей."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Збільшення"</string>
@@ -2045,5 +2049,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Мікрофон"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"показ поверх інших додатків на екрані"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Завантаження"</string>
</resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index e33f3f2..20f7621 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"اس کے ساتھ کھولیں"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s کے ساتھ کھولیں"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"کھولیں"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"اس کے ساتھ <xliff:g id="HOST">%1$s</xliff:g> لنکس کو کھولنے کے لیے رسائی ديں"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> کے ساتھ <xliff:g id="HOST">%1$s</xliff:g> لنکس کو کھولنے کے لیے رسائی ديں"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"رسائی دیں"</string>
<string name="whichEditApplication" msgid="144727838241402655">"اس کے ساتھ ترمیم کریں"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s کے ساتھ ترمیم کریں"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"ترمیم کریں"</string>
@@ -1567,6 +1570,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"کال قبول کریں؟"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"ہمیشہ"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"بس ایک مرتبہ"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ترتیبات"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s دفتری پروفائل کا تعاون نہیں کرتا ہے"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ٹیبلیٹ"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1646,7 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"رنگ کی تصحیح"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ایکسیسبیلٹی شارٹ کٹ نے <xliff:g id="SERVICE_NAME">%1$s</xliff:g> کو آن کر دیا"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ایکسیسبیلٹی شارٹ کٹ نے <xliff:g id="SERVICE_NAME">%1$s</xliff:g> کو آف کر دیا"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"موجودہ ایکسیسبیلٹی خصوصیت کو شروع کرنے کیلئے دوبارہ ایکسیسبیلٹی شارٹ کٹ استعمال کریں"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> کا استعمال کرنے کے لیے 3 سیکنڈ تک والیوم کی دونوں کلیدوں کو چھوئیں اور دبائے رکھیں"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ایکسیسبیلٹی بٹن پر تھپتھپانے وقت استعمال کرنے کیلئے ایک خصوصیت چنیں:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"خصوصیات تبدیل کرنے کیلئے، ایکسیسبیلٹی بٹن ٹچ کریں اور دبائے رکھیں۔"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"میگنیفکیشن"</string>
@@ -1976,5 +1980,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"کیمرا"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"مائیکروفون"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"آپ کی اسکرین پر دیگر ایپس پر دکھایا جا رہا ہے"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"لوڈ ہو رہا ہے"</string>
</resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 7742c3e..3f20dc1 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Ochish…"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s bilan ochish"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ochish"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"<xliff:g id="HOST">%1$s</xliff:g> havolalarini ushbu ilova bilan ochishga ruxsat bering:"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="HOST">%1$s</xliff:g> havolalarini <xliff:g id="APPLICATION">%2$s</xliff:g> bilan ochishga ruxsat bering"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Ruxsat berish"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Tahrirlash…"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"“%1$s” yordamida tahrirlash"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Tahrirlash"</string>
@@ -1567,6 +1570,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Qo‘ng‘iroqni qabul qilasizmi?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Har doim"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Faqat hozir"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Sozlamalar"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"“%1$s” ishchi profilni qo‘llab-quvvatlamaydi"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Planshet"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1646,7 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Rangni tuzatish"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> xizmati yoqildi"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> xizmati o‘chirib qo‘yildi"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Joriy maxsus imkoniyatlar funksiyasini boshlash uchun tezkor ishga tushirishdan qayta foydalaning"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> xizmatidan foydalanish uchun ikkala ovoz balandligi tugmalarini uzoq bosib turing"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Maxsus imkoniyatlar tugmasi bosilganda ishga tushadigan funksiyani tanlang:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Funksiyalarni o‘zgartirish uchun Maxsus imkoniyatlar tugmasini bosib turing."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Kattalashtirish"</string>
@@ -1976,5 +1980,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"ekranda boshqa ilovalar ustidan ochiladi"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Kun tartibi rejimi haqidagi bildirishnoma"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Batareya quvvati odatdagidan ertaroq tugashi mumkin"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Batareya quvvati uzoqroq ishlashi uchun Tejamkor rejim yoqildi"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Yuklanmoqda"</string>
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 86bb532..19c3913 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Mở bằng"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Mở bằng %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Mở"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Cấp quyền truy cập để mở đường dẫn liên kết <xliff:g id="HOST">%1$s</xliff:g> bằng"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Cấp quyền truy cập để mở đường dẫn liên kết <xliff:g id="HOST">%1$s</xliff:g> bằng <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Cấp quyền truy cập"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Chỉnh sửa bằng"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Chỉnh sửa bằng %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Chỉnh sửa"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Chấp nhận cuộc gọi?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Luôn chọn"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Chỉ một lần"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Cài đặt"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s không hỗ trợ hồ sơ công việc"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Máy tính bảng"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Sửa màu"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Đã bật phím tắt trợ năng <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Đã tắt phím tắt trợ năng <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Sử dụng lại Phím tắt hỗ trợ tiếp cận để bắt đầu tính năng hỗ trợ tiếp cận hiện tại"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Nhấn và giữ đồng thời cả hai phím âm lượng trong 3 giây để sử dụng <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Chọn tính năng sẽ sử dụng khi bạn nhấn nút Trợ năng:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Để thay đổi các tính năng, hãy chạm và giữ nút Trợ năng."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Phóng to"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Máy ảnh"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Micrô"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"hiển thị qua các ứng dụng khác trên màn hình của bạn"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"Đang tải"</string>
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index dbb7834..6720132 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"打开方式"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"使用%1$s打开"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"打开"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"授权使用以下应用打开 <xliff:g id="HOST">%1$s</xliff:g> 链接:"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"授权使用<xliff:g id="APPLICATION">%2$s</xliff:g>打开 <xliff:g id="HOST">%1$s</xliff:g> 链接"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"授予访问权限"</string>
<string name="whichEditApplication" msgid="144727838241402655">"编辑方式"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"使用%1$s编辑"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"编辑"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"要接听电话吗?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"始终"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"仅此一次"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"设置"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s不支持工作资料"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"平板电脑"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"电视"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"色彩校正"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"无障碍快捷方式已开启<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"无障碍快捷方式已关闭<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"再次使用无障碍快捷方式即可启动目前设置的无障碍功能"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"同时按住两个音量键 3 秒钟即可使用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"选择按下“无障碍”按钮时要使用的功能:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"要更改指定的功能,请触摸并按住“无障碍”按钮。"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"放大功能"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"相机"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"麦克风"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"显示在屏幕上其他应用的上层"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"正在加载"</string>
</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 6248db5..701e266 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"用於開啟的應用程式"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"使用 %1$s 開啟"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"開啟"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"授予存取權以透過以下應用程式開啟 <xliff:g id="HOST">%1$s</xliff:g> 連結:"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"授予存取權以透過<xliff:g id="APPLICATION">%2$s</xliff:g>開啟 <xliff:g id="HOST">%1$s</xliff:g> 連結"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"授予存取權"</string>
<string name="whichEditApplication" msgid="144727838241402655">"使用以下選擇器編輯:"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"使用 %1$s 編輯"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"編輯"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"接聽電話嗎?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"一律採用"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"只此一次"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"設定"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s 不支援公司檔案"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"平板電腦"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"電視"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"色彩校正"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"無障礙功能快速鍵已啟用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"無障礙功能快速鍵已停用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"再用一次無障礙功能捷徑,就可以啟用宜家設定咗嘅無障礙功能"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"㩒住兩個音量鍵 3 秒就可以用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"請選擇輕按「無障礙功能」按鈕時使用的功能:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"如要變更功能,可按住「無障礙功能」按鈕。"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"放大"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"相機"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"麥克風"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"顯示在畫面上的其他應用程式上層"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"正在載入"</string>
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 74da200..24a51bd 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"選擇開啟工具"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"透過 %1$s 開啟"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"開啟"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"授權系統使用以下應用程式開啟 <xliff:g id="HOST">%1$s</xliff:g> 連結"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"授權系統使用「<xliff:g id="APPLICATION">%2$s</xliff:g>」開啟 <xliff:g id="HOST">%1$s</xliff:g> 連結"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"授予存取權"</string>
<string name="whichEditApplication" msgid="144727838241402655">"選擇編輯工具"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"使用 %1$s 編輯"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"編輯"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"接聽電話嗎?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"一律採用"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"僅限一次"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"設定"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s 不支援工作設定檔"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"平板電腦"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"電視"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"色彩校正"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"協助工具捷徑啟用了「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"協助工具捷徑停用了「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"再次使用協助工具捷徑即可啟動目前設定的無障礙功能"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"同時按住調低及調高音量鍵三秒即可使用「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"輕觸 [協助工具] 按鈕後,選擇你想使用的功能:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"如要變更指派的功能,請按住 [協助工具] 按鈕。"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"放大"</string>
@@ -1975,5 +1979,11 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"相機"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"麥克風"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"顯示在畫面上的其他應用程式上層"</string>
+ <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+ <skip />
+ <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+ <skip />
<string name="car_loading_profile" msgid="3545132581795684027">"載入中"</string>
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 93b2ae6..f819945 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1128,6 +1128,9 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Vula nge-"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Vula nge-%1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Kuvuliwe"</string>
+ <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Nika ukufinyelela kuzixhumanisi ezivulekile ze-<xliff:g id="HOST">%1$s</xliff:g> nge-"</string>
+ <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Nika ukufinyelela kuzixhumanisi ze-<xliff:g id="HOST">%1$s</xliff:g> ezivulekile nge-<xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Nikeza ukufinyel"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Hlela nge-"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Hlela nge-%1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Hlela"</string>
@@ -1566,6 +1569,7 @@
<string name="SetupCallDefault" msgid="5834948469253758575">"Amukela ucingo?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Njalo"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Kanye nje"</string>
+ <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Izilungiselelo"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ayisekeli iphrofayela yomsebenzi"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Ithebulethi"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"I-TV"</string>
@@ -1645,7 +1649,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Ukulungiswa kombala"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Isinqamuleli sokufinyelela sivule i-<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Isinqamuleli sokufinyelela sivale i-<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Sebenzisa isinqamuleli sokufinyelela futhi ukuze uqale isici samanje sokufinyelela"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Cindezela uphinde ubambe bobabili okhiye bevolumu ngamasekhondi amathathu ukuze usebenzise i-<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Khetha isici ozosisebenzisa uma uthepha inkinobho yokufinyelela:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Ukuze ushintshe izici, thinta uphinde ubambe inkinobho yokufinyelela."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ukukhuliswa"</string>
@@ -1975,5 +1979,8 @@
<string name="notification_appops_camera_active" msgid="5050283058419699771">"Ikhamera"</string>
<string name="notification_appops_microphone_active" msgid="4335305527588191730">"Imakrofoni"</string>
<string name="notification_appops_overlay_active" msgid="633813008357934729">"iboniswa ngaphezulu kwezinye izinhlelo zokusebenza kusikrini sakho"</string>
+ <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Isaziso solwazi lwe-Routine Mode"</string>
+ <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Ibhethri lingaphela ngaphambi kokushaja okuvamile"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Isilondolozi sebhethri siyasebenza ngaphandle kwempilo yebhethri"</string>
<string name="car_loading_profile" msgid="3545132581795684027">"Iyalayisha"</string>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 140225e..1feb59a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1152,6 +1152,10 @@
Settings.System.NOTIFICATION_VIBRATION_INTENSITY more details on the constant values and
meanings. -->
<integer name="config_defaultNotificationVibrationIntensity">2</integer>
+ <!-- The default intensity level for ring vibrations. See
+ Settings.System.RING_VIBRATION_INTENSITY more details on the constant values and
+ meanings. -->
+ <integer name="config_defaultRingVibrationIntensity">2</integer>
<bool name="config_use_strict_phone_number_comparation">false</bool>
@@ -3419,6 +3423,23 @@
-->
<string name="config_defaultAugmentedAutofillService" translatable="false"></string>
+ <!-- The package name for the system's app prediction service.
+ This service must be trusted, as it can be activated without explicit consent of the user.
+ Example: "com.android.intelligence/.AppPredictionService"
+ -->
+ <string name="config_defaultAppPredictionService" translatable="false"></string>
+
+ <!-- The package name for the system's content suggestions service.
+ Provides suggestions for text and image selection regions in snapshots of apps and should
+ be able to classify the type of entities in those selections.
+
+ This service must be trusted, as it can be activated without explicit consent of the user.
+ If no service with the specified name exists on the device, content suggestions wil be
+ disabled.
+ Example: "com.android.contentsuggestions/.ContentSuggestionsService"
+ -->
+ <string name="config_defaultContentSuggestionsService" translatable="false"></string>
+
<!-- Whether the device uses the default focus highlight when focus state isn't specified. -->
<bool name="config_useDefaultFocusHighlight">true</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f8c9037..010accf 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3275,6 +3275,8 @@
<java-symbol type="string" name="config_defaultWellbeingPackage" />
<java-symbol type="string" name="config_defaultContentCaptureService" />
<java-symbol type="string" name="config_defaultAugmentedAutofillService" />
+ <java-symbol type="string" name="config_defaultAppPredictionService" />
+ <java-symbol type="string" name="config_defaultContentSuggestionsService" />
<java-symbol type="string" name="notification_channel_foreground_service" />
<java-symbol type="string" name="foreground_service_app_in_background" />
@@ -3489,6 +3491,7 @@
<java-symbol type="integer" name="config_defaultHapticFeedbackIntensity" />
<java-symbol type="integer" name="config_defaultNotificationVibrationIntensity" />
+ <java-symbol type="integer" name="config_defaultRingVibrationIntensity" />
<java-symbol type="bool" name="config_maskMainBuiltInDisplayCutout" />
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 1750dac..0f83a29 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -19,28 +19,35 @@
import static android.content.Intent.ACTION_EDIT;
import static android.content.Intent.ACTION_VIEW;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.app.Activity;
import android.app.ActivityThread;
import android.app.IApplicationThread;
+import android.app.servertransaction.ActivityConfigurationChangeItem;
import android.app.servertransaction.ActivityRelaunchItem;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.ClientTransactionItem;
import android.app.servertransaction.ResumeActivityItem;
import android.app.servertransaction.StopActivityItem;
import android.content.Intent;
+import android.content.res.Configuration;
import android.os.IBinder;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.util.MergedConfiguration;
+import android.view.Display;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.concurrent.CountDownLatch;
+
/**
* Test for verifying {@link android.app.ActivityThread} class.
* Build/Install/Run:
@@ -50,8 +57,12 @@
@MediumTest
public class ActivityThreadTest {
- private final ActivityTestRule mActivityTestRule =
- new ActivityTestRule(TestActivity.class, true /* initialTouchMode */,
+ // The first sequence number to try with. Use a large number to avoid conflicts with the first a
+ // few sequence numbers the framework used to launch the test activity.
+ private static final int BASE_SEQ = 10000;
+
+ private final ActivityTestRule<TestActivity> mActivityTestRule =
+ new ActivityTestRule<>(TestActivity.class, true /* initialTouchMode */,
false /* launchActivity */);
@Test
@@ -129,6 +140,179 @@
});
}
+ @Test
+ public void testHandleActivityConfigurationChanged() {
+ final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ final int numOfConfig = activity.mNumOfConfigChanges;
+ applyConfigurationChange(activity, BASE_SEQ);
+ assertEquals(numOfConfig + 1, activity.mNumOfConfigChanges);
+ });
+ }
+
+ @Test
+ public void testHandleActivityConfigurationChanged_DropStaleConfigurations() {
+ final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ // Set the sequence number to BASE_SEQ.
+ applyConfigurationChange(activity, BASE_SEQ);
+
+ final int orientation = activity.mConfig.orientation;
+ final int numOfConfig = activity.mNumOfConfigChanges;
+
+ // Try to apply an old configuration change.
+ applyConfigurationChange(activity, BASE_SEQ - 1);
+ assertEquals(numOfConfig, activity.mNumOfConfigChanges);
+ assertEquals(orientation, activity.mConfig.orientation);
+ });
+ }
+
+ @Test
+ public void testHandleActivityConfigurationChanged_ApplyNewConfigurations() {
+ final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ // Set the sequence number to BASE_SEQ and record the final sequence number it used.
+ final int seq = applyConfigurationChange(activity, BASE_SEQ);
+
+ final int orientation = activity.mConfig.orientation;
+ final int numOfConfig = activity.mNumOfConfigChanges;
+
+ // Try to apply an new configuration change.
+ applyConfigurationChange(activity, seq + 1);
+ assertEquals(numOfConfig + 1, activity.mNumOfConfigChanges);
+ assertNotEquals(orientation, activity.mConfig.orientation);
+ });
+ }
+
+ @Test
+ public void testHandleActivityConfigurationChanged_PickNewerPendingConfiguration() {
+ final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ // Set the sequence number to BASE_SEQ and record the final sequence number it used.
+ final int seq = applyConfigurationChange(activity, BASE_SEQ);
+
+ final int orientation = activity.mConfig.orientation;
+ final int numOfConfig = activity.mNumOfConfigChanges;
+
+ final ActivityThread activityThread = activity.getActivityThread();
+
+ final Configuration pendingConfig = new Configuration();
+ pendingConfig.orientation = orientation == Configuration.ORIENTATION_LANDSCAPE
+ ? Configuration.ORIENTATION_PORTRAIT
+ : Configuration.ORIENTATION_LANDSCAPE;
+ pendingConfig.seq = seq + 2;
+ activityThread.updatePendingActivityConfiguration(activity.getActivityToken(),
+ pendingConfig);
+
+ final Configuration newConfig = new Configuration();
+ newConfig.orientation = orientation;
+ newConfig.seq = seq + 1;
+
+ activityThread.handleActivityConfigurationChanged(activity.getActivityToken(),
+ newConfig, Display.INVALID_DISPLAY);
+ assertEquals(numOfConfig + 1, activity.mNumOfConfigChanges);
+ assertEquals(pendingConfig.orientation, activity.mConfig.orientation);
+ });
+ }
+
+ @Test
+ public void testHandleActivityConfigurationChanged_OnlyAppliesNewestConfiguration()
+ throws Exception {
+ final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+
+ final ActivityThread activityThread = activity.getActivityThread();
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ final Configuration config = new Configuration();
+ config.seq = BASE_SEQ;
+ config.orientation = Configuration.ORIENTATION_PORTRAIT;
+
+ activityThread.handleActivityConfigurationChanged(activity.getActivityToken(),
+ config, Display.INVALID_DISPLAY);
+ });
+
+ final int numOfConfig = activity.mNumOfConfigChanges;
+ final IApplicationThread appThread = activityThread.getApplicationThread();
+
+ activity.mConfigLatch = new CountDownLatch(1);
+ activity.mTestLatch = new CountDownLatch(1);
+
+ Configuration config = new Configuration();
+ config.seq = BASE_SEQ + 1;
+ config.smallestScreenWidthDp = 100;
+ appThread.scheduleTransaction(newActivityConfigTransaction(activity, config));
+
+ // Wait until the main thread is performing the configuration change for the configuration
+ // with sequence number BASE_SEQ + 1 before proceeding. This is to mimic the situation where
+ // the activity takes very long time to process configuration changes.
+ activity.mTestLatch.await();
+
+ config = new Configuration();
+ config.seq = BASE_SEQ + 2;
+ config.smallestScreenWidthDp = 200;
+ appThread.scheduleTransaction(newActivityConfigTransaction(activity, config));
+
+ config = new Configuration();
+ config.seq = BASE_SEQ + 3;
+ config.smallestScreenWidthDp = 300;
+ appThread.scheduleTransaction(newActivityConfigTransaction(activity, config));
+
+ config = new Configuration();
+ config.seq = BASE_SEQ + 4;
+ config.smallestScreenWidthDp = 400;
+ appThread.scheduleTransaction(newActivityConfigTransaction(activity, config));
+
+ activity.mConfigLatch.countDown();
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ activity.mConfigLatch = null;
+ activity.mTestLatch = null;
+
+ // Only two more configuration changes: one with seq BASE_SEQ + 1; another with seq
+ // BASE_SEQ + 4. Configurations scheduled in between should be dropped.
+ assertEquals(numOfConfig + 2, activity.mNumOfConfigChanges);
+ assertEquals(400, activity.mConfig.smallestScreenWidthDp);
+ }
+
+ /**
+ * Calls {@link ActivityThread#handleActivityConfigurationChanged(IBinder, Configuration, int)}
+ * to try to push activity configuration to the activity for the given sequence number.
+ * <p>
+ * It uses orientation to push the configuration and it tries a different orientation if the
+ * first attempt doesn't make through, to rule out the possibility that the previous
+ * configuration already has the same orientation.
+ *
+ * @param activity the test target activity
+ * @param seq the specified sequence number
+ * @return the sequence number this method tried with the last time, so that the caller can use
+ * the next sequence number for next configuration update.
+ */
+ private int applyConfigurationChange(TestActivity activity, int seq) {
+ final ActivityThread activityThread = activity.getActivityThread();
+
+ final int numOfConfig = activity.mNumOfConfigChanges;
+ Configuration config = new Configuration();
+ config.orientation = Configuration.ORIENTATION_PORTRAIT;
+ config.seq = seq;
+ activityThread.handleActivityConfigurationChanged(activity.getActivityToken(), config,
+ Display.INVALID_DISPLAY);
+
+ if (activity.mNumOfConfigChanges > numOfConfig) {
+ return config.seq;
+ }
+
+ config = new Configuration();
+ config.orientation = Configuration.ORIENTATION_LANDSCAPE;
+ config.seq = seq + 1;
+ activityThread.handleActivityConfigurationChanged(activity.getActivityToken(), config,
+ Display.INVALID_DISPLAY);
+
+ return config.seq;
+ }
+
private static ClientTransaction newRelaunchResumeTransaction(Activity activity) {
final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(null,
null, 0, new MergedConfiguration(), false /* preserveWindow */);
@@ -162,6 +346,16 @@
return transaction;
}
+ private static ClientTransaction newActivityConfigTransaction(Activity activity,
+ Configuration config) {
+ final ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem.obtain(config);
+
+ final ClientTransaction transaction = newTransaction(activity);
+ transaction.addCallback(item);
+
+ return transaction;
+ }
+
private static ClientTransaction newTransaction(Activity activity) {
final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
return ClientTransaction.obtain(appThread, activity.getActivityToken());
@@ -169,5 +363,37 @@
// Test activity
public static class TestActivity extends Activity {
+ int mNumOfConfigChanges;
+ final Configuration mConfig = new Configuration();
+
+ /**
+ * A latch used to notify tests that we're about to wait for configuration latch. This
+ * is used to notify test code that preExecute phase for activity configuration change
+ * transaction has passed.
+ */
+ volatile CountDownLatch mTestLatch;
+ /**
+ * If not {@code null} {@link #onConfigurationChanged(Configuration)} won't return until the
+ * latch reaches 0.
+ */
+ volatile CountDownLatch mConfigLatch;
+
+ @Override
+ public void onConfigurationChanged(Configuration config) {
+ super.onConfigurationChanged(config);
+ mConfig.setTo(config);
+ ++mNumOfConfigChanges;
+
+ if (mConfigLatch != null) {
+ if (mTestLatch != null) {
+ mTestLatch.countDown();
+ }
+ try {
+ mConfigLatch.await();
+ } catch (InterruptedException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
}
}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index f863356..1ed5ce4 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -27,6 +27,7 @@
import static java.lang.reflect.Modifier.isStatic;
import android.platform.test.annotations.Presubmit;
+import android.provider.Settings.Global;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -270,7 +271,6 @@
Settings.Global.GNSS_SATELLITE_BLACKLIST,
Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS,
Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
- Settings.Global.HDMI_CONTROL_AUTO_TV_OFF_ENABLED,
Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
Settings.Global.HDMI_CONTROL_ENABLED,
Settings.Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
@@ -550,7 +550,12 @@
Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS,
Settings.Global.BACKUP_MULTI_USER_ENABLED,
Settings.Global.ISOLATED_STORAGE_LOCAL,
- Settings.Global.ISOLATED_STORAGE_REMOTE);
+ Settings.Global.ISOLATED_STORAGE_REMOTE,
+ Settings.Global.APPOP_HISTORY_PARAMETERS,
+ Settings.Global.APPOP_HISTORY_MODE,
+ Settings.Global.APPOP_HISTORY_INTERVAL_MULTIPLIER,
+ Settings.Global.APPOP_HISTORY_BASE_INTERVAL_MILLIS);
+
private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS =
newHashSet(
Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
index 80ab4ea..d161059 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
@@ -18,7 +18,7 @@
## The application with a minimal main dex
include $(CLEAR_VARS)
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex android-support-multidex-instrumentation android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex android-support-multidex-instrumentation androidx.test.rules
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml
index 98d8f27..d9d9eb2 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml
@@ -30,7 +30,7 @@
android:targetPackage="com.android.multidexlegacyandexception"
android:label="Test for MultiDexLegacyAndException" />
- <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.multidexlegacyandexception"
android:label="Test for MultiDexLegacyAndException" />
</manifest>
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/MultiDexAndroidJUnitRunner.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/MultiDexAndroidJUnitRunner.java
index 92a3b0c..fae345f 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/MultiDexAndroidJUnitRunner.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/MultiDexAndroidJUnitRunner.java
@@ -17,8 +17,9 @@
package com.android.multidexlegacyandexception.tests;
import android.os.Bundle;
+
import androidx.multidex.MultiDex;
-import android.support.test.runner.AndroidJUnitRunner;
+import androidx.test.runner.AndroidJUnitRunner;
public class MultiDexAndroidJUnitRunner extends AndroidJUnitRunner {
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/NoActivityJUnit4Test.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/NoActivityJUnit4Test.java
index 94a5b7f..f4b02d0 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/NoActivityJUnit4Test.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/NoActivityJUnit4Test.java
@@ -16,7 +16,8 @@
package com.android.multidexlegacyandexception.tests;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.runner.RunWith;
/**
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index b9b1cdc..b4f19c9 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -39,7 +39,7 @@
virtual ~WeakLooperCallback() { }
public:
- WeakLooperCallback(const wp<LooperCallback>& callback) :
+ explicit WeakLooperCallback(const wp<LooperCallback>& callback) :
mCallback(callback) {
}
diff --git a/libs/protoutil/include/android/util/EncodedBuffer.h b/libs/protoutil/include/android/util/EncodedBuffer.h
index c84de4c..0b7f6e46 100644
--- a/libs/protoutil/include/android/util/EncodedBuffer.h
+++ b/libs/protoutil/include/android/util/EncodedBuffer.h
@@ -38,13 +38,13 @@
{
public:
EncodedBuffer();
- EncodedBuffer(size_t chunkSize);
+ explicit EncodedBuffer(size_t chunkSize);
~EncodedBuffer();
class Pointer {
public:
Pointer();
- Pointer(size_t chunkSize);
+ explicit Pointer(size_t chunkSize);
size_t pos() const;
size_t index() const;
@@ -161,7 +161,7 @@
friend class iterator;
class iterator {
public:
- iterator(const EncodedBuffer& buffer);
+ explicit iterator(const EncodedBuffer& buffer);
/**
* Returns the number of bytes written in the buffer
diff --git a/location/lib/Android.bp b/location/lib/Android.bp
index b09335c..35f2877 100644
--- a/location/lib/Android.bp
+++ b/location/lib/Android.bp
@@ -18,5 +18,7 @@
name: "com.android.location.provider",
srcs: ["java/**/*.java"],
api_packages: ["com.android.location.provider"],
- metalava_enabled: false,
+ srcs_lib: "framework",
+ srcs_lib_whitelist_dirs: ["location/java"],
+ srcs_lib_whitelist_pkgs: ["com.android.internal.location"],
}
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index 1ee851f..7b20f7a 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -250,7 +250,8 @@
if (controllerInfo.mAllowedCommands == null) {
// For trusted apps, send non-null allowed commands to keep
// connection.
- controllerInfo.mAllowedCommands = new Session2CommandGroup();
+ controllerInfo.mAllowedCommands =
+ new Session2CommandGroup.Builder().build();
}
if (DEBUG) {
Log.d(TAG, "Accepting connection: " + controllerInfo);
diff --git a/media/java/android/media/Session2Command.java b/media/java/android/media/Session2Command.java
index d2a5aae..8b285f2 100644
--- a/media/java/android/media/Session2Command.java
+++ b/media/java/android/media/Session2Command.java
@@ -36,8 +36,6 @@
* Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
* <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
* for consistent behavior across all devices.
- * </p>
- * @hide
*/
public final class Session2Command implements Parcelable {
/**
@@ -151,14 +149,17 @@
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ if (dest == null) {
+ throw new IllegalArgumentException("parcel shouldn't be null");
+ }
dest.writeInt(mCommandCode);
dest.writeString(mCustomCommand);
dest.writeBundle(mExtras);
}
@Override
- public boolean equals(Object obj) {
+ public boolean equals(@Nullable Object obj) {
if (!(obj instanceof Session2Command)) {
return false;
}
@@ -185,7 +186,7 @@
* @param resultCode result code
* @param resultData result data
*/
- public Result(int resultCode, Bundle resultData) {
+ public Result(int resultCode, @Nullable Bundle resultData) {
mResultCode = resultCode;
mResultData = resultData;
}
@@ -200,6 +201,7 @@
/**
* Returns the result data.
*/
+ @Nullable
public Bundle getResultData() {
return mResultData;
}
diff --git a/media/java/android/media/Session2CommandGroup.java b/media/java/android/media/Session2CommandGroup.java
index 4668ec4..519888e 100644
--- a/media/java/android/media/Session2CommandGroup.java
+++ b/media/java/android/media/Session2CommandGroup.java
@@ -35,7 +35,6 @@
* <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
* for consistent behavior across all devices.
* </p>
- * @hide
*/
public final class Session2CommandGroup implements Parcelable {
private static final String TAG = "Session2CommandGroup";
@@ -56,16 +55,11 @@
Set<Session2Command> mCommands = new HashSet<>();
/**
- * Default Constructor.
- */
- public Session2CommandGroup() {}
-
- /**
* Creates a new Session2CommandGroup with commands copied from another object.
*
* @param commands The collection of commands to copy.
*/
- public Session2CommandGroup(@Nullable Collection<Session2Command> commands) {
+ Session2CommandGroup(@Nullable Collection<Session2Command> commands) {
if (commands != null) {
mCommands.addAll(commands);
}
@@ -129,7 +123,10 @@
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ if (dest == null) {
+ throw new IllegalArgumentException("parcel shouldn't be null");
+ }
dest.writeParcelableArray(mCommands.toArray(new Session2Command[0]), 0);
}
@@ -149,6 +146,9 @@
* @param commandGroup
*/
public Builder(@NonNull Session2CommandGroup commandGroup) {
+ if (commandGroup == null) {
+ throw new IllegalArgumentException("command group shouldn't be null");
+ }
mCommands = commandGroup.getCommands();
}
diff --git a/media/java/android/media/Session2Token.java b/media/java/android/media/Session2Token.java
index 4634c69..e1fff38 100644
--- a/media/java/android/media/Session2Token.java
+++ b/media/java/android/media/Session2Token.java
@@ -171,7 +171,7 @@
dest.writeString(mPackageName);
dest.writeString(mServiceName);
// TODO: Uncomment below
- //dest.writeStrongBinder(mSessionLink.asBinder());
+ //dest.writeStrongBinder(mSessionLink.getBinder());
dest.writeString(mComponentName == null ? "" : mComponentName.flattenToString());
}
diff --git a/media/java/android/media/session/ControllerCallbackLink.aidl b/media/java/android/media/session/ControllerCallbackLink.aidl
new file mode 100644
index 0000000..8ee8c7d
--- /dev/null
+++ b/media/java/android/media/session/ControllerCallbackLink.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.session;
+
+parcelable ControllerCallbackLink;
diff --git a/media/java/android/media/session/ControllerCallbackLink.java b/media/java/android/media/session/ControllerCallbackLink.java
new file mode 100644
index 0000000..a143c9b
--- /dev/null
+++ b/media/java/android/media/session/ControllerCallbackLink.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.media.MediaMetadata;
+import android.media.session.MediaController.PlaybackInfo;
+import android.media.session.MediaSession.QueueItem;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+
+import java.util.List;
+
+/**
+ * Handles incoming commands to {@link MediaController.Callback}.
+ * <p>
+ * This API is not generally intended for third party application developers.
+ */
+public final class ControllerCallbackLink implements Parcelable {
+ final CallbackStub mCallbackStub;
+ final ISessionControllerCallback mIControllerCallback;
+
+ /**
+ * Constructor for stub (Callee)
+ * @hide
+ */
+ @SystemApi
+ public ControllerCallbackLink(@NonNull CallbackStub callbackStub) {
+ mCallbackStub = callbackStub;
+ mIControllerCallback = new CallbackStubProxy();
+ }
+
+ /**
+ * Constructor for interface (Caller)
+ */
+ ControllerCallbackLink(Parcel in) {
+ mCallbackStub = null;
+ mIControllerCallback = ISessionControllerCallback.Stub.asInterface(in.readStrongBinder());
+ }
+
+ /**
+ * Notify controller that the connected session is destroyed.
+ */
+ public void notifySessionDestroyed() {
+ try {
+ mIControllerCallback.notifySessionDestroyed();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify controller that the connected session sends an event.
+ *
+ * @param event the name of the event
+ * @param extras the extras included with the event
+ */
+ public void notifyEvent(@NonNull String event, @Nullable Bundle extras) {
+ try {
+ mIControllerCallback.notifyEvent(event, extras);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify controller that the current playback state is changed.
+ *
+ * @param state the new playback state
+ */
+ public void notifyPlaybackStateChanged(@Nullable PlaybackState state) {
+ try {
+ mIControllerCallback.notifyPlaybackStateChanged(state);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify controller that the current metadata is changed.
+ *
+ * @param metadata the new metadata
+ */
+ public void notifyMetadataChanged(@Nullable MediaMetadata metadata) {
+ try {
+ mIControllerCallback.notifyMetadataChanged(metadata);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify controller that the current queue is changed.
+ *
+ * @param queue the new queue
+ */
+ public void notifyQueueChanged(@Nullable List<QueueItem> queue) {
+ try {
+ mIControllerCallback.notifyQueueChanged(queue);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify controller that the current queue title is changed.
+ *
+ * @param title the new queue title
+ */
+ public void notifyQueueTitleChanged(@Nullable CharSequence title) {
+ try {
+ mIControllerCallback.notifyQueueTitleChanged(title);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify controller that the extras are changed.
+ *
+ * @param extras the new extras
+ */
+ public void notifyExtrasChanged(@Nullable Bundle extras) {
+ try {
+ mIControllerCallback.notifyExtrasChanged(extras);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify controller that the playback info is changed.
+ *
+ * @param info the new playback info
+ */
+ public void notifyVolumeInfoChanged(@NonNull PlaybackInfo info) {
+ try {
+ mIControllerCallback.notifyVolumeInfoChanged(info);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** Gets the binder */
+ @NonNull
+ public IBinder getBinder() {
+ return mIControllerCallback.asBinder();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeStrongBinder(mIControllerCallback.asBinder());
+ }
+
+ public static final Parcelable.Creator<ControllerCallbackLink> CREATOR =
+ new Parcelable.Creator<ControllerCallbackLink>() {
+ @Override
+ public ControllerCallbackLink createFromParcel(Parcel in) {
+ return new ControllerCallbackLink(in);
+ }
+
+ @Override
+ public ControllerCallbackLink[] newArray(int size) {
+ return new ControllerCallbackLink[size];
+ }
+ };
+
+ /**
+ * Class for Stub implementation
+ * @hide
+ */
+ @SystemApi
+ public abstract static class CallbackStub {
+ /** Stub method for ISessionControllerCallback.notifySessionDestroyed */
+ public void onSessionDestroyed() {
+ }
+
+ /** Stub method for ISessionControllerCallback.notifyEvent */
+ public void onEvent(@NonNull String event, @Nullable Bundle extras) {
+ }
+
+ /** Stub method for ISessionControllerCallback.notifyPlaybackStateChanged */
+ public void onPlaybackStateChanged(@Nullable PlaybackState state) {
+ }
+
+ /** Stub method for ISessionControllerCallback.notifyMetadataChanged */
+ public void onMetadataChanged(@Nullable MediaMetadata metadata) {
+ }
+
+ /** Stub method for ISessionControllerCallback.notifyQueueChanged */
+ public void onQueueChanged(@Nullable List<QueueItem> queue) {
+ }
+
+ /** Stub method for ISessionControllerCallback.notifyQueueTitleChanged */
+ public void onQueueTitleChanged(@Nullable CharSequence title) {
+ }
+
+ /** Stub method for ISessionControllerCallback.notifyExtrasChanged */
+ public void onExtrasChanged(@Nullable Bundle extras) {
+ }
+
+ /** Stub method for ISessionControllerCallback.notifyVolumeInfoChanged */
+ public void onVolumeInfoChanged(@NonNull PlaybackInfo info) {
+ }
+ }
+
+ private class CallbackStubProxy extends ISessionControllerCallback.Stub {
+ @Override
+ public void notifyEvent(String event, Bundle extras) {
+ mCallbackStub.onEvent(event, extras);
+ }
+
+ @Override
+ public void notifySessionDestroyed() {
+ mCallbackStub.onSessionDestroyed();
+ }
+
+ @Override
+ public void notifyPlaybackStateChanged(PlaybackState state) {
+ mCallbackStub.onPlaybackStateChanged(state);
+ }
+
+ @Override
+ public void notifyMetadataChanged(MediaMetadata metadata) {
+ mCallbackStub.onMetadataChanged(metadata);
+ }
+
+ @Override
+ public void notifyQueueChanged(List<QueueItem> queue) {
+ mCallbackStub.onQueueChanged(queue);
+ }
+
+ @Override
+ public void notifyQueueTitleChanged(CharSequence title) {
+ mCallbackStub.onQueueTitleChanged(title);
+ }
+
+ @Override
+ public void notifyExtrasChanged(Bundle extras) {
+ mCallbackStub.onExtrasChanged(extras);
+ }
+
+ @Override
+ public void notifyVolumeInfoChanged(PlaybackInfo info) {
+ mCallbackStub.onVolumeInfoChanged(info);
+ }
+ }
+}
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index bfc05fa..1524ad9 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -16,7 +16,6 @@
package android.media.session;
import android.app.PendingIntent;
-import android.content.pm.ParceledListSlice;
import android.media.AudioAttributes;
import android.media.MediaMetadata;
import android.media.session.ISessionController;
@@ -41,7 +40,8 @@
// These commands are for the TransportPerformer
void setMetadata(in MediaMetadata metadata, long duration, String metadataDescription);
void setPlaybackState(in PlaybackState state);
- void setQueue(in ParceledListSlice queue);
+ // TODO(b/122432476): Replace List with MediaParceledListSlice
+ void setQueue(in List<MediaSession.QueueItem> queue);
void setQueueTitle(CharSequence title);
void setExtras(in Bundle extras);
void setRatingType(int type);
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
index 626338d..9b86bfc 100644
--- a/media/java/android/media/session/ISessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -17,7 +17,7 @@
import android.content.Intent;
import android.media.Rating;
-import android.media.session.ISessionControllerCallback;
+import android.media.session.ControllerCallbackLink;
import android.net.Uri;
import android.os.Bundle;
import android.os.ResultReceiver;
@@ -26,46 +26,46 @@
* @hide
*/
oneway interface ISessionCallback {
- void onCommand(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ void notifyCommand(String packageName, int pid, int uid, in ControllerCallbackLink caller,
String command, in Bundle args, in ResultReceiver cb);
- void onMediaButton(String packageName, int pid, int uid, in Intent mediaButtonIntent,
+ void notifyMediaButton(String packageName, int pid, int uid, in Intent mediaButtonIntent,
int sequenceNumber, in ResultReceiver cb);
- void onMediaButtonFromController(String packageName, int pid, int uid,
- ISessionControllerCallback caller, in Intent mediaButtonIntent);
+ void notifyMediaButtonFromController(String packageName, int pid, int uid,
+ in ControllerCallbackLink caller, in Intent mediaButtonIntent);
// These callbacks are for the TransportPerformer
- void onPrepare(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onPrepareFromMediaId(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String mediaId, in Bundle extras);
- void onPrepareFromSearch(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String query, in Bundle extras);
- void onPrepareFromUri(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ void notifyPrepare(String packageName, int pid, int uid, in ControllerCallbackLink caller);
+ void notifyPrepareFromMediaId(String packageName, int pid, int uid,
+ in ControllerCallbackLink caller, String mediaId, in Bundle extras);
+ void notifyPrepareFromSearch(String packageName, int pid, int uid,
+ in ControllerCallbackLink caller, String query, in Bundle extras);
+ void notifyPrepareFromUri(String packageName, int pid, int uid,
+ in ControllerCallbackLink caller, in Uri uri, in Bundle extras);
+ void notifyPlay(String packageName, int pid, int uid, in ControllerCallbackLink caller);
+ void notifyPlayFromMediaId(String packageName, int pid, int uid,
+ in ControllerCallbackLink caller, String mediaId, in Bundle extras);
+ void notifyPlayFromSearch(String packageName, int pid, int uid,
+ in ControllerCallbackLink caller, String query, in Bundle extras);
+ void notifyPlayFromUri(String packageName, int pid, int uid, in ControllerCallbackLink caller,
in Uri uri, in Bundle extras);
- void onPlay(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onPlayFromMediaId(String packageName, int pid, int uid, ISessionControllerCallback caller,
- String mediaId, in Bundle extras);
- void onPlayFromSearch(String packageName, int pid, int uid, ISessionControllerCallback caller,
- String query, in Bundle extras);
- void onPlayFromUri(String packageName, int pid, int uid, ISessionControllerCallback caller,
- in Uri uri, in Bundle extras);
- void onSkipToTrack(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ void notifySkipToTrack(String packageName, int pid, int uid, in ControllerCallbackLink caller,
long id);
- void onPause(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onStop(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onNext(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onPrevious(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onFastForward(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onRewind(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onSeekTo(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ void notifyPause(String packageName, int pid, int uid, in ControllerCallbackLink caller);
+ void notifyStop(String packageName, int pid, int uid, in ControllerCallbackLink caller);
+ void notifyNext(String packageName, int pid, int uid, in ControllerCallbackLink caller);
+ void notifyPrevious(String packageName, int pid, int uid, in ControllerCallbackLink caller);
+ void notifyFastForward(String packageName, int pid, int uid, in ControllerCallbackLink caller);
+ void notifyRewind(String packageName, int pid, int uid, in ControllerCallbackLink caller);
+ void notifySeekTo(String packageName, int pid, int uid, in ControllerCallbackLink caller,
long pos);
- void onRate(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ void notifyRate(String packageName, int pid, int uid, in ControllerCallbackLink caller,
in Rating rating);
- void onCustomAction(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ void notifyCustomAction(String packageName, int pid, int uid, in ControllerCallbackLink caller,
String action, in Bundle args);
// These callbacks are for volume handling
- void onAdjustVolume(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ void notifyAdjustVolume(String packageName, int pid, int uid, in ControllerCallbackLink caller,
int direction);
- void onSetVolumeTo(String packageName, int pid, int uid,
- ISessionControllerCallback caller, int value);
+ void notifySetVolumeTo(String packageName, int pid, int uid,
+ in ControllerCallbackLink caller, int value);
}
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index a843881..2ba09fd 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -17,10 +17,9 @@
import android.app.PendingIntent;
import android.content.Intent;
-import android.content.pm.ParceledListSlice;
import android.media.MediaMetadata;
import android.media.Rating;
-import android.media.session.ISessionControllerCallback;
+import android.media.session.ControllerCallbackLink;
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
@@ -36,12 +35,12 @@
* @hide
*/
interface ISessionController {
- void sendCommand(String packageName, ISessionControllerCallback caller,
+ void sendCommand(String packageName, in ControllerCallbackLink caller,
String command, in Bundle args, in ResultReceiver cb);
- boolean sendMediaButton(String packageName, ISessionControllerCallback caller,
+ boolean sendMediaButton(String packageName, in ControllerCallbackLink caller,
boolean asSystemService, in KeyEvent mediaButton);
- void registerCallbackListener(String packageName, ISessionControllerCallback cb);
- void unregisterCallbackListener(ISessionControllerCallback cb);
+ void registerCallbackListener(String packageName, in ControllerCallbackLink cb);
+ void unregisterCallbackListener(in ControllerCallbackLink cb);
boolean isTransportControlEnabled();
String getPackageName();
String getTag();
@@ -49,40 +48,40 @@
long getFlags();
MediaController.PlaybackInfo getVolumeAttributes();
void adjustVolume(String packageName, String opPackageName,
- in ISessionControllerCallback caller, boolean asSystemService, int direction,
+ in ControllerCallbackLink caller, boolean asSystemService, int direction,
int flags);
- void setVolumeTo(String packageName, String opPackageName, in ISessionControllerCallback caller,
+ void setVolumeTo(String packageName, String opPackageName, in ControllerCallbackLink caller,
int value, int flags);
// These commands are for the TransportControls
- void prepare(String packageName, ISessionControllerCallback caller);
- void prepareFromMediaId(String packageName, ISessionControllerCallback caller,
+ void prepare(String packageName, in ControllerCallbackLink caller);
+ void prepareFromMediaId(String packageName, in ControllerCallbackLink caller,
String mediaId, in Bundle extras);
- void prepareFromSearch(String packageName, ISessionControllerCallback caller,
+ void prepareFromSearch(String packageName, in ControllerCallbackLink caller,
String string, in Bundle extras);
- void prepareFromUri(String packageName, ISessionControllerCallback caller,
+ void prepareFromUri(String packageName, in ControllerCallbackLink caller,
in Uri uri, in Bundle extras);
- void play(String packageName, ISessionControllerCallback caller);
- void playFromMediaId(String packageName, ISessionControllerCallback caller,
+ void play(String packageName, in ControllerCallbackLink caller);
+ void playFromMediaId(String packageName, in ControllerCallbackLink caller,
String mediaId, in Bundle extras);
- void playFromSearch(String packageName, ISessionControllerCallback caller,
+ void playFromSearch(String packageName, in ControllerCallbackLink caller,
String string, in Bundle extras);
- void playFromUri(String packageName, ISessionControllerCallback caller,
+ void playFromUri(String packageName, in ControllerCallbackLink caller,
in Uri uri, in Bundle extras);
- void skipToQueueItem(String packageName, ISessionControllerCallback caller, long id);
- void pause(String packageName, ISessionControllerCallback caller);
- void stop(String packageName, ISessionControllerCallback caller);
- void next(String packageName, ISessionControllerCallback caller);
- void previous(String packageName, ISessionControllerCallback caller);
- void fastForward(String packageName, ISessionControllerCallback caller);
- void rewind(String packageName, ISessionControllerCallback caller);
- void seekTo(String packageName, ISessionControllerCallback caller, long pos);
- void rate(String packageName, ISessionControllerCallback caller, in Rating rating);
- void sendCustomAction(String packageName, ISessionControllerCallback caller,
+ void skipToQueueItem(String packageName, in ControllerCallbackLink caller, long id);
+ void pause(String packageName, in ControllerCallbackLink caller);
+ void stop(String packageName, in ControllerCallbackLink caller);
+ void next(String packageName, in ControllerCallbackLink caller);
+ void previous(String packageName, in ControllerCallbackLink caller);
+ void fastForward(String packageName, in ControllerCallbackLink caller);
+ void rewind(String packageName, in ControllerCallbackLink caller);
+ void seekTo(String packageName, in ControllerCallbackLink caller, long pos);
+ void rate(String packageName, in ControllerCallbackLink caller, in Rating rating);
+ void sendCustomAction(String packageName, in ControllerCallbackLink caller,
String action, in Bundle args);
MediaMetadata getMetadata();
PlaybackState getPlaybackState();
- ParceledListSlice getQueue();
+ List<MediaSession.QueueItem> getQueue();
CharSequence getQueueTitle();
Bundle getExtras();
int getRatingType();
diff --git a/media/java/android/media/session/ISessionControllerCallback.aidl b/media/java/android/media/session/ISessionControllerCallback.aidl
index fac8897..5c02e7c 100644
--- a/media/java/android/media/session/ISessionControllerCallback.aidl
+++ b/media/java/android/media/session/ISessionControllerCallback.aidl
@@ -15,25 +15,24 @@
package android.media.session;
-import android.content.pm.ParceledListSlice;
import android.media.MediaMetadata;
-import android.media.session.PlaybackState;
import android.media.session.MediaController;
import android.media.session.MediaSession;
+import android.media.session.PlaybackState;
import android.os.Bundle;
/**
* @hide
*/
oneway interface ISessionControllerCallback {
- void onEvent(String event, in Bundle extras);
- void onSessionDestroyed();
+ void notifyEvent(String event, in Bundle extras);
+ void notifySessionDestroyed();
// These callbacks are for the TransportController
- void onPlaybackStateChanged(in PlaybackState state);
- void onMetadataChanged(in MediaMetadata metadata);
- void onQueueChanged(in ParceledListSlice queue);
- void onQueueTitleChanged(CharSequence title);
- void onExtrasChanged(in Bundle extras);
- void onVolumeInfoChanged(in MediaController.PlaybackInfo info);
+ void notifyPlaybackStateChanged(in PlaybackState state);
+ void notifyMetadataChanged(in MediaMetadata metadata);
+ void notifyQueueChanged(in List<MediaSession.QueueItem> queue);
+ void notifyQueueTitleChanged(CharSequence title);
+ void notifyExtrasChanged(in Bundle extras);
+ void notifyVolumeInfoChanged(in MediaController.PlaybackInfo info);
}
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 51148e2..7ac3ef2 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -23,7 +23,7 @@
import android.media.session.IOnMediaKeyListener;
import android.media.session.IOnVolumeKeyLongPressListener;
import android.media.session.ISession;
-import android.media.session.ISessionCallback;
+import android.media.session.SessionCallbackLink;
import android.os.Bundle;
import android.view.KeyEvent;
@@ -32,9 +32,10 @@
* @hide
*/
interface ISessionManager {
- ISession createSession(String packageName, in ISessionCallback cb, String tag, int userId);
+ ISession createSession(String packageName, in SessionCallbackLink cb, String tag, int userId);
void notifySession2Created(in Session2Token sessionToken);
List<IBinder> getSessions(in ComponentName compName, int userId);
+ List<Session2Token> getSession2Tokens(int userId);
void dispatchMediaKeyEvent(String packageName, boolean asSystemService, in KeyEvent keyEvent,
boolean needWakeLock);
void dispatchVolumeKeyEvent(String packageName, String opPackageName, boolean asSystemService,
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index ef2df15..a1b8170 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -21,12 +21,12 @@
import android.annotation.UnsupportedAppUsage;
import android.app.PendingIntent;
import android.content.Context;
-import android.content.pm.ParceledListSlice;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.MediaMetadata;
import android.media.Rating;
import android.media.VolumeProvider;
+import android.media.session.MediaSession.QueueItem;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -72,7 +72,8 @@
private final MediaSession.Token mToken;
private final Context mContext;
- private final CallbackStub mCbStub = new CallbackStub(this);
+ private final ControllerCallbackLink mCbStub =
+ new ControllerCallbackLink(new CallbackStub(this));
private final ArrayList<MessageHandler> mCallbacks = new ArrayList<MessageHandler>();
private final Object mLock = new Object();
@@ -251,10 +252,7 @@
*/
public @Nullable List<MediaSession.QueueItem> getQueue() {
try {
- ParceledListSlice queue = mSessionBinder.getQueue();
- if (queue != null) {
- return queue.getList();
- }
+ return mSessionBinder.getQueue();
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling getQueue.", e);
}
@@ -1113,10 +1111,10 @@
};
}
- private final static class CallbackStub extends ISessionControllerCallback.Stub {
+ private static final class CallbackStub extends ControllerCallbackLink.CallbackStub {
private final WeakReference<MediaController> mController;
- public CallbackStub(MediaController controller) {
+ CallbackStub(MediaController controller) {
mController = new WeakReference<MediaController>(controller);
}
@@ -1153,9 +1151,7 @@
}
@Override
- public void onQueueChanged(ParceledListSlice parceledQueue) {
- List<MediaSession.QueueItem> queue = parceledQueue == null ? null : parceledQueue
- .getList();
+ public void onQueueChanged(List<QueueItem> queue) {
MediaController controller = mController.get();
if (controller != null) {
controller.postMessage(MSG_UPDATE_QUEUE, queue, null);
@@ -1185,7 +1181,6 @@
controller.postMessage(MSG_UPDATE_VOLUME, info, null);
}
}
-
}
private final static class MessageHandler extends Handler {
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index df8cc35..e07cf15 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -24,7 +24,6 @@
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ParceledListSlice;
import android.media.AudioAttributes;
import android.media.MediaDescription;
import android.media.MediaMetadata;
@@ -130,7 +129,7 @@
private final MediaSession.Token mSessionToken;
private final MediaController mController;
private final ISession mBinder;
- private final CallbackStub mCbStub;
+ private final SessionCallbackLink mCbStub;
// Do not change the name of mCallback. Support lib accesses this by using reflection.
@UnsupportedAppUsage
@@ -173,7 +172,7 @@
}
mMaxBitmapSize = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize);
- mCbStub = new CallbackStub(this);
+ mCbStub = new SessionCallbackLink(new CallbackStub(this));
MediaSessionManager manager = (MediaSessionManager) context
.getSystemService(Context.MEDIA_SESSION_SERVICE);
try {
@@ -467,7 +466,7 @@
*/
public void setQueue(@Nullable List<QueueItem> queue) {
try {
- mBinder.setQueue(queue == null ? null : new ParceledListSlice<QueueItem>(queue));
+ mBinder.setQueue(queue);
} catch (RemoteException e) {
Log.wtf("Dead object in setQueue.", e);
}
@@ -1063,7 +1062,7 @@
/**
* @hide
*/
- public static class CallbackStub extends ISessionCallback.Stub {
+ public static final class CallbackStub extends SessionCallbackLink.CallbackStub {
private WeakReference<MediaSession> mMediaSession;
public CallbackStub(MediaSession session) {
@@ -1071,14 +1070,14 @@
}
private static RemoteUserInfo createRemoteUserInfo(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
+ ControllerCallbackLink caller) {
return new RemoteUserInfo(packageName, pid, uid,
- caller != null ? caller.asBinder() : null);
+ caller != null ? caller.getBinder() : null);
}
@Override
public void onCommand(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String command, Bundle args, ResultReceiver cb) {
+ ControllerCallbackLink caller, String command, Bundle args, ResultReceiver cb) {
MediaSession session = mMediaSession.get();
if (session != null) {
session.dispatchCommand(createRemoteUserInfo(packageName, pid, uid, caller),
@@ -1104,7 +1103,7 @@
@Override
public void onMediaButtonFromController(String packageName, int pid, int uid,
- ISessionControllerCallback caller, Intent mediaButtonIntent) {
+ ControllerCallbackLink caller, Intent mediaButtonIntent) {
MediaSession session = mMediaSession.get();
if (session != null) {
session.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid, caller),
@@ -1114,7 +1113,7 @@
@Override
public void onPrepare(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
+ ControllerCallbackLink caller) {
MediaSession session = mMediaSession.get();
if (session != null) {
session.dispatchPrepare(createRemoteUserInfo(packageName, pid, uid, caller));
@@ -1123,7 +1122,7 @@
@Override
public void onPrepareFromMediaId(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String mediaId,
+ ControllerCallbackLink caller, String mediaId,
Bundle extras) {
MediaSession session = mMediaSession.get();
if (session != null) {
@@ -1134,7 +1133,7 @@
@Override
public void onPrepareFromSearch(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String query,
+ ControllerCallbackLink caller, String query,
Bundle extras) {
MediaSession session = mMediaSession.get();
if (session != null) {
@@ -1145,7 +1144,7 @@
@Override
public void onPrepareFromUri(String packageName, int pid, int uid,
- ISessionControllerCallback caller, Uri uri, Bundle extras) {
+ ControllerCallbackLink caller, Uri uri, Bundle extras) {
MediaSession session = mMediaSession.get();
if (session != null) {
session.dispatchPrepareFromUri(createRemoteUserInfo(packageName, pid, uid, caller),
@@ -1155,7 +1154,7 @@
@Override
public void onPlay(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
+ ControllerCallbackLink caller) {
MediaSession session = mMediaSession.get();
if (session != null) {
session.dispatchPlay(createRemoteUserInfo(packageName, pid, uid, caller));
@@ -1164,7 +1163,7 @@
@Override
public void onPlayFromMediaId(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String mediaId,
+ ControllerCallbackLink caller, String mediaId,
Bundle extras) {
MediaSession session = mMediaSession.get();
if (session != null) {
@@ -1175,7 +1174,7 @@
@Override
public void onPlayFromSearch(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String query,
+ ControllerCallbackLink caller, String query,
Bundle extras) {
MediaSession session = mMediaSession.get();
if (session != null) {
@@ -1186,7 +1185,7 @@
@Override
public void onPlayFromUri(String packageName, int pid, int uid,
- ISessionControllerCallback caller, Uri uri, Bundle extras) {
+ ControllerCallbackLink caller, Uri uri, Bundle extras) {
MediaSession session = mMediaSession.get();
if (session != null) {
session.dispatchPlayFromUri(createRemoteUserInfo(packageName, pid, uid, caller),
@@ -1196,7 +1195,7 @@
@Override
public void onSkipToTrack(String packageName, int pid, int uid,
- ISessionControllerCallback caller, long id) {
+ ControllerCallbackLink caller, long id) {
MediaSession session = mMediaSession.get();
if (session != null) {
session.dispatchSkipToItem(createRemoteUserInfo(packageName, pid, uid, caller), id);
@@ -1205,7 +1204,7 @@
@Override
public void onPause(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
+ ControllerCallbackLink caller) {
MediaSession session = mMediaSession.get();
if (session != null) {
session.dispatchPause(createRemoteUserInfo(packageName, pid, uid, caller));
@@ -1214,7 +1213,7 @@
@Override
public void onStop(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
+ ControllerCallbackLink caller) {
MediaSession session = mMediaSession.get();
if (session != null) {
session.dispatchStop(createRemoteUserInfo(packageName, pid, uid, caller));
@@ -1223,7 +1222,7 @@
@Override
public void onNext(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
+ ControllerCallbackLink caller) {
MediaSession session = mMediaSession.get();
if (session != null) {
session.dispatchNext(createRemoteUserInfo(packageName, pid, uid, caller));
@@ -1232,7 +1231,7 @@
@Override
public void onPrevious(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
+ ControllerCallbackLink caller) {
MediaSession session = mMediaSession.get();
if (session != null) {
session.dispatchPrevious(createRemoteUserInfo(packageName, pid, uid, caller));
@@ -1241,7 +1240,7 @@
@Override
public void onFastForward(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
+ ControllerCallbackLink caller) {
MediaSession session = mMediaSession.get();
if (session != null) {
session.dispatchFastForward(createRemoteUserInfo(packageName, pid, uid, caller));
@@ -1250,7 +1249,7 @@
@Override
public void onRewind(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
+ ControllerCallbackLink caller) {
MediaSession session = mMediaSession.get();
if (session != null) {
session.dispatchRewind(createRemoteUserInfo(packageName, pid, uid, caller));
@@ -1259,7 +1258,7 @@
@Override
public void onSeekTo(String packageName, int pid, int uid,
- ISessionControllerCallback caller, long pos) {
+ ControllerCallbackLink caller, long pos) {
MediaSession session = mMediaSession.get();
if (session != null) {
session.dispatchSeekTo(createRemoteUserInfo(packageName, pid, uid, caller), pos);
@@ -1267,7 +1266,7 @@
}
@Override
- public void onRate(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ public void onRate(String packageName, int pid, int uid, ControllerCallbackLink caller,
Rating rating) {
MediaSession session = mMediaSession.get();
if (session != null) {
@@ -1277,7 +1276,7 @@
@Override
public void onCustomAction(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String action, Bundle args) {
+ ControllerCallbackLink caller, String action, Bundle args) {
MediaSession session = mMediaSession.get();
if (session != null) {
session.dispatchCustomAction(createRemoteUserInfo(packageName, pid, uid, caller),
@@ -1287,7 +1286,7 @@
@Override
public void onAdjustVolume(String packageName, int pid, int uid,
- ISessionControllerCallback caller, int direction) {
+ ControllerCallbackLink caller, int direction) {
MediaSession session = mMediaSession.get();
if (session != null) {
session.dispatchAdjustVolume(createRemoteUserInfo(packageName, pid, uid, caller),
@@ -1297,7 +1296,7 @@
@Override
public void onSetVolumeTo(String packageName, int pid, int uid,
- ISessionControllerCallback caller, int value) {
+ ControllerCallbackLink caller, int value) {
MediaSession session = mMediaSession.get();
if (session != null) {
session.dispatchSetVolumeTo(createRemoteUserInfo(packageName, pid, uid, caller),
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index ef5cf00..56ea484 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -98,7 +98,7 @@
* @return The binder object from the system
* @hide
*/
- public @NonNull ISession createSession(@NonNull MediaSession.CallbackStub cbStub,
+ public @NonNull ISession createSession(@NonNull SessionCallbackLink cbStub,
@NonNull String tag, int userId) throws RemoteException {
return mService.createSession(mContext.getPackageName(), cbStub, tag, userId);
}
@@ -179,6 +179,44 @@
}
/**
+ * Gets a list of {@link Session2Token} with type {@link Session2Token#TYPE_SESSION} for the
+ * current user.
+ * <p>
+ * Although this API can be used without any restriction, each session owners can accept or
+ * reject your uses of {@link MediaSession2}.
+ *
+ * @return A list of {@link Session2Token}.
+ * @hide
+ */
+ // TODO: unhide
+ @NonNull
+ public List<Session2Token> getSession2Tokens() {
+ return getSession2Tokens(UserHandle.myUserId());
+ }
+
+ /**
+ * Gets a list of {@link Session2Token} with type {@link Session2Token#TYPE_SESSION} for the
+ * given user.
+ * <p>
+ * If you want to get tokens for another user, you must hold the
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission.
+ *
+ * @param userId The user id to fetch sessions for.
+ * @return A list of {@link Session2Token}
+ * @hide
+ */
+ // TODO: unhide
+ @NonNull
+ public List<Session2Token> getSession2Tokens(int userId) {
+ try {
+ return mService.getSession2Tokens(userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to get session tokens", e);
+ }
+ return new ArrayList<>();
+ }
+
+ /**
* Add a listener to be notified when the list of active sessions
* changes.This requires the
* android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by
diff --git a/media/java/android/media/session/SessionCallbackLink.aidl b/media/java/android/media/session/SessionCallbackLink.aidl
new file mode 100644
index 0000000..c489e5b
--- /dev/null
+++ b/media/java/android/media/session/SessionCallbackLink.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.session;
+
+parcelable SessionCallbackLink;
diff --git a/media/java/android/media/session/SessionCallbackLink.java b/media/java/android/media/session/SessionCallbackLink.java
new file mode 100644
index 0000000..7547bff
--- /dev/null
+++ b/media/java/android/media/session/SessionCallbackLink.java
@@ -0,0 +1,776 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.media.Rating;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+
+/**
+ * Handles incoming commands to {@link MediaSession.Callback}.
+ * <p>
+ * This API is not generally intended for third party application developers.
+ */
+public final class SessionCallbackLink implements Parcelable {
+ final CallbackStub mCallbackStub;
+ final ISessionCallback mISessionCallback;
+
+ /**
+ * Constructor for stub (Callee)
+ */
+ SessionCallbackLink(@NonNull CallbackStub callbackStub) {
+ mCallbackStub = callbackStub;
+ mISessionCallback = new CallbackStubProxy();
+ }
+
+ /**
+ * Constructor for interface (Caller)
+ */
+ SessionCallbackLink(Parcel in) {
+ mCallbackStub = null;
+ mISessionCallback = ISessionCallback.Stub.asInterface(in.readStrongBinder());
+ }
+
+ /**
+ * Notify session that a controller sends a command.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ * @param command the name of the command
+ * @param args the arguments included with the command
+ * @param cb the result receiver for getting the result of the command
+ */
+ public void notifyCommand(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, @NonNull String command,
+ @Nullable Bundle args, @Nullable ResultReceiver cb) {
+ try {
+ mISessionCallback.notifyCommand(packageName, pid, uid, caller, command, args, cb);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify session that the android system sends a media button event.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param mediaButtonIntent the media button intent
+ * @param sequenceNumber the sequence number of this call
+ * @param cb the result receiver for getting the result of the command
+ */
+ public void notifyMediaButton(@NonNull String packageName, int pid, int uid,
+ @NonNull Intent mediaButtonIntent, int sequenceNumber,
+ @Nullable ResultReceiver cb) {
+ try {
+ mISessionCallback.notifyMediaButton(packageName, pid, uid, mediaButtonIntent,
+ sequenceNumber, cb);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify session that a controller sends a media button event.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ * @param mediaButtonIntent the media button intent
+ */
+ public void notifyMediaButtonFromController(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, @NonNull Intent mediaButtonIntent) {
+ try {
+ mISessionCallback.notifyMediaButtonFromController(packageName, pid, uid, caller,
+ mediaButtonIntent);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify session that a controller requests preparing media.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ */
+ public void notifyPrepare(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller) {
+ try {
+ mISessionCallback.notifyPrepare(packageName, pid, uid, caller);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify session that a controller requests preparing media from given media ID.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ * @param mediaId the ID of the media
+ * @param extras the extras included with this request.
+ */
+ public void notifyPrepareFromMediaId(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, @NonNull String mediaId,
+ @Nullable Bundle extras) {
+ try {
+ mISessionCallback.notifyPrepareFromMediaId(packageName, pid, uid, caller, mediaId,
+ extras);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify session that a controller requests preparing media from given search query.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ * @param query the search query
+ * @param extras the extras included with this request.
+ */
+ public void notifyPrepareFromSearch(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, @NonNull String query,
+ @Nullable Bundle extras) {
+ try {
+ mISessionCallback.notifyPrepareFromSearch(packageName, pid, uid, caller, query, extras);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify session that a controller requests preparing media from given uri.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ * @param uri the uri of the media
+ * @param extras the extras included with this request.
+ */
+ public void notifyPrepareFromUri(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, @NonNull Uri uri, @Nullable Bundle extras) {
+ try {
+ mISessionCallback.notifyPrepareFromUri(packageName, pid, uid, caller, uri, extras);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify session that a controller requests playing media.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ */
+ public void notifyPlay(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller) {
+ try {
+ mISessionCallback.notifyPlay(packageName, pid, uid, caller);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify session that a controller requests playing media from given media ID.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ * @param mediaId the ID of the media
+ * @param extras the extras included with this request.
+ */
+ public void notifyPlayFromMediaId(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, @NonNull String mediaId,
+ @Nullable Bundle extras) {
+ try {
+ mISessionCallback.notifyPlayFromMediaId(packageName, pid, uid, caller, mediaId, extras);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify session that a controller requests playing media from given search query.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ * @param query the search query
+ * @param extras the extras included with this request.
+ */
+ public void notifyPlayFromSearch(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, @NonNull String query,
+ @Nullable Bundle extras) {
+ try {
+ mISessionCallback.notifyPlayFromSearch(packageName, pid, uid, caller, query, extras);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify session that a controller requests playing media from given uri.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ * @param uri the uri of the media
+ * @param extras the extras included with this request.
+ */
+ public void notifyPlayFromUri(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, @NonNull Uri uri, @Nullable Bundle extras) {
+ try {
+ mISessionCallback.notifyPlayFromUri(packageName, pid, uid, caller, uri, extras);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify session that a controller requests skipping to the queue item with given ID.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ * @param id the queue id of the item
+ */
+ public void notifySkipToTrack(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, long id) {
+ try {
+ mISessionCallback.notifySkipToTrack(packageName, pid, uid, caller, id);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify session that a controller requests pausing media.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ */
+ public void notifyPause(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller) {
+ try {
+ mISessionCallback.notifyPause(packageName, pid, uid, caller);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify session that a controller requests stopping media.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ */
+ public void notifyStop(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller) {
+ try {
+ mISessionCallback.notifyStop(packageName, pid, uid, caller);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify session that a controller requests skipping to the next queue item.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ */
+ public void notifyNext(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller) {
+ try {
+ mISessionCallback.notifyNext(packageName, pid, uid, caller);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify session that a controller requests skipping to the previous queue item.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ */
+ public void notifyPrevious(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller) {
+ try {
+ mISessionCallback.notifyPrevious(packageName, pid, uid, caller);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify session that a controller requests fast-forwarding.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ */
+ public void notifyFastForward(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller) {
+ try {
+ mISessionCallback.notifyFastForward(packageName, pid, uid, caller);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify session that a controller requests rewinding.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ */
+ public void notifyRewind(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller) {
+ try {
+ mISessionCallback.notifyRewind(packageName, pid, uid, caller);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify session that a controller requests seeking to the specific position.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ * @param pos the position to move to, in milliseconds
+ */
+ public void notifySeekTo(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, long pos) {
+ try {
+ mISessionCallback.notifySeekTo(packageName, pid, uid, caller, pos);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify session that a controller requests rating of the current media.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ * @param rating the rating of the current media
+ */
+ public void notifyRate(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, @NonNull Rating rating) {
+ try {
+ mISessionCallback.notifyRate(packageName, pid, uid, caller, rating);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify session that a controller sends a custom action.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ * @param action the name of the action
+ * @param args the arguments included with this action
+ */
+ public void notifyCustomAction(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, @NonNull String action, @Nullable Bundle args) {
+ try {
+ mISessionCallback.notifyCustomAction(packageName, pid, uid, caller, action, args);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify session that a controller requests adjusting volume.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ * @param direction the direction of the volume change.
+ */
+ public void notifyAdjustVolume(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, int direction) {
+ try {
+ mISessionCallback.notifyAdjustVolume(packageName, pid, uid, caller, direction);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Notify session that a controller requests setting volume.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ * @param value the volume value to set
+ */
+ public void notifySetVolumeTo(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, int value) {
+ try {
+ mISessionCallback.notifySetVolumeTo(packageName, pid, uid, caller, value);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** Gets the binder */
+ @NonNull
+ public IBinder getBinder() {
+ return mISessionCallback.asBinder();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeStrongBinder(mISessionCallback.asBinder());
+ }
+
+ public static final Parcelable.Creator<SessionCallbackLink> CREATOR =
+ new Parcelable.Creator<SessionCallbackLink>() {
+ @Override
+ public SessionCallbackLink createFromParcel(Parcel in) {
+ return new SessionCallbackLink(in);
+ }
+
+ @Override
+ public SessionCallbackLink[] newArray(int size) {
+ return new SessionCallbackLink[size];
+ }
+ };
+
+ /**
+ * Class for Stub implementation
+ */
+ abstract static class CallbackStub {
+ /** Stub method for ISessionCallback.notifyCommand */
+ public void onCommand(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, @NonNull String command,
+ @Nullable Bundle args, @Nullable ResultReceiver cb) {
+ }
+
+ /** Stub method for ISessionCallback.notifyMediaButton */
+ public void onMediaButton(@NonNull String packageName, int pid, int uid,
+ @NonNull Intent mediaButtonIntent, int sequenceNumber,
+ @Nullable ResultReceiver cb) {
+ }
+
+ /** Stub method for ISessionCallback.notifyMediaButtonFromController */
+ public void onMediaButtonFromController(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, @NonNull Intent mediaButtonIntent) {
+ }
+
+ /** Stub method for ISessionCallback.notifyPrepare */
+ public void onPrepare(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller) {
+ }
+
+ /** Stub method for ISessionCallback.notifyPrepareFromMediaId */
+ public void onPrepareFromMediaId(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, @NonNull String mediaId,
+ @Nullable Bundle extras) {
+ }
+
+ /** Stub method for ISessionCallback.notifyPrepareFromSearch */
+ public void onPrepareFromSearch(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, String query, @Nullable Bundle extras) {
+ }
+
+ /** Stub method for ISessionCallback.notifyPrepareFromUri */
+ public void onPrepareFromUri(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, @NonNull Uri uri, @Nullable Bundle extras) {
+ }
+
+ /** Stub method for ISessionCallback.notifyPlay */
+ public void onPlay(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller) {
+ }
+
+ /** Stub method for ISessionCallback.notifyPlayFromMediaId */
+ public void onPlayFromMediaId(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, @NonNull String mediaId,
+ @Nullable Bundle extras) {
+ }
+
+ /** Stub method for ISessionCallback.notifyPlayFromSearch */
+ public void onPlayFromSearch(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, String query, @Nullable Bundle extras) {
+ }
+
+ /** Stub method for ISessionCallback.notifyPlayFromUri */
+ public void onPlayFromUri(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, @NonNull Uri uri, @Nullable Bundle extras) {
+ }
+
+ /** Stub method for ISessionCallback.notifySkipToTrack */
+ public void onSkipToTrack(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, long id) {
+ }
+
+ /** Stub method for ISessionCallback.notifyPause */
+ public void onPause(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller) {
+ }
+
+ /** Stub method for ISessionCallback.notifyStop */
+ public void onStop(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller) {
+ }
+
+ /** Stub method for ISessionCallback.notifyNext */
+ public void onNext(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller) {
+ }
+
+ /** Stub method for ISessionCallback.notifyPrevious */
+ public void onPrevious(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller) {
+ }
+
+ /** Stub method for ISessionCallback.notifyFastForward */
+ public void onFastForward(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller) {
+ }
+
+ /** Stub method for ISessionCallback.notifyRewind */
+ public void onRewind(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller) {
+ }
+
+ /** Stub method for ISessionCallback.notifySeekTo */
+ public void onSeekTo(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, long pos) {
+ }
+
+ /** Stub method for ISessionCallback.notifyRate */
+ public void onRate(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, @NonNull Rating rating) {
+ }
+
+ /** Stub method for ISessionCallback.notifyCustomAction */
+ public void onCustomAction(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, @NonNull String action,
+ @Nullable Bundle args) {
+ }
+
+ /** Stub method for ISessionCallback.notifyAdjustVolume */
+ public void onAdjustVolume(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, int direction) {
+ }
+
+ /** Stub method for ISessionCallback.notifySetVolumeTo */
+ public void onSetVolumeTo(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, int value) {
+ }
+ }
+
+ private class CallbackStubProxy extends ISessionCallback.Stub {
+ @Override
+ public void notifyCommand(String packageName, int pid, int uid,
+ ControllerCallbackLink caller, String command, Bundle args, ResultReceiver cb) {
+ mCallbackStub.onCommand(packageName, pid, uid, caller, command, args, cb);
+ }
+
+ @Override
+ public void notifyMediaButton(String packageName, int pid, int uid,
+ Intent mediaButtonIntent, int sequenceNumber, ResultReceiver cb) {
+ mCallbackStub.onMediaButton(packageName, pid, uid, mediaButtonIntent, sequenceNumber,
+ cb);
+ }
+
+ @Override
+ public void notifyMediaButtonFromController(String packageName, int pid, int uid,
+ ControllerCallbackLink caller, Intent mediaButtonIntent) {
+ mCallbackStub.onMediaButtonFromController(packageName, pid, uid, caller,
+ mediaButtonIntent);
+ }
+
+ @Override
+ public void notifyPrepare(String packageName, int pid, int uid,
+ ControllerCallbackLink caller) {
+ mCallbackStub.onPrepare(packageName, pid, uid, caller);
+ }
+
+ @Override
+ public void notifyPrepareFromMediaId(String packageName, int pid, int uid,
+ ControllerCallbackLink caller, String mediaId, Bundle extras) {
+ mCallbackStub.onPrepareFromMediaId(packageName, pid, uid, caller, mediaId, extras);
+ }
+
+ @Override
+ public void notifyPrepareFromSearch(String packageName, int pid, int uid,
+ ControllerCallbackLink caller, String query, Bundle extras) {
+ mCallbackStub.onPrepareFromSearch(packageName, pid, uid, caller, query, extras);
+ }
+
+ @Override
+ public void notifyPrepareFromUri(String packageName, int pid, int uid,
+ ControllerCallbackLink caller, Uri uri, Bundle extras) {
+ mCallbackStub.onPrepareFromUri(packageName, pid, uid, caller, uri, extras);
+ }
+
+ @Override
+ public void notifyPlay(String packageName, int pid, int uid,
+ ControllerCallbackLink caller) {
+ mCallbackStub.onPlay(packageName, pid, uid, caller);
+ }
+
+ @Override
+ public void notifyPlayFromMediaId(String packageName, int pid, int uid,
+ ControllerCallbackLink caller, String mediaId, Bundle extras) {
+ mCallbackStub.onPlayFromMediaId(packageName, pid, uid, caller, mediaId, extras);
+ }
+
+ @Override
+ public void notifyPlayFromSearch(String packageName, int pid, int uid,
+ ControllerCallbackLink caller, String query, Bundle extras) {
+ mCallbackStub.onPlayFromSearch(packageName, pid, uid, caller, query, extras);
+ }
+
+ @Override
+ public void notifyPlayFromUri(String packageName, int pid, int uid,
+ ControllerCallbackLink caller, Uri uri, Bundle extras) {
+ mCallbackStub.onPlayFromUri(packageName, pid, uid, caller, uri, extras);
+ }
+
+ @Override
+ public void notifySkipToTrack(String packageName, int pid, int uid,
+ ControllerCallbackLink caller, long id) {
+ mCallbackStub.onSkipToTrack(packageName, pid, uid, caller, id);
+ }
+
+ @Override
+ public void notifyPause(String packageName, int pid, int uid,
+ ControllerCallbackLink caller) {
+ mCallbackStub.onPause(packageName, pid, uid, caller);
+ }
+
+ @Override
+ public void notifyStop(String packageName, int pid, int uid,
+ ControllerCallbackLink caller) {
+ mCallbackStub.onStop(packageName, pid, uid, caller);
+ }
+
+ @Override
+ public void notifyNext(String packageName, int pid, int uid,
+ ControllerCallbackLink caller) {
+ mCallbackStub.onNext(packageName, pid, uid, caller);
+ }
+
+ @Override
+ public void notifyPrevious(String packageName, int pid, int uid,
+ ControllerCallbackLink caller) {
+ mCallbackStub.onPrevious(packageName, pid, uid, caller);
+ }
+
+ @Override
+ public void notifyFastForward(String packageName, int pid, int uid,
+ ControllerCallbackLink caller) {
+ mCallbackStub.onFastForward(packageName, pid, uid, caller);
+ }
+
+ @Override
+ public void notifyRewind(String packageName, int pid, int uid,
+ ControllerCallbackLink caller) {
+ mCallbackStub.onRewind(packageName, pid, uid, caller);
+ }
+
+ @Override
+ public void notifySeekTo(String packageName, int pid, int uid,
+ ControllerCallbackLink caller, long pos) {
+ mCallbackStub.onSeekTo(packageName, pid, uid, caller, pos);
+ }
+
+ @Override
+ public void notifyRate(String packageName, int pid, int uid, ControllerCallbackLink caller,
+ Rating rating) {
+ mCallbackStub.onRate(packageName, pid, uid, caller, rating);
+ }
+
+ @Override
+ public void notifyCustomAction(String packageName, int pid, int uid,
+ ControllerCallbackLink caller, String action, Bundle args) {
+ mCallbackStub.onCustomAction(packageName, pid, uid, caller, action, args);
+ }
+
+ @Override
+ public void notifyAdjustVolume(String packageName, int pid, int uid,
+ ControllerCallbackLink caller, int direction) {
+ mCallbackStub.onAdjustVolume(packageName, pid, uid, caller, direction);
+ }
+
+ @Override
+ public void notifySetVolumeTo(String packageName, int pid, int uid,
+ ControllerCallbackLink caller, int value) {
+ mCallbackStub.onSetVolumeTo(packageName, pid, uid, caller, value);
+ }
+ }
+}
diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java
index fa69062..ada77c5 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerManager.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java
@@ -372,6 +372,7 @@
* @hide
*/
@RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
+ @UnsupportedAppUsage
public int getModelState(UUID soundModelId) {
if (soundModelId == null) {
return STATUS_ERROR;
diff --git a/media/lib/signer/Android.bp b/media/lib/signer/Android.bp
index 8c43683..44f8725 100644
--- a/media/lib/signer/Android.bp
+++ b/media/lib/signer/Android.bp
@@ -18,5 +18,7 @@
name: "com.android.mediadrm.signer",
srcs: ["java/**/*.java"],
api_packages: ["com.android.mediadrm.signer"],
- metalava_enabled: false,
+ srcs_lib: "framework",
+ srcs_lib_whitelist_dirs: ["media/java"],
+ srcs_lib_whitelist_pkgs: ["android.media"],
}
diff --git a/packages/AppPredictionLib/Android.bp b/packages/AppPredictionLib/Android.bp
new file mode 100644
index 0000000..e0f4ded
--- /dev/null
+++ b/packages/AppPredictionLib/Android.bp
@@ -0,0 +1,24 @@
+// 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.
+
+android_library {
+ name: "app_prediction",
+
+ sdk_version: "system_current",
+ min_sdk_version: "system_current",
+
+ srcs: [
+ "src/**/*.java",
+ ],
+}
diff --git a/packages/AppPredictionLib/AndroidManifest.xml b/packages/AppPredictionLib/AndroidManifest.xml
new file mode 100644
index 0000000..b992788
--- /dev/null
+++ b/packages/AppPredictionLib/AndroidManifest.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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.app.prediction">
+</manifest>
diff --git a/packages/AppPredictionLib/src/com/android/app/prediction/Constants.java b/packages/AppPredictionLib/src/com/android/app/prediction/Constants.java
new file mode 100644
index 0000000..0993c9a
--- /dev/null
+++ b/packages/AppPredictionLib/src/com/android/app/prediction/Constants.java
@@ -0,0 +1,71 @@
+/*
+ * 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.app.prediction;
+
+/**
+ * Constants to be used with {@link android.app.prediction.AppPredictor}.
+ */
+public class Constants {
+
+ /**
+ * UI surface for predictions displayed on the user's home screen
+ */
+ public static final String UI_SURFACE_HOME = "home";
+
+ /**
+ * UI surface for predictions displayed on the recents/task switcher view
+ */
+ public static final String UI_SURFACE_RECENTS = "recents";
+
+ /**
+ * UI surface for predictions displayed on the share sheet.
+ */
+ public static final String UI_SURFACE_SHARE = "share";
+
+ /**
+ * Location constant when an app target or shortcut is started from the apps list
+ */
+ public static final String LAUNCH_LOCATION_APPS_LIST = "apps_list";
+
+ /**
+ * Location constant when an app target or shortcut is started from the user's home screen
+ */
+ public static final String LAUNCH_LOCATION_APPS_HOME = "home";
+
+ /**
+ * Location constant when an app target or shortcut is started from task switcher
+ */
+ public static final String LAUNCH_LOCATION_APPS_RECENTS = "recents";
+
+ /**
+ * Location constant when an app target or shortcut is started in the share sheet while it is
+ * in collapsed state (showing a limited set of result).
+ */
+ public static final String LAUNCH_LOCATION_APPS_SHARE_COLLAPSED = "share_collapsed";
+
+ /**
+ * Location constant when an app target or shortcut is started in the share sheet while it is
+ * in expended state and showing all the results.
+ */
+ public static final String LAUNCH_LOCATION_APPS_SHARE_EXPANDED = "shared_expanded";
+
+ /**
+ * Location constant when an app target or shortcut is started in the share sheet when the
+ * target is displayed as a placeholder for an deprecated object.
+ */
+ public static final String LAUNCH_LOCATION_APPS_SHARE_LEGACY = "share_legacy";
+}
diff --git a/packages/PackageInstaller/res/values-da/strings.xml b/packages/PackageInstaller/res/values-da/strings.xml
index 933ff3f..9b57186 100644
--- a/packages/PackageInstaller/res/values-da/strings.xml
+++ b/packages/PackageInstaller/res/values-da/strings.xml
@@ -90,7 +90,7 @@
<string name="anonymous_source_continue" msgid="4375745439457209366">"Fortsæt"</string>
<string name="external_sources_settings" msgid="4046964413071713807">"Indstillinger"</string>
<string name="wear_app_channel" msgid="1960809674709107850">"Installerer/afinstallerer Wear-apps"</string>
- <string name="app_installed_notification_channel_description" msgid="2695385797601574123">"Underretning om appinstallation"</string>
+ <string name="app_installed_notification_channel_description" msgid="2695385797601574123">"Notifikation om appinstallation"</string>
<string name="notification_installation_success_message" msgid="6450467996056038442">"Appen er installeret"</string>
<string name="notification_installation_success_status" msgid="3172502643504323321">"\"<xliff:g id="APPNAME">%1$s</xliff:g>\" er installeret"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-mr/strings.xml b/packages/PackageInstaller/res/values-mr/strings.xml
index 2182631..4deab35 100644
--- a/packages/PackageInstaller/res/values-mr/strings.xml
+++ b/packages/PackageInstaller/res/values-mr/strings.xml
@@ -59,7 +59,7 @@
<string name="uninstall_update_text" msgid="863648314632448705">"फॅक्टरी आवृत्तीसह हे अॅप बदलायचे का? सर्व डेटा काढला जाईल."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"फॅक्टरी आवृत्तीसह हे अॅप बदलायचे? सर्व डेटा काढला जाईल. हे कार्य प्रोफाइल असलेल्यांसह या डिव्हाइसच्या सर्व वापरकर्त्यांना प्रभावित करते."</string>
<string name="uninstall_remove_contributed_files" msgid="2048594420923203453">"<xliff:g id="SIZE">%1$s</xliff:g> आकाराच्या संबंधित मीडिया फायलीदेखील काढा."</string>
- <string name="uninstall_keep_data" msgid="7002379587465487550">"अॅप डेटा पैकी <xliff:g id="SIZE">%1$s</xliff:g> ठेवा."</string>
+ <string name="uninstall_keep_data" msgid="7002379587465487550">"ॲप डेटा पैकी <xliff:g id="SIZE">%1$s</xliff:g> ठेवा."</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"अनइंस्टॉल रन होत आहेत"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"अनइंस्टॉल करता आले नाही"</string>
<string name="uninstalling" msgid="8709566347688966845">"अनइंस्टॉल करत आहे…"</string>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 1dd7838..ac34a99e 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nuwe rugsteunwagwoord ingestel"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nuwe wagwoord en bevestiging stem nie ooreen nie"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Rugsteunwagwoord kon nie ingestel word nie"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Laai tans …"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Lewendig (verstek)"</item>
<item msgid="8446070607501413455">"Natuurlik"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Vra elke keer"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Totdat jy dit afskakel"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Sopas"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Aansluitingprogram om opgedateerde grafikadrywer in ontwikkeling te gebruik"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Foonluidspreker"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 2ce5f44..9405b7d 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"በመጫን ላይ…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"ነዛሪ (ነባሪ)"</item>
<item msgid="8446070607501413455">"ተፈጥሯዊ"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ሁልጊዜ ጠይቅ"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"እስኪያጠፉት ድረስ"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"ልክ አሁን"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"በግንባታ ላይ የተዘመነ የግራፊክስ ነጂን ለመጠቀም መተግበሪያን መርጠው ያስገቡ"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"የስልክ ድምጽ ማጉያ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 23f3a12..8ffd7a9 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"جارٍ التحميل…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"نابض بالحياة (تلقائي)"</item>
<item msgid="8446070607501413455">"طبيعي"</item>
@@ -453,6 +454,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"الطلب في كل مرة"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"إلى أن توقف الوضع يدويًا"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"للتو"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"فعِّل التطبيق لاستخدام برنامج تشغيل الرسومات المُحدَّث في تطوير البرامج."</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"مكبر صوت الهاتف"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-as/arrays.xml b/packages/SettingsLib/res/values-as/arrays.xml
index 39c0b00..c0a2179 100644
--- a/packages/SettingsLib/res/values-as/arrays.xml
+++ b/packages/SettingsLib/res/values-as/arrays.xml
@@ -40,7 +40,7 @@
<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="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>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 86d1459..3ad13bd 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -32,11 +32,11 @@
<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_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_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>
@@ -55,16 +55,16 @@
<string name="bluetooth_disconnected" msgid="6557104142667339895">"সংযোগ বিচ্ছিন্ন কৰা হ’ল"</string>
<string name="bluetooth_disconnecting" msgid="8913264760027764974">"সংযোগ বিচ্ছিন্ন কৰি থকা হৈছে…"</string>
<string name="bluetooth_connecting" msgid="8555009514614320497">"সংযোগ কৰি থকা হৈছে…"</string>
- <string name="bluetooth_connected" msgid="5427152882755735944">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> সংযোগ কৰা হ\'ল"</string>
+ <string name="bluetooth_connected" msgid="5427152882755735944">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> সংযোগ কৰা হ’ল"</string>
<string name="bluetooth_pairing" msgid="1426882272690346242">"যোৰা লগোৱা হৈছে…"</string>
- <string name="bluetooth_connected_no_headset" msgid="616068069034994802">"সংযোগ কৰা হ\'ল (ফ\'ন নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_a2dp" msgid="3736431800395923868">"সংযোগ কৰা হ\'ল (মিডিয়া নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_map" msgid="3200033913678466453">"সংযোগ কৰা হ\'ল (বাৰ্তাত প্ৰৱেশাধিকাৰ নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_headset_no_a2dp" msgid="2047403011284187056">"সংযোগ কৰা হ\'ল (কোনো ফ\'ন বা মিডিয়া নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_battery_level" msgid="5162924691231307748">"সংযোগ কৰা হ\'ল, বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_headset_battery_level" msgid="1610296229139400266">"সংযোগ কৰা হ\'ল (ফ\'ন নাই), বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_a2dp_battery_level" msgid="3908466636369853652">"সংযোগ কৰা হ\'ল (মিডিয়া নাই), বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="1163440823807659316">"সংযোগ কৰা হ\'ল (কোনো ফ\'ন বা মিডিয়া নাই), বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_headset" msgid="616068069034994802">"সংযোগ কৰা হ’ল (ফ\'ন নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_a2dp" msgid="3736431800395923868">"সংযোগ কৰা হ’ল (মিডিয়া নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_map" msgid="3200033913678466453">"সংযোগ কৰা হ’ল (বাৰ্তাত প্ৰৱেশাধিকাৰ নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_headset_no_a2dp" msgid="2047403011284187056">"সংযোগ কৰা হ’ল (কোনো ফ\'ন বা মিডিয়া নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_connected_battery_level" msgid="5162924691231307748">"সংযোগ কৰা হ’ল, বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_headset_battery_level" msgid="1610296229139400266">"সংযোগ কৰা হ’ল (ফ\'ন নাই), বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_a2dp_battery_level" msgid="3908466636369853652">"সংযোগ কৰা হ’ল (মিডিয়া নাই), বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="1163440823807659316">"সংযোগ কৰা হ’ল (কোনো ফ\'ন বা মিডিয়া নাই), বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level" msgid="3149689299296462009">"সক্ৰিয়, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> বেটাৰি"</string>
<string name="bluetooth_battery_level" msgid="1447164613319663655">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> বেটাৰি"</string>
<string name="bluetooth_active_no_battery_level" msgid="8380223546730241956">"সক্ৰিয়"</string>
@@ -81,9 +81,9 @@
<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>
<string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"শ্ৰৱণ যন্ত্ৰ"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"শ্ৰৱণ যন্ত্ৰৰ লগত সংযোগ কৰা হ\'ল"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"শ্ৰৱণ যন্ত্ৰৰ লগত সংযোগ কৰা হ’ল"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"মিডিয়া অডিঅ’লৈ সংযোগ হৈছে"</string>
- <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ফোন অডিঅ\'ৰ লগত সংযোগ কৰা হ\'ল"</string>
+ <string name="bluetooth_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>
@@ -206,10 +206,10 @@
<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_display_certification" msgid="8611569543791307533">"বেতাঁৰ ডিছপ্লে’ প্ৰমাণীকৰণ"</string>
<string name="wifi_verbose_logging" msgid="4203729756047242344">"ৱাই-ফাই ভাৰ্ব\'ছ লগিং সক্ষম কৰক"</string>
<string name="wifi_connected_mac_randomization" msgid="3168165236877957767">"সংযুক্ত MAC যাদৃচ্ছিকৰণ"</string>
- <string name="mobile_data_always_on" msgid="8774857027458200434">"ম\'বাইল ডেটা সদা-সক্ৰিয়"</string>
+ <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>
@@ -233,7 +233,7 @@
<string name="private_dns_mode_provider" msgid="8354935160639360804">"ব্যক্তিগত ডিএনএছ প্ৰদানকাৰীৰ হোষ্টনাম"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"ডিএনএছ সেৱা যোগানকাৰীৰ হ\'ষ্টনাম দিয়ক"</string>
<string name="private_dns_mode_provider_failure" msgid="231837290365031223">"সংযোগ কৰিব পৰা নগ\'ল"</string>
- <string name="wifi_display_certification_summary" msgid="1155182309166746973">"বেতাঁৰ ডিছপ্লে প্ৰমাণপত্ৰৰ বাবে বিকল্পসমূহ দেখুৱাওক"</string>
+ <string name="wifi_display_certification_summary" msgid="1155182309166746973">"বেতাঁৰ ডিছপ্লে’ প্ৰমাণপত্ৰৰ বাবে বিকল্পসমূহ দেখুৱাওক"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"ৱাই-ফাই লগিঙৰ মাত্ৰা বঢ়াওক, Wi‑Fi পিকাৰত প্ৰতি SSID RSSI দেখুৱাওক"</string>
<string name="wifi_connected_mac_randomization_summary" msgid="1743059848752201485">"ৱাই-ফাই নেটৱৰ্কৰ লগত সংযোগ কৰি থকাৰ সময়ত MAC ঠিকনা যাদৃচ্ছিক কৰক"</string>
<string name="wifi_metered_label" msgid="4514924227256839725">"নিৰিখ-নিৰ্দিষ্ট"</string>
@@ -249,7 +249,7 @@
<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="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>
@@ -285,7 +285,7 @@
<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="4117270979975470789">"আপডেট চাওক দেখুৱাওক"</string>
+ <string name="show_hw_screen_updates" msgid="4117270979975470789">"আপডে’ট চাওক দেখুৱাওক"</string>
<string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"অঁকাৰ সময়ত ৱিণ্ড\'ৰ ভিতৰত ফ্লাশ্ব দৰ্শন"</string>
<string name="show_hw_layers_updates" msgid="5645728765605699821">"হাৰ্ডৱেৰৰ তৰপৰ আপডেইট দেখুৱাওক"</string>
<string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"হাৰ্ডৱেৰ লেয়াৰ আপডেইট হওতে সিঁহতক সেউজীয়া ৰঙেৰে ফ্লাশ্ব কৰক"</string>
@@ -327,9 +327,10 @@
<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_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 name="loading_injected_setting_summary" msgid="4095178591461231376">"ল’ড হৈ আছে…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"জীৱন্ত (ডিফ\'ল্ট)"</item>
<item msgid="8446070607501413455">"প্ৰাকৃতিক"</item>
@@ -422,15 +423,15 @@
<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="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>
<string name="wifi_status_mac_randomized" msgid="5589328382467438245">"MAC ক্ৰমানুসৰি ছেট কৰা হোৱা নাই"</string>
<plurals name="wifi_tether_connected_summary" formatted="false" msgid="3871603864314407780">
- <item quantity="one">%1$dটা ডিভাইচ সংযোগ হ\'ল</item>
- <item quantity="other">%1$dটা ডিভাইচ সংযোগ হ\'ল</item>
+ <item quantity="one">%1$dটা ডিভাইচ সংযোগ হ’ল</item>
+ <item quantity="other">%1$dটা ডিভাইচ সংযোগ হ’ল</item>
</plurals>
<string name="accessibility_manual_zen_more_time" msgid="1636187409258564291">"অধিক সময়।"</string>
<string name="accessibility_manual_zen_less_time" msgid="6590887204171164991">"কম সময়।"</string>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"প্ৰতিবাৰতে সোধক"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"আপুনি অফ নকৰা পর্যন্ত"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"এই মাত্ৰ"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"বিকাশকাৰ্য চলি থকা আপডে\'টেড গ্ৰাফিক ড্ৰাইভাৰ ব্যৱহাৰ কৰিবলৈ এপ্ অপ্ট ইন কৰক"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ফ’নৰ স্পীকাৰ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 17d0ca6..daa9c8f 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Yeni rezerv parolu ayarlandı"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Yeni parol və parolun təkrarı uyğun gəlmir"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Yedəkləmə parolu xətası"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Yüklənir…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Canlı (defolt)"</item>
<item msgid="8446070607501413455">"Təbii"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Hər dəfə soruşun"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Deaktiv edənə qədər"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"İndicə"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Qrafik drayverdən istifadə etmək üçün tətbiq seçin"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefon spikeri"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 56052d2..44f14df 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Postavljena je nova lozinka rezervne kopije"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nova lozinka i njena potvrda se ne podudaraju"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Postavljanje lozinke rezervne kopije nije uspelo"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Učitava se…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Živopisan (podrazumevano)"</item>
<item msgid="8446070607501413455">"Prirodan"</item>
@@ -450,6 +451,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Uvek pitaj"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Dok ne isključite"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Upravo"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Omogući aplikaciju za korišćenje upravljačkog programa grafičke katice u razvoju"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Zvučnik telefona"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index f2c2046..2dcdd37 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"Ідзе загрузка…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Сочны (па змаўчанні)"</item>
<item msgid="8446070607501413455">"Натуральны"</item>
@@ -451,6 +452,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Заўсёды пытацца"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Пакуль не выключыце"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Зараз"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Выбраная праграма, якая выкарыстоўвае абноўлены драйвер графічнай сістэмы (падчас распрацоўкі)"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Дынамік тэлефона"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 5b8d6b8..1e2f0f4 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"Зарежда се…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Ярък (по подразбиране)"</item>
<item msgid="8446070607501413455">"Естествен"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Да се пита винаги"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"До изключване"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Току-що"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Включване на приложението за използване на актуализирания графичен драйвер в разработка"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Високоговорител на телефона"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 7efad99..4ec893b 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"লোড হচ্ছে…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"ভাইব্রেন্ট (ডিফল্ট)"</item>
<item msgid="8446070607501413455">"প্রাকৃতিক"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"প্রতিবার জিজ্ঞেস করা হবে"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"যতক্ষণ না আপনি বন্ধ করছেন"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"এখনই"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ডেভলপমেন্টে আপডেট হওয়া গ্রাফিক্স ড্রাইভার ব্যবহার করতে অ্যাপ বেছে নিন"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ফেনের স্পিকার"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 92435f7..a0a0e2a 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nova lozinka za sigurnosnu kopiju je postavljena"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nova lozinka i potvrda se ne podudaraju"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nije uspjelo postavljanje lozinke za sigurnosnu kopiju"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Učitavanje…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Živopisno (zadano)"</item>
<item msgid="8446070607501413455">"Prirodan"</item>
@@ -450,6 +451,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Pitaj svaki put"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Dok ne isključite"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Upravo"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Prijavi aplikaciju za korištenje ažuriranog grafičkog drajvera u razvoju"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Zvučnik telefona"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 3182f16..0bd6a1b 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"S\'ha definit una contrasenya de seguretat nova"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"La contrasenya nova i la confirmació no coincideixen"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Error en definir la contrasenya de seguretat"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Carregant…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Vibrant (predeterminat)"</item>
<item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Pregunta sempre"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Fins que no ho desactivis"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Ara mateix"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Aplicació activada per utilitzar el controlador de gràfics actualitzat en desenvolupament"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altaveu del telèfon"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 3785433..69c22ec 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nové heslo pro zálohy je nastaveno"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nové heslo se neshoduje s potvrzením hesla."</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nastavení hesla pro zálohy selhalo"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Načítání…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Jasné (výchozí)"</item>
<item msgid="8446070607501413455">"Přirozené"</item>
@@ -451,6 +452,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Pokaždé se zeptat"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Dokud tuto funkci nevypnete"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Právě teď"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Přihlaste aplikaci k použití vyvíjeného aktualizovaného grafického ovladače"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Reproduktor telefonu"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index eeeccee..077258a 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -73,8 +73,8 @@
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Filoverførsel"</string>
<string name="bluetooth_profile_hid" msgid="3680729023366986480">"Inputenhed"</string>
<string name="bluetooth_profile_pan" msgid="3391606497945147673">"Internetadgang"</string>
- <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Deling af kontaktpersoner"</string>
- <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Brug til deling af kontaktpersoner"</string>
+ <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Deling af kontakter"</string>
+ <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Brug til deling af kontakter"</string>
<string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Deling af internetforbindelse"</string>
<string name="bluetooth_profile_map" msgid="1019763341565580450">"Sms-beskeder"</string>
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM-adgang"</string>
@@ -102,7 +102,7 @@
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Par"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ACCEPTÉR PARRING"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Annuller"</string>
- <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Parring giver adgang til dine kontaktpersoner og din opkaldshistorik, når enhederne er forbundet."</string>
+ <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Parring giver adgang til dine kontakter og din opkaldshistorik, når enhederne er forbundet."</string>
<string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Der kunne ikke parres med <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Der kunne ikke parres med <xliff:g id="DEVICE_NAME">%1$s</xliff:g> på grund af en forkert pinkode eller adgangsnøgle."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Der kan ikke kommunikeres med <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
@@ -252,7 +252,7 @@
<string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Hold altid mobildata aktiveret, selv når Wi-Fi er aktiveret (for at skifte hurtigt mellem netværk)."</string>
<string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Brug hardwareacceleration ved netdeling, hvis det er muligt"</string>
<string name="adb_warning_title" msgid="6234463310896563253">"Vil du tillade USB-fejlretning?"</string>
- <string name="adb_warning_message" msgid="7316799925425402244">"USB-fejlretning er kun beregnet til udvikling og kan bruges til at kopiere data mellem din computer og enheden, installere apps på enheden uden underretning og læse logdata."</string>
+ <string name="adb_warning_message" msgid="7316799925425402244">"USB-fejlretning er kun beregnet til udvikling og kan bruges til at kopiere data mellem din computer og enheden, installere apps på enheden uden notifikation og læse logdata."</string>
<string name="adb_keys_warning_message" msgid="5659849457135841625">"Vil du ophæve adgangen til USB-fejlfinding for alle computere, du tidligere har godkendt?"</string>
<string name="dev_settings_warning_title" msgid="7244607768088540165">"Vil du tillade udviklingsindstillinger?"</string>
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Disse indstillinger er kun beregnet til brug i forbindelse med udvikling. De kan forårsage, at din enhed og dens apps går ned eller ikke fungerer korrekt."</string>
@@ -316,8 +316,8 @@
<string name="app_process_limit_title" msgid="4280600650253107163">"Grænse for baggrundsprocesser"</string>
<string name="show_all_anrs" msgid="4924885492787069007">"Vis ANR-fejl i baggrunden"</string>
<string name="show_all_anrs_summary" msgid="6636514318275139826">"Vis dialogboksen \"Appen svarer ikke\" for baggrundsapps"</string>
- <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Vis advarsler om underretningskanal"</string>
- <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Viser en advarsel, når en app sender en underretning uden en gyldig kanal"</string>
+ <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Vis advarsler om notifikationskanal"</string>
+ <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Viser en advarsel, når en app sender en notifikation uden en gyldig kanal"</string>
<string name="force_allow_on_external" msgid="3215759785081916381">"Gennemtving tilladelse til eksternt lager"</string>
<string name="force_allow_on_external_summary" msgid="3640752408258034689">"Gør det muligt at overføre enhver app til et eksternt lager uafhængigt af manifestværdier"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Tving aktiviteter til at kunne tilpasses"</string>
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Ny adgangskode til sikkerhedskopi er angivet"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Ny adgangskode og bekræftelse matcher ikke"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Fejl ved angivelse af adgangskode til sikkerhedskopi"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Indlæser…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Klare (standard)"</item>
<item msgid="8446070607501413455">"Naturlige"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Spørg hver gang"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Indtil du deaktiverer"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Lige nu"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Tilvælg en app, der skal bruge den opdaterede grafikdriver under udvikling"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefonens højttaler"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 95f7416..c4e03ad 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Neues Sicherungspasswort festgelegt"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Das neue Passwort und die Bestätigung stimmen nicht überein."</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Fehler beim Festlegen des Sicherungspassworts"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Wird geladen…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Brillant (Standardeinstellung)"</item>
<item msgid="8446070607501413455">"Natürlich"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Jedes Mal fragen"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Bis zur Deaktivierung"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Gerade eben"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"App aktivieren, um den aktualisierten Grafiktreiber in der Entwicklung zu verwenden"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefon-Lautsprecher"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 310b6cf..642e862 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"Φόρτωση…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Ζωντανό (προεπιλογή)"</item>
<item msgid="8446070607501413455">"Φυσικό"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Να ερωτώμαι κάθε φορά"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Μέχρι την απενεργοποίηση"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Μόλις τώρα"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Επιλέξτε μια εφαρμογή για τη χρήση του ενημερωμένου προγράμματος οδήγησης γραφικών σε ανάπτυξη"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Ηχείο τηλεφώνου"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 5b11d63..0cdfaf2 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"New backup password set"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"New password and confirmation don\'t match"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Failure setting backup password"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Loading…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Vibrant (default)"</item>
<item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Ask every time"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Until you turn off"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Just now"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Opt in app to use updated graphics driver in development"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Phone speaker"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 5b11d63..0cdfaf2 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"New backup password set"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"New password and confirmation don\'t match"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Failure setting backup password"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Loading…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Vibrant (default)"</item>
<item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Ask every time"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Until you turn off"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Just now"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Opt in app to use updated graphics driver in development"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Phone speaker"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 5b11d63..0cdfaf2 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"New backup password set"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"New password and confirmation don\'t match"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Failure setting backup password"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Loading…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Vibrant (default)"</item>
<item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Ask every time"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Until you turn off"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Just now"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Opt in app to use updated graphics driver in development"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Phone speaker"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 5b11d63..0cdfaf2 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"New backup password set"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"New password and confirmation don\'t match"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Failure setting backup password"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Loading…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Vibrant (default)"</item>
<item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Ask every time"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Until you turn off"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Just now"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Opt in app to use updated graphics driver in development"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Phone speaker"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index d7ed49a..eda4d1b 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"New backup password set"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"New password and confirmation don’t match"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Failure setting backup password"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Loading…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Vibrant (default)"</item>
<item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Ask every time"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Until you turn off"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Just now"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Opt in app to use updated graphcis driver in developement"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Phone speaker"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index ecec63c..bd3d1b7 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nueva contraseña de copia de seguridad definida"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"La nueva contraseña y la de confirmación no coinciden."</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Error al definir contraseña de copia de seguridad"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Cargando…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Vibrante (predeterminado)"</item>
<item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Preguntar siempre"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Hasta que lo desactives"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Recién"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Habilitar app para que use el controlador de gráficos actualizado en el desarrollo"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altavoz del teléfono"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index b8fdf30..94f88eb 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nueva contraseña de seguridad establecida"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"La nueva contraseña y la de confirmación no coinciden"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Error al establecer la contraseña de seguridad"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Cargando…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Vibrante (predeterminado)"</item>
<item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Preguntar siempre"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Hasta que se desactive"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Justo ahora"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Habilitar aplicación para usar controlador de gráficos actualizado en desarrollo"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altavoz del teléfono"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 1246626..31527dc 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Uus varuparool on määratud"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Uus parool ja kinnitus ei ühti"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Varuparooli määramine ebaõnnestus"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Laadimine …"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Ere (vaikeseade)"</item>
<item msgid="8446070607501413455">"Loomulikud"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Küsi iga kord"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Kuni välja lülitate"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Äsja"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Lubage rakendus, et kasutada arenduses olevat värskendatud graafikadraiverit"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefoni kõlar"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 68b4840..dd77284 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Babeskopiaren pasahitz berria ezarri da"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Pasahitz berria eta berrespena ez datoz bat"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Ezin izan da babeskopiaren pasahitza ezarri"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Kargatzen…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Bizia (balio lehenetsia)"</item>
<item msgid="8446070607501413455">"Naturala"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Galdetu beti"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Desaktibatu arte"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Oraintxe"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Hautatu zein aplikaziorekin erabili nahi duzun garatze-prozesuan dagoen grafikoen kontrolatzaile eguneratua"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefonoaren bozgorailua"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 7882b056..57f8960 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"بارگیری…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"پرطروات (پیشفرض)"</item>
<item msgid="8446070607501413455">"طبیعی"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"هربار پرسیده شود"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"تا زمانیکه آن را خاموش کنید"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"هماکنون"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"برنامه انتخابشده برای استفاده از درایور گرافیک بهروزرسانیشده در برنامهنویس"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"بلندگوی تلفن"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 1904c4d..922d8d3 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Uusi varasalasana asetettiin"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Uusi salasana ja vahvistus eivät täsmää"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Varasalasanan asetus epäonnistui"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Ladataan…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Voimakas (oletus)"</item>
<item msgid="8446070607501413455">"Luonnollinen"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Kysy aina"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Kunnes poistat sen käytöstä"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Äsken"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Lisää sovellus käyttämään päivitettyä grafiikkaohjainta kehitysvaiheessa"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Puhelimen kaiutin"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 45b2872..765a80f 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Le nouveau mot de passe de secours a bien été défini."</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Le nouveau mot de passe et sa confirmation ne correspondent pas."</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Échec de la définition du mot de passe de secours."</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Chargement en cours…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Vibrantes (par défaut)"</item>
<item msgid="8446070607501413455">"Naturelles"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Toujours demander"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Jusqu\'à la désactivation"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"À l\'instant"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Sélectionnez l\'application pour utiliser le pilote graphique mis à jour en mode de conception"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Haut-parleur du téléphone"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 13361d7..198b922 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Le nouveau mot de passe de secours a bien été défini."</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Le nouveau mot de passe et sa confirmation ne correspondent pas."</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Échec de la définition du mot de passe de secours."</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Chargement…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Couleurs éclatantes (par défaut)"</item>
<item msgid="8446070607501413455">"Couleurs naturelles"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Toujours demander"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Jusqu\'à la désactivation"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"À l\'instant"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Sélectionner une application pour le développement de laquelle utiliser le pilote graphique mis à jour"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Haut-parleur du téléphone"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index e8cf009..de5e7e41 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Novo contrasinal da copia de seguranza definido"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"O contrasinal novo e a confirmación non coinciden"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Erro ao definir un contrasinal da copia de seguranza"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Cargando…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Brillante (predeterminado)"</item>
<item msgid="8446070607501413455">"Naturais"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Preguntar sempre"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Ata a desactivación"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Agora mesmo"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Subscribirse á aplicación para utilizar o controlador de gráficos actualizado en desenvolvemento"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altofalante do teléfono"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 918920d..993eed1 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"લોડ થઈ રહ્યું છે…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"વાઇબ્રન્ટ (ડિફોલ્ટ)"</item>
<item msgid="8446070607501413455">"કુદરતી"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"દર વખતે પૂછો"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"તમે બંધ ન કરો ત્યાં સુધી"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"હમણાં જ"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"અપડેટ કરેલ ગ્રાફિક્સ ડ્રાઇવરનો ઉપયોગ કરવા માટે અૅપ પસંદ કરો"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ફોન સ્પીકર"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 890d036..faf551e 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"लोड हो रहा है…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"चमकीला (डिफ़ॉल्ट)"</item>
<item msgid="8446070607501413455">"स्वाभाविक"</item>
@@ -416,7 +417,7 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"कस्टम (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</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_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>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"हर बार पूछें"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"जब तक आप इसे बंद नहीं करते"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"अभी-अभी"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"डेवलपमेंट में अपडेट किए गए ग्राफ़िक्स ड्राइवर का इस्तेमाल करने के लिए ऐप्लिकेशन में ऑप्ट इन करें"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"फ़ोन स्पीकर"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 1464b91..5f04b65 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nova zaporka za sigurnosnu kopiju postavljena"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nova zaporka i potvrda ne odgovaraju"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nije uspjelo postavljanje zaporke za sigurnosnu kopiju"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Učitavanje…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Živopisno (zadano)"</item>
<item msgid="8446070607501413455">"Prirodno"</item>
@@ -450,6 +451,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Pitaj svaki put"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Dok ne isključite"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Upravo sad"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Uključi aplikaciju za upotrebu ažuriranog upravljačkog programa u razvoju"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Zvučnik telefona"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index c9fdd45..7469c1a 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Új mentési jelszó beállítva"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Az új jelszó és a megerősítése nem egyezik."</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Hiba a mentési jelszó beállítása során"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Betöltés…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Élénk (alapértelmezett)"</item>
<item msgid="8446070607501413455">"Természetes"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Mindig kérdezzen rá"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Kikapcsolásig"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Az imént"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"A frissített, fejlesztés alatt álló grafikus drivert használja a választott alkalmazás"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefon hangszórója"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 3b13ed1..b27bb7e 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"Բեռնում…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Պայծառ (կանխադրված)"</item>
<item msgid="8446070607501413455">"Բնական"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Հարցնել ամեն անգամ"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Մինչև չանջատեք"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Հենց նոր"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Ընտրված հավելվածը, որը պետք է օգտագործի թարմացված գրաֆիկական սարքավարը մշակման ժամանակ"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Հեռախոսի բարձրախոս"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 4d1b2df..342a505 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Sandi cadangan baru telah disetel"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Sandi baru dan konfirmasinya tidak cocok."</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Gagal menyetel sandi cadangan"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Memuat…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Terang (default)"</item>
<item msgid="8446070607501413455">"Alami"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Selalu tanya"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Sampai Anda menonaktifkannya"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Baru saja"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Ikut sertakan aplikasi untuk menggunakan driver grafis yang diupdate dalam pengembangan"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Speaker ponsel"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 600ffa4..8f1b9a1 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nýtt aðgangsorð fyrir afritun valið"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nýja aðgangsorðið og staðfestingaraðgangsorðið eru ekki eins"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Villa við að velja aðgangsorð fyrir afritun"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Hleður…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Líflegir (sjálfgefið)"</item>
<item msgid="8446070607501413455">"Náttúrulegir"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Spyrja í hvert skipti"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Þar til þú slekkur"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Rétt í þessu"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Velja að nota uppfærðan myndefnisrekil í þróun í forriti"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Símahátalari"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 068aa91..6600ca2 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nuova password di backup impostata"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Le password inserite non corrispondono"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Impossibile impostare la password di backup"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Caricamento…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Vivaci (opzione predefinita)"</item>
<item msgid="8446070607501413455">"Naturali"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Chiedi ogni volta"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Fino alla disattivazione"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Adesso"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Attiva l\'app per utilizzare il driver grafico aggiornato nella versione di sviluppo"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altoparlante telefono"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index fa38f77..a8da0b1 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"טוען…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"דינמי (ברירת מחדל)"</item>
<item msgid="8446070607501413455">"טבעי"</item>
@@ -451,6 +452,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"שאל בכל פעם"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"עד הכיבוי"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"הרגע"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"האפליקציה שנבחרה לשימוש במנהל ההתקן המעודכן לגרפיקה שבפיתוח"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"רמקול של טלפון"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 9927654..ea62637 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"読み込んでいます…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"鮮やか(既定)"</item>
<item msgid="8446070607501413455">"自然"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"毎回確認"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"OFF にするまで"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"たった今"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"更新したグラフィックス ドライバを開発に使用するオプトイン アプリ"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"スマートフォンのスピーカー"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 7ba0153..bd88435 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"მიმდინარეობს ჩატვირთვა…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"მკვეთრი (ნაგულისხმევი)"</item>
<item msgid="8446070607501413455">"ბუნებრივი"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ყოველთვის მკითხეთ"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"გამორთვამდე"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"ახლახან"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"გააქტიურების აპი, რომელიც გამოიყენებს შემუშავების პროცესში მყოფ, განახლებულ გრაფიკულ დრაივერს"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ტელეფონის დინამიკი"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index d5b4441..d22b139 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"Жүктелуде…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Жарқын (әдепкі)"</item>
<item msgid="8446070607501413455">"Табиғи"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Әрдайым сұрау"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Өшірілгенге дейін"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Дәл қазір"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Әзірлеу барысында қолданба жаңартылған графика драйверін пайдаланады"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Телефон динамигі"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index d1d1c76..d516db9 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"កំពុងផ្ទុក…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"រស់រវើក (លំនាំដើម)"</item>
<item msgid="8446070607501413455">"ធម្មជាតិ"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"សួរគ្រប់ពេល"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"រហូតទាល់តែអ្នកបិទ"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"អម្បាញ់មិញ"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ភ្ជាប់កម្មវិធី ដើម្បីប្រើដ្រាយវើក្រាហ្វិកដែលបានដំឡើងជំនាន់សម្រាប់ការអភិវឌ្ឍ"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ឧបករណ៍បំពងសំឡេងទូរសព្ទ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 46759f5..94a711c 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"ಲೋಡ್ ಆಗುತ್ತಿದೆ…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"ಸ್ಪಂದನಾತ್ಮಕ (ಡೀಫಾಲ್ಟ್)"</item>
<item msgid="8446070607501413455">"ಪ್ರಾಕೃತಿಕ"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ಪ್ರತಿ ಬಾರಿ ಕೇಳಿ"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"ನೀವು ಆಫ್ ಮಾಡುವವರೆಗೆ"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"ಇದೀಗ"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ಅಭಿವೃದ್ಧಿಯಲ್ಲಿ ಅಪ್ಡೇಟ್ ಮಾಡಲಾದ ಗ್ರಾಫಿಕ್ಗಳ ಡ್ರೈವರ್ ಬಳಸಲು ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ಫೋನ್ ಸ್ಪೀಕರ್"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 067175b..0b4125f 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"로드 중…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"생동감(기본값)"</item>
<item msgid="8446070607501413455">"내츄럴"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"항상 확인"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"사용 중지할 때까지"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"조금 전"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"개발 중인 업데이트된 그래픽 드라이버를 사용할 앱을 선택하세요."</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"휴대전화 스피커"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 8e994da..42dc97e 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"Жүктөлүүдө…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Толкундуу (демейки)"</item>
<item msgid="8446070607501413455">"Табигый"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Ар дайым суралсын"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Бул функция өчүрүлгөнгө чейин"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Азыр эле"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Иштеп чыгууда жаңыртылган графикалык драйверлерди пайдалануу үчүн колдонмону кошуңуз"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Телефондун динамиги"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 7bf46c0..0505a5d 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"ກຳລັງໂຫລດ…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"ຕົວສັ່ນ (ມາດຕະຖານ)"</item>
<item msgid="8446070607501413455">"ທຳມະຊາດ"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ຖາມທຸກເທື່ອ"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"ຈົນກວ່າທ່ານຈະປິດ"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"ຕອນນີ້"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ເຂົ້າຮ່ວມແອັບເພື່ອໃຊ້ໄດຣເວີກຣາຟິກທີ່ອັບເດດແລ້ວໃນການພັດທະນາ"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ລຳໂພງໂທລະສັບ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 9da3d52..e1412e7 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nustatytas naujas atsarginės kopijos slaptažodis"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Naujas slaptažodis ir patvirtinimas neatitinka"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nustatant atsarginės kopijos slaptažodį įvyko klaida"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Įkeliama…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Ryškus (numatytasis)"</item>
<item msgid="8446070607501413455">"Natūralus"</item>
@@ -451,6 +452,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Klausti kaskart"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Kol išjungsite"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Ką tik"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Pasirinkti programą, kuri bus naudojama su atnaujinta kuriama grafikos tvarkykle"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefono garsiakalbis"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 2233468..5082775 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Jaunā dublējuma parole ir iestatīta."</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Jaunā parole un apstiprinājums neatbilst."</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Iestatot dublējuma paroli, radās kļūme."</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Notiek ielāde…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Spilgts (noklusējums)"</item>
<item msgid="8446070607501413455">"Dabisks"</item>
@@ -450,6 +451,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Vaicāt katru reizi"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Līdz brīdim, kad izslēgsiet"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Tikko"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Izvēlēties izmantot atjaunināto grafikas dzini šīs lietotnes izstrādē"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Tālruņa skaļrunis"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 534d154..99cf468 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"Се вчитува…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Динамично (стандардно)"</item>
<item msgid="8446070607501413455">"Природно"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Секогаш прашувај"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Додека не го исклучите"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Неодамнешни"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Прифатете ја апликацијата за да се користи ажурираниот драјвер за графика во програмирање"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Телефонски звучник"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 7a335cd..a0222ad 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"ലോഡ് ചെയ്യുന്നു…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"വൈബ്രന്റ് (സ്ഥിരമായത്)"</item>
<item msgid="8446070607501413455">"സ്വാഭാവികം"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"എപ്പോഴും ചോദിക്കുക"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"നിങ്ങൾ ഓഫാക്കുന്നത് വരെ"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"ഇപ്പോൾ"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"വികസനത്തിൽ, അപ്ഡേറ്റ് ചെയ്ത ഗ്രാഫിക്സ് ഡ്രൈവർ ഉപയോഗിക്കാൻ ഓപ്റ്റ് ഇൻ ചെയ്യുക"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ഫോൺ സ്പീക്കർ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 4816643..5b2acac 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"Ачаалж байна…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Хурц (үндсэн)"</item>
<item msgid="8446070607501413455">"Байгалийн"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Тухай бүрт асуух"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Таныг унтраах хүртэл"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Дөнгөж сая"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Хөгжүүлэлтэд буй шинэчилсэн график драйверийг ашиглахын тулд аппад нэгдэх"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Утасны чанга яригч"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 5b09b29..891ada8 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"लोड करत आहे…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"सशक्त (डीफॉल्ट)"</item>
<item msgid="8446070607501413455">"नैसर्गिक"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"प्रत्येक वेळी विचारा"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"तुम्ही बंद करेपर्यंत"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"आत्ताच"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"अपडेट केलेले ग्राफिक ड्राइव्हर डेव्हलमेंटमध्ये वापरण्यासाठी अॅप निवडा"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"फोनचा स्पीकर"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 3593882..8030c3e 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Kata laluan sandaran baharu telah ditetapkan"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Kata laluan baharu dan pengesahan tidak sepadan"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Gagal menetapkan kata laluan sandaran"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Memuatkan…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Terang (lalai)"</item>
<item msgid="8446070607501413455">"Semula Jadi"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Tanya setiap kali"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Sehingga anda matikan"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Sebentar tadi"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Sertakan apl untuk menggunakan pemacu grafik yang dikemas kini dalam pembangunan"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Pembesar suara telefon"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 7ac3742..c543974 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"ဖွင့်နေသည်…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"တက်ကြွခြင်း (မူလ)"</item>
<item msgid="8446070607501413455">"သဘာဝ"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"အမြဲမေးပါ"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"သင်ပိတ်လိုက်သည် အထိ"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"ယခုလေးတင်"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ဆော့ဖ်ဝဲရေးဆွဲမှုအတွင်း အပ်ဒိတ်လုပ်ထားသော ဂရပ်ဖစ်ဒရိုင်ဗာကို အသုံးပြုရန် အက်ပ်ကို ရွေးချယ်ပါ"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ဖုန်းစပီကာ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index e810ba2..c4ad033 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nytt passord for sikkerhetskopiering er angitt."</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Gjentakelsen av passordet er ikke identisk med det første du skrev inn"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Kunne ikke angi nytt passord for sikkerhetskopiering"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Laster inn …"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Krystallklar (standard)"</item>
<item msgid="8446070607501413455">"Naturlig"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Spør hver gang"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Til du slår av"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Nå nettopp"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Velg app for å bruke en oppdatert grafikkdriver som er under utvikling"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefonhøyttaler"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 0b4510fd..f67e05c 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -231,7 +231,7 @@
<string name="private_dns_mode_off" msgid="8236575187318721684">"निष्क्रिय छ"</string>
<string name="private_dns_mode_opportunistic" msgid="8314986739896927399">"स्वचालित"</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="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS प्रदायकको होस्टनाम प्रविष्टि गर्नुहोस्"</string>
<string name="private_dns_mode_provider_failure" msgid="231837290365031223">"जडान गर्न सकिएन"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ताररहित प्रदर्शन प्रमाणीकरणका लागि विकल्पहरू देखाउनुहोस्"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi-Fi लग स्तर बढाउनुहोस्, Wi-Fi चयनकर्तामा प्रति SSID RSSI देखाइन्छ"</string>
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"लोड गर्दै…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"जोसिलो (पूर्व निर्धारित)"</item>
<item msgid="8446070607501413455">"प्राकृतिक"</item>
@@ -415,7 +416,7 @@
<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="content_description_menu_button" msgid="8182594799812351266">"मेनु"</string>
- <string name="retail_demo_reset_message" msgid="118771671364131297">"डेमो मोडमा फ्याक्ट्री रिसेट गर्न पासवर्ड प्रविष्ट गर्नुहोस्"</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>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"प्रत्येक पटक सोध्नुहोस्"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"तपाईंले निष्क्रिय नपार्दासम्म"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"अहिले भर्खरै"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"विकासको क्रममा अद्यावधिक गरिएको ग्राफिक ड्राइभर प्रयोग गर्न अप्ट इन गर्नुहोस्"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"फोनको स्पिकर"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index f227e1c..d2fd4e24 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -236,7 +236,7 @@
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Opties weergeven voor certificering van draadloze weergave"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Logniveau voor wifi verhogen, weergeven per SSID RSSI in wifi-kiezer"</string>
<string name="wifi_connected_mac_randomization_summary" msgid="1743059848752201485">"Een willekeurig MAC-adres bij het maken van verbinding met wifi-netwerken"</string>
- <string name="wifi_metered_label" msgid="4514924227256839725">"Betaald"</string>
+ <string name="wifi_metered_label" msgid="4514924227256839725">"Met datalimiet"</string>
<string name="wifi_unmetered_label" msgid="6124098729457992931">"Gratis"</string>
<string name="select_logd_size_title" msgid="7433137108348553508">"Logger-buffergrootten"</string>
<string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Kies Logger-grootten per logbuffer"</string>
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nieuw back-upwachtwoord ingesteld"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nieuw wachtwoord en bevestiging komen niet overeen."</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Instellen van back-upwachtwoord is mislukt"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Laden…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Levendig (standaard)"</item>
<item msgid="8446070607501413455">"Natuurlijk"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Altijd vragen"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Totdat je uitschakelt"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Zojuist"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Meld een app aan om het geüpdatete grafische stuurprogramma in ontwikkeling te gebruiken"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefoonluidspreker"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index bf8493a..bed22a7 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"ଲୋଡ୍ ହେଉଛି…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"ଜୀବନ୍ତ (ପୂର୍ବ-ନିର୍ଦ୍ଧାରିତ)"</item>
<item msgid="8446070607501413455">"ପ୍ରାକୃତିକ"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ପ୍ରତ୍ୟେକ ଥର ପଚାରନ୍ତୁ"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"ଆପଣ ବନ୍ଦ ନକରିବା ପର୍ଯ୍ୟନ୍ତ DND ଅନ୍ ରହିବ"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"ଏହିକ୍ଷଣି"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ଡେଭଲପ୍ମେଣ୍ଟରେ ଅପ୍ଡେଟ୍ ଗ୍ରାଫିକ୍ସ ଡ୍ରାଇଭର୍ ବ୍ୟବହାର କରିବାକୁ ଆପ୍ଟ ଇନ୍ ଅପ୍ଲିକେସନ୍"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ଫୋନ୍ ସ୍ପିକର୍"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index f948a7e..1c2a947 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"ਚਮਕੀਲਾ (ਪੂਰਵ-ਨਿਰਧਾਰਤ)"</item>
<item msgid="8446070607501413455">"ਕੁਦਰਤੀ"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ਹਰ ਵਾਰ ਪੁੱਛੋ"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਬੰਦ ਨਹੀਂ ਕਰਦੇ"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"ਹੁਣੇ ਹੀ"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ਅੱਪਡੇਟ ਕੀਤੇ ਵਿਕਾਸ-ਅਧੀਨ ਗ੍ਰਾਫਿਕਸ ਡਰਾਈਵਰ ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਐਪ ਦੀ ਚੋਣ ਕਰੋ"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ਫ਼ੋਨ ਦਾ ਸਪੀਕਰ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index c75a894..1a0a30d 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nowe hasło kopii zapasowej zostało ustawione"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nowe hasła nie pasują do siebie"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nie udało się ustawić hasła kopii zapasowej"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Ładuję…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Żywe (domyślnie)"</item>
<item msgid="8446070607501413455">"Naturalne"</item>
@@ -451,6 +452,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Zawsze pytaj"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Dopóki nie wyłączysz"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Przed chwilą"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Wybierz aplikację, która ma używać opracowywanego sterownika grafiki"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Głośnik telefonu"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index c273f59..2795d47 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nova senha de backup definida"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"A nova senha e a confirmação não coincidem."</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Falha ao definir a senha de backup"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Carregando…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Vibrante (padrão)"</item>
<item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Perguntar sempre"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Até você desativar"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Agora"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Ative o app para usar o driver gráfico atualizado no desenvolvimento"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Alto-falante do smartphone"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 26e4729..fd15210 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nova palavra-passe da cópia de segurança definida"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"A nova palavra-passe e a confirmação não coincidem"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Falha na definição da palavra-passe da cópia de segurança"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"A carregar…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Vibrante (predefinição)"</item>
<item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Perguntar sempre"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Até ser desativado"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Agora mesmo"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Optar pela aplicação para utilizar a placa gráfica atualizada em desenvolvimento"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altifalante do telemóvel"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index c273f59..2795d47 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nova senha de backup definida"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"A nova senha e a confirmação não coincidem."</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Falha ao definir a senha de backup"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Carregando…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Vibrante (padrão)"</item>
<item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Perguntar sempre"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Até você desativar"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Agora"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Ative o app para usar o driver gráfico atualizado no desenvolvimento"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Alto-falante do smartphone"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 94f4842..ecdd003 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"A fost setată o parolă de rezervă nouă"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Parola nouă și confirmarea acesteia nu se potrivesc."</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Setarea parolei de rezervă a eșuat"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Se încarcă…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Vibrant (prestabilit)"</item>
<item msgid="8446070607501413455">"Natural"</item>
@@ -450,6 +451,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Întreabă de fiecare dată"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Până când dezactivați"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Chiar acum"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Aplicația pentru înscriere pentru a folosi driverul actualizat al plăcii grafice este în dezvoltare"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Difuzorul telefonului"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 1c331d8..74075c5 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"Загрузка…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Насыщенный (по умолчанию)"</item>
<item msgid="8446070607501413455">"Естественный"</item>
@@ -451,6 +452,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Всегда спрашивать"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Пока вы не отключите"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Только что"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Приложение будет использовать обновленный драйвер графической системы (на стадии разработки)"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Встроенный динамик"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 608ff7f..fc90db5 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"පූරණය වේ…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"දීප්තිමත් (පෙරනිමිය)"</item>
<item msgid="8446070607501413455">"ස්වභාවික"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"සෑම විටම ඉල්ලන්න"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"ඔබ ක්රියාවිරහිත කරන තුරු"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"මේ දැන්"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"වැඩිදියුණු වෙමින් ඇති යාවත්කාලීන කළ චිත්රක ධාවකය භාවිත කිරීමට යෙදුමට ඇතුළු වන්න"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"දුරකථන ස්පීකරය"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 2f76ef9..ed51f55 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nové heslo pre zálohy je nastavené"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nové heslo a potvrdenie sa nezhodujú"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nastavenie hesla pre zálohy zlyhalo"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Načítava sa…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Sýty (predvolený)"</item>
<item msgid="8446070607501413455">"Prirodzený"</item>
@@ -451,6 +452,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Vždy sa opýtať"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Dokiaľ túto funkciu nevypnete"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Teraz"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Prihlásiť aplikáciu, ktorá má používať aktualizovaný ovládač grafickej karty vo vývoji"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Reproduktor telefónu"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 64124cb..ad47f75 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Novo geslo je nastavljeno"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Novo geslo in potrditev se ne ujemata."</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nastavitev gesla ni uspela"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Nalaganje …"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Živo (privzeto)"</item>
<item msgid="8446070607501413455">"Naravno"</item>
@@ -451,6 +452,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Vedno vprašaj"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Dokler ne izklopite"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Pravkar"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Omogočena aplikacija za uporabo posodobljenega grafičnega gonilnika pri razvoju"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Zvočnik telefona"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 25d575e..f8f491b 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Fjalëkalimi i ri u vendos"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Fjalëkalimi i ri dhe konfirmimi nuk përputhen"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Vendosja e fjalëkalimit dështoi"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Po ngarkohet…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Të gjalla (parazgjedhja)"</item>
<item msgid="8446070607501413455">"Natyrale"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Pyet çdo herë"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Deri sa ta çaktivizosh"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Pikërisht tani"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Prano aplikacionin për të përdorur drejtuesin e përditësuar të grafikës që është në zhvillim"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altoparlanti i telefonit"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index b58b47c..3fe40f9 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"Учитава се…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Живописан (подразумевано)"</item>
<item msgid="8446070607501413455">"Природан"</item>
@@ -450,6 +451,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Увек питај"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Док не искључите"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Управо"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Омогући апликацију за коришћење управљачког програма графичке катице у развоју"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Звучник телефона"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 7198b84..186395e 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Ett nytt lösenord har angetts"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Det nya lösenordet och bekräftelsen stämmer inte överens"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Det gick inte att ange lösenordet"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Läser in …"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Starka (standard)"</item>
<item msgid="8446070607501413455">"Naturliga"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Fråga varje gång"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Tills du inaktiverar funktionen"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Nyss"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Välj om appen ska använda den uppdaterade grafikdrivrutinen under utveckling"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Mobilens högtalare"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 657b54f..03e0c3a 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nenosiri jipya la hifadhi rudufu limewekwa"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nenosiri jipya na uthibitisho havioani"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Imeshindwa kuweka nenosiri la hifadhi rudufu"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Inapakia…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Maridadi (chaguomsingi)"</item>
<item msgid="8446070607501413455">"Asili"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Uliza kila wakati"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Hadi utakapoizima"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Sasa hivi"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Chagua programu itakayotumia kiendeshaji cha michoro kilichosasishwa katika hatua ya kusanidi"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Spika ya simu"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 59b42d8..0efd285 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"ஏற்றுகிறது…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"வைபிரன்ட் (இயல்பு)"</item>
<item msgid="8446070607501413455">"இயற்கை வண்ணம்"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ஒவ்வொரு முறையும் கேள்"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"ஆஃப் செய்யும் வரை"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"சற்றுமுன்"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"உருவாக்கத்திலுள்ள புதுப்பிக்கப்பட்ட கிராஃபிக்ஸ் டிரைவரைப் பயன்படுத்த ஆப்ஸைத் தேர்ந்தெடுக்கவும்"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"மொபைல் ஸ்பீக்கர்"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index af233da..2caa2ef 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"లోడ్ చేస్తోంది…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"సచేతనం (డిఫాల్ట్)"</item>
<item msgid="8446070607501413455">"సహజం"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ప్రతిసారి అడుగు"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"మీరు ఆఫ్ చేసే వరకు"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"ఇప్పుడే"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"అభివృద్దిలో అప్డేట్ చేసిన గ్రాఫిక్ డ్రైవర్ను ఉపయోగించడానికి యాప్ని ప్రారంభించండి"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ఫోన్ స్పీకర్"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 636c3f2..03bf354 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"กำลังโหลด…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"สด (ค่าเริ่มต้น)"</item>
<item msgid="8446070607501413455">"ธรรมชาติ"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ถามทุกครั้ง"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"จนกว่าคุณจะปิด"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"เมื่อสักครู่"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"เลือกใช้แอปเพื่อใช้ไดรเวอร์กราฟิกที่อัปเดตในการพัฒนา"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ลำโพงโทรศัพท์"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 1bcc36a..3f5cca2 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Naitakda ang bagong backup na password"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Hindi tugma ang password at kumpirmasyon"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nabigo sa pagtatakda ng backup na password"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Naglo-load…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Vibrant (default)"</item>
<item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Magtanong palagi"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Hanggang sa i-off mo"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Ngayon lang"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"App sa pag-opt in para magamit ang na-update na graphics driver na ginagawa"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Speaker ng telepono"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index ff669f6..b0a782a 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Yeni yedekleme şifresi ayarlandı"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Yeni şifre ve onayı eşleşmiyor."</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Yedekleme şifresi ayarlanamadı"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Yükleniyor…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Canlı (varsayılan)"</item>
<item msgid="8446070607501413455">"Doğal"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Her zaman sor"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Siz kapatana kadar"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Az önce"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Güncellenmiş grafik sürücüsünü geliştirme ortamında kullanmak için uygulamayı kaydedin"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefon hoparlörü"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 2ded8c1..2b63573 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"Завантаження…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Насичений (за умовчанням)"</item>
<item msgid="8446070607501413455">"Природний"</item>
@@ -451,6 +452,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Запитувати щоразу"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Доки ви не вимкнете"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Щойно"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Вибраний додаток, який використовуватиме оновлений графічний драйвер під час розробки"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Динамік телефона"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 7dc4690..d7123a6 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"لوڈ ہو رہی ہے…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"پرجوش (ڈیفالٹ)"</item>
<item msgid="8446070607501413455">"قدرتی"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ہر بار پوچھیں"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"یہاں تک کہ آپ آف کر دیں"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"ابھی ابھی"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ڈیولپمنٹ میں اپ ڈیٹ کردہ گرافکس ڈرائیور کو استعمال کرنے کے لیے ایپ آپٹ ان کریں"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"فون اسپیکر"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 5f92c9a..51156d7 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Yangi zaxira paroli o‘rnatildi"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Parollar bir-biriga mos kelmadi"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Zaxira parolini o‘rnatib bo‘lmadi"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Yuklanmoqda…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Yorqin (birlamchi)"</item>
<item msgid="8446070607501413455">"Tabiiy"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Har safar so‘ralsin"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Bekor qilinmaguncha"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Hozir"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Ilova yangilangan grafik drayverdan (hali ishlov jarayonida) foydalanadi"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefon karnayi"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index eb10fb1..13a9322 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Đã đặt mật khẩu sao lưu mới"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Mật khẩu mới và xác nhận không khớp"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Đặt mật khẩu sao lưu không thành công"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Đang tải…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Sống động (mặc định)"</item>
<item msgid="8446070607501413455">"Tự nhiên"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Luôn hỏi"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Cho đến khi bạn tắt"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Vừa xong"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Chọn ứng dụng để sử dụng trình điều khiển đồ họa được cập nhật trong giai đoạn phát triển"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Loa điện thoại"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 7b14138..866c143 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"正在加载…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"鲜亮(默认)"</item>
<item msgid="8446070607501413455">"自然"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"每次都询问"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"直到您将其关闭"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"刚刚"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"为应用启用更新后的显卡驱动,以在开发过程中使用"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"手机扬声器"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 48b6959..f63ba3a 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"正在載入…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"生動 (預設)"</item>
<item msgid="8446070607501413455">"自然"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"每次都詢問"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"直至您關閉為止"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"剛剛"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"請選取應用程式,以在開發階段使用更新的顯示卡驅動程式"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"手機喇叭"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 684569b..93592a79 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -330,6 +330,7 @@
<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 name="loading_injected_setting_summary" msgid="4095178591461231376">"載入中…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"鮮活 (預設)"</item>
<item msgid="8446070607501413455">"自然"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"每次都詢問"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"直到你關閉為止"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"剛剛"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"選取要在開發階段使用最新版繪圖驅動程式的應用程式"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"手機喇叭"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index d107a5a..dd2f3d8 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -330,6 +330,7 @@
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Iphasiwedi entsha eyisipele isethiwe"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Iphasiwedi entsha nokuqinisekisa akufani"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Ukungaphumeleli kokusetha iphasiwedi eyisipele"</string>
+ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Iyalayisha…"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"Dlidlizela (okuzenzakalelayo)"</item>
<item msgid="8446070607501413455">"Kwemvelo"</item>
@@ -449,6 +450,5 @@
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Buza njalo"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Uze uvale isikrini"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"Khona manje"</string>
- <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Uhlelo lokusebenza lokukhetha ukungena olungasebenzisa idrayivu yamagrafikhi ekuthuthukiseni"</string>
<string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Isipikha sefoni"</string>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 419273e..bcf37ff 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1557,6 +1557,10 @@
Settings.Global.ZRAM_ENABLED,
GlobalSettingsProto.ZRAM_ENABLED);
+ dumpSetting(s, p,
+ Global.APP_OPS_CONSTANTS,
+ GlobalSettingsProto.APP_OPS_CONSTANTS);
+
p.end(token);
// Please insert new settings using the same order as in GlobalSettingsProto.
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index bff2c84..fa95bf2 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -134,6 +134,8 @@
<uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
<uses-permission android:name="android.permission.MANAGE_AUTO_FILL" />
<uses-permission android:name="android.permission.MANAGE_CONTENT_CAPTURE" />
+ <uses-permission android:name="android.permission.MANAGE_CONTENT_SUGGESTIONS" />
+ <uses-permission android:name="android.permission.MANAGE_APP_PREDICTIONS" />
<uses-permission android:name="android.permission.NETWORK_SETTINGS" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.SET_TIME" />
@@ -162,6 +164,8 @@
<uses-permission android:name="android.permission.SUSPEND_APPS" />
<uses-permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND" />
+ <uses-permission android:name="android.permission.MANAGE_APPOPS" />
+
<application android:label="@string/app_label"
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true">
diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
index 2000104..74002ac 100644
--- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -51,11 +51,4 @@
android:layout_width="wrap_content"
android:paddingEnd="2dp" />
- <TextView
- android:id="@+id/batteryRemainingText"
- android:textAppearance="@style/TextAppearance.QS.TileLabel"
- android:layout_height="match_parent"
- android:layout_width="wrap_content"
- android:gravity="center_vertical" />
-
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
index 4b65b6a..cd9f780 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
@@ -64,11 +64,5 @@
<include layout="@layout/ongoing_privacy_chip" />
- <com.android.systemui.BatteryMeterView
- android:id="@+id/battery"
- android:layout_height="match_parent"
- android:layout_width="wrap_content"
- android:gravity="center_vertical|end"
- android:layout_gravity="center_vertical|end" />
</LinearLayout>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 34c208a..02062bb 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -43,6 +43,14 @@
android:visibility="invisible" />
</com.android.systemui.statusbar.BackDropView>
+ <com.android.systemui.wallpaper.AodMaskView
+ android:id="@+id/aod_mask"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:importantForAccessibility="no"
+ android:visibility="invisible"
+ sysui:ignoreRightInset="true" />
+
<com.android.systemui.statusbar.ScrimView
android:id="@+id/scrim_behind"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index eed44dd..de2a950 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors is af"</string>
<string name="device_services" msgid="1191212554435440592">"Toesteldienste"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Titelloos"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 7c09112..4154643 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"ዳሳሾች ጠፍተዋል"</string>
<string name="device_services" msgid="1191212554435440592">"የመሣሪያ አገልግሎቶች"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"ርዕስ የለም"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 16abb68..579964d 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -914,6 +914,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"إيقاف أجهزة الاستشعار"</string>
<string name="device_services" msgid="1191212554435440592">"خدمات الأجهزة"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"بلا عنوان"</string>
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 25f7b5b..8113504 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -889,8 +889,6 @@
<item quantity="other"><xliff:g id="NUM_APPS_1">%d</xliff:g>টা অন্য এপ্</item>
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"ছেন্সৰ অফ হৈ আছে"</string>
- <!-- no translation found for device_services (1191212554435440592) -->
- <skip />
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="device_services" msgid="1191212554435440592">"ডিভাইচ সেৱা"</string>
+ <string name="music_controls_no_title" msgid="5236895307087002011">"কোনো শিৰোনাম নাই"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 4cc91d2..6a27dbb 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -176,7 +176,7 @@
<string name="accessibility_no_sim" msgid="8274017118472455155">"Няма SIM-карты."</string>
<string name="accessibility_cell_data" msgid="5326139158682385073">"Мабільная перадача даных"</string>
<string name="accessibility_cell_data_on" msgid="5927098403452994422">"Мабільная перадача даных уключана"</string>
- <string name="cell_data_off_content_description" msgid="4356113230238585072">"Мабільны інтэрнэт выключаны"</string>
+ <string name="cell_data_off_content_description" msgid="4356113230238585072">"Мабільная перадача даных выключана"</string>
<string name="cell_data_off" msgid="1051264981229902873">"Выключаны"</string>
<string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Сувязь па Bluetooth."</string>
<string name="accessibility_airplane_mode" msgid="834748999790763092">"Рэжым палёту."</string>
@@ -865,7 +865,7 @@
<string name="qs_dnd_replace" msgid="8019520786644276623">"Замяніць"</string>
<string name="running_foreground_services_title" msgid="381024150898615683">"Праграмы, якія працуюць у фонавым рэжыме"</string>
<string name="running_foreground_services_msg" msgid="6326247670075574355">"Дакраніцеся, каб даведацца пра выкарыстанне трафіка і акумулятара"</string>
- <string name="mobile_data_disable_title" msgid="1068272097382942231">"Адключыць мабільны інтэрнэт?"</string>
+ <string name="mobile_data_disable_title" msgid="1068272097382942231">"Выключыць мабільную перадачу даных?"</string>
<string name="mobile_data_disable_message" msgid="4756541658791493506">"У вас не будзе доступу да даных ці інтэрнэту праз аператара <xliff:g id="CARRIER">%s</xliff:g>. Інтэрнэт будзе даступны толькі праз Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6078110473451946831">"ваш аператар"</string>
<string name="touch_filtered_warning" msgid="8671693809204767551">"Праграма хавае запыт на дазвол, таму ваш адказ немагчыма спраўдзіць у Наладах."</string>
@@ -904,6 +904,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Датчыкі выкл."</string>
<string name="device_services" msgid="1191212554435440592">"Сэрвісы прылады"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Без назвы"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index ede7af9..e9effcf 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Сензорите са изключени"</string>
<string name="device_services" msgid="1191212554435440592">"Услуги за устройството"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Няма заглавие"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 76a344f..0724e37 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"সেন্সর বন্ধ"</string>
<string name="device_services" msgid="1191212554435440592">"ডিভাইস সংক্রান্ত পরিষেবা"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"কোনও শীর্ষক নেই"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 69550b0..4e8e833 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors desactivats"</string>
<string name="device_services" msgid="1191212554435440592">"Serveis per a dispositius"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Sense títol"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index cf116e3..30bf1de 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -902,6 +902,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzory jsou vypnuty"</string>
<string name="device_services" msgid="1191212554435440592">"Služby zařízení"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Bez názvu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index ce9a821..ad4afcf 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -21,9 +21,9 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7164937344850004466">"System-UI"</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"Ryd"</string>
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ingen underretninger"</string>
+ <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ingen notifikationer"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"I gang"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Underretninger"</string>
+ <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifikationer"</string>
<string name="battery_low_title" msgid="9187898087363540349">"Enheden løber muligvis snart tør for batteri"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> tilbage"</string>
<string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Der er <xliff:g id="PERCENTAGE">%1$s</xliff:g> tilbage eller ca. <xliff:g id="TIME">%2$s</xliff:g>, alt efter hvordan du bruger enheden"</string>
@@ -41,7 +41,7 @@
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automatisk skærmrotation"</string>
<string name="status_bar_settings_mute_label" msgid="554682549917429396">"LYDLØS"</string>
<string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
- <string name="status_bar_settings_notifications" msgid="397146176280905137">"Underretninger"</string>
+ <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notifikationer"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Netdeling via Bluetooth anvendt"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Konfigurer inputmetoder"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fysisk tastatur"</string>
@@ -71,7 +71,7 @@
<string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Screenshottet kan ikke gemmes, fordi der er begrænset lagerplads"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Appen eller din organisation tillader ikke, at du tager screenshots"</string>
<string name="screenrecord_name" msgid="4196719243134204796">"Skærmoptagelse"</string>
- <string name="screenrecord_channel_description" msgid="4630777331970993858">"Konstant underretning om skærmoptagelse"</string>
+ <string name="screenrecord_channel_description" msgid="4630777331970993858">"Konstant notifikation om skærmoptagelse"</string>
<string name="screenrecord_start_label" msgid="5177739269492196055">"Start optagelse"</string>
<string name="screenrecord_mic_label" msgid="4522870600914810019">"Optag voiceover"</string>
<string name="screenrecord_taps_label" msgid="1776467076607964790">"Vis tryk"</string>
@@ -187,9 +187,9 @@
<string name="accessibility_battery_level" msgid="7451474187113371965">"Batteri <xliff:g id="NUMBER">%d</xliff:g> procent."</string>
<string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Batteriet oplades. <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> %%."</string>
<string name="accessibility_settings_button" msgid="799583911231893380">"Systemindstillinger."</string>
- <string name="accessibility_notifications_button" msgid="4498000369779421892">"Underretninger."</string>
- <string name="accessibility_overflow_action" msgid="5681882033274783311">"Se alle underretninger"</string>
- <string name="accessibility_remove_notification" msgid="3603099514902182350">"Ryd underretning."</string>
+ <string name="accessibility_notifications_button" msgid="4498000369779421892">"Notifikationer."</string>
+ <string name="accessibility_overflow_action" msgid="5681882033274783311">"Se alle notifikationer"</string>
+ <string name="accessibility_remove_notification" msgid="3603099514902182350">"Ryd notifikation."</string>
<string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS aktiveret."</string>
<string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS samler data."</string>
<string name="accessibility_tty_enabled" msgid="4613200365379426561">"TeleTypewriter aktiveret."</string>
@@ -199,8 +199,8 @@
<skip />
<!-- no translation found for accessibility_work_mode (702887484664647430) -->
<skip />
- <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Underretningen er annulleret."</string>
- <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Underretningspanel."</string>
+ <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notifikationen er annulleret."</string>
+ <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Notifikationspanel."</string>
<string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Hurtige indstillinger."</string>
<string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Låseskærm."</string>
<string name="accessibility_desc_settings" msgid="3417884241751434521">"Indstillinger"</string>
@@ -265,14 +265,14 @@
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Søger efter GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Placeringen er angivet ved hjælp af GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Aktive placeringsanmodninger"</string>
- <string name="accessibility_clear_all" msgid="5235938559247164925">"Ryd alle underretninger."</string>
+ <string name="accessibility_clear_all" msgid="5235938559247164925">"Ryd alle notifikationer."</string>
<string name="notification_group_overflow_indicator" msgid="1863231301642314183">"<xliff:g id="NUMBER">%s</xliff:g> mere"</string>
<string name="notification_group_overflow_indicator_ambient" msgid="879560382990377886">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, +<xliff:g id="OVERFLOW">%2$s</xliff:g>"</string>
<plurals name="notification_group_overflow_description" formatted="false" msgid="4579313201268495404">
- <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> underretning mere i gruppen.</item>
- <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> underretninger mere i gruppen.</item>
+ <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> notifikation mere i gruppen.</item>
+ <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> notifikationer mere i gruppen.</item>
</plurals>
- <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Underretningsindstillinger"</string>
+ <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Notifikationsindstillinger"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Indstillinger for <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skærmen roterer automatisk."</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Skærmen er nu låst i liggende retning."</string>
@@ -347,7 +347,7 @@
<item quantity="one">%d enhed</item>
<item quantity="other">%d enheder</item>
</plurals>
- <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Underretninger"</string>
+ <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notifikationer"</string>
<string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Lommelygte"</string>
<string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Mobildata"</string>
<string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"Dataforbrug"</string>
@@ -382,7 +382,7 @@
<string name="zen_silence_introduction_voice" msgid="3948778066295728085">"Dette blokerer ALLE lyde og vibrationer, bl.a. fra alarmer, musik, videoer og spil. Du vil stadig kunne foretage telefonopkald."</string>
<string name="zen_silence_introduction" msgid="3137882381093271568">"Dette blokerer ALLE lyde og vibrationer, bl.a. fra alarmer, musik, videoer og spil."</string>
<string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
- <string name="speed_bump_explanation" msgid="1288875699658819755">"Mindre presserende underretninger nedenfor"</string>
+ <string name="speed_bump_explanation" msgid="1288875699658819755">"Mindre presserende notifikationer nedenfor"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Tryk igen for at åbne"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Stryg opad for at låse op"</string>
<string name="do_disclosure_generic" msgid="5615898451805157556">"Denne enhed administreres af din organisation"</string>
@@ -439,9 +439,9 @@
<string name="media_projection_remember_text" msgid="3103510882172746752">"Vis ikke igen"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Ryd alt"</string>
<string name="manage_notifications_text" msgid="2386728145475108753">"Administrer"</string>
- <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"Underretninger er sat på pause af Forstyr ikke"</string>
+ <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"Notifikationer er sat på pause af Forstyr ikke"</string>
<string name="media_projection_action_text" msgid="8470872969457985954">"Start nu"</string>
- <string name="empty_shade_text" msgid="708135716272867002">"Ingen underretninger"</string>
+ <string name="empty_shade_text" msgid="708135716272867002">"Ingen notifikationer"</string>
<string name="profile_owned_footer" msgid="8021888108553696069">"Profilen kan overvåges"</string>
<string name="vpn_footer" msgid="2388611096129106812">"Netværket kan være overvåget"</string>
<string name="branded_vpn_footer" msgid="2168111859226496230">"Netværket kan være overvåget"</string>
@@ -501,7 +501,7 @@
<string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"Låst op for <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="keyguard_indication_trust_managed" msgid="8319646760022357585">"<xliff:g id="TRUST_AGENT">%1$s</xliff:g> kører"</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Enheden vil forblive låst, indtil du manuelt låser den op"</string>
- <string name="hidden_notifications_title" msgid="7139628534207443290">"Modtag underretninger hurtigere"</string>
+ <string name="hidden_notifications_title" msgid="7139628534207443290">"Modtag notifikationer hurtigere"</string>
<string name="hidden_notifications_text" msgid="2326409389088668981">"Se dem, før du låser op"</string>
<string name="hidden_notifications_cancel" msgid="3690709735122344913">"Nej tak"</string>
<string name="hidden_notifications_setup" msgid="41079514801976810">"Konfigurer"</string>
@@ -530,7 +530,7 @@
<string name="stream_ring" msgid="8213049469184048338">"Ring"</string>
<string name="stream_music" msgid="9086982948697544342">"Medie"</string>
<string name="stream_alarm" msgid="5209444229227197703">"Alarm"</string>
- <string name="stream_notification" msgid="2563720670905665031">"Underretning"</string>
+ <string name="stream_notification" msgid="2563720670905665031">"Notifikation"</string>
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Tonesignalfrekvens (DTMF)"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Hjælpefunktioner"</string>
@@ -549,7 +549,7 @@
<string name="volume_ringer_hint_unmute" msgid="6602880133293060368">"slå lyden til"</string>
<string name="volume_ringer_hint_vibrate" msgid="4036802135666515202">"vibrer"</string>
<string name="volume_dialog_title" msgid="7272969888820035876">"%s lydstyrkeknapper"</string>
- <string name="volume_dialog_ringer_guidance_ring" msgid="3360373718388509040">"Der afspilles lyd ved opkald og underretninger (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
+ <string name="volume_dialog_ringer_guidance_ring" msgid="3360373718388509040">"Der afspilles lyd ved opkald og notifikationer (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
<string name="output_title" msgid="5355078100792942802">"Medieafspilning"</string>
<string name="output_calls_title" msgid="8717692905017206161">"Udgang til telefonopkald"</string>
<string name="output_none_found" msgid="5544982839808921091">"Der blev ikke fundet nogen enheder"</string>
@@ -595,25 +595,25 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Vil du slå Bluetooth til?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Bluetooth skal være slået til, før du kan knytte dit tastatur til din tablet."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Slå til"</string>
- <string name="show_silently" msgid="6841966539811264192">"Vis underretninger lydløst"</string>
- <string name="block" msgid="2734508760962682611">"Bloker alle underretninger"</string>
+ <string name="show_silently" msgid="6841966539811264192">"Vis notifikationer lydløst"</string>
+ <string name="block" msgid="2734508760962682611">"Bloker alle notifikationer"</string>
<string name="do_not_silence" msgid="6878060322594892441">"Skal ikke sættes på lydløs"</string>
<string name="do_not_silence_block" msgid="4070647971382232311">"Skal ikke sættes på lydløs eller blokeres"</string>
- <string name="tuner_full_importance_settings" msgid="3207312268609236827">"Kontrolelementer til underretning om strøm"</string>
+ <string name="tuner_full_importance_settings" msgid="3207312268609236827">"Kontrolelementer til notifikation om strøm"</string>
<string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Til"</string>
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Fra"</string>
- <string name="power_notification_controls_description" msgid="4372459941671353358">"Med kontrolelementer til underretninger om strøm kan du konfigurere et vigtighedsniveau fra 0 til 5 for en apps underretninger. \n\n"<b>"Niveau 5"</b>\n"- Vis øverst på listen over underretninger \n- Tillad afbrydelse af fuld skærm \n- Se altid smugkig \n\n"<b>"Niveau 4"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se altid smugkig \n\n"<b>"Niveau 3"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se aldrig smugkig \n\n"<b>"Niveau 2"</b>\n"- Ingen afbrydelse af fuld skærm \n Se aldrig smugkig \n- Ingen lyd og vibration \n\n"<b>"Niveau 1"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se aldrig smugkig \n- Ingen lyd eller vibration \n- Skjul fra låseskærm og statusbjælke \n- Vis nederst på listen over underretninger \n\n"<b>"Niveau 0"</b>\n"- Bloker alle underretninger fra appen."</string>
- <string name="notification_header_default_channel" msgid="7506845022070889909">"Underretninger"</string>
- <string name="notification_channel_disabled" msgid="344536703863700565">"Du får ikke længere vist disse underretninger"</string>
- <string name="notification_channel_minimized" msgid="1664411570378910931">"Disse underretninger minimeres"</string>
- <string name="notification_channel_silenced" msgid="2877199534497961942">"Disse underretninger vises lydløst"</string>
- <string name="notification_channel_unsilenced" msgid="4790904571552394137">"Disse underretninger underretter dig"</string>
- <string name="inline_blocking_helper" msgid="3055064577771478591">"Du afviser som regel disse underretninger. \nVil du blive ved med at se dem?"</string>
- <string name="inline_keep_showing" msgid="8945102997083836858">"Vil du fortsætte med at se disse underretninger?"</string>
- <string name="inline_stop_button" msgid="4172980096860941033">"Stop underretninger"</string>
+ <string name="power_notification_controls_description" msgid="4372459941671353358">"Med kontrolelementer til notifikationer om strøm kan du konfigurere et vigtighedsniveau fra 0 til 5 for en apps notifikationer. \n\n"<b>"Niveau 5"</b>\n"- Vis øverst på listen over notifikationer \n- Tillad afbrydelse af fuld skærm \n- Se altid smugkig \n\n"<b>"Niveau 4"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se altid smugkig \n\n"<b>"Niveau 3"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se aldrig smugkig \n\n"<b>"Niveau 2"</b>\n"- Ingen afbrydelse af fuld skærm \n Se aldrig smugkig \n- Ingen lyd og vibration \n\n"<b>"Niveau 1"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se aldrig smugkig \n- Ingen lyd eller vibration \n- Skjul fra låseskærm og statusbjælke \n- Vis nederst på listen over notifikationer \n\n"<b>"Niveau 0"</b>\n"- Bloker alle notifikationer fra appen."</string>
+ <string name="notification_header_default_channel" msgid="7506845022070889909">"Notifikationer"</string>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Du får ikke længere vist disse notifikationer"</string>
+ <string name="notification_channel_minimized" msgid="1664411570378910931">"Disse notifikationer minimeres"</string>
+ <string name="notification_channel_silenced" msgid="2877199534497961942">"Disse notifikationer vises lydløst"</string>
+ <string name="notification_channel_unsilenced" msgid="4790904571552394137">"Disse notifikationer underretter dig"</string>
+ <string name="inline_blocking_helper" msgid="3055064577771478591">"Du afviser som regel disse notifikationer. \nVil du blive ved med at se dem?"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Vil du fortsætte med at se disse notifikationer?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Stop notifikationer"</string>
<!-- no translation found for inline_block_button (8735843688021655065) -->
<skip />
- <string name="inline_keep_button" msgid="6665940297019018232">"Fortsæt med at vise underretninger"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Fortsæt med at vise notifikationer"</string>
<string name="inline_minimize_button" msgid="966233327974702195">"Minimer"</string>
<string name="inline_silent_button_silent" msgid="4411510650503783646">"Vis lydløst"</string>
<!-- no translation found for inline_silent_button_stay_silent (6308371431217601009) -->
@@ -622,8 +622,8 @@
<skip />
<!-- no translation found for inline_silent_button_keep_alerting (327696842264359693) -->
<skip />
- <string name="inline_keep_showing_app" msgid="1723113469580031041">"Vil du fortsætte med at se underretninger fra denne app?"</string>
- <string name="notification_unblockable_desc" msgid="1037434112919403708">"Disse underretninger kan ikke deaktiveres"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Vil du fortsætte med at se notifikationer fra denne app?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Disse notifikationer kan ikke deaktiveres"</string>
<string name="notification_delegate_header" msgid="9167022191405284627">"via <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="appops_camera" msgid="8100147441602585776">"Denne app anvender kameraet."</string>
<string name="appops_microphone" msgid="741508267659494555">"Denne app anvender mikrofonen."</string>
@@ -634,15 +634,15 @@
<string name="appops_camera_mic_overlay" msgid="6718768197048030993">"Denne app vises over andre apps på din skærm og anvender mikrofonen og kameraet."</string>
<string name="notification_appops_settings" msgid="1028328314935908050">"Indstillinger"</string>
<string name="notification_appops_ok" msgid="1156966426011011434">"OK"</string>
- <string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Styring af underretninger for <xliff:g id="APP_NAME">%1$s</xliff:g> blev åbnet"</string>
- <string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Styring af underretninger for <xliff:g id="APP_NAME">%1$s</xliff:g> blev lukket"</string>
- <string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Tillad underretninger fra denne kanal"</string>
+ <string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Styring af notifikationer for <xliff:g id="APP_NAME">%1$s</xliff:g> blev åbnet"</string>
+ <string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Styring af notifikationer for <xliff:g id="APP_NAME">%1$s</xliff:g> blev lukket"</string>
+ <string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Tillad notifikationer fra denne kanal"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Flere indstillinger"</string>
<string name="notification_app_settings" msgid="420348114670768449">"Tilpas"</string>
<string name="notification_done" msgid="5279426047273930175">"Udfør"</string>
<string name="inline_undo" msgid="558916737624706010">"Fortryd"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
- <string name="notification_menu_gear_description" msgid="2204480013726775108">"kontrolelementer til underretninger"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"kontrolelementer til notifikationer"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"Indstillinger for udsættelse"</string>
<string name="notification_menu_snooze_action" msgid="1112254519029621372">"Udsæt"</string>
<string name="snooze_undo" msgid="6074877317002985129">"FORTRYD"</string>
@@ -689,7 +689,7 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Start"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Seneste"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Tilbage"</string>
- <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Underretninger"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifikationer"</string>
<string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Tastaturgenveje"</string>
<string name="keyboard_shortcut_group_system_switch_input" msgid="8413348767825486492">"Skift tastaturlayout"</string>
<string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applikationer"</string>
@@ -759,7 +759,7 @@
<item msgid="2139628951880142927">"Vis procent ved opladning (standard)"</item>
<item msgid="3327323682209964956">"Vis ikke dette ikon"</item>
</string-array>
- <string name="tuner_low_priority" msgid="1325884786608312358">"Vis ikoner for underretninger med lav prioritet"</string>
+ <string name="tuner_low_priority" msgid="1325884786608312358">"Vis ikoner for notifikationer med lav prioritet"</string>
<string name="other" msgid="4060683095962566764">"Andet"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Adskiller til opdelt skærm"</string>
<string name="accessibility_action_divider_left_full" msgid="2801570521881574972">"Vis venstre del i fuld skærm"</string>
@@ -779,7 +779,7 @@
<string name="accessibility_qs_edit_tile_add" msgid="3520406665865985109">"Føj <xliff:g id="TILE_NAME">%1$s</xliff:g> til position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_move" msgid="3108103090006972938">"Flyt <xliff:g id="TILE_NAME">%1$s</xliff:g> til position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Redigeringsværktøj for Hurtige indstillinger."</string>
- <string name="accessibility_desc_notification_icon" msgid="8352414185263916335">"<xliff:g id="ID_1">%1$s</xliff:g>-underretning: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+ <string name="accessibility_desc_notification_icon" msgid="8352414185263916335">"<xliff:g id="ID_1">%1$s</xliff:g>-notifikation: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="dock_forced_resizable" msgid="5914261505436217520">"Appen fungerer muligvis ikke i opdelt skærm."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Appen understøtter ikke opdelt skærm."</string>
<string name="forced_resizable_secondary_display" msgid="4230857851756391925">"Appen fungerer muligvis ikke på sekundære skærme."</string>
@@ -828,7 +828,7 @@
<string name="tuner_right" msgid="6222734772467850156">"Højre"</string>
<string name="tuner_menu" msgid="191640047241552081">"Menu"</string>
<string name="tuner_app" msgid="3507057938640108777">"Appen <xliff:g id="APP">%1$s</xliff:g>"</string>
- <string name="notification_channel_alerts" msgid="4496839309318519037">"Underretninger"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Notifikationer"</string>
<string name="notification_channel_battery" msgid="5786118169182888462">"Batteri"</string>
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Generelle meddelelser"</string>
@@ -852,7 +852,7 @@
<string name="qs_dnd_keep" msgid="1825009164681928736">"Behold"</string>
<string name="qs_dnd_replace" msgid="8019520786644276623">"Erstat"</string>
<string name="running_foreground_services_title" msgid="381024150898615683">"Apps, der kører i baggrunden"</string>
- <string name="running_foreground_services_msg" msgid="6326247670075574355">"Tryk for at se oplysninger om batteri- og dataforbrug"</string>
+ <string name="running_foreground_services_msg" msgid="6326247670075574355">"Tryk for at se info om batteri- og dataforbrug"</string>
<string name="mobile_data_disable_title" msgid="1068272097382942231">"Vil du deaktivere mobildata?"</string>
<string name="mobile_data_disable_message" msgid="4756541658791493506">"Du vil ikke have data- eller internetadgang via <xliff:g id="CARRIER">%s</xliff:g>. Der vil kunne være adgang til internettet via Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6078110473451946831">"dit mobilselskab"</string>
@@ -876,7 +876,7 @@
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8640691753867990511">"Apps anvender enhedens <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<!-- no translation found for ongoing_privacy_chip_content_multiple_apps_single_op (4871926099254314088) -->
<string name="ongoing_privacy_dialog_cancel" msgid="5479124524931216790">"Luk"</string>
- <string name="ongoing_privacy_dialog_open_settings" msgid="2074844974365194279">"Se oplysninger"</string>
+ <string name="ongoing_privacy_dialog_open_settings" msgid="2074844974365194279">"Se info"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App, der anvender din/dit <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps, der anvender din/dit <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Deaktiver sensorer"</string>
<string name="device_services" msgid="1191212554435440592">"Enhedstjenester"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Ingen titel"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 447f8b9..0be730a 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -894,6 +894,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensoren aus"</string>
<string name="device_services" msgid="1191212554435440592">"Gerätedienste"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Kein Titel"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 5e2fb03..703bc40 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string>
<string name="device_services" msgid="1191212554435440592">"Device Services"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 3891569..31fd04a 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string>
<string name="device_services" msgid="1191212554435440592">"Device Services"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 5e2fb03..703bc40 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string>
<string name="device_services" msgid="1191212554435440592">"Device Services"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 5e2fb03..703bc40 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string>
<string name="device_services" msgid="1191212554435440592">"Device Services"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 9ef6a83..761acf6 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -889,8 +889,6 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%d</xliff:g> app más</item>
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Se desactivaron los sensores"</string>
- <!-- no translation found for device_services (1191212554435440592) -->
- <skip />
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="device_services" msgid="1191212554435440592">"Servicios del dispositivo"</string>
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Sin título"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index f4e107d..0b3ba5d 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensores desactivados"</string>
<string name="device_services" msgid="1191212554435440592">"Servicios del dispositivo"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Sin título"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index d8568df..e318291 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Andurid on välja lülitatud"</string>
<string name="device_services" msgid="1191212554435440592">"Seadme teenused"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Pealkiri puudub"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index cfdf7a5..5b9f0cf 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sentsoreak desaktibatuta daude"</string>
<string name="device_services" msgid="1191212554435440592">"Gailuetarako zerbitzuak"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Ez du izenik"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index cd92d45..931def7 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Anturit pois päältä"</string>
<string name="device_services" msgid="1191212554435440592">"Laitepalvelut"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Ei nimeä"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 695a6a5..d1412aa 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Capteurs désactivés"</string>
<string name="device_services" msgid="1191212554435440592">"Services de l\'appareil"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Sans titre"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index a1a0352..8ba575b 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Capteurs désactivés"</string>
<string name="device_services" msgid="1191212554435440592">"Services pour l\'appareil"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Sans titre"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 7f111e8..2784567 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Desactivar sensores"</string>
<string name="device_services" msgid="1191212554435440592">"Servizos do dispositivo"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Sen título"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 8525094..f17a7f6 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -889,8 +889,6 @@
<item quantity="other"><xliff:g id="NUM_APPS_1">%d</xliff:g> અન્ય ઍપ</item>
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"સેન્સર બંધ છે"</string>
- <!-- no translation found for device_services (1191212554435440592) -->
- <skip />
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="device_services" msgid="1191212554435440592">"ડિવાઇસ સેવાઓ"</string>
+ <string name="music_controls_no_title" msgid="5236895307087002011">"કોઈ શીર્ષક નથી"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index ae12412..49d923a 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Érzékelők kikapcsolva"</string>
<string name="device_services" msgid="1191212554435440592">"Eszközszolgáltatások"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Nincs cím"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index ffcc762..dc592c5 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Տվիչներն անջատած են"</string>
<string name="device_services" msgid="1191212554435440592">"Սարքի ծառայություններ"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Անանուն"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index eb99a6c..1b43e65 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensor nonaktif"</string>
<string name="device_services" msgid="1191212554435440592">"Layanan Perangkat"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Tanpa judul"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 0040c3c..36b557d 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Slökkt á skynjurum"</string>
<string name="device_services" msgid="1191212554435440592">"Tækjaþjónusta"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Enginn titill"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 83956e8..21c259a 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensori disattivati"</string>
<string name="device_services" msgid="1191212554435440592">"Servizi del dispositivo"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Senza titolo"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index f7d52ed..ff88a0d 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"センサー OFF"</string>
<string name="device_services" msgid="1191212554435440592">"デバイス サービス"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"タイトルなし"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index a1788fc..41ef3e2 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Датчиктер өшірулі"</string>
<string name="device_services" msgid="1191212554435440592">"Құрылғы қызметтері"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Атауы жоқ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 0cbd06c..5520cb0 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"បិទឧបករណ៍ចាប់សញ្ញា"</string>
<string name="device_services" msgid="1191212554435440592">"សេវាកម្មឧបករណ៍"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"គ្មានចំណងជើង"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 9f46742..f829c12 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -889,8 +889,6 @@
<item quantity="other"><xliff:g id="NUM_APPS_1">%d</xliff:g> ಇತರ ಆ್ಯಪ್ಗಳು</item>
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"ಸೆನ್ಸರ್ಗಳು ಆಫ್"</string>
- <!-- no translation found for device_services (1191212554435440592) -->
- <skip />
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="device_services" msgid="1191212554435440592">"ಸಾಧನ ಸೇವೆಗಳು"</string>
+ <string name="music_controls_no_title" msgid="5236895307087002011">"ಯಾವುದೇ ಶೀರ್ಷಿಕೆಯಿಲ್ಲ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 581ffa9..f5168fb 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"센서 사용 안함"</string>
<string name="device_services" msgid="1191212554435440592">"기기 서비스"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"제목 없음"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index ba5a0ac..9558c3a 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Сенсорлорду өчүрүү"</string>
<string name="device_services" msgid="1191212554435440592">"Түзмөк кызматтары"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Аталышы жок"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 46cd3f0..5786fb0 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -901,8 +901,6 @@
<item quantity="other">Dar <xliff:g id="NUM_APPS_1">%d</xliff:g> programų</item>
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Jutikliai išjungti"</string>
- <!-- no translation found for device_services (1191212554435440592) -->
- <skip />
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="device_services" msgid="1191212554435440592">"Įrenginio paslaugos"</string>
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Nėra pavadinimo"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index a1203d5..cebd91c 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -896,6 +896,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensori izslēgti"</string>
<string name="device_services" msgid="1191212554435440592">"Ierīces pakalpojumi"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Nav nosaukuma"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index a3fd2d5..df1bdbb 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Сензорите се исклучени"</string>
<string name="device_services" msgid="1191212554435440592">"Услуги за уредот"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Без наслов"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index f3075b8..5800e0e 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"സെൻസറുകൾ ഓഫാണ്"</string>
<string name="device_services" msgid="1191212554435440592">"ഉപകരണ സേവനങ്ങള്"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"പേരില്ല"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 7236893..e96865e 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Мэдрэгчийг унтраах"</string>
<string name="device_services" msgid="1191212554435440592">"Төхөөрөмжийн үйлчилгээ"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Гарчиггүй"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 59e481c..6022a9c 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -889,8 +889,6 @@
<item quantity="other">इतर <xliff:g id="NUM_APPS_1">%d</xliff:g> अॅप्स</item>
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"सेन्सर बंद आहेत"</string>
- <!-- no translation found for device_services (1191212554435440592) -->
- <skip />
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="device_services" msgid="1191212554435440592">"डिव्हाइस सेवा"</string>
+ <string name="music_controls_no_title" msgid="5236895307087002011">"शीर्षक नाही"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index e77771d..1a9eb1c 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Penderia dimatikan"</string>
<string name="device_services" msgid="1191212554435440592">"Perkhidmatan Peranti"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Tiada tajuk"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index e5561e8..dbfa01e 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"အာရုံခံကိရိယာများ ပိတ်ထားသည်"</string>
<string name="device_services" msgid="1191212554435440592">"စက်ပစ္စည်းဝန်ဆောင်မှုများ"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"ခေါင်းစဉ် မရှိပါ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index a1a12bd..e790684 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensorer er av"</string>
<string name="device_services" msgid="1191212554435440592">"Enhetstjenester"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Ingen tittel"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 096db56..9b4441f 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -889,8 +889,6 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%d</xliff:g> अन्य अनुप्रयोग</item>
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"सेन्सरहरू निष्क्रिय छन्"</string>
- <!-- no translation found for device_services (1191212554435440592) -->
- <skip />
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="device_services" msgid="1191212554435440592">"यन्त्रका सेवाहरू"</string>
+ <string name="music_controls_no_title" msgid="5236895307087002011">"शीर्षक छैन"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 3607ff8..e570789 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensoren uit"</string>
<string name="device_services" msgid="1191212554435440592">"Apparaatservices"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Geen titel"</string>
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 5cb98ee..dd260b1 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -889,8 +889,6 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%d</xliff:g>ଟି ଅନ୍ୟ ଆପ୍</item>
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"ସେନ୍ସର୍ଗୁଡ଼ିକ ବନ୍ଦ ଅଛି"</string>
- <!-- no translation found for device_services (1191212554435440592) -->
- <skip />
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="device_services" msgid="1191212554435440592">"ଡିଭାଇସ୍ ସେବାଗୁଡିକ"</string>
+ <string name="music_controls_no_title" msgid="5236895307087002011">"କୌଣସି ଶୀର୍ଷକ ନାହିଁ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 3702e2b..e36fea2 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -889,8 +889,6 @@
<item quantity="other"><xliff:g id="NUM_APPS_1">%d</xliff:g> ਹੋਰ ਐਪਾਂ</item>
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"ਸੈਂਸਰ ਬੰਦ ਕਰੋ"</string>
- <!-- no translation found for device_services (1191212554435440592) -->
- <skip />
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="device_services" msgid="1191212554435440592">"ਡੀਵਾਈਸ ਸੇਵਾਵਾਂ"</string>
+ <string name="music_controls_no_title" msgid="5236895307087002011">"ਕੋਈ ਸਿਰਲੇਖ ਨਹੀਂ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 4ece82c..ed2902f 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -901,8 +901,6 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%d</xliff:g> inna aplikacja</item>
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Wyłącz czujniki"</string>
- <!-- no translation found for device_services (1191212554435440592) -->
- <skip />
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="device_services" msgid="1191212554435440592">"Usługi urządzenia"</string>
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Bez tytułu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 375f5e8..c1858fc 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -889,8 +889,6 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%d</xliff:g> outra aplicação</item>
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensores desativados"</string>
- <!-- no translation found for device_services (1191212554435440592) -->
- <skip />
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="device_services" msgid="1191212554435440592">"Serviços do dispositivo"</string>
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Sem título"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 24254f6..c393bde 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -896,6 +896,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzori dezactivați"</string>
<string name="device_services" msgid="1191212554435440592">"Servicii pentru dispozitiv"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Fără titlu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index a5d4059..e643c8f 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -902,6 +902,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Датчики отключены"</string>
<string name="device_services" msgid="1191212554435440592">"Сервисы устройства"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Без названия"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index d9ba8de..bcc444f 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -901,8 +901,6 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%d</xliff:g> ďalšia aplikácia</item>
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzory sú vypnuté"</string>
- <!-- no translation found for device_services (1191212554435440592) -->
- <skip />
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="device_services" msgid="1191212554435440592">"Služby zariadenia"</string>
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Bez názvu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 5048227..706e700 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -902,6 +902,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Izklop za tipala"</string>
<string name="device_services" msgid="1191212554435440592">"Storitve naprave"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Brez naslova"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 22ffa81..3c8c3ab 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -800,7 +800,7 @@
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimera"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Stäng"</string>
<string name="pip_phone_settings" msgid="8080777499521528521">"Inställningar"</string>
- <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Tryck och dra nedåt för att avvisa"</string>
+ <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Tryck och dra nedåt för att ta bort"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Meny"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> visas i bild-i-bild"</string>
<string name="pip_notification_message" msgid="5619512781514343311">"Om du inte vill att den här funktionen används i <xliff:g id="NAME">%s</xliff:g> öppnar du inställningarna genom att trycka. Sedan inaktiverar du funktionen."</string>
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensorer har inaktiverats"</string>
<string name="device_services" msgid="1191212554435440592">"Enhetstjänster"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Ingen titel"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index a35c78c..f75cc4d 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -889,8 +889,6 @@
<item quantity="one">வேறு <xliff:g id="NUM_APPS_0">%d</xliff:g> ஆப்ஸ்</item>
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"சென்சார்களை ஆஃப் செய்தல்"</string>
- <!-- no translation found for device_services (1191212554435440592) -->
- <skip />
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="device_services" msgid="1191212554435440592">"சாதன சேவைகள்"</string>
+ <string name="music_controls_no_title" msgid="5236895307087002011">"தலைப்பு இல்லை"</string>
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index e7eafbe..894263e 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -889,8 +889,6 @@
<item quantity="one">మరో <xliff:g id="NUM_APPS_0">%d</xliff:g> యాప్</item>
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"సెన్సార్లు ఆఫ్"</string>
- <!-- no translation found for device_services (1191212554435440592) -->
- <skip />
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="device_services" msgid="1191212554435440592">"పరికర సేవలు"</string>
+ <string name="music_controls_no_title" msgid="5236895307087002011">"శీర్షిక లేదు"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 05df7bd..ae581ac 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"เซ็นเซอร์ปิดอยู่"</string>
<string name="device_services" msgid="1191212554435440592">"บริการของอุปกรณ์"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"ไม่มีชื่อ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 3bd6ea6..ab20ff0 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Naka-off ang mga sensor"</string>
<string name="device_services" msgid="1191212554435440592">"Mga Serbisyo ng Device"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Walang pamagat"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 4962b16..32201fb 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensörler kapalı"</string>
<string name="device_services" msgid="1191212554435440592">"Cihaz Hizmetleri"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Başlıksız"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 3a59029..ee9da5e 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"سینسرز آف ہیں"</string>
<string name="device_services" msgid="1191212554435440592">"آلہ کی سروس"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"کوئی عنوان نہیں ہے"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 3388bcb..488bfae 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensorlar nofaol"</string>
<string name="device_services" msgid="1191212554435440592">"Qurilma xizmatlari"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Nomsiz"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 3ebb8dd..125eb72 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Tắt cảm biến"</string>
<string name="device_services" msgid="1191212554435440592">"Dịch vụ cho thiết bị"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"Không có tiêu đề"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index d480a8a..d6fd3d89 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"已关闭传感器"</string>
<string name="device_services" msgid="1191212554435440592">"设备服务"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"无标题"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 7ff70d9..dbe24bb 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -890,6 +890,5 @@
</plurals>
<string name="sensor_privacy_mode" msgid="8982771253020769598">"已關閉感應器"</string>
<string name="device_services" msgid="1191212554435440592">"裝置服務"</string>
- <!-- no translation found for music_controls_no_title (5236895307087002011) -->
- <skip />
+ <string name="music_controls_no_title" msgid="5236895307087002011">"無標題"</string>
</resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 59838d2..633f868 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -109,5 +109,10 @@
<!-- Optional cancel button on Keyguard -->
<item type="id" name="cancel_button"/>
+
+ <!-- AodMaskView transition tag -->
+ <item type="id" name="aod_mask_transition_progress_tag" />
+ <item type="id" name="aod_mask_transition_progress_end_tag" />
+ <item type="id" name="aod_mask_transition_progress_start_tag" />
</resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 1c8a672..3cfd6a9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -55,6 +55,10 @@
* Consumer that accepts the a new ClockPlugin implementation when the Extension reloads.
*/
private final Consumer<ClockPlugin> mClockPluginConsumer = plugin -> setClockPlugin(plugin);
+ /**
+ * Maintain state so that a newly connected plugin can be initialized.
+ */
+ private float mDarkAmount;
private final StatusBarStateController.StateListener mStateListener =
new StatusBarStateController.StateListener() {
@@ -83,6 +87,13 @@
super(context, attrs);
}
+ /**
+ * Returns if this view is presenting a custom clock, or the default implementation.
+ */
+ public boolean hasCustomClock() {
+ return mClockPlugin != null;
+ }
+
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@@ -147,6 +158,7 @@
mClockPlugin = plugin;
mClockPlugin.setStyle(getPaint().getStyle());
mClockPlugin.setTextColor(getCurrentTextColor());
+ mClockPlugin.setDarkAmount(mDarkAmount);
}
/**
@@ -208,6 +220,7 @@
* @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake.
*/
public void setDarkAmount(float darkAmount) {
+ mDarkAmount = darkAmount;
if (mClockPlugin != null) {
mClockPlugin.setDarkAmount(darkAmount);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index c6f1726..f0cdc89 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -141,6 +141,13 @@
onDensityOrFontScaleChanged();
}
+ /**
+ * If we're presenting a custom clock of just the default one.
+ */
+ public boolean hasCustomClock() {
+ return mClockView.hasCustomClock();
+ }
+
private void setEnableMarquee(boolean enabled) {
if (DEBUG) Log.v(TAG, "Schedule setEnableMarquee: " + (enabled ? "Enable" : "Disable"));
if (enabled) {
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 6864ea1..2006794 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -40,7 +40,6 @@
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.LayoutInflater;
-import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -56,7 +55,6 @@
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-import com.android.systemui.statusbar.policy.IconLogger;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
import com.android.systemui.util.Utils.DisableStateTracker;
@@ -71,11 +69,12 @@
@Retention(SOURCE)
- @IntDef({MODE_DEFAULT, MODE_ON, MODE_OFF})
+ @IntDef({MODE_DEFAULT, MODE_ON, MODE_OFF, MODE_ESTIMATE})
public @interface BatteryPercentMode {}
public static final int MODE_DEFAULT = 0;
public static final int MODE_ON = 1;
public static final int MODE_OFF = 2;
+ public static final int MODE_ESTIMATE = 3;
private final BatteryMeterDrawableBase mDrawable;
private final String mSlotBattery;
@@ -93,6 +92,7 @@
// Some places may need to show the battery conditionally, and not obey the tuner
private boolean mIgnoreTunerUpdates;
private boolean mIsSubscribedForTunerUpdates;
+ private boolean mCharging;
private int mDarkModeBackgroundColor;
private int mDarkModeFillColor;
@@ -276,9 +276,6 @@
public void onTuningChanged(String key, String newValue) {
if (StatusBarIconController.ICON_BLACKLIST.equals(key)) {
ArraySet<String> icons = StatusBarIconController.getIconBlacklist(newValue);
- boolean hidden = icons.contains(mSlotBattery);
- Dependency.get(IconLogger.class).onIconVisibility(mSlotBattery, !hidden);
- setVisibility(hidden ? View.GONE : View.VISIBLE);
}
}
@@ -308,6 +305,7 @@
public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
mDrawable.setBatteryLevel(level);
mDrawable.setCharging(pluggedIn);
+ mCharging = pluggedIn;
mLevel = level;
updatePercentText();
setContentDescription(
@@ -337,9 +335,19 @@
}
private void updatePercentText() {
+ if (mBatteryController == null) {
+ return;
+ }
+
if (mBatteryPercentView != null) {
- mBatteryPercentView.setText(
- NumberFormat.getPercentInstance().format(mLevel / 100f));
+ if (mShowPercentMode == MODE_ESTIMATE && !mCharging) {
+ mBatteryController.getEstimatedTimeRemainingString((String estimate) -> {
+ mBatteryPercentView.setText(estimate);
+ });
+ } else {
+ mBatteryPercentView.setText(
+ NumberFormat.getPercentInstance().format(mLevel / 100f));
+ }
}
}
@@ -350,7 +358,7 @@
SHOW_BATTERY_PERCENT, 0, mUser);
if ((mShowPercentAvailable && systemSetting && mShowPercentMode != MODE_OFF)
- || mShowPercentMode == MODE_ON) {
+ || mShowPercentMode == MODE_ON || mShowPercentMode == MODE_ESTIMATE) {
if (!showing) {
mBatteryPercentView = loadPercentView();
if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor);
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 9d81064..ec6ecc6 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -86,7 +86,6 @@
import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.FlashlightController;
import com.android.systemui.statusbar.policy.HotspotController;
-import com.android.systemui.statusbar.policy.IconLogger;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
import com.android.systemui.statusbar.policy.LocationController;
import com.android.systemui.statusbar.policy.NetworkController;
@@ -217,7 +216,6 @@
@Inject Lazy<LeakDetector> mLeakDetector;
@Inject Lazy<LeakReporter> mLeakReporter;
@Inject Lazy<GarbageMonitor> mGarbageMonitor;
- @Inject Lazy<IconLogger> mIconLogger;
@Inject Lazy<TunerService> mTunerService;
@Inject Lazy<StatusBarWindowController> mStatusBarWindowController;
@Inject Lazy<DarkIconDispatcher> mDarkIconDispatcher;
@@ -392,8 +390,6 @@
mProviders.put(PowerUI.WarningsUI.class, mWarningsUI::get);
- mProviders.put(IconLogger.class, mIconLogger::get);
-
mProviders.put(LightBarController.class, mLightBarController::get);
mProviders.put(IWindowManager.class, mIWindowManager::get);
diff --git a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
index f324a05b..ce9c637 100644
--- a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
@@ -46,8 +46,6 @@
import com.android.systemui.statusbar.policy.FlashlightControllerImpl;
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.HotspotControllerImpl;
-import com.android.systemui.statusbar.policy.IconLogger;
-import com.android.systemui.statusbar.policy.IconLoggerImpl;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
import com.android.systemui.statusbar.policy.LocationController;
@@ -133,11 +131,6 @@
/**
*/
@Binds
- public abstract IconLogger provideIconLogger(IconLoggerImpl loggerImpl);
-
- /**
- */
- @Binds
public abstract CastController provideCastController(CastControllerImpl controllerImpl);
/**
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index d0111cb..f66a57b 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -40,6 +40,7 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
import com.android.systemui.statusbar.ScrimView;
+import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotificationData;
@@ -136,8 +137,8 @@
}
public NotificationIconAreaController createNotificationIconAreaController(Context context,
- StatusBar statusBar) {
- return new NotificationIconAreaController(context, statusBar);
+ StatusBar statusBar, StatusBarStateController statusBarStateController) {
+ return new NotificationIconAreaController(context, statusBar, statusBarStateController);
}
public KeyguardIndicationController createKeyguardIndicationController(Context context,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
index b8c69c80..c927677 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
@@ -77,7 +77,6 @@
private final DevicePolicyManager mDevicePolicyManager;
private final float mAnimationTranslationOffset;
private final int mErrorColor;
- private final int mTextColor;
private final float mDialogWidth;
private final DialogViewCallback mCallback;
@@ -92,6 +91,8 @@
protected final Button mNegativeButton;
protected final Button mTryAgainButton;
+ protected final int mTextColor;
+
private Bundle mBundle;
private int mLastState;
@@ -108,6 +109,7 @@
protected abstract boolean shouldAnimateForTransition(int oldState, int newState);
protected abstract int getDelayAfterAuthenticatedDurationMs();
protected abstract boolean shouldGrayAreaDismissDialog();
+ protected abstract void handleClearMessage(boolean requireTryAgain);
private final Runnable mShowAnimationRunnable = new Runnable() {
@Override
@@ -421,20 +423,6 @@
return mLayout;
}
- // Clears the temporary message and shows the help message. If requireTryAgain is true,
- // we will start the authenticating state again.
- private void handleClearMessage(boolean requireTryAgain) {
- if (!requireTryAgain) {
- updateState(STATE_AUTHENTICATING);
- mErrorText.setText(getHintStringResourceId());
- mErrorText.setTextColor(mTextColor);
- mErrorText.setVisibility(View.VISIBLE);
- } else {
- updateState(STATE_IDLE);
- mErrorText.setVisibility(View.INVISIBLE);
- }
- }
-
// Shows an error/help message
private void showTemporaryMessage(String message, boolean requireTryAgain) {
mHandler.removeMessages(MSG_CLEAR_MESSAGE);
@@ -475,11 +463,6 @@
}
public void showTryAgainButton(boolean show) {
- if (show) {
- mTryAgainButton.setVisibility(View.VISIBLE);
- } else {
- mTryAgainButton.setVisibility(View.GONE);
- }
}
public void restoreState(Bundle bundle) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
index 359cb04..9fba44b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
@@ -210,6 +210,22 @@
bundle.putInt(KEY_DIALOG_SIZE, mSize);
}
+
+ @Override
+ protected void handleClearMessage(boolean requireTryAgain) {
+ // Clears the temporary message and shows the help message. If requireTryAgain is true,
+ // we will start the authenticating state again.
+ if (!requireTryAgain) {
+ updateState(STATE_AUTHENTICATING);
+ mErrorText.setText(getHintStringResourceId());
+ mErrorText.setTextColor(mTextColor);
+ mErrorText.setVisibility(View.VISIBLE);
+ } else {
+ updateState(STATE_IDLE);
+ mErrorText.setVisibility(View.INVISIBLE);
+ }
+ }
+
@Override
public void restoreState(Bundle bundle) {
super.restoreState(bundle);
@@ -271,7 +287,11 @@
// of the elements in here.
updateSize(SIZE_BIG);
} else {
- super.showTryAgainButton(show);
+ if (show) {
+ mTryAgainButton.setVisibility(View.VISIBLE);
+ } else {
+ mTryAgainButton.setVisibility(View.GONE);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java
index d63836b..c9b30ba 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java
@@ -32,6 +32,14 @@
DialogViewCallback callback) {
super(context, callback);
}
+
+ @Override
+ protected void handleClearMessage(boolean requireTryAgain) {
+ updateState(STATE_AUTHENTICATING);
+ mErrorText.setText(getHintStringResourceId());
+ mErrorText.setTextColor(mTextColor);
+ }
+
@Override
protected int getHintStringResourceId() {
return R.string.fingerprint_dialog_touch_sensor;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index 1718cff..4ff27b1 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -48,7 +48,7 @@
*
* It does not collect touch events when the bouncer shows up.
*/
-public class FalsingManager implements SensorEventListener {
+public class FalsingManager implements SensorEventListener, StateListener {
private static final String ENFORCE_BOUNCER = "falsing_manager_enforce_bouncer";
private static final int[] CLASSIFIER_SENSORS = new int[] {
@@ -84,8 +84,6 @@
private boolean mShowingAod;
private Runnable mPendingWtf;
- private final StateListener mStateListener = this::setStatusBarState;
-
protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
@@ -108,7 +106,7 @@
UserHandle.USER_ALL);
updateConfiguration();
- Dependency.get(StatusBarStateController.class).addCallback(mStateListener);
+ Dependency.get(StatusBarStateController.class).addCallback(this);
}
public static FalsingManager getInstance(Context context) {
@@ -282,14 +280,15 @@
updateSessionActive();
}
- private void setStatusBarState(int state) {
+ @Override
+ public void onStateChanged(int newState) {
if (FalsingLog.ENABLED) {
FalsingLog.i("setStatusBarState", new StringBuilder()
.append("from=").append(StatusBarState.toShortString(mState))
- .append(" to=").append(StatusBarState.toShortString(state))
+ .append(" to=").append(StatusBarState.toShortString(newState))
.toString());
}
- mState = state;
+ mState = newState;
updateSessionActive();
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
index 4388200..6ed1eba 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
@@ -119,12 +119,13 @@
appName.text = app.applicationName
if (showIcons) {
- dialogBuilder.generateIconsForApp(types).forEach {
+ dialogBuilder.generateIconsForApp(types).forEachIndexed { index, it ->
it.setBounds(0, 0, iconSize, iconSize)
val image = ImageView(context).apply {
imageTintList = ColorStateList.valueOf(iconColor)
setImageDrawable(it)
}
+ image.contentDescription = types[index].getName(context)
icons.addView(image, lp)
}
icons.visibility = View.VISIBLE
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 28285e14..75ab5df 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -141,14 +141,11 @@
private View mStatusSeparator;
private ImageView mRingerModeIcon;
private TextView mRingerModeTextView;
- private BatteryMeterView mBatteryMeterView;
private Clock mClockView;
private DateView mDateView;
private OngoingPrivacyChip mPrivacyChip;
private Space mSpace;
private BatteryMeterView mBatteryRemainingIcon;
- private TextView mBatteryRemainingText;
- private boolean mShowBatteryPercentAndEstimate;
private PrivacyItemController mPrivacyItemController;
/** Counts how many times the long press tooltip has been shown to the user. */
@@ -229,13 +226,6 @@
// Set the correct tint for the status icons so they contrast
mIconManager.setTint(fillColor);
- mShowBatteryPercentAndEstimate = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_battery_percentage_setting_available);
-
- mBatteryMeterView = findViewById(R.id.battery);
- mBatteryMeterView.setPercentShowMode(mShowBatteryPercentAndEstimate
- ? BatteryMeterView.MODE_ON : BatteryMeterView.MODE_OFF);
- mBatteryMeterView.setOnClickListener(this);
mClockView = findViewById(R.id.clock);
mClockView.setOnClickListener(this);
mDateView = findViewById(R.id.date);
@@ -245,13 +235,8 @@
// Tint for the battery icons are handled in setupHost()
mBatteryRemainingIcon = findViewById(R.id.batteryRemainingIcon);
- mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_OFF);
// Don't need to worry about tuner settings for this icon
mBatteryRemainingIcon.setIgnoreTunerUpdates(true);
-
- mBatteryRemainingText = findViewById(R.id.batteryRemainingText);
- mBatteryRemainingText.setTextColor(fillColor);
-
updateShowPercent();
}
@@ -268,10 +253,8 @@
}
private void setChipVisibility(boolean chipVisible) {
- mBatteryMeterView.setVisibility(View.VISIBLE);
if (chipVisible) {
mPrivacyChip.setVisibility(View.VISIBLE);
- if (mHasTopCutout) mBatteryMeterView.setVisibility(View.GONE);
} else {
mPrivacyChip.setVisibility(View.GONE);
}
@@ -339,7 +322,6 @@
// Update color schemes in landscape to use wallpaperTextColor
boolean shouldUseWallpaperTextColor =
newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE;
- mBatteryMeterView.useWallpaperTextColor(shouldUseWallpaperTextColor);
mClockView.useWallpaperTextColor(shouldUseWallpaperTextColor);
}
@@ -415,13 +397,6 @@
.build();
}
- private void updateBatteryRemainingText() {
- if (!mShowBatteryPercentAndEstimate) {
- return;
- }
- mBatteryRemainingText.setText(mBatteryController.getEstimatedTimeRemainingString());
- }
-
public void setExpanded(boolean expanded) {
if (mExpanded == expanded) return;
mExpanded = expanded;
@@ -519,7 +494,6 @@
}
}
mSpace.setLayoutParams(lp);
- // Decide whether to show BatteryMeterView
setChipVisibility(mPrivacyChip.getVisibility() == View.VISIBLE);
return super.onApplyWindowInsets(insets);
}
@@ -546,7 +520,6 @@
mAlarmController.addCallback(this);
mContext.registerReceiver(mRingerReceiver,
new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
- updateBatteryRemainingText();
} else {
mZenController.removeCallback(this);
mAlarmController.removeCallback(this);
@@ -559,9 +532,6 @@
if (v == mClockView) {
mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
AlarmClock.ACTION_SHOW_ALARMS),0);
- } else if (v == mBatteryMeterView) {
- mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
- Intent.ACTION_POWER_USAGE_SUMMARY),0);
} else if (v == mPrivacyChip) {
Handler mUiHandler = new Handler(Looper.getMainLooper());
mUiHandler.post(() -> {
@@ -713,9 +683,6 @@
mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
mHeaderQsPanel.setHost(host, null /* No customization in header */);
- // Use SystemUI context to get battery meter colors, and let it use the default tint (white)
- mBatteryMeterView.setColorsFromContext(mHost.getContext());
- mBatteryMeterView.onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
Rect tintArea = new Rect(0, 0, 0, 0);
int colorForeground = Utils.getColorAttrDefaultColor(getContext(),
@@ -763,22 +730,8 @@
.getIntForUser(getContext().getContentResolver(),
SHOW_BATTERY_PERCENT, 0, ActivityManager.getCurrentUser());
- mShowBatteryPercentAndEstimate = systemSetting;
-
- updateBatteryViews();
- }
-
- private void updateBatteryViews() {
- if (mShowBatteryPercentAndEstimate) {
- mBatteryMeterView.setPercentShowMode(BatteryMeterView.MODE_ON);
- mBatteryRemainingIcon.setVisibility(View.VISIBLE);
- mBatteryRemainingText.setVisibility(View.VISIBLE);
- updateBatteryRemainingText();
- } else {
- mBatteryMeterView.setPercentShowMode(BatteryMeterView.MODE_OFF);
- mBatteryRemainingIcon.setVisibility(View.GONE);
- mBatteryRemainingText.setVisibility(View.GONE);
- }
+ mBatteryRemainingIcon.setPercentShowMode(systemSetting
+ ? BatteryMeterView.MODE_ESTIMATE : BatteryMeterView.MODE_ON);
}
private final class PercentSettingObserver extends ContentObserver {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 91b34fc..bd9ca1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -55,7 +55,7 @@
* overflow icons that don't fit into the regular list anymore.
*/
public class NotificationShelf extends ActivatableNotificationView implements
- View.OnLayoutChangeListener {
+ View.OnLayoutChangeListener, StateListener {
private static final boolean USE_ANIMATIONS_WHEN_OPENING =
SystemProperties.getBoolean("debug.icon_opening_animations", true);
@@ -95,8 +95,6 @@
private int mCutoutHeight;
private int mGapHeight;
- private final StateListener mStateListener = this::setStatusBarState;
-
public NotificationShelf(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -121,13 +119,13 @@
protected void onAttachedToWindow() {
super.onAttachedToWindow();
Dependency.get(StatusBarStateController.class)
- .addCallback(mStateListener, StatusBarStateController.RANK_SHELF);
+ .addCallback(this, StatusBarStateController.RANK_SHELF);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
+ Dependency.get(StatusBarStateController.class).removeCallback(this);
}
public void bind(AmbientState ambientState, NotificationStackScrollLayout hostLayout) {
@@ -174,6 +172,24 @@
updateInteractiveness();
}
+ /**
+ * Alpha animation with translation played when this view is visible on AOD.
+ */
+ public void fadeInTranslating() {
+ mShelfIcons.setTranslationY(-mShelfAppearTranslation);
+ mShelfIcons.setAlpha(0);
+ mShelfIcons.animate()
+ .setInterpolator(Interpolators.DECELERATE_QUINT)
+ .translationY(0)
+ .setDuration(SHELF_IN_TRANSLATION_DURATION)
+ .start();
+ mShelfIcons.animate()
+ .alpha(1)
+ .setInterpolator(Interpolators.LINEAR)
+ .setDuration(SHELF_IN_TRANSLATION_DURATION)
+ .start();
+ }
+
@Override
protected View getContentView() {
return mShelfIcons;
@@ -225,7 +241,7 @@
}
viewState.hasItemsInStableShelf = lastViewState.inShelf;
viewState.hidden = !mAmbientState.isShadeExpanded()
- || mAmbientState.isQsCustomizerShowing() || mAmbientState.isFullyDark();
+ || mAmbientState.isQsCustomizerShowing();
viewState.maxShelfEnd = maxShelfEnd;
} else {
viewState.hidden = true;
@@ -420,7 +436,7 @@
float maxTop = row.getTranslationY();
StatusBarIconView icon = row.getEntry().expandedIcon;
float shelfIconPosition = getTranslationY() + icon.getTop() + icon.getTranslationY();
- if (shelfIconPosition < maxTop) {
+ if (shelfIconPosition < maxTop && !mAmbientState.isDark()) {
int top = (int) (maxTop - shelfIconPosition);
Rect clipRect = new Rect(0, top, icon.getWidth(), Math.max(top, icon.getHeight()));
icon.setClipBounds(clipRect);
@@ -431,7 +447,7 @@
private void updateContinuousClipping(final ExpandableNotificationRow row) {
StatusBarIconView icon = row.getEntry().expandedIcon;
- boolean needsContinuousClipping = ViewState.isAnimatingY(icon);
+ boolean needsContinuousClipping = ViewState.isAnimatingY(icon) && !mAmbientState.isDark();
boolean isContinuousClipping = icon.getTag(TAG_CONTINUOUS_CLIPPING) != null;
if (needsContinuousClipping && !isContinuousClipping) {
final ViewTreeObserver observer = icon.getViewTreeObserver();
@@ -622,7 +638,9 @@
iconState.translateContent = false;
}
float transitionAmount;
- if (isLastChild || !USE_ANIMATIONS_WHEN_OPENING || iconState.useFullTransitionAmount
+ if (mAmbientState.isDarkAtAll() && !row.isInShelf()) {
+ transitionAmount = mAmbientState.isFullyDark() ? 1 : 0;
+ } else if (isLastChild || !USE_ANIMATIONS_WHEN_OPENING || iconState.useFullTransitionAmount
|| iconState.useLinearTransitionAmount) {
transitionAmount = iconTransitionAmount;
} else {
@@ -860,8 +878,9 @@
mCollapsedIcons.addOnLayoutChangeListener(this);
}
- private void setStatusBarState(int statusBarState) {
- mStatusBarState = statusBarState;
+ @Override
+ public void onStateChanged(int newState) {
+ mStatusBarState = newState;
updateInteractiveness();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 3c13354..19ed13e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -206,6 +206,10 @@
mIconScale = SYSTEM_ICON_SCALE;
}
+ public float getIconScaleFullyDark() {
+ return (float) mStatusBarIconDrawingSizeDark / mStatusBarIconDrawingSize;
+ }
+
public float getIconScale() {
return mIconScale;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
index 087b655..54bce1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
@@ -331,7 +331,8 @@
*
* @param newState the new {@link StatusBarState}
*/
- public void onStateChanged(int newState);
+ default void onStateChanged(int newState) {
+ }
/**
* Callback to be notified when Dozing changes. Dozing is stored separately from state.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 80db6c1..2d1f989 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -113,6 +113,7 @@
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationSnooze;
import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
+import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
@@ -430,7 +431,7 @@
private int mHeadsUpInset;
private HeadsUpAppearanceController mHeadsUpAppearanceController;
private NotificationIconAreaController mIconAreaController;
- private float mVerticalPanelTranslation;
+ private float mHorizontalPanelTranslation;
private final NotificationLockscreenUserManager mLockscreenUserManager =
Dependency.get(NotificationLockscreenUserManager.class);
protected final NotificationGutsManager mGutsManager =
@@ -458,6 +459,10 @@
private final NotificationGutsManager
mNotificationGutsManager = Dependency.get(NotificationGutsManager.class);
+ /**
+ * If the {@link NotificationShelf} should be visible when dark.
+ */
+ private boolean mShowDarkShelf;
@Inject
public NotificationStackScrollLayout(
@@ -1196,7 +1201,7 @@
mIsClipped = clipped;
}
- if (mPulsing) {
+ if (mPulsing || mAmbientState.isFullyDark() && mShowDarkShelf) {
setClipBounds(null);
} else if (mAmbientState.isDarkAtAll()) {
setClipBounds(mBackgroundAnimationRect);
@@ -4361,6 +4366,9 @@
if (mAmbientState.isDark() == dark) {
return;
}
+ if (!dark) {
+ mShowDarkShelf = false;
+ }
mAmbientState.setDark(dark);
if (animate && mAnimationsEnabled) {
mDarkNeedsAnimation = true;
@@ -4377,12 +4385,12 @@
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updatePanelTranslation() {
- setTranslationX(mVerticalPanelTranslation + mAntiBurnInOffsetX * mInterpolatedDarkAmount);
+ setTranslationX(mHorizontalPanelTranslation + mAntiBurnInOffsetX * mInterpolatedDarkAmount);
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void setVerticalPanelTranslation(float verticalPanelTranslation) {
- mVerticalPanelTranslation = verticalPanelTranslation;
+ public void setHorizontalPanelTranslation(float verticalPanelTranslation) {
+ mHorizontalPanelTranslation = verticalPanelTranslation;
updatePanelTranslation();
}
@@ -4422,9 +4430,9 @@
boolean nowDarkAtAll = mAmbientState.isDarkAtAll();
if (nowFullyDark != wasFullyDark) {
updateContentHeight();
- }
- if (mIconAreaController != null) {
- mIconAreaController.setDarkAmount(interpolatedDarkAmount);
+ if (nowFullyDark && mShowDarkShelf) {
+ updateDarkShelfVisibility();
+ }
}
if (!wasDarkAtAll && nowDarkAtAll) {
resetExposedMenuView(true /* animate */, true /* animate */);
@@ -4435,6 +4443,22 @@
requestChildrenUpdate();
}
+ /**
+ * If the shelf should be visible when the device is in ambient mode (dozing.)
+ */
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ public void setShowDarkShelf(boolean showDarkShelf) {
+ mShowDarkShelf = showDarkShelf;
+ }
+
+ private void updateDarkShelfVisibility() {
+ DozeParameters dozeParameters = DozeParameters.getInstance(mContext);
+ if (dozeParameters.shouldControlScreenOff()) {
+ mShelf.fadeInTranslating();
+ }
+ updateClipping();
+ }
+
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void notifyDarkAnimationStart(boolean dark) {
// We only swap the scaling factor if we're fully dark or fully awake to avoid
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index f907b65..35763dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -215,7 +215,10 @@
}
}
- if (mStatusBarStateController.isDozing()) {
+ // The shelf will be hidden when dozing with a custom clock, we must show notification
+ // icons in this occasion.
+ if (mStatusBarStateController.isDozing()
+ && mStatusBarComponent.getPanel().hasCustomClock()) {
state |= DISABLE_CLOCK | DISABLE_SYSTEM_INFO;
state &= ~DISABLE_NOTIFICATION_ICONS;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 0fada66..7f75223 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -58,7 +58,7 @@
*/
public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
ViewTreeObserver.OnComputeInternalInsetsListener, VisualStabilityManager.Callback,
- OnHeadsUpChangedListener, ConfigurationController.ConfigurationListener {
+ OnHeadsUpChangedListener, ConfigurationController.ConfigurationListener, StateListener {
private static final String TAG = "HeadsUpManagerPhone";
private final View mStatusBarWindowView;
@@ -83,7 +83,6 @@
private boolean mIsObserving;
private int mStatusBarState;
- private final StateListener mStateListener = this::setStatusBarState;
private AnimationStateHandler mAnimationStateHandler;
private BubbleController mBubbleController = Dependency.get(BubbleController.class);
@@ -129,7 +128,7 @@
updateTouchableRegionListener();
}
});
- Dependency.get(StatusBarStateController.class).addCallback(mStateListener);
+ Dependency.get(StatusBarStateController.class).addCallback(this);
mBubbleController.setBubbleStateChangeListener((hasBubbles) -> {
if (!hasBubbles) {
mBubbleGoingAway = true;
@@ -143,7 +142,7 @@
}
public void destroy() {
- Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
+ Dependency.get(StatusBarStateController.class).removeCallback(this);
}
private void initResources() {
@@ -225,11 +224,9 @@
}
}
- /**
- * Set the current state of the statusbar.
- */
- private void setStatusBarState(int statusBarState) {
- mStatusBarState = statusBarState;
+ @Override
+ public void onStateChanged(int newState) {
+ mStatusBarState = newState;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationAssistantAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationAssistantAction.java
new file mode 100644
index 0000000..ebcd39b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationAssistantAction.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.annotation.NonNull;
+import android.os.Bundle;
+import android.view.MotionEvent;
+
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.recents.OverviewProxyService;
+
+/**
+ * Assistant is triggered with this action
+ */
+public class NavigationAssistantAction extends NavigationGestureAction {
+ private static final String TAG = "NavigationAssistantActions";
+
+ private final AssistManager mAssistManager;
+
+ public NavigationAssistantAction(@NonNull NavigationBarView navigationBarView,
+ @NonNull OverviewProxyService service, AssistManager assistManager) {
+ super(navigationBarView, service);
+ mAssistManager = assistManager;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+
+ @Override
+ public void onGestureStart(MotionEvent event) {
+ mAssistManager.startAssist(new Bundle());
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
index 9c8b1b1..93605ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
@@ -67,7 +67,7 @@
@Override
public boolean isEnabled() {
- return !getGlobalBoolean(NavigationPrototypeController.NAVBAR_EXPERIMENTS_DISABLED);
+ return true;
}
@Override
@@ -102,8 +102,7 @@
}
private boolean shouldExecuteBackOnUp() {
- return !getGlobalBoolean(NavigationPrototypeController.NAVBAR_EXPERIMENTS_DISABLED)
- && getGlobalBoolean(BACK_AFTER_END_PROP);
+ return getGlobalBoolean(BACK_AFTER_END_PROP);
}
private void sendEvent(int action, int code) {
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 6d97d67..d3c6a1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -269,7 +269,7 @@
mIsOnDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
}
- mNavigationBarView.setComponents(mStatusBar.getPanel());
+ mNavigationBarView.setComponents(mStatusBar.getPanel(), mAssistManager);
mNavigationBarView.setDisabledFlags(mDisabledFlags1);
mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);
mNavigationBarView.setOnTouchListener(this::onNavigationTouch);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 2fc7b78..8bf1c58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -69,6 +69,7 @@
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.assist.AssistManager;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.statusbar.phone.NavGesture;
import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
@@ -156,6 +157,7 @@
private QuickStepAction mQuickStepAction;
private NavigationBackAction mBackAction;
private QuickSwitchAction mQuickSwitchAction;
+ private NavigationAssistantAction mAssistantAction;
/**
* Helper that is responsible for showing the right toast when a disallowed activity operation
@@ -366,8 +368,12 @@
return mBarTransitions.getLightTransitionsController();
}
- public void setComponents(NotificationPanelView panel) {
+ public void setComponents(NotificationPanelView panel, AssistManager assistManager) {
mPanelView = panel;
+ if (mAssistantAction == null) {
+ mAssistantAction = new NavigationAssistantAction(this, mOverviewProxyService,
+ assistManager);
+ }
if (mGestureHelper instanceof QuickStepController) {
((QuickStepController) mGestureHelper).setComponents(this);
updateNavigationGestures();
@@ -398,6 +404,10 @@
return mBackAction;
case NavigationPrototypeController.ACTION_QUICKSWITCH:
return mQuickSwitchAction;
+ case NavigationPrototypeController.ACTION_ASSISTANT:
+ return mAssistantAction;
+ case NavigationPrototypeController.ACTION_NOTHING:
+ return null;
default:
return defaultAction;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java
index 8c57fc3..a5d9382 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java
@@ -24,6 +24,7 @@
import android.annotation.NonNull;
import android.content.Context;
import android.graphics.Canvas;
+import android.provider.Settings;
import android.view.MotionEvent;
import com.android.systemui.recents.OverviewProxyService;
@@ -32,6 +33,9 @@
* A gesture action that would be triggered and reassigned by {@link QuickStepController}
*/
public abstract class NavigationGestureAction {
+ private static final String ENABLE_TASK_STABILIZER_FLAG = "ENABLE_TASK_STABILIZER";
+
+ static private boolean sLastTaskStabilizationFlag;
protected final NavigationBarView mNavigationBarView;
protected final OverviewProxyService mProxySender;
@@ -45,6 +49,9 @@
@NonNull OverviewProxyService service) {
mNavigationBarView = navigationBarView;
mProxySender = service;
+ sLastTaskStabilizationFlag = Settings.Global.getInt(
+ mNavigationBarView.getContext().getContentResolver(),
+ ENABLE_TASK_STABILIZER_FLAG, 0) != 0;
}
/**
@@ -74,6 +81,15 @@
*/
public void startGesture(MotionEvent event) {
mIsActive = true;
+
+ // Tell launcher that this action requires a stable task list or not
+ boolean flag = requiresStableTaskList();
+ if (flag != sLastTaskStabilizationFlag) {
+ Settings.Global.putInt(mNavigationBarView.getContext().getContentResolver(),
+ ENABLE_TASK_STABILIZER_FLAG, flag ? 1 : 0);
+ sLastTaskStabilizationFlag = flag;
+ }
+
onGestureStart(event);
}
@@ -146,6 +162,13 @@
*/
public abstract boolean isEnabled();
+ /**
+ * @return action requires a stable task list from launcher
+ */
+ protected boolean requiresStableTaskList() {
+ return false;
+ }
+
protected void onDarkIntensityChange(float intensity) {
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
index fb6254b..a09e585 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
@@ -22,7 +22,6 @@
import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -36,18 +35,20 @@
private static final String HIDE_BACK_BUTTON_SETTING = "quickstepcontroller_hideback";
private static final String HIDE_HOME_BUTTON_SETTING = "quickstepcontroller_hidehome";
- static final String NAVBAR_EXPERIMENTS_DISABLED = "navbarexperiments_disabled";
private final String GESTURE_MATCH_SETTING = "quickstepcontroller_gesture_match_map";
public static final String NAV_COLOR_ADAPT_ENABLE_SETTING = "navbar_color_adapt_enable";
@Retention(RetentionPolicy.SOURCE)
- @IntDef({ACTION_DEFAULT, ACTION_QUICKSTEP, ACTION_QUICKSCRUB, ACTION_BACK})
+ @IntDef({ACTION_DEFAULT, ACTION_QUICKSTEP, ACTION_QUICKSCRUB, ACTION_BACK,
+ ACTION_QUICKSWITCH, ACTION_NOTHING, ACTION_ASSISTANT})
@interface GestureAction {}
static final int ACTION_DEFAULT = 0;
static final int ACTION_QUICKSTEP = 1;
static final int ACTION_QUICKSCRUB = 2;
static final int ACTION_BACK = 3;
static final int ACTION_QUICKSWITCH = 4;
+ static final int ACTION_NOTHING = 5;
+ static final int ACTION_ASSISTANT = 6;
private OnPrototypeChangedListener mListener;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 1fb5484..077fcda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -23,6 +23,7 @@
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -36,13 +37,15 @@
* A controller for the space in the status bar to the left of the system icons. This area is
* normally reserved for notifications.
*/
-public class NotificationIconAreaController implements DarkReceiver {
+public class NotificationIconAreaController implements DarkReceiver,
+ StatusBarStateController.StateListener {
public static final String LOW_PRIORITY = "low_priority";
private final ContrastColorUtil mContrastColorUtil;
private final NotificationEntryManager mEntryManager;
private final Runnable mUpdateStatusBarIcons = this::updateStatusBarIcons;
+ private final StatusBarStateController mStatusBarStateController;
private final TunerService.Tunable mTunable = new TunerService.Tunable() {
@Override
public void onTuningChanged(String key, String newValue) {
@@ -86,11 +89,14 @@
private final ViewClippingUtil.ClippingParameters mClippingParameters =
view -> view instanceof StatusBarWindowView;
- public NotificationIconAreaController(Context context, StatusBar statusBar) {
+ public NotificationIconAreaController(Context context, StatusBar statusBar,
+ StatusBarStateController statusBarStateController) {
mStatusBar = statusBar;
mContrastColorUtil = ContrastColorUtil.getInstance(context);
mContext = context;
mEntryManager = Dependency.get(NotificationEntryManager.class);
+ mStatusBarStateController = statusBarStateController;
+ mStatusBarStateController.addCallback(this);
Dependency.get(TunerService.class).addTunable(mTunable, LOW_PRIORITY);
@@ -373,24 +379,6 @@
v.setDecorColor(mIconTint);
}
- /**
- * Dark amount, from 0 to 1, representing being awake or in AOD.
- */
- public void setDarkAmount(float darkAmount) {
- mDarkAmount = darkAmount;
- if (darkAmount == 0 || darkAmount == 1) {
- ViewClippingUtil.setClippingDeactivated(mNotificationIcons, darkAmount != 0,
- mClippingParameters);
- }
- dozeTimeTick();
-
- boolean fullyDark = darkAmount == 1f;
- if (mFullyDark != fullyDark) {
- mFullyDark = fullyDark;
- updateShelfIcons();
- }
- }
-
public void setDark(boolean dark) {
mNotificationIcons.setDark(dark, false, 0);
mShelfIcons.setDark(dark, false, 0);
@@ -408,10 +396,45 @@
* Moves icons whenever the device wakes up in AOD, to avoid burn in.
*/
public void dozeTimeTick() {
+ if (mNotificationIcons.getVisibility() != View.VISIBLE) {
+ return;
+ }
+
+ if (mDarkAmount == 0 && !mStatusBarStateController.isDozing()) {
+ mNotificationIcons.setTranslationX(0);
+ mNotificationIcons.setTranslationY(0);
+ return;
+ }
+
int yOffset = (mKeyguardStatusBarHeight - getHeight()) / 2;
int translationX = getBurnInOffset(mBurnInOffset, true /* xAxis */);
int translationY = getBurnInOffset(mBurnInOffset, false /* xAxis */) + yOffset;
- mNotificationIcons.setTranslationX(translationX * mDarkAmount);
- mNotificationIcons.setTranslationY(translationY * mDarkAmount);
+ mNotificationIcons.setTranslationX(translationX);
+ mNotificationIcons.setTranslationY(translationY);
+ }
+
+ @Override
+ public void onDozingChanged(boolean isDozing) {
+ dozeTimeTick();
+ }
+
+ @Override
+ public void onDozeAmountChanged(float linear, float eased) {
+ boolean wasOrIsAwake = mDarkAmount == 0 || linear == 0;
+ boolean wasOrIsDozing = mDarkAmount == 1 || linear == 1;
+ mDarkAmount = linear;
+ if (wasOrIsAwake) {
+ ViewClippingUtil.setClippingDeactivated(mNotificationIcons, mDarkAmount != 0,
+ mClippingParameters);
+ }
+ if (wasOrIsAwake || wasOrIsDozing) {
+ dozeTimeTick();
+ }
+
+ boolean fullyDark = mDarkAmount == 1f;
+ if (mFullyDark != fullyDark) {
+ mFullyDark = fullyDark;
+ updateShelfIcons();
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 964b2210..009afca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -128,6 +128,7 @@
}
}.setDuration(CONTENT_FADE_DURATION);
+ private static final int MAX_VISIBLE_ICONS_WHEN_DARK = 5;
public static final int MAX_STATIC_ICONS = 4;
private static final int MAX_DOTS = 1;
@@ -371,7 +372,8 @@
float translationX = getActualPaddingStart();
int firstOverflowIndex = -1;
int childCount = getChildCount();
- int maxVisibleIcons = mIsStaticLayout ? MAX_STATIC_ICONS : childCount;
+ int maxVisibleIcons = mDark ? MAX_VISIBLE_ICONS_WHEN_DARK :
+ mIsStaticLayout ? MAX_STATIC_ICONS : childCount;
float layoutEnd = getLayoutEnd();
float overflowStart = getMaxOverflowStart();
mVisualOverflowStart = 0;
@@ -387,6 +389,9 @@
boolean forceOverflow = mSpeedBumpIndex != -1 && i >= mSpeedBumpIndex
&& iconState.iconAppearAmount > 0.0f || i >= maxVisibleIcons;
boolean noOverflowAfter = i == childCount - 1;
+ float drawingScale = mDark && view instanceof StatusBarIconView
+ ? ((StatusBarIconView) view).getIconScaleFullyDark()
+ : 1f;
if (mOpenedAmount != 0.0f) {
noOverflowAfter = noOverflowAfter && !hasAmbient && !forceOverflow;
}
@@ -402,7 +407,7 @@
mVisualOverflowStart = Math.min(translationX, mVisualOverflowStart);
}
}
- translationX += iconState.iconAppearAmount * view.getWidth();
+ translationX += iconState.iconAppearAmount * view.getWidth() * drawingScale;
}
mNumDots = 0;
if (firstOverflowIndex != -1) {
@@ -432,6 +437,32 @@
mFirstVisibleIconState = mIconStates.get(getChildAt(0));
}
+ boolean center = mDark;
+ if (center && translationX < getLayoutEnd()) {
+ float initialTranslation =
+ mFirstVisibleIconState == null ? 0 : mFirstVisibleIconState.xTranslation;
+
+ float contentWidth = 0;
+ if (mLastVisibleIconState != null) {
+ contentWidth = mLastVisibleIconState.xTranslation + mIconSize;
+ contentWidth = Math.min(getWidth(), contentWidth) - initialTranslation;
+ }
+ float availableSpace = getLayoutEnd() - getActualPaddingStart();
+ float delta = (availableSpace - contentWidth) / 2;
+
+ if (firstOverflowIndex != -1) {
+ // If we have an overflow, only count those half for centering because the dots
+ // don't have a lot of visual weight.
+ float deltaIgnoringOverflow = (getLayoutEnd() - mVisualOverflowStart) / 2;
+ delta = (deltaIgnoringOverflow + delta) / 2;
+ }
+ for (int i = 0; i < childCount; i++) {
+ View view = getChildAt(i);
+ IconState iconState = mIconStates.get(view);
+ iconState.xTranslation += delta;
+ }
+ }
+
if (isLayoutRtl()) {
for (int i = 0; i < childCount; i++) {
View view = getChildAt(i);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 75adf50..31310f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -50,6 +50,7 @@
import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.keyguard.KeyguardClockSwitch;
@@ -142,7 +143,8 @@
private KeyguardStatusBarView mKeyguardStatusBar;
private QS mQs;
private FrameLayout mQsFrame;
- private KeyguardStatusView mKeyguardStatusView;
+ @VisibleForTesting
+ protected KeyguardStatusView mKeyguardStatusView;
private View mQsNavbarScrim;
protected NotificationsQuickSettingsContainer mNotificationContainerParent;
protected NotificationStackScrollLayout mNotificationStackScroller;
@@ -327,6 +329,13 @@
mDisplayId = context.getDisplayId();
}
+ /**
+ * Returns if there's a custom clock being presented.
+ */
+ public boolean hasCustomClock() {
+ return mKeyguardStatusView.hasCustomClock();
+ }
+
private void setStatusBar(StatusBar bar) {
mStatusBar = bar;
mKeyguardBottomArea.setStatusBar(mStatusBar);
@@ -1233,7 +1242,7 @@
updateDozingVisibilities(false /* animate */);
}
- resetVerticalPanelPosition();
+ resetHorizontalPanelPosition();
updateQsState();
}
@@ -2043,7 +2052,7 @@
super.onConfigurationChanged(newConfig);
mAffordanceHelper.onConfigurationChanged();
if (newConfig.orientation != mLastOrientation) {
- resetVerticalPanelPosition();
+ resetHorizontalPanelPosition();
}
mLastOrientation = newConfig.orientation;
}
@@ -2529,7 +2538,7 @@
@Override
protected void onClosingFinished() {
super.onClosingFinished();
- resetVerticalPanelPosition();
+ resetHorizontalPanelPosition();
setClosingWithAlphaFadeout(false);
}
@@ -2546,7 +2555,7 @@
*/
protected void updateVerticalPanelPosition(float x) {
if (mNotificationStackScroller.getWidth() * 1.75f > getWidth()) {
- resetVerticalPanelPosition();
+ resetHorizontalPanelPosition();
return;
}
float leftMost = mPositionMinSideMargin + mNotificationStackScroller.getWidth() / 2;
@@ -2556,16 +2565,17 @@
x = getWidth() / 2;
}
x = Math.min(rightMost, Math.max(leftMost, x));
- setVerticalPanelTranslation(x -
- (mNotificationStackScroller.getLeft() + mNotificationStackScroller.getWidth() / 2));
+ float center =
+ mNotificationStackScroller.getLeft() + mNotificationStackScroller.getWidth() / 2;
+ setHorizontalPanelTranslation(x - center);
}
- private void resetVerticalPanelPosition() {
- setVerticalPanelTranslation(0f);
+ private void resetHorizontalPanelPosition() {
+ setHorizontalPanelTranslation(0f);
}
- protected void setVerticalPanelTranslation(float translation) {
- mNotificationStackScroller.setVerticalPanelTranslation(translation);
+ protected void setHorizontalPanelTranslation(float translation) {
+ mNotificationStackScroller.setHorizontalPanelTranslation(translation);
mQsFrame.setTranslationX(translation);
int size = mVerticalTranslationListener.size();
for (int i = 0; i < size; i++) {
@@ -2773,6 +2783,9 @@
if (dozing == mDozing) return;
mDozing = dozing;
mNotificationStackScroller.setDark(mDozing, animate, wakeUpTouchLocation);
+ if (mDozing) {
+ mNotificationStackScroller.setShowDarkShelf(!hasCustomClock());
+ }
if (mBarState == StatusBarState.KEYGUARD
|| mBarState == StatusBarState.SHADE_LOCKED) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 021b430..f17145d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -142,8 +142,8 @@
private boolean mIgnoreXTouchSlop;
private boolean mExpandLatencyTracking;
protected final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
- protected final StatusBarStateController
- mStatusBarStateController = Dependency.get(StatusBarStateController.class);
+ protected final StatusBarStateController mStatusBarStateController =
+ Dependency.get(StatusBarStateController.class);
protected void onExpandingFinished() {
mBar.onExpandingFinished();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepAction.java
index b18b79e..1999f9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepAction.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepAction.java
@@ -47,6 +47,10 @@
return mNavigationBarView.isQuickStepSwipeUpEnabled();
}
+ protected boolean requiresStableTaskList() {
+ return true;
+ }
+
@Override
public void onGestureStart(MotionEvent event) {
try {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index fb3c4aa..72519ba3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -219,6 +219,14 @@
public void prepare(ScrimState previousState) {
}
+ /**
+ * Check if lockscreen wallpaper or music album art exists.
+ * @return true if lockscreen wallpaper or music album art exists.
+ */
+ public boolean hasBackdrop() {
+ return mHasBackdrop;
+ }
+
public int getIndex() {
return mIndex;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 6f877ba..3f93192 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -70,6 +70,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -98,6 +99,7 @@
import android.service.notification.StatusBarNotification;
import android.util.DisplayMetrics;
import android.util.EventLog;
+import android.util.FeatureFlagUtils;
import android.util.Log;
import android.util.Slog;
import android.view.Display;
@@ -478,8 +480,13 @@
WallpaperInfo info = wallpaperManager.getWallpaperInfo(UserHandle.USER_CURRENT);
final boolean deviceSupportsAodWallpaper = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_dozeSupportsAodWallpaper);
+ final boolean aodImageWallpaperEnabled = FeatureFlagUtils.isEnabled(mContext,
+ FeatureFlagUtils.AOD_IMAGEWALLPAPER_ENABLED);
+ updateAodMaskVisibility(deviceSupportsAodWallpaper && aodImageWallpaperEnabled);
+ // If WallpaperInfo is null, it must be ImageWallpaper.
final boolean supportsAmbientMode = deviceSupportsAodWallpaper
- && info != null && info.supportsAmbientMode();
+ && (info == null && aodImageWallpaperEnabled
+ || info != null && info.supportsAmbientMode());
mStatusBarWindowController.setWallpaperSupportsAmbientMode(supportsAmbientMode);
mScrimController.setWallpaperSupportsAmbientMode(supportsAmbientMode);
@@ -581,6 +588,7 @@
protected NotificationPresenter mPresenter;
private NotificationActivityStarter mNotificationActivityStarter;
private boolean mPulsing;
+ private ContentObserver mFeatureFlagObserver;
@Override
public void onActiveStateChanged(int code, int uid, String packageName, boolean active) {
@@ -697,6 +705,9 @@
mContext.registerReceiverAsUser(mWallpaperChangedReceiver, UserHandle.ALL,
wallpaperChangedFilter, null /* broadcastPermission */, null /* scheduler */);
mWallpaperChangedReceiver.onReceive(mContext, null);
+ mFeatureFlagObserver = new FeatureFlagObserver(
+ FeatureFlagUtils.AOD_IMAGEWALLPAPER_ENABLED /* feature */,
+ () -> mWallpaperChangedReceiver.onReceive(mContext, null) /* callback */);
// Set up the initial notification state. This needs to happen before CommandQueue.disable()
setUpPresenter();
@@ -789,7 +800,7 @@
mNotificationLogger.setUpWithContainer(notifListContainer);
mNotificationIconAreaController = SystemUIFactory.getInstance()
- .createNotificationIconAreaController(context, this);
+ .createNotificationIconAreaController(context, this, mStatusBarStateController);
inflateShelf();
mNotificationIconAreaController.setupShelf(mNotificationShelf);
@@ -4415,4 +4426,33 @@
public @TransitionMode int getStatusBarMode() {
return mStatusBarMode;
}
+
+ private void updateAodMaskVisibility(boolean supportsAodWallpaper) {
+ View mask = mStatusBarWindow.findViewById(R.id.aod_mask);
+ if (mask != null) {
+ mask.setVisibility(supportsAodWallpaper ? View.VISIBLE : View.INVISIBLE);
+ }
+ }
+
+ private final class FeatureFlagObserver extends ContentObserver {
+ private final Runnable mCallback;
+
+ FeatureFlagObserver(String feature, Runnable callback) {
+ this(null, feature, callback);
+ }
+
+ private FeatureFlagObserver(Handler handler, String feature, Runnable callback) {
+ super(handler);
+ mCallback = callback;
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(feature), false, this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ if (mCallback != null) {
+ mStatusBarWindow.post(mCallback);
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index db7589d..f846036 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -36,7 +36,6 @@
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-import com.android.systemui.statusbar.policy.IconLogger;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -61,7 +60,6 @@
private final ArrayList<IconManager> mIconGroups = new ArrayList<>();
private final ArraySet<String> mIconBlacklist = new ArraySet<>();
- private final IconLogger mIconLogger = Dependency.get(IconLogger.class);
// Points to light or dark context depending on the... context?
private Context mContext;
@@ -147,7 +145,6 @@
int viewIndex = getViewIndex(index, holder.getTag());
boolean blocked = mIconBlacklist.contains(slot);
- mIconLogger.onIconVisibility(getSlotName(index), holder.isVisible());
mIconGroups.forEach(l -> l.onIconAdded(viewIndex, slot, blocked, holder));
}
@@ -281,8 +278,6 @@
return;
}
- mIconLogger.onIconHidden(slotName);
-
int slotIndex = getSlotIndex(slotName);
List<StatusBarIconHolder> iconsToRemove = slot.getHolderListInViewOrder();
for (StatusBarIconHolder holder : iconsToRemove) {
@@ -297,7 +292,6 @@
if (getIcon(index, tag) == null) {
return;
}
- mIconLogger.onIconHidden(getSlotName(index));
super.removeIcon(index, tag);
int viewIndex = getViewIndex(index, 0);
mIconGroups.forEach(l -> l.onRemoveIcon(viewIndex));
@@ -305,7 +299,6 @@
private void handleSet(int index, StatusBarIconHolder holder) {
int viewIndex = getViewIndex(index, holder.getTag());
- mIconLogger.onIconVisibility(getSlotName(index), holder.isVisible());
mIconGroups.forEach(l -> l.onSetIconHolder(viewIndex, holder));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 3ddfc0c..8d58410 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -53,7 +53,8 @@
/**
*/
@Singleton
-public class StatusBarRemoteInputCallback implements Callback, Callbacks {
+public class StatusBarRemoteInputCallback implements Callback, Callbacks,
+ StatusBarStateController.StateListener {
private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
private final StatusBarStateController mStatusBarStateController
@@ -63,7 +64,6 @@
private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
private final Context mContext;
private View mPendingWorkRemoteInputView;
- private final StatusBarStateController.StateListener mStateListener = this::setStatusBarState;
private View mPendingRemoteInputView;
private final ShadeController mShadeController = Dependency.get(ShadeController.class);
private KeyguardManager mKeyguardManager;
@@ -78,13 +78,14 @@
mContext = context;
mContext.registerReceiverAsUser(mChallengeReceiver, UserHandle.ALL,
new IntentFilter(ACTION_DEVICE_LOCKED_CHANGED), null, null);
- mStatusBarStateController.addCallback(mStateListener);
+ mStatusBarStateController.addCallback(this);
mKeyguardManager = context.getSystemService(KeyguardManager.class);
mCommandQueue = getComponent(context, CommandQueue.class);
mCommandQueue.addCallback(this);
}
- private void setStatusBarState(int state) {
+ @Override
+ public void onStateChanged(int state) {
if (state == StatusBarState.SHADE && mStatusBarStateController.leaveOpenOnKeyguardHide()) {
if (!mStatusBarStateController.isKeyguardRequested()) {
if (mPendingRemoteInputView != null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index f65f826..5e94152 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -48,18 +48,36 @@
}
/**
- * A listener that will be notified whenever a change in battery level or power save mode
- * has occurred.
+ * A listener that will be notified whenever a change in battery level or power save mode has
+ * occurred.
*/
interface BatteryStateChangeCallback {
- default void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {}
- default void onPowerSaveChanged(boolean isPowerSave) {}
+
+ default void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+ }
+
+ default void onPowerSaveChanged(boolean isPowerSave) {
+ }
}
/**
- * If available, get the estimated battery time remaining as a string
+ * If available, get the estimated battery time remaining as a string.
+ *
+ * @param completion A lambda that will be called with the result of fetching the estimate. The
+ * first time this method is called may need to be dispatched to a background thread. The
+ * completion is called on the main thread
*/
- default String getEstimatedTimeRemainingString() {
- return null;
+ default void getEstimatedTimeRemainingString(EstimateFetchCompletion completion) {}
+
+ /**
+ * Callback called when the estimated time remaining text is fetched.
+ */
+ public interface EstimateFetchCompletion {
+
+ /**
+ * The callback
+ * @param estimate the estimate
+ */
+ void onBatteryRemainingEstimateRetrieved(String estimate);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index 6190c8f..af3c96f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -27,9 +27,12 @@
import android.os.PowerSaveState;
import android.util.Log;
+import androidx.annotation.Nullable;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.fuelgauge.BatterySaverUtils;
import com.android.settingslib.utils.PowerUtil;
+import com.android.systemui.Dependency;
import com.android.systemui.power.EnhancedEstimates;
import com.android.systemui.power.Estimate;
@@ -56,6 +59,7 @@
private final EnhancedEstimates mEstimates;
private final ArrayList<BatteryController.BatteryStateChangeCallback> mChangeCallbacks = new ArrayList<>();
+ private final ArrayList<EstimateFetchCompletion> mFetchCallbacks = new ArrayList<>();
private final PowerManager mPowerManager;
private final Handler mHandler;
private final Context mContext;
@@ -70,6 +74,7 @@
private boolean mHasReceivedBattery = false;
private Estimate mEstimate;
private long mLastEstimateTimestamp = -1;
+ private boolean mFetchingEstimate = false;
@Inject
public BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates) {
@@ -197,20 +202,61 @@
}
@Override
- public String getEstimatedTimeRemainingString() {
- if (mEstimate == null
- || System.currentTimeMillis() > mLastEstimateTimestamp + UPDATE_GRANULARITY_MSEC) {
- updateEstimate();
+ public void getEstimatedTimeRemainingString(EstimateFetchCompletion completion) {
+ if (mEstimate != null
+ && mLastEstimateTimestamp > System.currentTimeMillis() - UPDATE_GRANULARITY_MSEC) {
+ String percentage = generateTimeRemainingString();
+ completion.onBatteryRemainingEstimateRetrieved(percentage);
+ return;
}
- // Estimates may not exist yet even if we've checked
+
+ // Need to fetch or refresh the estimate, but it may involve binder calls so offload the
+ // work
+ synchronized (mFetchCallbacks) {
+ mFetchCallbacks.add(completion);
+ }
+ updateEstimateInBackground();
+ }
+
+ @Nullable
+ private String generateTimeRemainingString() {
if (mEstimate == null) {
return null;
}
- final String percentage = NumberFormat.getPercentInstance().format((double) mLevel / 100.0);
+
+ String percentage = NumberFormat.getPercentInstance().format((double) mLevel / 100.0);
return PowerUtil.getBatteryRemainingShortStringFormatted(
mContext, mEstimate.estimateMillis);
}
+ private void updateEstimateInBackground() {
+ if (mFetchingEstimate) {
+ // Already dispatched a fetch. It will notify all listeners when finished
+ return;
+ }
+
+ mFetchingEstimate = true;
+ Dependency.get(Dependency.BG_HANDLER).post(() -> {
+ mEstimate = mEstimates.getEstimate();
+ mLastEstimateTimestamp = System.currentTimeMillis();
+ mFetchingEstimate = false;
+
+ Dependency.get(Dependency.MAIN_HANDLER).post(this::notifyEstimateFetchCallbacks);
+ });
+ }
+
+ private void notifyEstimateFetchCallbacks() {
+ String estimate = generateTimeRemainingString();
+
+ synchronized (mFetchCallbacks) {
+ for (EstimateFetchCompletion completion : mFetchCallbacks) {
+ completion.onBatteryRemainingEstimateRetrieved(estimate);
+ }
+
+ mFetchCallbacks.clear();
+ }
+ }
+
private void updateEstimate() {
mEstimate = mEstimates.getEstimate();
mLastEstimateTimestamp = System.currentTimeMillis();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index de7ef3b..4299af7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -274,7 +274,6 @@
private void updateClockVisibility() {
boolean visible = shouldBeVisible();
- Dependency.get(IconLogger.class).onIconVisibility("clock", visible);
int visibility = visible ? View.VISIBLE : View.GONE;
super.setVisibility(visibility);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IconLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IconLogger.java
deleted file mode 100644
index 710e1df..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IconLogger.java
+++ /dev/null
@@ -1,29 +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 com.android.systemui.statusbar.policy;
-
-public interface IconLogger {
-
- void onIconShown(String tag);
- void onIconHidden(String tag);
-
- default void onIconVisibility(String tag, boolean visible) {
- if (visible) {
- onIconShown(tag);
- } else {
- onIconHidden(tag);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IconLoggerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IconLoggerImpl.java
deleted file mode 100644
index ba6369e..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IconLoggerImpl.java
+++ /dev/null
@@ -1,115 +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 com.android.systemui.statusbar.policy;
-
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_NUM_STATUS_ICONS;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_STATUS_ICONS;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.STATUS_BAR_ICONS_CHANGED;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_ACTION;
-import static com.android.systemui.Dependency.BG_LOOPER_NAME;
-
-import android.content.Context;
-import android.metrics.LogMaker;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.ArraySet;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.internal.logging.MetricsLogger;
-
-import java.util.Arrays;
-import java.util.List;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-
-public class IconLoggerImpl implements IconLogger {
-
- // Minimum ms between log statements.
- // NonFinalForTesting
- @VisibleForTesting
- protected static long MIN_LOG_INTERVAL = 1000;
-
- private final Context mContext;
- private final Handler mHandler;
- private final MetricsLogger mLogger;
- private final ArraySet<String> mIcons = new ArraySet<>();
- private final List<String> mIconIndex;
- private long mLastLog = System.currentTimeMillis();
-
- @Inject
- public IconLoggerImpl(Context context, @Named(BG_LOOPER_NAME) Looper bgLooper,
- MetricsLogger logger) {
- mContext = context;
- mHandler = new Handler(bgLooper);
- mLogger = logger;
- String[] icons = mContext.getResources().getStringArray(
- com.android.internal.R.array.config_statusBarIcons);
- mIconIndex = Arrays.asList(icons);
- doLog();
- }
-
- @Override
- public void onIconShown(String tag) {
- synchronized (mIcons) {
- if (mIcons.contains(tag)) return;
- mIcons.add(tag);
- }
- if (!mHandler.hasCallbacks(mLog)) {
- mHandler.postDelayed(mLog, MIN_LOG_INTERVAL);
- }
- }
-
- @Override
- public void onIconHidden(String tag) {
- synchronized (mIcons) {
- if (!mIcons.contains(tag)) return;
- mIcons.remove(tag);
- }
- if (!mHandler.hasCallbacks(mLog)) {
- mHandler.postDelayed(mLog, MIN_LOG_INTERVAL);
- }
- }
-
- private void doLog() {
- long time = System.currentTimeMillis();
- long timeSinceLastLog = time - mLastLog;
- mLastLog = time;
-
- ArraySet<String> icons;
- synchronized (mIcons) {
- icons = new ArraySet<>(mIcons);
- }
- mLogger.write(new LogMaker(STATUS_BAR_ICONS_CHANGED)
- .setType(TYPE_ACTION)
- .setLatency(timeSinceLastLog)
- .addTaggedData(FIELD_NUM_STATUS_ICONS, icons.size())
- .addTaggedData(FIELD_STATUS_ICONS, getBitField(icons)));
- }
-
- private int getBitField(ArraySet<String> icons) {
- int iconsVisible = 0;
- for (String icon : icons) {
- int index = mIconIndex.indexOf(icon);
- if (index >= 0) {
- iconsVisible |= (1 << index);
- }
- }
- return iconsVisible;
- }
-
- private final Runnable mLog = this::doLog;
-}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.java b/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.java
new file mode 100644
index 0000000..52cabe2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.java
@@ -0,0 +1,222 @@
+/*
+ * 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.systemui.wallpaper;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.RectF;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
+import android.util.AttributeSet;
+import android.util.FeatureFlagUtils;
+import android.util.Log;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.widget.ImageView;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.AnimatableProperty;
+import com.android.systemui.statusbar.notification.PropertyAnimator;
+import com.android.systemui.statusbar.notification.stack.AnimationProperties;
+import com.android.systemui.statusbar.phone.ScrimState;
+
+/**
+ * A view that draws mask upon either image wallpaper or music album art in AOD.
+ */
+public class AodMaskView extends ImageView implements StatusBarStateController.StateListener,
+ ImageWallpaperTransformer.TransformationListener {
+ private static final String TAG = AodMaskView.class.getSimpleName();
+ private static final int TRANSITION_DURATION = 1000;
+
+ private static final AnimatableProperty TRANSITION_PROGRESS = AnimatableProperty.from(
+ "transition_progress",
+ AodMaskView::setTransitionAmount,
+ AodMaskView::getTransitionAmount,
+ R.id.aod_mask_transition_progress_tag,
+ R.id.aod_mask_transition_progress_start_tag,
+ R.id.aod_mask_transition_progress_end_tag
+ );
+
+ private final AnimationProperties mTransitionProperties = new AnimationProperties();
+ private final ImageWallpaperTransformer mTransformer;
+ private final RectF mBounds = new RectF();
+ private boolean mChangingStates;
+ private boolean mNeedMask;
+ private float mTransitionAmount;
+ private final WallpaperManager mWallpaperManager;
+ private final DisplayManager mDisplayManager;
+ private DisplayListener mDisplayListener = new DisplayListener() {
+ @Override
+ public void onDisplayAdded(int displayId) {
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ // We just support DEFAULT_DISPLAY currently.
+ if (displayId == Display.DEFAULT_DISPLAY) {
+ mTransformer.updateDisplayInfo(getDisplayInfo(displayId));
+ }
+ }
+ };
+
+ public AodMaskView(Context context) {
+ this(context, null);
+ }
+
+ public AodMaskView(Context context, AttributeSet attrs) {
+ this(context, attrs, null);
+ }
+
+ @VisibleForTesting
+ public AodMaskView(Context context, AttributeSet attrs, ImageWallpaperTransformer transformer) {
+ super(context, attrs);
+ setClickable(false);
+
+ StatusBarStateController controller = Dependency.get(StatusBarStateController.class);
+ if (controller != null) {
+ controller.addCallback(this);
+ } else {
+ Log.d(TAG, "Can not get StatusBarStateController!");
+ }
+
+ mDisplayManager = (DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE);
+ mDisplayManager.registerDisplayListener(mDisplayListener, null);
+ mWallpaperManager =
+ (WallpaperManager) getContext().getSystemService(Context.WALLPAPER_SERVICE);
+
+ if (transformer == null) {
+ mTransformer = new ImageWallpaperTransformer(this);
+ mTransformer.addFilter(new ScrimFilter());
+ mTransformer.addFilter(new VignetteFilter());
+ mTransformer.updateOffsets();
+ mTransformer.updateDisplayInfo(getDisplayInfo(Display.DEFAULT_DISPLAY));
+
+ mTransitionProperties.setDuration(TRANSITION_DURATION);
+ mTransitionProperties.setAnimationFinishListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mTransformer.setIsTransiting(false);
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mTransformer.setIsTransiting(true);
+ }
+ });
+ } else {
+ // This part should only be hit by test cases.
+ mTransformer = transformer;
+ }
+ }
+
+ private DisplayInfo getDisplayInfo(int displayId) {
+ DisplayInfo displayInfo = new DisplayInfo();
+ mDisplayManager.getDisplay(displayId).getDisplayInfo(displayInfo);
+ return displayInfo;
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ mBounds.set(0, 0, w, h);
+ mTransformer.updateOffsets();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ if (mNeedMask) {
+ mTransformer.drawTransformedImage(canvas, null /* target */, null /* src */, mBounds);
+ }
+ }
+
+ private boolean checkIfNeedMask() {
+ // We need mask for ImageWallpaper / LockScreen Wallpaper (Music album art).
+ return mWallpaperManager.getWallpaperInfo() == null || ScrimState.AOD.hasBackdrop();
+ }
+
+ @Override
+ public void onStatePreChange(int oldState, int newState) {
+ mChangingStates = oldState != newState;
+ mNeedMask = checkIfNeedMask();
+ }
+
+ @Override
+ public void onStatePostChange() {
+ mChangingStates = false;
+ }
+
+ @Override
+ public void onStateChanged(int newState) {
+ }
+
+ @Override
+ public void onDozingChanged(boolean isDozing) {
+ if (!mNeedMask) {
+ return;
+ }
+
+ boolean enabled = checkFeatureIsEnabled();
+ mTransformer.updateAmbientModeState(enabled && isDozing);
+
+ if (enabled && !mChangingStates) {
+ setAnimatorProperty(isDozing);
+ } else {
+ invalidate();
+ }
+ }
+
+ private boolean checkFeatureIsEnabled() {
+ return FeatureFlagUtils.isEnabled(
+ getContext(), FeatureFlagUtils.AOD_IMAGEWALLPAPER_ENABLED);
+ }
+
+ @VisibleForTesting
+ void setAnimatorProperty(boolean isDozing) {
+ PropertyAnimator.setProperty(
+ this,
+ TRANSITION_PROGRESS,
+ isDozing ? 1f : 0f /* newEndValue */,
+ mTransitionProperties,
+ true /* animated */);
+ }
+
+ @Override
+ public void onTransformationUpdated() {
+ invalidate();
+ }
+
+ private void setTransitionAmount(float amount) {
+ mTransitionAmount = amount;
+ mTransformer.updateTransitionAmount(amount);
+ }
+
+ private float getTransitionAmount() {
+ return mTransitionAmount;
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpaper/ImageWallpaperFilter.java b/packages/SystemUI/src/com/android/systemui/wallpaper/ImageWallpaperFilter.java
new file mode 100644
index 0000000..d457dac
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpaper/ImageWallpaperFilter.java
@@ -0,0 +1,81 @@
+/*
+ * 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.systemui.wallpaper;
+
+import android.animation.ValueAnimator;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.RectF;
+
+/**
+ * Abstract filter used by static image wallpaper.
+ */
+abstract class ImageWallpaperFilter {
+ protected static final boolean DEBUG = false;
+
+ private ImageWallpaperTransformer mTransformer;
+
+ /**
+ * Apply this filter to the bitmap before drawing on canvas.
+ * @param c The canvas that will draw to.
+ * @param bitmap The bitmap to apply this filter.
+ * @param src The subset of the bitmap to be drawn.
+ * @param dest The rectangle that the bitmap will be scaled/translated to fit into.
+ */
+ public abstract void apply(@NonNull Canvas c, @Nullable Bitmap bitmap,
+ @Nullable Rect src, @NonNull RectF dest);
+
+ /**
+ * Notifies the occurrence of built-in transition of the animation.
+ * @param animator The animator which was animated.
+ */
+ public abstract void onAnimatorUpdate(ValueAnimator animator);
+
+ /**
+ * Notifies the occurrence of another transition of the animation.
+ * @param amount The transition amount.
+ */
+ public abstract void onTransitionAmountUpdate(float amount);
+
+ /**
+ * To set the associated transformer.
+ * @param transformer The transformer that is associated with this filter.
+ */
+ public void setTransformer(ImageWallpaperTransformer transformer) {
+ if (transformer != null) {
+ mTransformer = transformer;
+ }
+ }
+
+ protected ImageWallpaperTransformer getTransformer() {
+ return mTransformer;
+ }
+
+ /**
+ * Notifies the changing of the offset value of the ImageWallpaper.
+ * @param force True to force re-evaluate offsets.
+ * @param xOffset X offset of the ImageWallpaper in percentage.
+ * @param yOffset Y offset of the ImageWallpaper in percentage.
+ */
+ public void onOffsetsUpdate(boolean force, float xOffset, float yOffset) {
+ // No-op
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpaper/ImageWallpaperTransformer.java b/packages/SystemUI/src/com/android/systemui/wallpaper/ImageWallpaperTransformer.java
new file mode 100644
index 0000000..25b0b0a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpaper/ImageWallpaperTransformer.java
@@ -0,0 +1,173 @@
+/*
+ * 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.systemui.wallpaper;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.view.DisplayInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class is used to manage the filters that will be applied.
+ */
+public class ImageWallpaperTransformer {
+ private static final String TAG = ImageWallpaperTransformer.class.getSimpleName();
+
+ private DisplayInfo mDisplayInfo;
+ private final List<ImageWallpaperFilter> mFilters;
+ private final TransformationListener mListener;
+ private boolean mIsInAmbientMode;
+ private boolean mIsTransiting;
+
+ /**
+ * Constructor.
+ * @param listener A listener to inform you the transformation has updated.
+ */
+ public ImageWallpaperTransformer(TransformationListener listener) {
+ mFilters = new ArrayList<>();
+ mListener = listener;
+ }
+
+ /**
+ * Claim that we want to use the specified filter.
+ * @param filter The filter will be used.
+ */
+ public void addFilter(ImageWallpaperFilter filter) {
+ if (filter != null) {
+ filter.setTransformer(this);
+ mFilters.add(filter);
+ }
+ }
+
+ /**
+ * Check if any transition is running.
+ * @return True if the transition is running, false otherwise.
+ */
+ boolean isTransiting() {
+ return mIsTransiting;
+ }
+
+ /**
+ * Indicate if any transition is running. <br/>
+ * @param isTransiting True if the transition is running.
+ */
+ void setIsTransiting(boolean isTransiting) {
+ mIsTransiting = isTransiting;
+ }
+
+ /**
+ * Check if the device is in ambient mode.
+ * @return True if the device is in ambient mode, false otherwise.
+ */
+ public boolean isInAmbientMode() {
+ return mIsInAmbientMode;
+ }
+
+ /**
+ * Update current state of ambient mode.
+ * @param isInAmbientMode Current ambient mode state.
+ */
+ public void updateAmbientModeState(boolean isInAmbientMode) {
+ mIsInAmbientMode = isInAmbientMode;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ int idx = 0;
+ for (ImageWallpaperFilter filter : mFilters) {
+ sb.append(idx++).append(": ").append(filter.getClass().getSimpleName()).append("\n");
+ }
+ if (sb.length() == 0) {
+ sb.append("No filters applied");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Set a new display info.
+ * @param displayInfo New display info.
+ */
+ public void updateDisplayInfo(DisplayInfo displayInfo) {
+ mDisplayInfo = displayInfo;
+ }
+
+ /**
+ * To get current display info.
+ * @return Current display info.
+ */
+ public DisplayInfo getDisplayInfo() {
+ return mDisplayInfo;
+ }
+
+ /**
+ * Update the offsets with default value.
+ */
+ public void updateOffsets() {
+ this.updateOffsets(true, 0f, .5f);
+ }
+
+ /**
+ * To notify the filters that the offset of the ImageWallpaper changes.
+ * @param force True to force re-evaluate offsets.
+ * @param offsetX X offset of the ImageWallpaper in percentage.
+ * @param offsetY Y offset of the ImageWallpaper in percentage.
+ */
+ public void updateOffsets(boolean force, float offsetX, float offsetY) {
+ mFilters.forEach(filter -> filter.onOffsetsUpdate(force, offsetX, offsetY));
+ }
+
+ /**
+ * Apply all specified filters to the bitmap then draw to the canvas.
+ * @param c The canvas that will draw to.
+ * @param target The bitmap to apply filters.
+ * @param src The subset of the bitmap to be drawn
+ * @param dest The rectangle that the bitmap will be scaled/translated to fit into.
+ */
+ void drawTransformedImage(@NonNull Canvas c, @Nullable Bitmap target,
+ @Nullable Rect src, @NonNull RectF dest) {
+ mFilters.forEach(filter -> filter.apply(c, target, src, dest));
+ }
+
+ /**
+ * Update the transition amount. <br/>
+ * Must invoke this to update transition amount if not running built-in transition.
+ * @param amount The transition amount.
+ */
+ void updateTransitionAmount(float amount) {
+ mFilters.forEach(filter -> filter.onTransitionAmountUpdate(amount));
+ if (mListener != null) {
+ mListener.onTransformationUpdated();
+ }
+ }
+
+ /**
+ * An interface that informs the transformation status.
+ */
+ public interface TransformationListener {
+ /**
+ * Notifies the update of the transformation.
+ */
+ void onTransformationUpdated();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpaper/ScrimFilter.java b/packages/SystemUI/src/com/android/systemui/wallpaper/ScrimFilter.java
new file mode 100644
index 0000000..637e48e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpaper/ScrimFilter.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wallpaper;
+
+import android.animation.ValueAnimator;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+
+/**
+ * A filter that implements 70% black scrim effect.
+ */
+public class ScrimFilter extends ImageWallpaperFilter {
+ private static final int MAX_ALPHA = (int) (255 * .7f);
+ private static final int MIN_ALPHA = 0;
+
+ private final Paint mPaint;
+
+ public ScrimFilter() {
+ mPaint = new Paint();
+ mPaint.setColor(Color.BLACK);
+ mPaint.setAlpha(MAX_ALPHA);
+ }
+
+ @Override
+ public void apply(Canvas c, Bitmap bitmap, Rect src, RectF dest) {
+ ImageWallpaperTransformer transformer = getTransformer();
+
+ // If it is not in the transition, we need to set the property according to aod state.
+ if (!transformer.isTransiting()) {
+ mPaint.setAlpha(transformer.isInAmbientMode() ? MAX_ALPHA : MIN_ALPHA);
+ }
+
+ c.drawRect(dest, mPaint);
+ }
+
+ @Override
+ public void onAnimatorUpdate(ValueAnimator animator) {
+ ImageWallpaperTransformer transformer = getTransformer();
+ float fraction = animator.getAnimatedFraction();
+ float factor = transformer.isInAmbientMode() ? fraction : 1f - fraction;
+ mPaint.setAlpha((int) (factor * MAX_ALPHA));
+ }
+
+ @Override
+ public void onTransitionAmountUpdate(float amount) {
+ mPaint.setAlpha((int) (amount * MAX_ALPHA));
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpaper/VignetteFilter.java b/packages/SystemUI/src/com/android/systemui/wallpaper/VignetteFilter.java
new file mode 100644
index 0000000..ad0b98b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpaper/VignetteFilter.java
@@ -0,0 +1,124 @@
+/*
+ * 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.systemui.wallpaper;
+
+import android.animation.ValueAnimator;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PointF;
+import android.graphics.RadialGradient;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Shader;
+import android.util.Log;
+import android.view.DisplayInfo;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * A filter that implements vignette effect.
+ */
+public class VignetteFilter extends ImageWallpaperFilter {
+ private static final String TAG = VignetteFilter.class.getSimpleName();
+ private static final int MAX_ALPHA = 255;
+ private static final int MIN_ALPHA = 0;
+
+ private final Paint mPaint;
+ private final Matrix mMatrix;
+ private final Shader mShader;
+
+ private float mXOffset;
+ private float mYOffset;
+ private float mCenterX;
+ private float mCenterY;
+ private float mStretchX;
+ private float mStretchY;
+ private boolean mCalculateOffsetNeeded;
+
+ public VignetteFilter() {
+ mPaint = new Paint();
+ mMatrix = new Matrix();
+ mShader = new RadialGradient(0, 0, 1,
+ Color.TRANSPARENT, Color.BLACK, Shader.TileMode.CLAMP);
+ }
+
+ @Override
+ public void apply(Canvas c, Bitmap bitmap, Rect src, RectF dest) {
+ DisplayInfo info = getTransformer().getDisplayInfo();
+
+ if (mCalculateOffsetNeeded) {
+ int lw = info.logicalWidth;
+ int lh = info.logicalHeight;
+ mCenterX = lw / 2 + (dest.width() - lw) * mXOffset;
+ mCenterY = lh / 2 + (dest.height() - lh) * mYOffset;
+ mStretchX = info.logicalWidth / 2;
+ mStretchY = info.logicalHeight / 2;
+ mCalculateOffsetNeeded = false;
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "apply: lw=" + info.logicalWidth + ", lh=" + info.logicalHeight
+ + ", center=(" + mCenterX + "," + mCenterY + ")"
+ + ", stretch=(" + mStretchX + "," + mStretchY + ")");
+ }
+
+ mMatrix.reset();
+ mMatrix.postTranslate(mCenterX, mCenterY);
+ mMatrix.postScale(mStretchX, mStretchY, mCenterX, mCenterY);
+ mShader.setLocalMatrix(mMatrix);
+ mPaint.setShader(mShader);
+
+ ImageWallpaperTransformer transformer = getTransformer();
+
+ // If it is not in the transition, we need to set the property according to aod state.
+ if (!transformer.isTransiting()) {
+ mPaint.setAlpha(transformer.isInAmbientMode() ? MAX_ALPHA : MIN_ALPHA);
+ }
+
+ c.drawRect(dest, mPaint);
+ }
+
+ @Override
+ public void onAnimatorUpdate(ValueAnimator animator) {
+ ImageWallpaperTransformer transformer = getTransformer();
+ float fraction = animator.getAnimatedFraction();
+ float factor = transformer.isInAmbientMode() ? fraction : 1f - fraction;
+ mPaint.setAlpha((int) (factor * MAX_ALPHA));
+ }
+
+ @Override
+ public void onTransitionAmountUpdate(float amount) {
+ mPaint.setAlpha((int) (amount * MAX_ALPHA));
+ }
+
+ @Override
+ public void onOffsetsUpdate(boolean force, float xOffset, float yOffset) {
+ if (force || mXOffset != xOffset || mYOffset != yOffset) {
+ mXOffset = xOffset;
+ mYOffset = yOffset;
+ mCalculateOffsetNeeded = true;
+ }
+ }
+
+ @VisibleForTesting
+ public PointF getCenterPoint() {
+ return new PointF(mCenterX, mCenterY);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
index 8e02f57..fbc1c20 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -132,6 +132,17 @@
}
@Test
+ public void onPluginConnected_darkAmountInitialized() {
+ // GIVEN that the dark amount has already been set
+ mKeyguardClockSwitch.setDarkAmount(0.5f);
+ // WHEN a plugin is connected
+ ClockPlugin plugin = mock(ClockPlugin.class);
+ mKeyguardClockSwitch.getClockPluginConsumer().accept(plugin);
+ // THEN dark amount should be initalized on the plugin.
+ verify(plugin).setDarkAmount(0.5f);
+ }
+
+ @Test
public void onPluginDisconnected_showDefaultClock() {
ClockPlugin plugin = mock(ClockPlugin.class);
TextClock pluginView = new TextClock(getContext());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java
index 521d5d1..53ad0b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java
@@ -16,17 +16,12 @@
package com.android.systemui;
-
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.graphics.Bitmap;
@@ -58,13 +53,15 @@
@Mock private SurfaceHolder mSurfaceHolder;
@Mock private DisplayInfo mDisplayInfo;
- CountDownLatch mEventCountdown;
+ private CountDownLatch mEventCountdown;
+ private CountDownLatch mAmbientEventCountdown;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mEventCountdown = new CountDownLatch(1);
+ mAmbientEventCountdown = new CountDownLatch(2);
mImageWallpaper = new ImageWallpaper() {
@Override
@@ -86,6 +83,11 @@
assertTrue("mFixedSizeAllowed should be true", allowed);
mEventCountdown.countDown();
}
+
+ @Override
+ public void onAmbientModeChanged(boolean inAmbientMode, long duration) {
+ mAmbientEventCountdown.countDown();
+ }
};
}
};
@@ -132,4 +134,23 @@
verify(mSurfaceHolder, times(1)).setFixedSize(ImageWallpaper.DrawableEngine.MIN_BACKGROUND_WIDTH, ImageWallpaper.DrawableEngine.MIN_BACKGROUND_HEIGHT);
}
+ @Test
+ public void testDeliversAmbientModeChanged() {
+ ImageWallpaper.DrawableEngine wallpaperEngine =
+ (ImageWallpaper.DrawableEngine) mImageWallpaper.onCreateEngine();
+
+ assertEquals("setFixedSizeAllowed should have been called.",
+ 0, mEventCountdown.getCount());
+
+ wallpaperEngine.setCreated(true);
+ wallpaperEngine.doAmbientModeChanged(false, 1000);
+ assertFalse("ambient mode should be false", wallpaperEngine.isInAmbientMode());
+ assertEquals("onAmbientModeChanged should have been called.",
+ 1, mAmbientEventCountdown.getCount());
+
+ wallpaperEngine.doAmbientModeChanged(true, 1000);
+ assertTrue("ambient mode should be true", wallpaperEngine.isInAmbientMode());
+ assertEquals("onAmbientModeChanged should have been called.",
+ 0, mAmbientEventCountdown.getCount());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 214404c..c140ba2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -142,6 +142,7 @@
doNothing().when(mGroupManager).collapseAllGroups();
doNothing().when(mExpandHelper).cancelImmediately();
doNothing().when(notificationShelf).setAnimationsEnabled(anyBoolean());
+ doNothing().when(notificationShelf).fadeInTranslating();
mOriginalInterruptionModelSetting = Settings.Secure.getInt(mContext.getContentResolver(),
NOTIFICATION_NEW_INTERRUPTION_MODEL, 0);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
index add8838..a72be7a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
@@ -57,13 +57,15 @@
@Before
public void setup() {
mSysuiContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
- mSysuiContext.putComponent(StatusBar.class, mock(StatusBar.class));
+ StatusBar statusBar = mock(StatusBar.class);
+ mSysuiContext.putComponent(StatusBar.class, statusBar);
mSysuiContext.putComponent(TunerService.class, mock(TunerService.class));
mStatusBarStateController = mDependency
.injectMockDependency(StatusBarStateController.class);
injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
mMockNotificiationAreaController = mock(NotificationIconAreaController.class);
mNotificationAreaInner = mock(View.class);
+ when(statusBar.getPanel()).thenReturn(mock(NotificationPanelView.class));
when(mNotificationAreaInner.animate()).thenReturn(mock(ViewPropertyAnimator.class));
when(mMockNotificiationAreaController.getNotificationInnerAreaView()).thenReturn(
mNotificationAreaInner);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
new file mode 100644
index 0000000..b7b95ef
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.keyguard.KeyguardStatusView;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class NotificationPanelViewTest extends SysuiTestCase {
+
+ @Mock
+ private StatusBarStateController mStatusBarStateController;
+ @Mock
+ private NotificationStackScrollLayout mNotificationStackScrollLayout;
+ @Mock
+ private KeyguardStatusView mKeyguardStatusView;
+ private NotificationPanelView mNotificationPanelView;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mDependency.injectTestDependency(StatusBarStateController.class,
+ mStatusBarStateController);
+ mDependency.injectMockDependency(ShadeController.class);
+ mDependency.injectMockDependency(NotificationLockscreenUserManager.class);
+ mDependency.injectMockDependency(ConfigurationController.class);
+ mDependency.injectMockDependency(ZenModeController.class);
+ mNotificationPanelView = new TestableNotificationPanelView();
+ }
+
+ @Test
+ public void testSetDozing_notifiesNsslAndStateController() {
+ mNotificationPanelView.setDozing(true /* dozing */, true /* animate */, null /* touch */);
+ InOrder inOrder = inOrder(mNotificationStackScrollLayout, mStatusBarStateController);
+ inOrder.verify(mNotificationStackScrollLayout).setDark(eq(true), eq(true), eq(null));
+ inOrder.verify(mNotificationStackScrollLayout).setShowDarkShelf(eq(true));
+ inOrder.verify(mStatusBarStateController).setDozeAmount(eq(1f), eq(true));
+ }
+
+ @Test
+ public void testSetDozing_showsDarkShelfWithDefaultClock() {
+ when(mKeyguardStatusView.hasCustomClock()).thenReturn(false);
+ mNotificationPanelView.setDozing(true /* dozing */, true /* animate */, null /* touch */);
+ verify(mNotificationStackScrollLayout).setShowDarkShelf(eq(true));
+ }
+
+ @Test
+ public void testSetDozing_hidesDarkShelfWhenCustomClock() {
+ when(mKeyguardStatusView.hasCustomClock()).thenReturn(true);
+ mNotificationPanelView.setDozing(true /* dozing */, true /* animate */, null /* touch */);
+ verify(mNotificationStackScrollLayout).setShowDarkShelf(eq(false));
+ }
+
+ private class TestableNotificationPanelView extends NotificationPanelView {
+ TestableNotificationPanelView() {
+ super(NotificationPanelViewTest.this.mContext, null);
+ mNotificationStackScroller = mNotificationStackScrollLayout;
+ mKeyguardStatusView = NotificationPanelViewTest.this.mKeyguardStatusView;
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
index 2805908..382dde9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
@@ -97,6 +97,7 @@
doReturn(HIT_TARGET_NONE).when(mNavigationBarView).getDownHitTarget();
doReturn(backButton).when(mNavigationBarView).getBackButton();
doReturn(mResources).when(mNavigationBarView).getResources();
+ doReturn(mContext).when(mNavigationBarView).getContext();
mController = new QuickStepController(mContext);
mController.setComponents(mNavigationBarView);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/IconLoggerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/IconLoggerImplTest.java
deleted file mode 100644
index 5c34730..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/IconLoggerImplTest.java
+++ /dev/null
@@ -1,177 +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 com.android.systemui.statusbar.policy;
-
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_NUM_STATUS_ICONS;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_STATUS_ICONS;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent
- .RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS;
-
-import static org.junit.Assert.*;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import static java.lang.Thread.sleep;
-
-import android.metrics.LogMaker;
-import android.support.test.filters.SmallTest;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.MessageHandler;
-import android.testing.TestableLooper.RunWithLooper;
-import android.util.Log;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.SysuiTestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatcher;
-
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-@SmallTest
-public class IconLoggerImplTest extends SysuiTestCase {
-
- private MetricsLogger mMetricsLogger;
- private IconLoggerImpl mIconLogger;
- private TestableLooper mTestableLooper;
- private MessageHandler mMessageHandler;
-
- @Before
- public void setup() {
- IconLoggerImpl.MIN_LOG_INTERVAL = 5; // Low interval for testing
- mMetricsLogger = mock(MetricsLogger.class);
- mTestableLooper = TestableLooper.get(this);
- mMessageHandler = mock(MessageHandler.class);
- mTestableLooper.setMessageHandler(mMessageHandler);
- String[] iconArray = new String[] {
- "test_icon_1",
- "test_icon_2",
- };
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.array.config_statusBarIcons, iconArray);
- mIconLogger = new IconLoggerImpl(mContext, mTestableLooper.getLooper(), mMetricsLogger);
- when(mMessageHandler.onMessageHandled(any())).thenReturn(true);
- clearInvocations(mMetricsLogger);
- }
-
- @Test
- public void testIconShown() throws InterruptedException {
- // Should only get one message, for the same icon shown twice.
- mIconLogger.onIconShown("test_icon_2");
- mIconLogger.onIconShown("test_icon_2");
-
- // There should be some delay before execute.
- mTestableLooper.processAllMessages();
- verify(mMessageHandler, never()).onMessageHandled(any());
-
- sleep(10);
- mTestableLooper.processAllMessages();
- verify(mMessageHandler, times(1)).onMessageHandled(any());
- }
-
- @Test
- public void testIconHidden() throws InterruptedException {
- // Add the icon so that it can be removed.
- mIconLogger.onIconShown("test_icon_2");
- sleep(10);
- mTestableLooper.processAllMessages();
- clearInvocations(mMessageHandler);
-
- // Should only get one message, for the same icon shown twice.
- mIconLogger.onIconHidden("test_icon_2");
- mIconLogger.onIconHidden("test_icon_2");
-
- // There should be some delay before execute.
- mTestableLooper.processAllMessages();
- verify(mMessageHandler, never()).onMessageHandled(any());
-
- sleep(10);
- mTestableLooper.processAllMessages();
- verify(mMessageHandler, times(1)).onMessageHandled(any());
- }
-
- @Test
- public void testLog() throws InterruptedException {
- mIconLogger.onIconShown("test_icon_2");
- sleep(10);
- mTestableLooper.processAllMessages();
-
- verify(mMetricsLogger).write(argThat(maker -> {
- if (IconLoggerImpl.MIN_LOG_INTERVAL >
- (long) maker.getTaggedData(RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS)) {
- Log.e("IconLoggerImplTest", "Invalid latency "
- + maker.getTaggedData(RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS));
- return false;
- }
- if (1 != (int) maker.getTaggedData(FIELD_NUM_STATUS_ICONS)) {
- Log.e("IconLoggerImplTest", "Invalid icon count "
- + maker.getTaggedData(FIELD_NUM_STATUS_ICONS));
- return false;
- }
- return true;
- }));
- }
-
- @Test
- public void testBitField() throws InterruptedException {
- mIconLogger.onIconShown("test_icon_2");
- sleep(10);
- mTestableLooper.processAllMessages();
-
- verify(mMetricsLogger).write(argThat(maker -> {
- if ((1 << 1) != (int) maker.getTaggedData(FIELD_STATUS_ICONS)) {
- Log.e("IconLoggerImplTest", "Invalid bitfield " + Integer.toHexString(
- (Integer) maker.getTaggedData(FIELD_NUM_STATUS_ICONS)));
- return false;
- }
- return true;
- }));
-
- mIconLogger.onIconShown("test_icon_1");
- sleep(10);
- mTestableLooper.processAllMessages();
-
- verify(mMetricsLogger).write(argThat(maker -> {
- if ((1 << 1 | 1 << 0) != (int) maker.getTaggedData(FIELD_STATUS_ICONS)) {
- Log.e("IconLoggerImplTest", "Invalid bitfield " + Integer.toHexString(
- (Integer) maker.getTaggedData(FIELD_NUM_STATUS_ICONS)));
- return false;
- }
- return true;
- }));
-
- mIconLogger.onIconHidden("test_icon_2");
- sleep(10);
- mTestableLooper.processAllMessages();
-
- verify(mMetricsLogger).write(argThat(maker -> {
- if ((1 << 0) != (int) maker.getTaggedData(FIELD_STATUS_ICONS)) {
- Log.e("IconLoggerImplTest", "Invalid bitfield " + Integer.toHexString(
- (Integer) maker.getTaggedData(FIELD_STATUS_ICONS)));
- return false;
- }
- return true;
- }));
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpaper/AodMaskViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpaper/AodMaskViewTest.java
new file mode 100644
index 0000000..c44a366
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpaper/AodMaskViewTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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.systemui.wallpaper;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.RectF;
+import android.hardware.display.DisplayManager;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.FeatureFlagUtils;
+import android.view.DisplayInfo;
+import android.view.WindowManager;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AodMaskViewTest extends SysuiTestCase {
+ private AodMaskView mMaskView;
+ private DisplayInfo mDisplayInfo;
+ private ImageWallpaperTransformer mTransformer;
+
+ @Before
+ public void setUp() throws Exception {
+ DisplayManager displayManager =
+ spy((DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE));
+ doNothing().when(displayManager).registerDisplayListener(any(), any());
+ mContext.addMockSystemService(DisplayManager.class, displayManager);
+
+ WallpaperManager wallpaperManager =
+ spy((WallpaperManager) mContext.getSystemService(Context.WALLPAPER_SERVICE));
+ doReturn(null).when(wallpaperManager).getWallpaperInfo();
+ mContext.addMockSystemService(WallpaperManager.class, wallpaperManager);
+
+ mTransformer = spy(new ImageWallpaperTransformer(null /* listener */));
+ mMaskView = spy(new AodMaskView(getContext(), null /* attrs */, mTransformer));
+ mDisplayInfo = new DisplayInfo();
+
+ ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE))
+ .getDefaultDisplay().getDisplayInfo(mDisplayInfo);
+
+ FeatureFlagUtils.setEnabled(
+ mContext, FeatureFlagUtils.AOD_IMAGEWALLPAPER_ENABLED, true);
+ }
+
+ @After
+ public void tearDown() {
+ FeatureFlagUtils.setEnabled(
+ mContext, FeatureFlagUtils.AOD_IMAGEWALLPAPER_ENABLED, false);
+ }
+
+ @Test
+ public void testCreateMaskView_TransformerIsNotNull() {
+ assertNotNull("mTransformer should not be null", mTransformer);
+ }
+
+ @Test
+ public void testAodMaskView_ShouldNotClickable() {
+ assertFalse("MaskView should not be clickable", mMaskView.isClickable());
+ }
+
+ @Test
+ public void testAodMaskView_OnSizeChange_ShouldUpdateTransformerOffsets() {
+ mMaskView.onSizeChanged(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight, 0, 0);
+ verify(mTransformer, times(1)).updateOffsets();
+ }
+
+ @Test
+ public void testAodMaskView_OnDraw_ShouldDrawTransformedImage() {
+ Canvas c = new Canvas();
+ RectF bounds = new RectF(0, 0, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
+ mMaskView.onSizeChanged(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight, 0, 0);
+ mMaskView.onStatePreChange(0, 1);
+ mMaskView.onDraw(c);
+ verify(mTransformer, times(1)).drawTransformedImage(c, null, null, bounds);
+ }
+
+ @Test
+ public void testAodMaskView_IsDozing_ShouldUpdateAmbientModeState() {
+ doNothing().when(mMaskView).setAnimatorProperty(anyBoolean());
+ mMaskView.onStatePreChange(0, 1);
+ mMaskView.onDozingChanged(true);
+ verify(mTransformer, times(1)).updateAmbientModeState(true);
+ }
+
+ @Test
+ public void testAodMaskView_IsDozing_ShouldDoTransitionOrDrawFinalFrame() {
+ doNothing().when(mMaskView).setAnimatorProperty(anyBoolean());
+ mMaskView.onStatePreChange(0, 1);
+ mMaskView.onDozingChanged(true);
+ mMaskView.onStatePostChange();
+ mMaskView.onDozingChanged(false);
+ verify(mMaskView, times(1)).invalidate();
+ verify(mMaskView, times(1)).setAnimatorProperty(false);
+ }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpaper/ImageWallpaperTransformerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpaper/ImageWallpaperTransformerTest.java
new file mode 100644
index 0000000..55b0aae
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpaper/ImageWallpaperTransformerTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wallpaper;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PointF;
+import android.graphics.RectF;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.DisplayInfo;
+import android.view.WindowManager;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ImageWallpaperTransformerTest extends SysuiTestCase {
+ private DisplayInfo mDisplayInfo;
+ private Bitmap mBitmap;
+ private Canvas mCanvas;
+ private RectF mDestination;
+
+ @Before
+ public void setUp() throws Exception {
+ mDisplayInfo = new DisplayInfo();
+ ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
+ .getDefaultDisplay().getDisplayInfo(mDisplayInfo);
+ int dimension = Math.max(mDisplayInfo.logicalHeight, mDisplayInfo.logicalWidth);
+ mBitmap = Bitmap.createBitmap(dimension, dimension, Bitmap.Config.ARGB_8888);
+ mCanvas = new Canvas(mBitmap);
+ mCanvas.drawColor(Color.RED);
+ mDestination = new RectF(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
+ }
+
+ @Test
+ public void testVignetteFilter() {
+ VignetteFilter vignette = new VignetteFilter();
+
+ ImageWallpaperTransformer transformer = getTransformer(vignette);
+ transformer.drawTransformedImage(mCanvas, mBitmap, null, mDestination);
+
+ PointF center = vignette.getCenterPoint();
+ int p1 = mBitmap.getPixel((int) center.x, (int) center.y);
+ int p2 = mBitmap.getPixel(0, 0);
+ int p3 = mBitmap.getPixel(mBitmap.getWidth() - 1, mBitmap.getHeight() - 1);
+
+ assertThat(p1).isEqualTo(Color.RED);
+ assertThat(p2 | p3).isEqualTo(Color.BLACK);
+ }
+
+ @Test
+ public void testScrimFilter() {
+ getTransformer(new ScrimFilter())
+ .drawTransformedImage(mCanvas, mBitmap, null, mDestination);
+
+ int pixel = mBitmap.getPixel(0, 0);
+
+ // 0xff4d0000 is the result of 70% alpha pre-multiplied which is 0.7*(0,0,0)+0.3*(255,0,0).
+ assertThat(pixel).isEqualTo(0xff4d0000);
+ }
+
+ private ImageWallpaperTransformer getTransformer(ImageWallpaperFilter filter) {
+ ImageWallpaperTransformer transformer = new ImageWallpaperTransformer(null);
+ transformer.addFilter(filter);
+ transformer.updateDisplayInfo(mDisplayInfo);
+ transformer.updateOffsets();
+ transformer.updateAmbientModeState(true);
+ return transformer;
+ }
+}
diff --git a/packages/VpnDialogs/res/values-as/strings.xml b/packages/VpnDialogs/res/values-as/strings.xml
index 25f16e3..45d8458 100644
--- a/packages/VpnDialogs/res/values-as/strings.xml
+++ b/packages/VpnDialogs/res/values-as/strings.xml
@@ -21,7 +21,7 @@
<string name="legacy_title" msgid="192936250066580964">"ভিপিএন সংযোগ হৈ আছে"</string>
<string name="session" msgid="6470628549473641030">"ছেশ্বন:"</string>
<string name="duration" msgid="3584782459928719435">"সময়সীমা:"</string>
- <string name="data_transmitted" msgid="7988167672982199061">"পঠিওৱা হ\'ল:"</string>
+ <string name="data_transmitted" msgid="7988167672982199061">"পঠিওৱা হ’ল:"</string>
<string name="data_received" msgid="4062776929376067820">"পোৱা গ\'ল:"</string>
<string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_1">%2$s</xliff:g> পেকেট / <xliff:g id="NUMBER_0">%1$s</xliff:g> বাইট"</string>
<string name="always_on_disconnected_title" msgid="1906740176262776166">"সদা-সক্ৰিয় ভিপিএনৰ লগত সংযোগ কৰিবপৰা নাই"</string>
diff --git a/packages/VpnDialogs/res/values-ne/strings.xml b/packages/VpnDialogs/res/values-ne/strings.xml
index 5019a06..b716c35 100644
--- a/packages/VpnDialogs/res/values-ne/strings.xml
+++ b/packages/VpnDialogs/res/values-ne/strings.xml
@@ -25,7 +25,7 @@
<string name="data_received" msgid="4062776929376067820">"प्राप्त भयो:"</string>
<string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> बाइटहरू / <xliff:g id="NUMBER_1">%2$s</xliff:g> प्याकेटहरू"</string>
<string name="always_on_disconnected_title" msgid="1906740176262776166">"सधैँ-सक्रिय रहने VPN सेवामा जडान गर्न सकिँदैन"</string>
- <string name="always_on_disconnected_message" msgid="555634519845992917">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> लाई सधैँ जडान भइरहनेगरि सेटअप गरिएको छ तर यसलाई अहिले नै जडान गर्न मिल्दैन। तपाईंको फोन <xliff:g id="VPN_APP_1">%1$s</xliff:g> मा पुन: जडान नहुँदासम्म यसले कुनै सार्वजनिक नेटवर्क प्रयोग गर्नेछ।"</string>
+ <string name="always_on_disconnected_message" msgid="555634519845992917">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> लाई सधैँ जडान भइरहनेगरि सेटअप गरिएको छ तर यसलाई अहिले नै जडान गर्न मिल्दैन। तपाईंको फोन <xliff:g id="VPN_APP_1">%1$s</xliff:g> मा पुन: जडान नहुँदासम्म यसले कुनै सार्वजनिक नेटवर्क प्रयोग गर्ने छ।"</string>
<string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"<xliff:g id="VPN_APP">%1$s</xliff:g> लाई सधैँ पनि जडान भइरहनेगरि सेटअप गरिएको छ तर यसलाई अहिले नै जडान गर्न मिल्दैन। VPN पुन: जडान नहुँदासम्म तपाईंसँग कुनै पनि इन्टरनेट रहनेछैन।"</string>
<string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string>
<string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN सम्बन्धी सेटिङहरू परिवर्तन गर्नुहोस्"</string>
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 665773c..aff5e13 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -5325,7 +5325,7 @@
// OS: P
ACCESSIBILITY_VIBRATION = 1292;
- // OPEN: Settings > Accessibility > Vibration > Ring & notification vibration
+ // OPEN: Settings > Accessibility > Vibration > Notification vibration
// CATEGORY: SETTINGS
// OS: P
ACCESSIBILITY_VIBRATION_NOTIFICATION = 1293;
@@ -6763,6 +6763,11 @@
// OS: Q
ACTION_TEXT_CLASSIFIER_ACTIONS_GENERATED = 1619;
+ // OPEN: Settings > Accessibility > Vibration > Ring vibration
+ // CATEGORY: SETTINGS
+ // OS: Q
+ ACCESSIBILITY_VIBRATION_RING = 1620;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/Android.bp b/services/Android.bp
index 01734f4..31385ed 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -17,13 +17,16 @@
static_libs: [
"services.core",
"services.accessibility",
+ "services.appprediction",
"services.appwidget",
"services.autofill",
"services.backup",
"services.companion",
"services.contentcapture",
+ "services.contentsuggestions",
"services.coverage",
"services.devicepolicy",
+ "services.ipmemorystore",
"services.midi",
"services.net",
"services.print",
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
index 17bf570..6a97fbb 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
@@ -32,7 +32,6 @@
import android.text.TextUtils;
import android.util.MathUtils;
import android.util.Slog;
-import android.util.SparseArray;
import android.view.Display;
import android.view.MagnificationSpec;
import android.view.View;
@@ -40,8 +39,6 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.SomeArgs;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.wm.WindowManagerInternal;
@@ -63,7 +60,7 @@
private static final String LOG_TAG = "MagnificationController";
public static final float MIN_SCALE = 1.0f;
- public static final float MAX_SCALE = 5.0f;
+ public static final float MAX_SCALE = 8.0f;
private static final boolean DEBUG_SET_MAGNIFICATION_SPEC = false;
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index 12e7376..80049e8 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -115,8 +115,11 @@
private static final boolean DEBUG_PANNING_SCALING = false || DEBUG_ALL;
private static final boolean DEBUG_EVENT_STREAM = false || DEBUG_ALL;
+ // The MIN_SCALE is different from MagnificationController.MIN_SCALE due
+ // to AccessibilityService.MagnificationController#setScale() has
+ // different scale range
private static final float MIN_SCALE = 2.0f;
- private static final float MAX_SCALE = 5.0f;
+ private static final float MAX_SCALE = MagnificationController.MAX_SCALE;
@VisibleForTesting final MagnificationController mMagnificationController;
diff --git a/services/appprediction/Android.bp b/services/appprediction/Android.bp
new file mode 100644
index 0000000..a7be587
--- /dev/null
+++ b/services/appprediction/Android.bp
@@ -0,0 +1,5 @@
+java_library_static {
+ name: "services.appprediction",
+ srcs: ["java/**/*.java"],
+ libs: ["services.core"],
+}
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
new file mode 100644
index 0000000..833eaa0
--- /dev/null
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
@@ -0,0 +1,156 @@
+/*
+ * 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.appprediction;
+
+import static android.Manifest.permission.MANAGE_APP_PREDICTIONS;
+import static android.content.Context.APP_PREDICTION_SERVICE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.prediction.AppPredictionContext;
+import android.app.prediction.AppPredictionSessionId;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.IPredictionCallback;
+import android.app.prediction.IPredictionManager;
+import android.content.Context;
+import android.content.pm.ParceledListSlice;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.os.UserHandle;
+
+import com.android.server.infra.AbstractMasterSystemService;
+import com.android.server.infra.FrameworkResourcesServiceNameResolver;
+
+import java.io.FileDescriptor;
+import java.util.function.Consumer;
+
+/**
+ * A service used to predict app and shortcut usage.
+ *
+ * <p>The data collected by this service can be analyzed and combined with other sources to provide
+ * predictions in different areas of the system such as Launcher and Share sheet.
+ */
+public class AppPredictionManagerService extends
+ AbstractMasterSystemService<AppPredictionManagerService, AppPredictionPerUserService> {
+
+ private static final String TAG = AppPredictionManagerService.class.getSimpleName();
+
+ private static final int MAX_TEMP_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
+
+ public AppPredictionManagerService(Context context) {
+ super(context, new FrameworkResourcesServiceNameResolver(context,
+ com.android.internal.R.string.config_defaultAppPredictionService), null);
+ }
+
+ @Override
+ protected AppPredictionPerUserService newServiceLocked(int resolvedUserId, boolean disabled) {
+ return new AppPredictionPerUserService(this, mLock, resolvedUserId);
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(APP_PREDICTION_SERVICE, new PredictionManagerServiceStub());
+ }
+
+ @Override
+ protected void enforceCallingPermissionForManagement() {
+ getContext().enforceCallingPermission(MANAGE_APP_PREDICTIONS, TAG);
+ }
+
+ @Override
+ protected int getMaximumTemporaryServiceDurationMs() {
+ return MAX_TEMP_SERVICE_DURATION_MS;
+ }
+
+ private class PredictionManagerServiceStub extends IPredictionManager.Stub {
+
+ @Override
+ public void createPredictionSession(@NonNull AppPredictionContext context,
+ @NonNull AppPredictionSessionId sessionId) {
+ runForUserLocked((service) ->
+ service.onCreatePredictionSessionLocked(context, sessionId));
+ }
+
+ @Override
+ public void notifyAppTargetEvent(@NonNull AppPredictionSessionId sessionId,
+ @NonNull AppTargetEvent event) {
+ runForUserLocked((service) -> service.notifyAppTargetEventLocked(sessionId, event));
+ }
+
+ @Override
+ public void notifyLocationShown(@NonNull AppPredictionSessionId sessionId,
+ @NonNull String launchLocation, @NonNull ParceledListSlice targetIds) {
+ runForUserLocked((service) ->
+ service.notifyLocationShownLocked(sessionId, launchLocation, targetIds));
+ }
+
+ @Override
+ public void sortAppTargets(@NonNull AppPredictionSessionId sessionId,
+ @NonNull ParceledListSlice targets,
+ IPredictionCallback callback) {
+ runForUserLocked((service) ->
+ service.sortAppTargetsLocked(sessionId, targets, callback));
+ }
+
+ @Override
+ public void registerPredictionUpdates(@NonNull AppPredictionSessionId sessionId,
+ @NonNull IPredictionCallback callback) {
+ runForUserLocked((service) ->
+ service.registerPredictionUpdatesLocked(sessionId, callback));
+ }
+
+ public void unregisterPredictionUpdates(@NonNull AppPredictionSessionId sessionId,
+ @NonNull IPredictionCallback callback) {
+ runForUserLocked((service) ->
+ service.unregisterPredictionUpdatesLocked(sessionId, callback));
+ }
+
+ @Override
+ public void requestPredictionUpdate(@NonNull AppPredictionSessionId sessionId) {
+ runForUserLocked((service) -> service.requestPredictionUpdateLocked(sessionId));
+ }
+
+ @Override
+ public void onDestroyPredictionSession(@NonNull AppPredictionSessionId sessionId) {
+ runForUserLocked((service) -> service.onDestroyPredictionSessionLocked(sessionId));
+ }
+
+ public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
+ @Nullable FileDescriptor err,
+ @NonNull String[] args, @Nullable ShellCallback callback,
+ @NonNull ResultReceiver resultReceiver) throws RemoteException {
+ new AppPredictionManagerServiceShellCommand(AppPredictionManagerService.this)
+ .exec(this, in, out, err, args, callback, resultReceiver);
+ }
+
+ private void runForUserLocked(@NonNull Consumer<AppPredictionPerUserService> c) {
+ final int userId = UserHandle.getCallingUserId();
+ // TODO(b/111701043): Determine what permission model we want for this
+ long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ final AppPredictionPerUserService service = getServiceForUserLocked(userId);
+ c.accept(service);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+ }
+}
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerServiceShellCommand.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerServiceShellCommand.java
new file mode 100644
index 0000000..ed7cc67
--- /dev/null
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerServiceShellCommand.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appprediction;
+
+import android.annotation.NonNull;
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+
+/**
+ * The shell command implementation for the AppPredictionManagerService.
+ */
+public class AppPredictionManagerServiceShellCommand extends ShellCommand {
+
+ private static final String TAG =
+ AppPredictionManagerServiceShellCommand.class.getSimpleName();
+
+ private final AppPredictionManagerService mService;
+
+ public AppPredictionManagerServiceShellCommand(@NonNull AppPredictionManagerService service) {
+ mService = service;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+ final PrintWriter pw = getOutPrintWriter();
+ switch (cmd) {
+ case "set": {
+ final String what = getNextArgRequired();
+ switch (what) {
+ case "temporary-service": {
+ final int userId = Integer.parseInt(getNextArgRequired());
+ String serviceName = getNextArg();
+ if (serviceName == null) {
+ mService.resetTemporaryService(userId);
+ return 0;
+ }
+ final int duration = Integer.parseInt(getNextArgRequired());
+ mService.setTemporaryService(userId, serviceName, duration);
+ pw.println("AppPredictionService temporarily set to " + serviceName
+ + " for " + duration + "ms");
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ return 0;
+ }
+
+ @Override
+ public void onHelp() {
+ try (PrintWriter pw = getOutPrintWriter()) {
+ pw.println("AppPredictionManagerService commands:");
+ pw.println(" help");
+ pw.println(" Prints this help text.");
+ pw.println("");
+ pw.println(" set temporary-service USER_ID [COMPONENT_NAME DURATION]");
+ pw.println(" Temporarily (for DURATION ms) changes the service implemtation.");
+ pw.println(" To reset, call with just the USER_ID argument.");
+ pw.println("");
+ }
+ }
+}
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
new file mode 100644
index 0000000..24d592c
--- /dev/null
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
@@ -0,0 +1,218 @@
+/*
+ * 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.appprediction;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppGlobals;
+import android.app.prediction.AppPredictionContext;
+import android.app.prediction.AppPredictionSessionId;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.IPredictionCallback;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.ServiceInfo;
+import android.os.RemoteException;
+import android.service.appprediction.AppPredictionService;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.infra.AbstractPerUserSystemService;
+
+/**
+ * Per-user instance of {@link AppPredictionManagerService}.
+ */
+public class AppPredictionPerUserService extends
+ AbstractPerUserSystemService<AppPredictionPerUserService, AppPredictionManagerService>
+ implements RemoteAppPredictionService.RemoteAppPredictionServiceCallbacks {
+
+ private static final String TAG = AppPredictionPerUserService.class.getSimpleName();
+
+ @Nullable
+ @GuardedBy("mLock")
+ private RemoteAppPredictionService mRemoteService;
+
+ protected AppPredictionPerUserService(AppPredictionManagerService master,
+ Object lock, int userId) {
+ super(master, lock, userId);
+ }
+
+ @Override // from PerUserSystemService
+ protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
+ throws NameNotFoundException {
+
+ ServiceInfo si;
+ try {
+ si = AppGlobals.getPackageManager().getServiceInfo(serviceComponent,
+ PackageManager.GET_META_DATA, mUserId);
+ } catch (RemoteException e) {
+ throw new NameNotFoundException("Could not get service for " + serviceComponent);
+ }
+ // TODO(b/111701043): must check that either the service is from a system component,
+ // or it matches a service set by shell cmd (so it can be used on CTS tests and when
+ // OEMs are implementing the real service and also verify the proper permissions
+ return si;
+ }
+
+ @GuardedBy("mLock")
+ @Override // from PerUserSystemService
+ protected boolean updateLocked(boolean disabled) {
+ final boolean enabledChanged = super.updateLocked(disabled);
+ if (enabledChanged) {
+ if (!isEnabledLocked()) {
+ // Clear the remote service for the next call
+ mRemoteService = null;
+ }
+ }
+ return enabledChanged;
+ }
+
+ /**
+ * Notifies the service of a new prediction session.
+ */
+ @GuardedBy("mLock")
+ public void onCreatePredictionSessionLocked(@NonNull AppPredictionContext context,
+ @NonNull AppPredictionSessionId sessionId) {
+ final RemoteAppPredictionService service = getRemoteServiceLocked();
+ if (service != null) {
+ service.onCreatePredictionSession(context, sessionId);
+ }
+ }
+
+ /**
+ * Records an app target event to the service.
+ */
+ @GuardedBy("mLock")
+ public void notifyAppTargetEventLocked(@NonNull AppPredictionSessionId sessionId,
+ @NonNull AppTargetEvent event) {
+ final RemoteAppPredictionService service = getRemoteServiceLocked();
+ if (service != null) {
+ service.notifyAppTargetEvent(sessionId, event);
+ }
+ }
+
+ /**
+ * Records when a launch location is shown.
+ */
+ @GuardedBy("mLock")
+ public void notifyLocationShownLocked(@NonNull AppPredictionSessionId sessionId,
+ @NonNull String launchLocation, @NonNull ParceledListSlice targetIds) {
+ final RemoteAppPredictionService service = getRemoteServiceLocked();
+ if (service != null) {
+ service.notifyLocationShown(sessionId, launchLocation, targetIds);
+ }
+ }
+
+ /**
+ * Requests the service to sort a list of apps or shortcuts.
+ */
+ @GuardedBy("mLock")
+ public void sortAppTargetsLocked(@NonNull AppPredictionSessionId sessionId,
+ @NonNull ParceledListSlice targets, @NonNull IPredictionCallback callback) {
+ final RemoteAppPredictionService service = getRemoteServiceLocked();
+ if (service != null) {
+ service.sortAppTargets(sessionId, targets, callback);
+ }
+ }
+
+ /**
+ * Registers a callback for continuous updates of predicted apps or shortcuts.
+ */
+ @GuardedBy("mLock")
+ public void registerPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
+ @NonNull IPredictionCallback callback) {
+ final RemoteAppPredictionService service = getRemoteServiceLocked();
+ if (service != null) {
+ service.registerPredictionUpdates(sessionId, callback);
+ }
+ }
+
+ /**
+ * Unregisters a callback for continuous updates of predicted apps or shortcuts.
+ */
+ @GuardedBy("mLock")
+ public void unregisterPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
+ @NonNull IPredictionCallback callback) {
+ final RemoteAppPredictionService service = getRemoteServiceLocked();
+ if (service != null) {
+ service.unregisterPredictionUpdates(sessionId, callback);
+ }
+ }
+
+ /**
+ * Requests a new set of predicted apps or shortcuts.
+ */
+ @GuardedBy("mLock")
+ public void requestPredictionUpdateLocked(@NonNull AppPredictionSessionId sessionId) {
+ final RemoteAppPredictionService service = getRemoteServiceLocked();
+ if (service != null) {
+ service.requestPredictionUpdate(sessionId);
+ }
+ }
+
+ /**
+ * Notifies the service of the end of an existing prediction session.
+ */
+ @GuardedBy("mLock")
+ public void onDestroyPredictionSessionLocked(@NonNull AppPredictionSessionId sessionId) {
+ final RemoteAppPredictionService service = getRemoteServiceLocked();
+ if (service != null) {
+ service.onDestroyPredictionSession(sessionId);
+ }
+ }
+
+ @Override
+ public void onFailureOrTimeout(boolean timedOut) {
+ if (isDebug()) {
+ Slog.d(TAG, "onFailureOrTimeout(): timed out=" + timedOut);
+ }
+
+ // Do nothing, we are just proxying to the prediction service
+ }
+
+ @Override
+ public void onServiceDied(RemoteAppPredictionService service) {
+ if (isDebug()) {
+ Slog.d(TAG, "onServiceDied():");
+ }
+
+ // Do nothing, we are just proxying to the prediction service
+ }
+
+ @GuardedBy("mLock")
+ @Nullable
+ private RemoteAppPredictionService getRemoteServiceLocked() {
+ if (mRemoteService == null) {
+ final String serviceName = getComponentNameLocked();
+ if (serviceName == null) {
+ if (mMaster.verbose) {
+ Slog.v(TAG, "getRemoteServiceLocked(): not set");
+ }
+ return null;
+ }
+ ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
+
+ mRemoteService = new RemoteAppPredictionService(getContext(),
+ AppPredictionService.SERVICE_INTERFACE, serviceComponent, mUserId, this,
+ mMaster.isBindInstantServiceAllowed(), mMaster.verbose);
+ }
+
+ return mRemoteService;
+ }
+}
diff --git a/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java b/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
new file mode 100644
index 0000000..45ea86f
--- /dev/null
+++ b/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
@@ -0,0 +1,142 @@
+/*
+ * 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.appprediction;
+
+import android.annotation.NonNull;
+import android.app.prediction.AppPredictionContext;
+import android.app.prediction.AppPredictionSessionId;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.IPredictionCallback;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ParceledListSlice;
+import android.os.IBinder;
+import android.service.appprediction.IPredictionService;
+import android.text.format.DateUtils;
+
+import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
+
+
+/**
+ * Proxy to the {@link android.service.appprediction.AppPredictionService} implemention in another
+ * process.
+ */
+public class RemoteAppPredictionService extends
+ AbstractMultiplePendingRequestsRemoteService<RemoteAppPredictionService,
+ IPredictionService> {
+
+ private static final String TAG = "RemoteAppPredictionService";
+
+ private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.SECOND_IN_MILLIS;
+
+ public RemoteAppPredictionService(Context context, String serviceInterface,
+ ComponentName componentName, int userId,
+ RemoteAppPredictionServiceCallbacks callback, boolean bindInstantServiceAllowed,
+ boolean verbose) {
+ super(context, serviceInterface, componentName, userId, callback, bindInstantServiceAllowed,
+ verbose, /* initialCapacity= */ 1);
+ }
+
+ @Override
+ protected IPredictionService getServiceInterface(IBinder service) {
+ return IPredictionService.Stub.asInterface(service);
+ }
+
+ @Override
+ protected long getTimeoutIdleBindMillis() {
+ return PERMANENT_BOUND_TIMEOUT_MS;
+ }
+
+ @Override
+ protected long getRemoteRequestMillis() {
+ return TIMEOUT_REMOTE_REQUEST_MILLIS;
+ }
+
+ /**
+ * Notifies the service of a new prediction session.
+ */
+ public void onCreatePredictionSession(@NonNull AppPredictionContext context,
+ @NonNull AppPredictionSessionId sessionId) {
+ scheduleAsyncRequest((s) -> s.onCreatePredictionSession(context, sessionId));
+ }
+
+ /**
+ * Records an app target event to the service.
+ */
+ public void notifyAppTargetEvent(@NonNull AppPredictionSessionId sessionId,
+ @NonNull AppTargetEvent event) {
+ scheduleAsyncRequest((s) -> s.notifyAppTargetEvent(sessionId, event));
+ }
+
+ /**
+ * Records when a launch location is shown.
+ */
+ public void notifyLocationShown(@NonNull AppPredictionSessionId sessionId,
+ @NonNull String launchLocation, @NonNull ParceledListSlice targetIds) {
+ scheduleAsyncRequest((s) -> s.notifyLocationShown(sessionId, launchLocation, targetIds));
+ }
+
+ /**
+ * Requests the service to sort a list of apps or shortcuts.
+ */
+ public void sortAppTargets(@NonNull AppPredictionSessionId sessionId,
+ @NonNull ParceledListSlice targets, @NonNull IPredictionCallback callback) {
+ scheduleAsyncRequest((s) -> s.sortAppTargets(sessionId, targets, callback));
+ }
+
+
+ /**
+ * Registers a callback for continuous updates of predicted apps or shortcuts.
+ */
+ public void registerPredictionUpdates(@NonNull AppPredictionSessionId sessionId,
+ @NonNull IPredictionCallback callback) {
+ scheduleAsyncRequest((s) -> s.registerPredictionUpdates(sessionId, callback));
+ }
+
+ /**
+ * Unregisters a callback for continuous updates of predicted apps or shortcuts.
+ */
+ public void unregisterPredictionUpdates(@NonNull AppPredictionSessionId sessionId,
+ @NonNull IPredictionCallback callback) {
+ scheduleAsyncRequest((s) -> s.unregisterPredictionUpdates(sessionId, callback));
+ }
+
+ /**
+ * Requests a new set of predicted apps or shortcuts.
+ */
+ public void requestPredictionUpdate(@NonNull AppPredictionSessionId sessionId) {
+ scheduleAsyncRequest((s) -> s.requestPredictionUpdate(sessionId));
+ }
+
+ /**
+ * Notifies the service of the end of an existing prediction session.
+ */
+ public void onDestroyPredictionSession(@NonNull AppPredictionSessionId sessionId) {
+ scheduleAsyncRequest((s) -> s.onDestroyPredictionSession(sessionId));
+ }
+
+ /**
+ * Failure callback
+ */
+ public interface RemoteAppPredictionServiceCallbacks
+ extends VultureCallback<RemoteAppPredictionService> {
+
+ /**
+ * Notifies a the failure or timeout of a remote call.
+ */
+ void onFailureOrTimeout(boolean timedOut);
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 34fe5d9..e8a52b4 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -139,9 +139,6 @@
if (mPendingRequest == pendingRequest) {
mPendingRequest = null;
}
- if (mPendingRequest == null) {
- scheduleUnbind();
- }
return true;
}
diff --git a/services/contentsuggestions/Android.bp b/services/contentsuggestions/Android.bp
new file mode 100644
index 0000000..fc09d2e
--- /dev/null
+++ b/services/contentsuggestions/Android.bp
@@ -0,0 +1,5 @@
+java_library_static {
+ name: "services.contentsuggestions",
+ srcs: ["java/**/*.java"],
+ libs: ["services.core"],
+}
\ No newline at end of file
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
new file mode 100644
index 0000000..58dbea4
--- /dev/null
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
@@ -0,0 +1,205 @@
+/*
+ * 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.contentsuggestions;
+
+import static android.Manifest.permission.MANAGE_CONTENT_SUGGESTIONS;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.IContentSuggestionsManager;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.content.Context;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import com.android.server.LocalServices;
+import com.android.server.infra.AbstractMasterSystemService;
+import com.android.server.infra.FrameworkResourcesServiceNameResolver;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
+import java.io.FileDescriptor;
+
+/**
+ * The system service for providing recents / overview with content suggestion selections and
+ * classifications.
+ *
+ * <p>Calls are received here from
+ * {@link android.app.contentsuggestions.ContentSuggestionsManager} then delegated to
+ * a per user version of the service. From there they are routed to the remote actual implementation
+ * that provides the suggestion selections and classifications.
+ */
+public class ContentSuggestionsManagerService extends
+ AbstractMasterSystemService<
+ ContentSuggestionsManagerService, ContentSuggestionsPerUserService> {
+
+ private static final String TAG = ContentSuggestionsManagerService.class.getSimpleName();
+ private static final boolean VERBOSE = false; // TODO: make dynamic
+
+ private static final int MAX_TEMP_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
+
+ private ActivityTaskManagerInternal mActivityTaskManagerInternal;
+
+ public ContentSuggestionsManagerService(Context context) {
+ super(context, new FrameworkResourcesServiceNameResolver(context,
+ com.android.internal.R.string.config_defaultContentSuggestionsService), null);
+ mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
+ }
+
+ @Override
+ protected ContentSuggestionsPerUserService newServiceLocked(int resolvedUserId,
+ boolean disabled) {
+ return new ContentSuggestionsPerUserService(this, mLock, resolvedUserId);
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(
+ Context.CONTENT_SUGGESTIONS_SERVICE, new ContentSuggestionsManagerStub());
+ }
+
+ @Override
+ protected void enforceCallingPermissionForManagement() {
+ getContext().enforceCallingPermission(MANAGE_CONTENT_SUGGESTIONS, TAG);
+ }
+
+ @Override
+ protected int getMaximumTemporaryServiceDurationMs() {
+ return MAX_TEMP_SERVICE_DURATION_MS;
+ }
+
+ private boolean isCallerRecents(int userId) {
+ if (mServiceNameResolver.isTemporary(userId)) {
+ // If a temporary service is set then skip the recents check
+ return true;
+ }
+ return mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid());
+ }
+
+ private void enforceCallerIsRecents(int userId, String func) {
+ if (isCallerRecents(userId)) {
+ return;
+ }
+
+ String msg = "Permission Denial: " + func + " from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ + " expected caller is recents";
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+
+ private class ContentSuggestionsManagerStub extends IContentSuggestionsManager.Stub {
+ @Override
+ public void provideContextImage(int taskId, @NonNull Bundle imageContextRequestExtras) {
+ if (imageContextRequestExtras == null) {
+ throw new IllegalArgumentException("Expected non-null imageContextRequestExtras");
+ }
+
+ final int userId = UserHandle.getCallingUserId();
+ enforceCallerIsRecents(userId, "provideContextImage");
+
+ synchronized (mLock) {
+ final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
+ if (service != null) {
+ service.provideContextImageLocked(taskId, imageContextRequestExtras);
+ } else {
+ if (VERBOSE) {
+ Slog.v(TAG, "provideContextImageLocked: no service for " + userId);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void suggestContentSelections(
+ @NonNull SelectionsRequest selectionsRequest,
+ @NonNull ISelectionsCallback selectionsCallback) {
+ final int userId = UserHandle.getCallingUserId();
+ enforceCallerIsRecents(userId, "suggestContentSelections");
+
+ synchronized (mLock) {
+ final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
+ if (service != null) {
+ service.suggestContentSelectionsLocked(selectionsRequest, selectionsCallback);
+ } else {
+ if (VERBOSE) {
+ Slog.v(TAG, "suggestContentSelectionsLocked: no service for " + userId);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void classifyContentSelections(
+ @NonNull ClassificationsRequest classificationsRequest,
+ @NonNull IClassificationsCallback callback) {
+ final int userId = UserHandle.getCallingUserId();
+ enforceCallerIsRecents(userId, "classifyContentSelections");
+
+ synchronized (mLock) {
+ final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
+ if (service != null) {
+ service.classifyContentSelectionsLocked(classificationsRequest, callback);
+ } else {
+ if (VERBOSE) {
+ Slog.v(TAG, "classifyContentSelectionsLocked: no service for " + userId);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void notifyInteraction(@NonNull String requestId, @NonNull Bundle bundle) {
+ final int userId = UserHandle.getCallingUserId();
+ enforceCallerIsRecents(userId, "notifyInteraction");
+
+ synchronized (mLock) {
+ final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
+ if (service != null) {
+ service.notifyInteractionLocked(requestId, bundle);
+ } else {
+ if (VERBOSE) {
+ Slog.v(TAG, "reportInteractionLocked: no service for " + userId);
+ }
+ }
+ }
+ }
+
+ public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
+ @Nullable FileDescriptor err,
+ @NonNull String[] args, @Nullable ShellCallback callback,
+ @NonNull ResultReceiver resultReceiver) throws RemoteException {
+ // Ensure that the caller is the shell process
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid != android.os.Process.SHELL_UID
+ && callingUid != android.os.Process.ROOT_UID) {
+ Slog.e(TAG, "Expected shell caller");
+ return;
+ }
+ new ContentSuggestionsManagerServiceShellCommand(ContentSuggestionsManagerService.this)
+ .exec(this, in, out, err, args, callback, resultReceiver);
+ }
+ }
+}
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerServiceShellCommand.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerServiceShellCommand.java
new file mode 100644
index 0000000..e34f1ea
--- /dev/null
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerServiceShellCommand.java
@@ -0,0 +1,84 @@
+/*
+ * 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.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+
+/**
+ * The shell command implementation for the ContentSuggestionsManagerService.
+ */
+public class ContentSuggestionsManagerServiceShellCommand extends ShellCommand {
+
+ private static final String TAG =
+ ContentSuggestionsManagerServiceShellCommand.class.getSimpleName();
+
+ private final ContentSuggestionsManagerService mService;
+
+ public ContentSuggestionsManagerServiceShellCommand(
+ @NonNull ContentSuggestionsManagerService service) {
+ mService = service;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+ final PrintWriter pw = getOutPrintWriter();
+ switch (cmd) {
+ case "set": {
+ final String what = getNextArgRequired();
+ switch (what) {
+ case "temporary-service": {
+ final int userId = Integer.parseInt(getNextArgRequired());
+ String serviceName = getNextArg();
+ if (serviceName == null) {
+ mService.resetTemporaryService(userId);
+ return 0;
+ }
+ final int duration = Integer.parseInt(getNextArgRequired());
+ mService.setTemporaryService(userId, serviceName, duration);
+ pw.println("ContentSuggestionsService temporarily set to " + serviceName
+ + " for " + duration + "ms");
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ return 0;
+ }
+
+ @Override
+ public void onHelp() {
+ try (PrintWriter pw = getOutPrintWriter()) {
+ pw.println("ContentSuggestionsManagerService commands:");
+ pw.println(" help");
+ pw.println(" Prints this help text.");
+ pw.println("");
+ pw.println(" set temporary-service USER_ID [COMPONENT_NAME DURATION]");
+ pw.println(" Temporarily (for DURATION ms) changes the service implemtation.");
+ pw.println(" To reset, call with just the USER_ID argument.");
+ pw.println("");
+ }
+ }
+}
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java
new file mode 100644
index 0000000..385bc6c
--- /dev/null
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java
@@ -0,0 +1,162 @@
+/*
+ * 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.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.AppGlobals;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.graphics.GraphicBuffer;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
+import com.android.server.infra.AbstractPerUserSystemService;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
+/**
+ * Per user delegate of {@link ContentSuggestionsManagerService}.
+ *
+ * <p>Main job is to forward calls to the remote implementation that can provide suggestion
+ * selections and classifications.
+ */
+public final class ContentSuggestionsPerUserService extends
+ AbstractPerUserSystemService<
+ ContentSuggestionsPerUserService, ContentSuggestionsManagerService> {
+ private static final String TAG = ContentSuggestionsPerUserService.class.getSimpleName();
+
+ @Nullable
+ @GuardedBy("mLock")
+ private RemoteContentSuggestionsService mRemoteService;
+
+ @NonNull
+ private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
+
+ ContentSuggestionsPerUserService(
+ ContentSuggestionsManagerService master, Object lock, int userId) {
+ super(master, lock, userId);
+ mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
+ }
+
+ @GuardedBy("mLock")
+ @Override // from PerUserSystemService
+ protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
+ throws PackageManager.NameNotFoundException {
+ ServiceInfo si;
+ try {
+ si = AppGlobals.getPackageManager().getServiceInfo(serviceComponent,
+ PackageManager.GET_META_DATA, mUserId);
+ } catch (RemoteException e) {
+ throw new PackageManager.NameNotFoundException(
+ "Could not get service for " + serviceComponent);
+ }
+ return si;
+ }
+
+ @GuardedBy("mLock")
+ @Override // from PerUserSystemService
+ protected boolean updateLocked(boolean disabled) {
+ final boolean enabledChanged = super.updateLocked(disabled);
+ if (enabledChanged) {
+ if (!isEnabledLocked()) {
+ // Clear the remote service for the next call
+ mRemoteService = null;
+ }
+ }
+ return enabledChanged;
+ }
+
+ @GuardedBy("mLock")
+ void provideContextImageLocked(int taskId, @NonNull Bundle imageContextRequestExtras) {
+ RemoteContentSuggestionsService service = getRemoteServiceLocked();
+ if (service != null) {
+ ActivityManager.TaskSnapshot snapshot =
+ mActivityTaskManagerInternal.getTaskSnapshot(taskId, false);
+ GraphicBuffer snapshotBuffer = null;
+ if (snapshot != null) {
+ snapshotBuffer = snapshot.getSnapshot();
+ }
+
+ service.provideContextImage(taskId, snapshotBuffer, imageContextRequestExtras);
+ }
+ }
+
+ @GuardedBy("mLock")
+ void suggestContentSelectionsLocked(
+ @NonNull SelectionsRequest selectionsRequest,
+ @NonNull ISelectionsCallback selectionsCallback) {
+ RemoteContentSuggestionsService service = getRemoteServiceLocked();
+ if (service != null) {
+ service.suggestContentSelections(selectionsRequest, selectionsCallback);
+ }
+ }
+
+ @GuardedBy("mLock")
+ void classifyContentSelectionsLocked(
+ @NonNull ClassificationsRequest classificationsRequest,
+ @NonNull IClassificationsCallback callback) {
+ RemoteContentSuggestionsService service = getRemoteServiceLocked();
+ if (service != null) {
+ service.classifyContentSelections(classificationsRequest, callback);
+ }
+ }
+
+ @GuardedBy("mLock")
+ void notifyInteractionLocked(@NonNull String requestId, @NonNull Bundle bundle) {
+ RemoteContentSuggestionsService service = getRemoteServiceLocked();
+ if (service != null) {
+ service.notifyInteraction(requestId, bundle);
+ }
+ }
+
+ @GuardedBy("mLock")
+ @Nullable
+ private RemoteContentSuggestionsService getRemoteServiceLocked() {
+ if (mRemoteService == null) {
+ final String serviceName = getComponentNameLocked();
+ if (serviceName == null) {
+ if (mMaster.verbose) {
+ Slog.v(TAG, "getRemoteServiceLocked(): not set");
+ }
+ return null;
+ }
+ ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
+
+ mRemoteService = new RemoteContentSuggestionsService(getContext(),
+ serviceComponent, mUserId,
+ new RemoteContentSuggestionsService.Callbacks() {
+ @Override
+ public void onServiceDied(
+ @NonNull RemoteContentSuggestionsService service) {
+ // TODO(b/120865921): properly implement
+ Slog.w(TAG, "remote content suggestions service died");
+ }
+ }, mMaster.isBindInstantServiceAllowed(), mMaster.verbose);
+ }
+
+ return mRemoteService;
+ }
+}
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/RemoteContentSuggestionsService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/RemoteContentSuggestionsService.java
new file mode 100644
index 0000000..bf48d76
--- /dev/null
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/RemoteContentSuggestionsService.java
@@ -0,0 +1,97 @@
+/*
+ * 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.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.content.ComponentName;
+import android.content.Context;
+import android.graphics.GraphicBuffer;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.service.contentsuggestions.ContentSuggestionsService;
+import android.service.contentsuggestions.IContentSuggestionsService;
+import android.text.format.DateUtils;
+
+import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
+
+/**
+ * Delegates calls from {@link ContentSuggestionsPerUserService} to the remote actual implementation
+ * of the suggestion selection and classification service.
+ */
+public class RemoteContentSuggestionsService extends
+ AbstractMultiplePendingRequestsRemoteService<RemoteContentSuggestionsService,
+ IContentSuggestionsService> {
+
+ private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.SECOND_IN_MILLIS;
+
+ RemoteContentSuggestionsService(Context context, ComponentName serviceName,
+ int userId, Callbacks callbacks,
+ boolean bindInstantServiceAllowed, boolean verbose) {
+ super(context, ContentSuggestionsService.SERVICE_INTERFACE, serviceName, userId, callbacks,
+ bindInstantServiceAllowed, verbose, /* initialCapacity= */ 1);
+ }
+
+ @Override
+ protected IContentSuggestionsService getServiceInterface(IBinder service) {
+ return IContentSuggestionsService.Stub.asInterface(service);
+ }
+
+ @Override
+ protected long getTimeoutIdleBindMillis() {
+ return PERMANENT_BOUND_TIMEOUT_MS;
+ }
+
+ @Override
+ protected long getRemoteRequestMillis() {
+ return TIMEOUT_REMOTE_REQUEST_MILLIS;
+ }
+
+ void provideContextImage(int taskId, @Nullable GraphicBuffer contextImage,
+ @NonNull Bundle imageContextRequestExtras) {
+ scheduleAsyncRequest((s) -> s.provideContextImage(taskId, contextImage,
+ imageContextRequestExtras));
+ }
+
+ void suggestContentSelections(
+ @NonNull SelectionsRequest selectionsRequest,
+ @NonNull ISelectionsCallback selectionsCallback) {
+ scheduleAsyncRequest(
+ (s) -> s.suggestContentSelections(selectionsRequest, selectionsCallback));
+ }
+
+ void classifyContentSelections(
+ @NonNull ClassificationsRequest classificationsRequest,
+ @NonNull IClassificationsCallback callback) {
+ scheduleAsyncRequest((s) -> s.classifyContentSelections(classificationsRequest, callback));
+ }
+
+ void notifyInteraction(@NonNull String requestId, @NonNull Bundle bundle) {
+ scheduleAsyncRequest((s) -> s.notifyInteraction(requestId, bundle));
+ }
+
+ interface Callbacks
+ extends VultureCallback<RemoteContentSuggestionsService> {
+ // NOTE: so far we don't need to notify the callback implementation
+ // (ContentSuggestionsManager) of the request results (success, timeouts, etc..), so this
+ // callback interface is empty.
+ }
+}
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index ea80ac1..80fda19 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -16,6 +16,22 @@
package com.android.server;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.FastImmutableArraySet;
+import android.util.Log;
+import android.util.LogPrinter;
+import android.util.MutableInt;
+import android.util.PrintWriterPrinter;
+import android.util.Printer;
+import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.util.FastPrintWriter;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -25,23 +41,6 @@
import java.util.List;
import java.util.Set;
-import android.net.Uri;
-import android.util.FastImmutableArraySet;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Log;
-import android.util.MutableInt;
-import android.util.PrintWriterPrinter;
-import android.util.Slog;
-import android.util.LogPrinter;
-import android.util.Printer;
-
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.util.proto.ProtoOutputStream;
-
-import com.android.internal.util.FastPrintWriter;
-
/**
* {@hide}
*/
@@ -788,6 +787,7 @@
+ filter.hasCategory(Intent.CATEGORY_DEFAULT));
if (!defaultOnly || filter.hasCategory(Intent.CATEGORY_DEFAULT)) {
final R oneResult = newResult(filter, match, userId);
+ if (debug) Slog.v(TAG, " Created result: " + oneResult);
if (oneResult != null) {
dest.add(oneResult);
if (debug) {
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index f27d373..8adc416 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.annotation.Nullable;
import android.content.Context;
import android.os.Environment;
import android.os.Handler;
@@ -29,6 +30,7 @@
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
@@ -46,8 +48,10 @@
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import java.util.Set;
/**
* Monitors the health of packages on the system and notifies interested observers when packages
@@ -58,7 +62,7 @@
// Duration to count package failures before it resets to 0
private static final int TRIGGER_DURATION_MS = 60000;
// Number of package failures within the duration above before we notify observers
- private static final int TRIGGER_FAILURE_COUNT = 5;
+ static final int TRIGGER_FAILURE_COUNT = 5;
private static final int DB_VERSION = 1;
private static final String TAG_PACKAGE_WATCHDOG = "package-watchdog";
private static final String TAG_PACKAGE = "package";
@@ -75,20 +79,13 @@
// Handler to run package cleanup runnables
private final Handler mTimerHandler;
private final Handler mIoHandler;
- // Contains (observer-name -> external-observer-handle) that have been registered during the
- // current boot.
- // It is populated when observers call #registerHealthObserver and it does not survive reboots.
- @GuardedBy("mLock")
- final ArrayMap<String, PackageHealthObserver> mRegisteredObservers = new ArrayMap<>();
- // Contains (observer-name -> internal-observer-handle) that have ever been registered from
+ // Contains (observer-name -> observer-handle) that have ever been registered from
// previous boots. Observers with all packages expired are periodically pruned.
// It is saved to disk on system shutdown and repouplated on startup so it survives reboots.
@GuardedBy("mLock")
- final ArrayMap<String, ObserverInternal> mAllObservers = new ArrayMap<>();
+ private final ArrayMap<String, ObserverInternal> mAllObservers = new ArrayMap<>();
// File containing the XML data of monitored packages /data/system/package-watchdog.xml
- private final AtomicFile mPolicyFile =
- new AtomicFile(new File(new File(Environment.getDataDirectory(), "system"),
- "package-watchdog.xml"));
+ private final AtomicFile mPolicyFile;
// Runnable to prune monitored packages that have expired
private final Runnable mPackageCleanup;
// Last SystemClock#uptimeMillis a package clean up was executed.
@@ -98,14 +95,32 @@
// 0 if mPackageCleanup not running.
private long mDurationAtLastReschedule;
+ // TODO(zezeozue): Remove redundant context param
private PackageWatchdog(Context context) {
mContext = context;
+ mPolicyFile = new AtomicFile(new File(new File(Environment.getDataDirectory(), "system"),
+ "package-watchdog.xml"));
mTimerHandler = new Handler(Looper.myLooper());
mIoHandler = BackgroundThread.getHandler();
mPackageCleanup = this::rescheduleCleanup;
loadFromFile();
}
+ /**
+ * Creates a PackageWatchdog for testing that uses the same {@code looper} for all handlers
+ * and creates package-watchdog.xml in an apps data directory.
+ */
+ @VisibleForTesting
+ PackageWatchdog(Context context, Looper looper) {
+ mContext = context;
+ mPolicyFile = new AtomicFile(new File(context.getFilesDir(), "package-watchdog.xml"));
+ mTimerHandler = new Handler(looper);
+ mIoHandler = mTimerHandler;
+ mPackageCleanup = this::rescheduleCleanup;
+ loadFromFile();
+ }
+
+
/** Creates or gets singleton instance of PackageWatchdog. */
public static PackageWatchdog getInstance(Context context) {
synchronized (PackageWatchdog.class) {
@@ -124,7 +139,10 @@
*/
public void registerHealthObserver(PackageHealthObserver observer) {
synchronized (mLock) {
- mRegisteredObservers.put(observer.getName(), observer);
+ ObserverInternal internalObserver = mAllObservers.get(observer.getName());
+ if (internalObserver != null) {
+ internalObserver.mRegisteredObserver = observer;
+ }
if (mDurationAtLastReschedule == 0) {
// Nothing running, schedule
rescheduleCleanup();
@@ -143,7 +161,7 @@
* or {@code durationMs} is less than 1
*/
public void startObservingHealth(PackageHealthObserver observer, List<String> packageNames,
- int durationMs) {
+ long durationMs) {
if (packageNames.isEmpty() || durationMs < 1) {
throw new IllegalArgumentException("Observation not started, no packages specified"
+ "or invalid duration");
@@ -180,11 +198,32 @@
public void unregisterHealthObserver(PackageHealthObserver observer) {
synchronized (mLock) {
mAllObservers.remove(observer.getName());
- mRegisteredObservers.remove(observer.getName());
}
saveToFileAsync();
}
+ /**
+ * Returns packages observed by {@code observer}
+ *
+ * @return an empty set if {@code observer} has some packages observerd from a previous boot
+ * but has not registered itself in the current boot to receive notifications. Returns null
+ * if there are no active packages monitored from any boot.
+ */
+ @Nullable
+ public Set<String> getPackages(PackageHealthObserver observer) {
+ synchronized (mLock) {
+ for (int i = 0; i < mAllObservers.size(); i++) {
+ if (observer.getName().equals(mAllObservers.keyAt(i))) {
+ if (observer.equals(mAllObservers.valueAt(i).mRegisteredObserver)) {
+ return mAllObservers.valueAt(i).mPackages.keySet();
+ }
+ return Collections.emptySet();
+ }
+ }
+ }
+ return null;
+ }
+
// TODO(zezeozue:) Accept current versionCodes of failing packages?
/**
* Called when a process fails either due to a crash or ANR.
@@ -198,24 +237,23 @@
public void onPackageFailure(String[] packages) {
ArrayMap<String, List<PackageHealthObserver>> packagesToReport = new ArrayMap<>();
synchronized (mLock) {
- if (mRegisteredObservers.isEmpty()) {
+ if (mAllObservers.isEmpty()) {
return;
}
for (int pIndex = 0; pIndex < packages.length; pIndex++) {
+ // Observers interested in receiving packageName failures
+ List<PackageHealthObserver> observersToNotify = new ArrayList<>();
for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
- // Observers interested in receiving packageName failures
- List<PackageHealthObserver> observersToNotify = new ArrayList<>();
- PackageHealthObserver activeObserver =
- mRegisteredObservers.get(mAllObservers.valueAt(oIndex).mName);
- if (activeObserver != null) {
- observersToNotify.add(activeObserver);
+ PackageHealthObserver registeredObserver =
+ mAllObservers.valueAt(oIndex).mRegisteredObserver;
+ if (registeredObserver != null) {
+ observersToNotify.add(registeredObserver);
}
-
- // Save interested observers and notify them outside the lock
- if (!observersToNotify.isEmpty()) {
- packagesToReport.put(packages[pIndex], observersToNotify);
- }
+ }
+ // Save interested observers and notify them outside the lock
+ if (!observersToNotify.isEmpty()) {
+ packagesToReport.put(packages[pIndex], observersToNotify);
}
}
}
@@ -223,8 +261,11 @@
// Notify observers
for (int pIndex = 0; pIndex < packagesToReport.size(); pIndex++) {
List<PackageHealthObserver> observers = packagesToReport.valueAt(pIndex);
+ String packageName = packages[pIndex];
for (int oIndex = 0; oIndex < observers.size(); oIndex++) {
- if (observers.get(oIndex).onHealthCheckFailed(packages[pIndex])) {
+ PackageHealthObserver observer = observers.get(oIndex);
+ if (mAllObservers.get(observer.getName()).onPackageFailure(packageName)
+ && observer.onHealthCheckFailed(packageName)) {
// Observer has handled, do not notify others
break;
}
@@ -275,10 +316,12 @@
// O if mPackageCleanup not running
long elapsedDurationMs = mUptimeAtLastRescheduleMs == 0
? 0 : uptimeMs - mUptimeAtLastRescheduleMs;
- // O if mPackageCleanup not running
+ // Less than O if mPackageCleanup unexpectedly didn't run yet even though
+ // and we are past the last duration scheduled to run
long remainingDurationMs = mDurationAtLastReschedule - elapsedDurationMs;
-
- if (mUptimeAtLastRescheduleMs == 0 || nextDurationToScheduleMs < remainingDurationMs) {
+ if (mUptimeAtLastRescheduleMs == 0
+ || remainingDurationMs <= 0
+ || nextDurationToScheduleMs < remainingDurationMs) {
// First schedule or an earlier reschedule
pruneObservers(elapsedDurationMs);
mTimerHandler.removeCallbacks(mPackageCleanup);
@@ -305,6 +348,7 @@
}
}
Slog.v(TAG, "Earliest package time is " + shortestDurationMs);
+
return shortestDurationMs;
}
@@ -409,6 +453,8 @@
static class ObserverInternal {
public final String mName;
public final ArrayMap<String, MonitoredPackage> mPackages;
+ @Nullable
+ public PackageHealthObserver mRegisteredObserver;
ObserverInternal(String name, List<MonitoredPackage> packages) {
mName = name;
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
new file mode 100644
index 0000000..93e1dd3
--- /dev/null
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksMockingServicesTests",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "android.support.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index faca750..ea6d435 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -141,6 +141,7 @@
private boolean mLowPowerMode;
private int mHapticFeedbackIntensity;
private int mNotificationIntensity;
+ private int mRingIntensity;
native static boolean vibratorExists();
native static void vibratorInit();
@@ -428,6 +429,10 @@
Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY),
true, mSettingObserver, UserHandle.USER_ALL);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY),
+ true, mSettingObserver, UserHandle.USER_ALL);
+
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -748,7 +753,9 @@
}
private int getCurrentIntensityLocked(Vibration vib) {
- if (vib.isNotification() || vib.isRingtone()){
+ if (vib.isRingtone()) {
+ return mRingIntensity;
+ } else if (vib.isNotification()) {
return mNotificationIntensity;
} else if (vib.isHapticFeedback()) {
return mHapticFeedbackIntensity;
@@ -770,7 +777,9 @@
}
final int defaultIntensity;
- if (vib.isNotification() || vib.isRingtone()) {
+ if (vib.isRingtone()) {
+ defaultIntensity = mVibrator.getDefaultRingVibrationIntensity();
+ } else if (vib.isNotification()) {
defaultIntensity = mVibrator.getDefaultNotificationVibrationIntensity();
} else if (vib.isHapticFeedback()) {
defaultIntensity = mVibrator.getDefaultHapticFeedbackIntensity();
@@ -933,6 +942,9 @@
mNotificationIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
mVibrator.getDefaultNotificationVibrationIntensity(), UserHandle.USER_CURRENT);
+ mRingIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.RING_VIBRATION_INTENSITY,
+ mVibrator.getDefaultRingVibrationIntensity(), UserHandle.USER_CURRENT);
}
@Override
@@ -1281,6 +1293,7 @@
pw.println(" mLowPowerMode=" + mLowPowerMode);
pw.println(" mHapticFeedbackIntensity=" + mHapticFeedbackIntensity);
pw.println(" mNotificationIntensity=" + mNotificationIntensity);
+ pw.println(" mRingIntensity=" + mRingIntensity);
pw.println("");
pw.println(" Previous vibrations:");
for (VibrationInfo info : mPreviousVibrations) {
diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java
index e5ab8fc..c316915 100644
--- a/services/core/java/com/android/server/adb/AdbService.java
+++ b/services/core/java/com/android/server/adb/AdbService.java
@@ -31,6 +31,7 @@
import android.os.SystemProperties;
import android.provider.Settings;
import android.service.adb.AdbServiceDumpProto;
+import android.sysprop.AdbProperties;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
@@ -185,7 +186,7 @@
mContext = context;
mContentResolver = context.getContentResolver();
- boolean secureAdbEnabled = SystemProperties.getBoolean("ro.adb.secure", false);
+ boolean secureAdbEnabled = AdbProperties.secure().orElse(false);
boolean dataEncrypted = "1".equals(SystemProperties.get("vold.decrypt"));
if (secureAdbEnabled && !dataEncrypted) {
mDebuggingManager = new AdbDebuggingManager(context);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index ed39d83..bab9a65 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -130,6 +130,9 @@
// calling startForeground() before we ANR + stop it.
static final int SERVICE_START_FOREGROUND_TIMEOUT = 10*1000;
+ // For how long after a whitelisted service's start its process can start a background activity
+ private static final int SERVICE_BG_ACTIVITY_START_TIMEOUT_MS = 10*1000;
+
final ActivityManagerService mAm;
// Maximum number of services that we allow to start in the background
@@ -398,6 +401,14 @@
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
throws TransactionTooLargeException {
+ return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired,
+ callingPackage, userId, false);
+ }
+
+ ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
+ int callingPid, int callingUid, boolean fgRequired, String callingPackage,
+ final int userId, boolean allowBackgroundActivityStarts)
+ throws TransactionTooLargeException {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
+ " type=" + resolvedType + " args=" + service.getExtras());
@@ -622,10 +633,28 @@
}
}
+ if (allowBackgroundActivityStarts) {
+ ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
+ if (proc != null) {
+ proc.addAllowBackgroundActivityStartsToken(r);
+ // schedule removal of the whitelisting token after the timeout
+ removeAllowBackgroundActivityStartsServiceToken(proc, r,
+ SERVICE_BG_ACTIVITY_START_TIMEOUT_MS);
+ }
+ }
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;
}
+ private void removeAllowBackgroundActivityStartsServiceToken(ProcessRecord proc,
+ ServiceRecord r, int delayMillis) {
+ mAm.mHandler.postDelayed(() -> {
+ if (proc != null) {
+ proc.removeAllowBackgroundActivityStartsToken(r);
+ }
+ }, delayMillis);
+ }
+
private boolean requestStartTargetPermissionsReviewIfNeededLocked(ServiceRecord r,
String callingPackage, int callingUid, Intent service, boolean callerFg,
final int userId) {
@@ -752,6 +781,9 @@
if (r.record != null) {
final long origId = Binder.clearCallingIdentity();
try {
+ // immediately remove bg activity whitelisting token if there was one
+ removeAllowBackgroundActivityStartsServiceToken(callerApp, r.record,
+ 0 /* delayMillis */);
stopServiceLocked(r.record);
} finally {
Binder.restoreCallingIdentity(origId);
@@ -1654,6 +1686,10 @@
}
}
+ if ((flags & Context.BIND_RESTRICT_ASSOCIATIONS) != 0) {
+ mAm.requireAllowedAssociationsLocked(s.appInfo.packageName);
+ }
+
mAm.startAssociationLocked(callerApp.uid, callerApp.processName,
callerApp.getCurProcState(), s.appInfo.uid, s.appInfo.longVersionCode,
s.instanceName, s.processName);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7f67230..26141f7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -329,7 +329,7 @@
import com.android.internal.util.function.QuadFunction;
import com.android.internal.util.function.TriFunction;
import com.android.server.AlarmManagerInternal;
-import com.android.server.AppOpsService;
+import com.android.server.appop.AppOpsService;
import com.android.server.AttributeCache;
import com.android.server.DeviceIdleController;
import com.android.server.DisplayThread;
@@ -2431,6 +2431,20 @@
}
/**
+ * Ensures that the given package name has an explicit set of allowed associations.
+ * If it does not, give it an empty set.
+ */
+ void requireAllowedAssociationsLocked(String packageName) {
+ if (mAllowedAssociations == null) {
+ mAllowedAssociations = new ArrayMap<>(
+ SystemConfig.getInstance().getAllowedAssociations());
+ }
+ if (mAllowedAssociations.get(packageName) == null) {
+ mAllowedAssociations.put(packageName, new ArraySet<>());
+ }
+ }
+
+ /**
* Returns true if the package {@code pkg1} running under user handle {@code uid1} is
* allowed association with the package {@code pkg2} running under user handle {@code uid2}.
* <p> If either of the packages are running as part of the core system, then the
@@ -2438,7 +2452,8 @@
*/
boolean validateAssociationAllowedLocked(String pkg1, int uid1, String pkg2, int uid2) {
if (mAllowedAssociations == null) {
- mAllowedAssociations = SystemConfig.getInstance().getAllowedAssociations();
+ mAllowedAssociations = new ArrayMap<>(
+ SystemConfig.getInstance().getAllowedAssociations());
}
// Interactions with the system uid are always allowed, since that is the core system
// that everyone needs to be able to interact with. Also allow reflexive associations
@@ -19480,8 +19495,8 @@
@Override
public ComponentName startServiceInPackage(int uid, Intent service, String resolvedType,
- boolean fgRequired, String callingPackage, int userId)
- throws TransactionTooLargeException {
+ boolean fgRequired, String callingPackage, int userId,
+ boolean allowBackgroundActivityStarts) throws TransactionTooLargeException {
synchronized(ActivityManagerService.this) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"startServiceInPackage: " + service + " type=" + resolvedType);
@@ -19489,7 +19504,8 @@
ComponentName res;
try {
res = mServices.startServiceLocked(null, service,
- resolvedType, -1, uid, fgRequired, callingPackage, userId);
+ resolvedType, -1, uid, fgRequired, callingPackage, userId,
+ allowBackgroundActivityStarts);
} finally {
Binder.restoreCallingIdentity(origId);
}
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index b675d9d..98c9ad6 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -51,6 +51,7 @@
public static final int FLAG_ACTIVITY_SENDER = 1 << 0;
public static final int FLAG_BROADCAST_SENDER = 1 << 1;
+ public static final int FLAG_SERVICE_SENDER = 1 << 2;
final PendingIntentController controller;
final Key key;
@@ -62,6 +63,7 @@
private RemoteCallbackList<IResultReceiver> mCancelCallbacks;
private ArraySet<IBinder> mAllowBgActivityStartsForActivitySender = new ArraySet<>();
private ArraySet<IBinder> mAllowBgActivityStartsForBroadcastSender = new ArraySet<>();
+ private ArraySet<IBinder> mAllowBgActivityStartsForServiceSender = new ArraySet<>();
String stringName;
String lastTagPrefix;
@@ -228,6 +230,9 @@
if ((flags & FLAG_BROADCAST_SENDER) != 0) {
mAllowBgActivityStartsForBroadcastSender.add(token);
}
+ if ((flags & FLAG_SERVICE_SENDER) != 0) {
+ mAllowBgActivityStartsForServiceSender.add(token);
+ }
}
public void registerCancelListenerLocked(IResultReceiver receiver) {
@@ -426,7 +431,8 @@
try {
controller.mAmInternal.startServiceInPackage(uid, finalIntent, resolvedType,
key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE,
- key.packageName, userId);
+ key.packageName, userId,
+ mAllowBgActivityStartsForServiceSender.contains(whitelistToken));
} catch (RuntimeException e) {
Slog.w(TAG, "Unable to send startService intent", e);
} catch (TransactionTooLargeException e) {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 0d0824a..054c830 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1142,11 +1142,13 @@
}
void addAllowBackgroundActivityStartsToken(Binder entity) {
+ if (entity == null) return;
mAllowBackgroundActivityStartsTokens.add(entity);
mWindowProcessController.setAllowBackgroundActivityStarts(true);
}
void removeAllowBackgroundActivityStartsToken(Binder entity) {
+ if (entity == null) return;
mAllowBackgroundActivityStartsTokens.remove(entity);
mWindowProcessController.setAllowBackgroundActivityStarts(
!mAllowBackgroundActivityStartsTokens.isEmpty());
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
similarity index 95%
rename from services/core/java/com/android/server/AppOpsService.java
rename to services/core/java/com/android/server/appop/AppOpsService.java
index 466fb4e..7ede6dc 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.appop;
import static android.app.AppOpsManager.OP_PLAY_AUDIO;
+import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
import static android.app.AppOpsManager.UID_STATE_CACHED;
import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
@@ -35,8 +36,7 @@
import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.AppOpsManager;
-import android.app.AppOpsManager.HistoricalOpEntry;
-import android.app.AppOpsManager.HistoricalPackageOps;
+import android.app.AppOpsManager.HistoricalOps;
import android.app.AppOpsManagerInternal;
import android.app.AppOpsManagerInternal.CheckOpsDelegate;
import android.content.BroadcastReceiver;
@@ -48,7 +48,6 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
-import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.media.AudioAttributes;
@@ -59,6 +58,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Process;
+import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -95,6 +95,8 @@
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.LocalServices;
+import com.android.server.LockGuard;
import libcore.util.EmptyArray;
import org.xmlpull.v1.XmlPullParser;
@@ -213,6 +215,8 @@
@VisibleForTesting
final SparseArray<UidState> mUidStates = new SparseArray<>();
+ private final HistoricalRegistry mHistoricalRegistry = new HistoricalRegistry(this);
+
long mLastRealtime;
/*
@@ -654,6 +658,7 @@
public void systemReady() {
mConstants.startMonitoring(mContext.getContentResolver());
+ mHistoricalRegistry.systemReady(mContext.getContentResolver());
synchronized (this) {
boolean changed = false;
@@ -1012,113 +1017,99 @@
}
@Override
- public @Nullable ParceledListSlice getAllHistoricalPackagesOps(@Nullable String[] opNames,
- long beginTimeMillis, long endTimeMillis) {
+ public void getHistoricalOps(int uid, @NonNull String packageName,
+ @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+ @NonNull RemoteCallback callback) {
+ Preconditions.checkArgument(uid == Process.INVALID_UID || uid >= 0,
+ "uid must be " + Process.INVALID_UID + " or non negative");
Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
"beginTimeMillis must be non negative and lesser than endTimeMillis");
+ Preconditions.checkNotNull(callback, "callback cannot be null");
+ checkValidOpsOrNull(opNames);
mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
- Binder.getCallingPid(), Binder.getCallingUid(), "getAllHistoricalPackagesOps");
+ Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
- ArrayList<HistoricalPackageOps> historicalPackageOpsList = null;
-
- final int uidStateCount = mUidStates.size();
- for (int i = 0; i < uidStateCount; i++) {
- final UidState uidState = mUidStates.valueAt(i);
- if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
- continue;
- }
- final ArrayMap<String, Ops> packages = uidState.pkgOps;
- final int packageCount = packages.size();
- for (int j = 0; j < packageCount; j++) {
- final Ops pkgOps = packages.valueAt(j);
- final AppOpsManager.HistoricalPackageOps historicalPackageOps =
- createHistoricalPackageOps(uidState.uid, pkgOps, opNames,
- beginTimeMillis, endTimeMillis);
- if (historicalPackageOps != null) {
- if (historicalPackageOpsList == null) {
- historicalPackageOpsList = new ArrayList<>();
- }
- historicalPackageOpsList.add(historicalPackageOps);
- }
- }
+ if (mHistoricalRegistry.getMode() == AppOpsManager.HISTORICAL_MODE_DISABLED) {
+ // TODO (bug:122218838): Remove once the feature fully enabled.
+ getHistoricalPackagesOpsCompat(uid, packageName, opNames, beginTimeMillis,
+ endTimeMillis, callback);
+ } else {
+ // Must not hold the appops lock
+ mHistoricalRegistry.getHistoricalOps(uid, packageName, opNames,
+ beginTimeMillis, endTimeMillis, callback);
}
-
- if (historicalPackageOpsList == null) {
- return null;
- }
-
- return new ParceledListSlice<>(historicalPackageOpsList);
}
- private static @Nullable HistoricalPackageOps createHistoricalPackageOps(int uid,
- @Nullable Ops pkgOps, @Nullable String[] opNames, long beginTimeMillis,
- long endTimeMillis) {
- // TODO: Implement historical data collection
- if (pkgOps == null) {
- return null;
+ private void getHistoricalPackagesOpsCompat(int uid, @NonNull String packageName,
+ @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+ @NonNull RemoteCallback callback) {
+ synchronized (AppOpsService.this) {
+ final HistoricalOps ops = new HistoricalOps(beginTimeMillis, endTimeMillis);
+ if (opNames == null) {
+ opNames = AppOpsManager.getOpStrs();
+ }
+ final int uidStateCount = mUidStates.size();
+ for (int uidIdx = 0; uidIdx < uidStateCount; uidIdx++) {
+ final UidState uidState = mUidStates.valueAt(uidIdx);
+ if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()
+ || (uid != Process.INVALID_UID && uid != uidState.uid)) {
+ continue;
+ }
+ final ArrayMap<String, Ops> packages = uidState.pkgOps;
+ final int packageCount = packages.size();
+ for (int pkgIdx = 0; pkgIdx < packageCount; pkgIdx++) {
+ final Ops pkgOps = packages.valueAt(pkgIdx);
+ if (packageName != null && !packageName.equals(pkgOps.packageName)) {
+ continue;
+ }
+ final int opCount = opNames.length;
+ for (int opIdx = 0; opIdx < opCount; opIdx++) {
+ final String opName = opNames[opIdx];
+ if (!ArrayUtils.contains(opNames, opName)) {
+ continue;
+ }
+ final int opCode = AppOpsManager.strOpToOp(opName);
+ final Op op = pkgOps.get(opCode);
+ if (op == null) {
+ continue;
+ }
+ final int stateCount = AppOpsManager._NUM_UID_STATE;
+ for (int stateIdx = 0; stateIdx < stateCount; stateIdx++) {
+ if (op.rejectTime[stateIdx] != 0) {
+ ops.increaseRejectCount(opCode, uidState.uid,
+ pkgOps.packageName, stateIdx, 1);
+ } else if (op.time[stateIdx] != 0) {
+ ops.increaseAccessCount(opCode, uidState.uid,
+ pkgOps.packageName, stateIdx, 1);
+ }
+ }
+ }
+ }
+ }
+ final Bundle payload = new Bundle();
+ payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, ops);
+ callback.sendResult(payload);
}
-
- final HistoricalPackageOps historicalPackageOps = new HistoricalPackageOps(uid,
- pkgOps.packageName);
-
- if (opNames == null) {
- opNames = AppOpsManager.getOpStrs();
- }
- for (String opName : opNames) {
- addHistoricOpEntry(AppOpsManager.strOpToOp(opName), pkgOps, historicalPackageOps);
- }
-
- return historicalPackageOps;
}
@Override
- public @Nullable HistoricalPackageOps getHistoricalPackagesOps(int uid,
- @NonNull String packageName, @Nullable String[] opNames,
- long beginTimeMillis, long endTimeMillis) {
- Preconditions.checkNotNull(packageName,
- "packageName cannot be null");
+ public void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName,
+ @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+ @NonNull RemoteCallback callback) {
+ Preconditions.checkArgument(uid == Process.INVALID_UID || uid >= 0,
+ "uid must be " + Process.INVALID_UID + " or non negative");
Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
"beginTimeMillis must be non negative and lesser than endTimeMillis");
+ Preconditions.checkNotNull(callback, "callback cannot be null");
+ checkValidOpsOrNull(opNames);
mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
- Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalPackagesOps");
+ Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
- final String resolvedPackageName = resolvePackageName(uid, packageName);
- if (resolvedPackageName == null) {
- return null;
- }
-
- // TODO: Implement historical data collection
- final Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */,
- false /* uidMismatchExpected */);
- return createHistoricalPackageOps(uid, pkgOps, opNames, beginTimeMillis, endTimeMillis);
- }
-
- private static void addHistoricOpEntry(int opCode, @NonNull Ops ops,
- @NonNull HistoricalPackageOps outHistoricalPackageOps) {
- final Op op = ops.get(opCode);
- if (op == null) {
- return;
- }
-
- final HistoricalOpEntry historicalOpEntry = new HistoricalOpEntry(opCode);
-
- // TODO: Keep per UID state duration
- for (int uidState = 0; uidState < AppOpsManager._NUM_UID_STATE; uidState++) {
- final int acceptCount;
- final int rejectCount;
- if (op.rejectTime[uidState] == 0) {
- acceptCount = 1;
- rejectCount = 0;
- } else {
- acceptCount = 0;
- rejectCount = 1;
- }
- historicalOpEntry.addEntry(uidState, acceptCount, rejectCount, 0);
- }
-
- outHistoricalPackageOps.addEntry(historicalOpEntry);
+ // Must not hold the appops lock
+ mHistoricalRegistry.getHistoricalOpsFromDiskRaw(uid, packageName, opNames,
+ beginTimeMillis, endTimeMillis, callback);
}
@Override
@@ -1884,6 +1875,8 @@
+ packageName);
op.rejectTime[uidState.state] = System.currentTimeMillis();
scheduleOpNotedIfNeededLocked(code, uid, packageName, uidMode);
+ mHistoricalRegistry.incrementOpRejected(op.op, uid, packageName,
+ uidState.state);
return uidMode;
}
} else {
@@ -1895,12 +1888,16 @@
+ packageName);
op.rejectTime[uidState.state] = System.currentTimeMillis();
scheduleOpNotedIfNeededLocked(op.op, uid, packageName, mode);
+ mHistoricalRegistry.incrementOpRejected(op.op, uid, packageName,
+ uidState.state);
return mode;
}
}
if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
+ " package " + packageName);
op.time[uidState.state] = System.currentTimeMillis();
+ mHistoricalRegistry.incrementOpAccessedCount(op.op, uid, packageName,
+ uidState.state);
op.rejectTime[uidState.state] = 0;
op.proxyUid = proxyUid;
op.proxyPackageName = proxyPackageName;
@@ -2035,6 +2032,8 @@
+ switchCode + " (" + code + ") uid " + uid + " package "
+ resolvedPackageName);
op.rejectTime[uidState.state] = System.currentTimeMillis();
+ mHistoricalRegistry.incrementOpRejected(op.op, uid, packageName,
+ uidState.state);
return uidMode;
}
} else {
@@ -2046,6 +2045,8 @@
+ switchCode + " (" + code + ") uid " + uid + " package "
+ resolvedPackageName);
op.rejectTime[uidState.state] = System.currentTimeMillis();
+ mHistoricalRegistry.incrementOpRejected(op.op, uid, packageName,
+ uidState.state);
return mode;
}
}
@@ -2054,6 +2055,8 @@
if (op.startNesting == 0) {
op.startRealtime = SystemClock.elapsedRealtime();
op.time[uidState.state] = System.currentTimeMillis();
+ mHistoricalRegistry.incrementOpAccessedCount(op.op, uid, packageName,
+ uidState.state);
op.rejectTime[uidState.state] = 0;
op.duration = -1;
scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, true);
@@ -2216,6 +2219,8 @@
if (op.startNesting <= 1 || finishNested) {
if (op.startNesting == 1 || finishNested) {
op.duration = (int)(SystemClock.elapsedRealtime() - op.startRealtime);
+ mHistoricalRegistry.increaseOpAccessDuration(op.op, op.uid, op.packageName,
+ op.uidState.state, op.duration);
op.time[op.uidState.state] = System.currentTimeMillis();
} else {
Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg "
@@ -2344,7 +2349,7 @@
ApplicationInfo appInfo = ActivityThread.getPackageManager()
.getApplicationInfo(packageName,
PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
UserHandle.getUserId(uid));
if (appInfo != null) {
pkgUid = appInfo.uid;
@@ -3427,9 +3432,9 @@
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
- int dumpOp = -1;
+ int dumpOp = OP_NONE;
String dumpPackage = null;
- int dumpUid = -1;
+ int dumpUid = Process.INVALID_UID;
int dumpMode = -1;
boolean dumpWatchers = false;
@@ -3748,8 +3753,8 @@
}
if (pkgOps != null) {
for (int pkgi = 0;
- (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
- pkgi++) {
+ (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
+ pkgi++) {
Ops ops = pkgOps.valueAt(pkgi);
if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
hasOp = true;
@@ -3973,6 +3978,9 @@
}
}
}
+
+ // Must not hold the appops lock
+ mHistoricalRegistry.dump(" ", pw, dumpUid, dumpPackage, dumpOp);
}
private static final class Restriction {
@@ -4093,6 +4101,47 @@
return false;
}
+ @Override
+ public void setHistoryParameters(@AppOpsManager.HistoricalMode int mode,
+ long baseSnapshotInterval, int compressionStep) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+ "setHistoryParameters");
+ // Must not hold the appops lock
+ mHistoricalRegistry.setHistoryParameters(mode, baseSnapshotInterval, compressionStep);
+ }
+
+ @Override
+ public void offsetHistory(long offsetMillis) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+ "offsetHistory");
+ // Must not hold the appops lock
+ mHistoricalRegistry.offsetHistory(offsetMillis);
+ }
+
+ @Override
+ public void addHistoricalOps(HistoricalOps ops) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+ "addHistoricalOps");
+ // Must not hold the appops lock
+ mHistoricalRegistry.addHistoricalOps(ops);
+ }
+
+ @Override
+ public void resetHistoryParameters() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+ "resetHistoryParameters");
+ // Must not hold the appops lock
+ mHistoricalRegistry.resetHistoryParameters();
+ }
+
+ @Override
+ public void clearHistory() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+ "clearHistory");
+ // Must not hold the appops lock
+ mHistoricalRegistry.clearHistory();
+ }
+
private void removeUidsForUserLocked(int userHandle) {
for (int i = mUidStates.size() - 1; i >= 0; --i) {
final int uid = mUidStates.keyAt(i);
@@ -4163,6 +4212,16 @@
return packageNames;
}
+ private static void checkValidOpsOrNull(String[] opNames) {
+ if (opNames != null) {
+ for (String opName : opNames) {
+ if (AppOpsManager.strOpToOp(opName) == AppOpsManager.OP_NONE) {
+ throw new IllegalArgumentException("Unknown op: " + opName);
+ }
+ }
+ }
+ }
+
private final class ClientRestrictionState implements DeathRecipient {
private final IBinder token;
SparseArray<boolean[]> perUserRestrictions;
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
new file mode 100644
index 0000000..8d7811f
--- /dev/null
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -0,0 +1,1495 @@
+/*
+ * 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.appop;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppOpsManager;
+import android.app.AppOpsManager.HistoricalMode;
+import android.app.AppOpsManager.HistoricalOp;
+import android.app.AppOpsManager.HistoricalOps;
+import android.app.AppOpsManager.HistoricalPackageOps;
+import android.app.AppOpsManager.HistoricalUidOps;
+import android.app.AppOpsManager.UidState;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Message;
+import android.os.Process;
+import android.os.RemoteCallback;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.TimeUtils;
+import android.util.Xml;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.AtomicDirectory;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.XmlUtils;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.FgThread;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * This class managers historical app op state. This includes reading, persistence,
+ * accounting, querying.
+ * <p>
+ * The history is kept forever in multiple files. Each file time contains the
+ * relative offset from the current time which time is encoded in the file name.
+ * The files contain historical app op state snapshots which have times that
+ * are relative to the time of the container file.
+ *
+ * The data in the files are stored in a logarithmic fashion where where every
+ * subsequent file would contain data for ten times longer interval with ten
+ * times more time distance between snapshots. Hence, the more time passes
+ * the lesser the fidelity.
+ * <p>
+ * For example, the first file would contain data for 1 days with snapshots
+ * every 0.1 days, the next file would contain data for the period 1 to 10
+ * days with snapshots every 1 days, and so on.
+ * <p>
+ * THREADING AND LOCKING: Reported ops must be processed as quickly as possible.
+ * We keep ops pending to be persisted in memory and write to disk on a background
+ * thread. Hence, methods that report op changes are locking only the in memory
+ * state guarded by the mInMemoryLock which happens to be the app ops service lock
+ * avoiding a lock addition on the critical path. When a query comes we need to
+ * evaluate it based off both in memory and on disk state. This means they need to
+ * be frozen with respect to each other and not change from the querying caller's
+ * perspective. To achieve this we add a dedicated mOnDiskLock to guard the on
+ * disk state. To have fast critical path we need to limit the locking of the
+ * mInMemoryLock, thus for operations that touch in memory and on disk state one
+ * must grab first the mOnDiskLock and then the mInMemoryLock and limit the
+ * in memory lock to extraction of relevant data. Locking order is critical to
+ * avoid deadlocks. The convention is that xxxDLocked suffix means the method
+ * must be called with the mOnDiskLock lock, xxxMLocked suffix means the method
+ * must be called with the mInMemoryLock, xxxDMLocked suffix means the method
+ * must be called with the mOnDiskLock and mInMemoryLock locks acquired in that
+ * exact order.
+ */
+// TODO (bug:122218838): Make sure we handle start of epoch time
+// TODO (bug:122218838): Validate changed time is handled correctly
+final class HistoricalRegistry {
+ private static final boolean DEBUG = false;
+
+ private static final String LOG_TAG = HistoricalRegistry.class.getSimpleName();
+
+ private static final String PARAMETER_DELIMITER = ",";
+ private static final String PARAMETER_ASSIGNMENT = "=";
+
+ @GuardedBy("mLock")
+ private @NonNull LinkedList<HistoricalOps> mPendingWrites = new LinkedList<>();
+
+ // Lock for read/write access to on disk state
+ private final Object mOnDiskLock = new Object();
+
+ //Lock for read/write access to in memory state
+ private final @NonNull Object mInMemoryLock;
+
+ private static final int MSG_WRITE_PENDING_HISTORY = 1;
+
+ // See mMode
+ private static final int DEFAULT_MODE = AppOpsManager.HISTORICAL_MODE_DISABLED;
+
+ // See mBaseSnapshotInterval
+ private static final long DEFAULT_SNAPSHOT_INTERVAL_MILLIS = TimeUnit.MINUTES.toMillis(15);
+
+ // See mIntervalCompressionMultiplier
+ private static final long DEFAULT_COMPRESSION_STEP = 10;
+
+ /**
+ * Whether history is enabled.
+ */
+ @GuardedBy("mInMemoryLock")
+ private int mMode = AppOpsManager.HISTORICAL_MODE_DISABLED;
+
+ /**
+ * This granularity has been chosen to allow clean delineation for intervals
+ * humans understand, 15 min, 60, min, a day, a week, a month (30 days).
+ */
+ @GuardedBy("mInMemoryLock")
+ private long mBaseSnapshotInterval = DEFAULT_SNAPSHOT_INTERVAL_MILLIS;
+
+ /**
+ * The compression between steps. Each subsequent step is this much longer
+ * in terms of duration and each snapshot is this much more apart from the
+ * previous step.
+ */
+ @GuardedBy("mInMemoryLock")
+ private long mIntervalCompressionMultiplier = DEFAULT_COMPRESSION_STEP;
+
+ // The current ops to which to add statistics.
+ @GuardedBy("mInMemoryLock")
+ private @Nullable HistoricalOps mCurrentHistoricalOps;
+
+ // The time we should write the next snapshot.
+ @GuardedBy("mInMemoryLock")
+ private long mNextPersistDueTimeMillis;
+
+ // How much to offset the history on the next write.
+ @GuardedBy("mInMemoryLock")
+ private long mPendingHistoryOffsetMillis;
+
+ // Object managing persistence (read/write)
+ @GuardedBy("mOnDiskLock")
+ private Persistence mPersistence = new Persistence(mBaseSnapshotInterval,
+ mIntervalCompressionMultiplier);
+
+ HistoricalRegistry(@NonNull Object lock) {
+ mInMemoryLock = lock;
+ if (mMode != AppOpsManager.HISTORICAL_MODE_DISABLED) {
+ synchronized (mInMemoryLock) {
+ // When starting always adjust history to now.
+ mPendingHistoryOffsetMillis = System.currentTimeMillis()
+ - mPersistence.getLastPersistTimeMillisDLocked();
+ }
+ }
+ }
+
+ void systemReady(@NonNull ContentResolver resolver) {
+ updateParametersFromSetting(resolver);
+ final Uri uri = Settings.Global.getUriFor(Settings.Global.APPOP_HISTORY_PARAMETERS);
+ resolver.registerContentObserver(uri, false, new ContentObserver(
+ FgThread.getHandler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateParametersFromSetting(resolver);
+ }
+ });
+ }
+
+ private void updateParametersFromSetting(@NonNull ContentResolver resolver) {
+ final String setting = Settings.Global.getString(resolver,
+ Settings.Global.APPOP_HISTORY_PARAMETERS);
+ if (setting == null) {
+ return;
+ }
+ String modeValue = null;
+ String baseSnapshotIntervalValue = null;
+ String intervalMultiplierValue = null;
+ final String[] parameters = setting.split(PARAMETER_DELIMITER);
+ for (String parameter : parameters) {
+ final String[] parts = parameter.split(PARAMETER_ASSIGNMENT);
+ if (parts.length == 2) {
+ final String key = parts[0].trim();
+ switch (key) {
+ case Settings.Global.APPOP_HISTORY_MODE: {
+ modeValue = parts[1].trim();
+ } break;
+ case Settings.Global.APPOP_HISTORY_BASE_INTERVAL_MILLIS: {
+ baseSnapshotIntervalValue = parts[1].trim();
+ } break;
+ case Settings.Global.APPOP_HISTORY_INTERVAL_MULTIPLIER: {
+ intervalMultiplierValue = parts[1].trim();
+ } break;
+ default: {
+ Slog.w(LOG_TAG, "Unknown parameter: " + parameter);
+ }
+ }
+ }
+ }
+ if (modeValue != null && baseSnapshotIntervalValue != null
+ && intervalMultiplierValue != null) {
+ try {
+ final int mode = AppOpsManager.parseHistoricalMode(modeValue);
+ final long baseSnapshotInterval = Long.parseLong(baseSnapshotIntervalValue);
+ final int intervalCompressionMultiplier = Integer.parseInt(intervalMultiplierValue);
+ setHistoryParameters(mode, baseSnapshotInterval,intervalCompressionMultiplier);
+ return;
+ } catch (NumberFormatException ignored) {}
+ }
+ Slog.w(LOG_TAG, "Bad value for" + Settings.Global.APPOP_HISTORY_PARAMETERS
+ + "=" + setting + " resetting!");
+ }
+
+ void dump(String prefix, PrintWriter pw, int filterUid,
+ String filterPackage, int filterOp) {
+ synchronized (mOnDiskLock) {
+ synchronized (mInMemoryLock) {
+ pw.println();
+ pw.print(prefix);
+ pw.print("History:");
+
+ pw.print(" mode=");
+ pw.println(AppOpsManager.historicalModeToString(mMode));
+
+ final StringDumpVisitor visitor = new StringDumpVisitor(prefix + " ",
+ pw, filterUid, filterPackage, filterOp);
+ final long nowMillis = System.currentTimeMillis();
+
+ // Dump in memory state first
+ final HistoricalOps currentOps = getUpdatedPendingHistoricalOpsMLocked(
+ nowMillis);
+ makeRelativeToEpochStart(currentOps, nowMillis);
+ currentOps.accept(visitor);
+
+ final List<HistoricalOps> ops = mPersistence.readHistoryDLocked();
+ if (ops != null) {
+ // TODO (bug:122218838): Make sure this is properly dumped
+ final long remainingToFillBatchMillis = mNextPersistDueTimeMillis
+ - nowMillis - mBaseSnapshotInterval;
+ final int opCount = ops.size();
+ for (int i = 0; i < opCount; i++) {
+ final HistoricalOps op = ops.get(i);
+ op.offsetBeginAndEndTime(remainingToFillBatchMillis);
+ makeRelativeToEpochStart(op, nowMillis);
+ op.accept(visitor);
+ }
+ } else {
+ pw.println(" Empty");
+ }
+ }
+ }
+ }
+
+ @HistoricalMode int getMode() {
+ synchronized (mInMemoryLock) {
+ return mMode;
+ }
+ }
+
+ @Nullable void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName,
+ @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+ @NonNull RemoteCallback callback) {
+ final HistoricalOps result = new HistoricalOps(beginTimeMillis, endTimeMillis);
+ mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, opNames,
+ beginTimeMillis, endTimeMillis);
+ final Bundle payload = new Bundle();
+ payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, result);
+ callback.sendResult(payload);
+ }
+
+ @Nullable void getHistoricalOps(int uid, @NonNull String packageName,
+ @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+ @NonNull RemoteCallback callback) {
+ final long currentTimeMillis = System.currentTimeMillis();
+ if (endTimeMillis == Long.MAX_VALUE) {
+ endTimeMillis = currentTimeMillis;
+ }
+
+ // Argument times are based off epoch start while our internal store is
+ // based off now, so take this into account.
+ final long inMemoryAdjBeginTimeMillis = Math.max(currentTimeMillis - endTimeMillis, 0);
+ final long inMemoryAdjEndTimeMillis = Math.max(currentTimeMillis - beginTimeMillis, 0);
+ final HistoricalOps result = new HistoricalOps(inMemoryAdjBeginTimeMillis,
+ inMemoryAdjEndTimeMillis);
+
+ synchronized (mOnDiskLock) {
+ final List<HistoricalOps> pendingWrites;
+ final HistoricalOps currentOps;
+ synchronized (mInMemoryLock) {
+ currentOps = getUpdatedPendingHistoricalOpsMLocked(currentTimeMillis);
+ if (!(inMemoryAdjBeginTimeMillis >= currentOps.getEndTimeMillis()
+ || inMemoryAdjEndTimeMillis <= currentOps.getBeginTimeMillis())) {
+ // Some of the current batch falls into the query, so extract that.
+ final HistoricalOps currentOpsCopy = new HistoricalOps(currentOps);
+ currentOpsCopy.filter(uid, packageName, opNames, inMemoryAdjBeginTimeMillis,
+ inMemoryAdjEndTimeMillis);
+ result.merge(currentOpsCopy);
+ }
+ pendingWrites = new ArrayList<>(mPendingWrites);
+ mPendingWrites.clear();
+ }
+
+ // If the query was only for in-memory state - done.
+ if (inMemoryAdjEndTimeMillis > currentOps.getEndTimeMillis()) {
+ // If there is a write in flight we need to force it now
+ persistPendingHistory(pendingWrites);
+ // Collect persisted state.
+ final long onDiskAndInMemoryOffsetMillis = currentTimeMillis
+ - mNextPersistDueTimeMillis + mBaseSnapshotInterval;
+ final long onDiskAdjBeginTimeMillis = Math.max(inMemoryAdjBeginTimeMillis
+ - onDiskAndInMemoryOffsetMillis, 0);
+ final long onDiskAdjEndTimeMillis = Math.max(inMemoryAdjEndTimeMillis
+ - onDiskAndInMemoryOffsetMillis, 0);
+ mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, opNames,
+ onDiskAdjBeginTimeMillis, onDiskAdjEndTimeMillis);
+ }
+
+ // Rebase the result time to be since epoch.
+ result.setBeginAndEndTime(beginTimeMillis, endTimeMillis);
+
+ // Send back the result.
+ final Bundle payload = new Bundle();
+ payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, result);
+ callback.sendResult(payload);
+ }
+ }
+
+ void incrementOpAccessedCount(int op, int uid, @NonNull String packageName,
+ @UidState int uidState) {
+ synchronized (mInMemoryLock) {
+ if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
+ getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis())
+ .increaseAccessCount(op, uid, packageName, uidState, 1);
+
+ }
+ }
+ }
+
+ void incrementOpRejected(int op, int uid, @NonNull String packageName,
+ @UidState int uidState) {
+ synchronized (mInMemoryLock) {
+ if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
+ getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis())
+ .increaseRejectCount(op, uid, packageName, uidState, 1);
+ }
+ }
+ }
+
+ void increaseOpAccessDuration(int op, int uid, @NonNull String packageName,
+ @UidState int uidState, long increment) {
+ synchronized (mInMemoryLock) {
+ if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
+ getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis())
+ .increaseAccessDuration(op, uid, packageName, uidState, increment);
+ }
+ }
+ }
+
+ void setHistoryParameters(@HistoricalMode int mode,
+ long baseSnapshotInterval, long intervalCompressionMultiplier) {
+ synchronized (mOnDiskLock) {
+ synchronized (mInMemoryLock) {
+ boolean resampleHistory = false;
+ Slog.i(LOG_TAG, "New history parameters: mode:"
+ + AppOpsManager.historicalModeToString(mMode) + " baseSnapshotInterval:"
+ + baseSnapshotInterval + " intervalCompressionMultiplier:"
+ + intervalCompressionMultiplier);
+ if (mMode != mode) {
+ mMode = mode;
+ if (mMode == AppOpsManager.HISTORICAL_MODE_DISABLED) {
+ clearHistoryOnDiskLocked();
+ }
+ }
+ if (mBaseSnapshotInterval != baseSnapshotInterval) {
+ mBaseSnapshotInterval = baseSnapshotInterval;
+ resampleHistory = true;
+ }
+ if (mIntervalCompressionMultiplier != intervalCompressionMultiplier) {
+ mIntervalCompressionMultiplier = intervalCompressionMultiplier;
+ resampleHistory = true;
+ }
+ if (resampleHistory) {
+ resampleHistoryOnDiskInMemoryDMLocked(0);
+ }
+ }
+ }
+ }
+
+ void offsetHistory(long offsetMillis) {
+ synchronized (mOnDiskLock) {
+ synchronized (mInMemoryLock) {
+ final List<HistoricalOps> history = mPersistence.readHistoryDLocked();
+ clearHistory();
+ if (history != null) {
+ final int historySize = history.size();
+ for (int i = 0; i < historySize; i++) {
+ final HistoricalOps ops = history.get(i);
+ ops.offsetBeginAndEndTime(offsetMillis);
+ }
+ if (offsetMillis < 0) {
+ pruneFutureOps(history);
+ }
+ mPersistence.persistHistoricalOpsDLocked(history);
+ }
+ }
+ }
+ }
+
+ void addHistoricalOps(HistoricalOps ops) {
+ final List<HistoricalOps> pendingWrites;
+ synchronized (mInMemoryLock) {
+ // The history files start from mBaseSnapshotInterval - take this into account.
+ ops.offsetBeginAndEndTime(mBaseSnapshotInterval);
+ mPendingWrites.offerFirst(ops);
+ pendingWrites = new ArrayList<>(mPendingWrites);
+ mPendingWrites.clear();
+ }
+ persistPendingHistory(pendingWrites);
+ }
+
+ private void resampleHistoryOnDiskInMemoryDMLocked(long offsetMillis) {
+ mPersistence = new Persistence(mBaseSnapshotInterval, mIntervalCompressionMultiplier);
+ offsetHistory(offsetMillis);
+ }
+
+ void resetHistoryParameters() {
+ setHistoryParameters(DEFAULT_MODE, DEFAULT_SNAPSHOT_INTERVAL_MILLIS,
+ DEFAULT_COMPRESSION_STEP);
+ }
+
+ void clearHistory() {
+ synchronized (mOnDiskLock) {
+ clearHistoryOnDiskLocked();
+ }
+ }
+
+ private void clearHistoryOnDiskLocked() {
+ BackgroundThread.getHandler().removeMessages(MSG_WRITE_PENDING_HISTORY);
+ synchronized (mInMemoryLock) {
+ mCurrentHistoricalOps = null;
+ mNextPersistDueTimeMillis = System.currentTimeMillis();
+ mPendingWrites.clear();
+ }
+ mPersistence.clearHistoryDLocked();
+ }
+
+ private @NonNull HistoricalOps getUpdatedPendingHistoricalOpsMLocked(long now) {
+ if (mCurrentHistoricalOps != null) {
+ final long remainingTimeMillis = mNextPersistDueTimeMillis - now;
+ if (remainingTimeMillis > mBaseSnapshotInterval) {
+ // If time went backwards we need to push history to the future with the
+ // overflow over our snapshot interval. If time went forward do nothing
+ // as we would naturally push history into the past on the next write.
+ mPendingHistoryOffsetMillis = remainingTimeMillis - mBaseSnapshotInterval;
+ }
+ final long elapsedTimeMillis = mBaseSnapshotInterval - remainingTimeMillis;
+ mCurrentHistoricalOps.setEndTime(elapsedTimeMillis);
+ if (remainingTimeMillis > 0) {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "Returning current in-memory state");
+ }
+ return mCurrentHistoricalOps;
+ }
+ if (mCurrentHistoricalOps.isEmpty()) {
+ mCurrentHistoricalOps.setBeginAndEndTime(0, 0);
+ mNextPersistDueTimeMillis = now + mBaseSnapshotInterval;
+ return mCurrentHistoricalOps;
+ }
+ // The current batch is full, so persist taking into account overdue persist time.
+ mCurrentHistoricalOps.offsetBeginAndEndTime(mBaseSnapshotInterval);
+ mCurrentHistoricalOps.setBeginTime(mCurrentHistoricalOps.getEndTimeMillis()
+ - mBaseSnapshotInterval);
+ final long overdueTimeMillis = Math.abs(remainingTimeMillis);
+ mCurrentHistoricalOps.offsetBeginAndEndTime(overdueTimeMillis);
+ schedulePersistHistoricalOpsMLocked(mCurrentHistoricalOps);
+ }
+ // The current batch is in the future, i.e. not complete yet.
+ mCurrentHistoricalOps = new HistoricalOps(0, 0);
+ mNextPersistDueTimeMillis = now + mBaseSnapshotInterval;
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "Returning new in-memory state");
+ }
+ return mCurrentHistoricalOps;
+ }
+
+ private void persistPendingHistory() {
+ final List<HistoricalOps> pendingWrites;
+ synchronized (mOnDiskLock) {
+ synchronized (mInMemoryLock) {
+ pendingWrites = new ArrayList<>(mPendingWrites);
+ mPendingWrites.clear();
+ if (mPendingHistoryOffsetMillis != 0) {
+ resampleHistoryOnDiskInMemoryDMLocked(mPendingHistoryOffsetMillis);
+ mPendingHistoryOffsetMillis = 0;
+ }
+ }
+ persistPendingHistory(pendingWrites);
+ }
+ }
+ private void persistPendingHistory(@NonNull List<HistoricalOps> pendingWrites) {
+ synchronized (mOnDiskLock) {
+ BackgroundThread.getHandler().removeMessages(MSG_WRITE_PENDING_HISTORY);
+ if (pendingWrites.isEmpty()) {
+ return;
+ }
+ final int opCount = pendingWrites.size();
+ // Pending writes are offset relative to each other, so take this
+ // into account to persist everything in one shot - single write.
+ for (int i = 0; i < opCount; i++) {
+ final HistoricalOps current = pendingWrites.get(i);
+ if (i > 0) {
+ final HistoricalOps previous = pendingWrites.get(i - 1);
+ current.offsetBeginAndEndTime(previous.getBeginTimeMillis());
+ }
+ }
+ mPersistence.persistHistoricalOpsDLocked(pendingWrites);
+ }
+ }
+
+ private void schedulePersistHistoricalOpsMLocked(@NonNull HistoricalOps ops) {
+ final Message message = PooledLambda.obtainMessage(
+ HistoricalRegistry::persistPendingHistory, HistoricalRegistry.this);
+ message.what = MSG_WRITE_PENDING_HISTORY;
+ BackgroundThread.getHandler().sendMessage(message);
+ mPendingWrites.offerFirst(ops);
+ }
+
+ private static void makeRelativeToEpochStart(@NonNull HistoricalOps ops, long nowMillis) {
+ ops.setBeginAndEndTime(nowMillis - ops.getEndTimeMillis(),
+ nowMillis- ops.getBeginTimeMillis());
+ }
+
+ private void pruneFutureOps(@NonNull List<HistoricalOps> ops) {
+ final int opCount = ops.size();
+ for (int i = opCount - 1; i >= 0; i--) {
+ final HistoricalOps op = ops.get(i);
+ if (op.getEndTimeMillis() <= mBaseSnapshotInterval) {
+ ops.remove(i);
+ } else if (op.getBeginTimeMillis() < mBaseSnapshotInterval) {
+ final double filterScale = (double) (op.getEndTimeMillis() - mBaseSnapshotInterval)
+ / (double) op.getDurationMillis();
+ Persistence.spliceFromBeginning(op, filterScale);
+ }
+ }
+ }
+
+ private static final class Persistence {
+ private static final boolean DEBUG = false;
+
+ private static final String LOG_TAG = Persistence.class.getSimpleName();
+
+ private static final String HISTORY_FILE_SUFFIX = ".xml";
+
+ private static final String TAG_HISTORY = "history";
+ private static final String TAG_OPS = "ops";
+ private static final String TAG_UID = "uid";
+ private static final String TAG_PACKAGE = "package";
+ private static final String TAG_OP = "op";
+ private static final String TAG_STATE = "state";
+
+ private static final String ATTR_VERSION = "version";
+ private static final String ATTR_NAME = "name";
+ private static final String ATTR_ACCESS_COUNT = "accessCount";
+ private static final String ATTR_REJECT_COUNT = "rejectCount";
+ private static final String ATTR_ACCESS_DURATION = "accessDuration";
+ private static final String ATTR_BEGIN_TIME = "beginTime";
+ private static final String ATTR_END_TIME = "endTime";
+ private static final String ATTR_OVERFLOW = "overflow";
+
+ private static final int CURRENT_VERSION = 1;
+
+ private final long mBaseSnapshotInterval;
+ private final long mIntervalCompressionMultiplier;
+
+ Persistence(long baseSnapshotInterval, long intervalCompressionMultiplier) {
+ mBaseSnapshotInterval = baseSnapshotInterval;
+ mIntervalCompressionMultiplier = intervalCompressionMultiplier;
+ }
+
+ private final AtomicDirectory mHistoricalAppOpsDir = new AtomicDirectory(
+ new File(new File(Environment.getDataSystemDeDirectory(), "appops"), "history"));
+
+ private File generateFile(@NonNull File baseDir, int depth) {
+ final long globalBeginMillis = computeGlobalIntervalBeginMillis(depth);
+ return new File(baseDir, Long.toString(globalBeginMillis) + HISTORY_FILE_SUFFIX);
+ }
+
+ void clearHistoryDLocked() {
+ mHistoricalAppOpsDir.delete();
+ }
+
+ void persistHistoricalOpsDLocked(@NonNull List<HistoricalOps> ops) {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "Persisting ops:\n" + opsToDebugString(ops));
+ enforceOpsWellFormed(ops);
+ }
+ try {
+ final File newBaseDir = mHistoricalAppOpsDir.startWrite();
+ final File oldBaseDir = mHistoricalAppOpsDir.getBackupDirectory();
+ handlePersistHistoricalOpsRecursiveDLocked(newBaseDir, oldBaseDir, ops, 0);
+ mHistoricalAppOpsDir.finishWrite();
+ } catch (Throwable t) {
+ Slog.wtf(LOG_TAG, "Failed to write historical app ops, restoring backup", t);
+ mHistoricalAppOpsDir.failWrite();
+ }
+ }
+
+ @Nullable List<HistoricalOps> readHistoryRawDLocked() {
+ return collectHistoricalOpsBaseDLocked(Process.INVALID_UID /*filterUid*/,
+ null /*filterPackageName*/, null /*filterOpNames*/,
+ 0 /*filterBeginTimeMills*/, Long.MAX_VALUE /*filterEndTimeMills*/);
+ }
+
+ @Nullable List<HistoricalOps> readHistoryDLocked() {
+ final List<HistoricalOps> result = readHistoryRawDLocked();
+ // Take into account in memory state duration.
+ if (result != null) {
+ final int opCount = result.size();
+ for (int i = 0; i < opCount; i++) {
+ result.get(i).offsetBeginAndEndTime(mBaseSnapshotInterval);
+ }
+ }
+ return result;
+ }
+
+ long getLastPersistTimeMillisDLocked() {
+ try {
+ final File baseDir = mHistoricalAppOpsDir.startRead();
+ final File file = generateFile(baseDir, 0);
+ if (file.exists()) {
+ return file.lastModified();
+ }
+ mHistoricalAppOpsDir.finishRead();
+ } catch (IOException e) {
+ Slog.wtf("Error reading historical app ops. Deleting history.", e);
+ mHistoricalAppOpsDir.delete();
+ }
+ return 0;
+ }
+
+ private void collectHistoricalOpsDLocked(@NonNull HistoricalOps currentOps,
+ int filterUid, @NonNull String filterPackageName, @Nullable String[] filterOpNames,
+ long filterBeingMillis, long filterEndMillis) {
+ final List<HistoricalOps> readOps = collectHistoricalOpsBaseDLocked(filterUid,
+ filterPackageName, filterOpNames, filterBeingMillis, filterEndMillis);
+ if (readOps != null) {
+ final int readCount = readOps.size();
+ for (int i = 0; i < readCount; i++) {
+ final HistoricalOps readOp = readOps.get(i);
+ currentOps.merge(readOp);
+ }
+ }
+ }
+
+ private @Nullable LinkedList<HistoricalOps> collectHistoricalOpsBaseDLocked(
+ int filterUid, @NonNull String filterPackageName, @Nullable String[] filterOpNames,
+ long filterBeginTimeMillis, long filterEndTimeMillis) {
+ try {
+ final File baseDir = mHistoricalAppOpsDir.startRead();
+ final File[] files = baseDir.listFiles();
+ if (files == null) {
+ return null;
+ }
+ final ArraySet<File> historyFiles = new ArraySet<>(files.length);
+ for (File file : files) {
+ if (file.isFile() && file.getName().endsWith(HISTORY_FILE_SUFFIX)) {
+ historyFiles.add(file);
+ }
+ }
+ final long[] globalContentOffsetMillis = {0};
+ final LinkedList<HistoricalOps> ops = collectHistoricalOpsRecursiveDLocked(
+ baseDir, filterUid, filterPackageName, filterOpNames, filterBeginTimeMillis,
+ filterEndTimeMillis, globalContentOffsetMillis, null /*outOps*/,
+ 0 /*depth*/, historyFiles);
+ mHistoricalAppOpsDir.finishRead();
+ return ops;
+ } catch (IOException | XmlPullParserException e) {
+ Slog.wtf("Error reading historical app ops. Deleting history.", e);
+ mHistoricalAppOpsDir.delete();
+ }
+ return null;
+ }
+
+ private @Nullable LinkedList<HistoricalOps> collectHistoricalOpsRecursiveDLocked(
+ @NonNull File baseDir, int filterUid, @NonNull String filterPackageName,
+ @Nullable String[] filterOpNames, long filterBeginTimeMillis,
+ long filterEndTimeMillis, @NonNull long[] globalContentOffsetMillis,
+ @Nullable LinkedList<HistoricalOps> outOps, int depth,
+ @NonNull ArraySet<File> historyFiles)
+ throws IOException, XmlPullParserException {
+ final long previousIntervalEndMillis = (long) Math.pow(mIntervalCompressionMultiplier,
+ depth) * mBaseSnapshotInterval;
+ final long currentIntervalEndMillis = (long) Math.pow(mIntervalCompressionMultiplier,
+ depth + 1) * mBaseSnapshotInterval;
+
+ filterBeginTimeMillis = Math.max(filterBeginTimeMillis - previousIntervalEndMillis, 0);
+ filterEndTimeMillis = filterEndTimeMillis - previousIntervalEndMillis;
+
+ // Read historical data at this level
+ final List<HistoricalOps> readOps = readHistoricalOpsLocked(baseDir,
+ previousIntervalEndMillis, currentIntervalEndMillis, filterUid,
+ filterPackageName, filterOpNames, filterBeginTimeMillis, filterEndTimeMillis,
+ globalContentOffsetMillis, depth, historyFiles);
+
+ // Empty is a special signal to stop diving
+ if (readOps != null && readOps.isEmpty()) {
+ return outOps;
+ }
+
+ // Collect older historical data from subsequent levels
+ outOps = collectHistoricalOpsRecursiveDLocked(
+ baseDir, filterUid, filterPackageName, filterOpNames, filterBeginTimeMillis,
+ filterEndTimeMillis, globalContentOffsetMillis, outOps, depth + 1,
+ historyFiles);
+
+ // Make older historical data relative to the current historical level
+ if (outOps != null) {
+ final int opCount = outOps.size();
+ for (int i = 0; i < opCount; i++) {
+ final HistoricalOps collectedOp = outOps.get(i);
+ collectedOp.offsetBeginAndEndTime(currentIntervalEndMillis);
+ }
+ }
+
+ if (readOps != null) {
+ if (outOps == null) {
+ outOps = new LinkedList<>();
+ }
+ // Add the read ops to output
+ final int opCount = readOps.size();
+ for (int i = opCount - 1; i >= 0; i--) {
+ outOps.offerFirst(readOps.get(i));
+ }
+ }
+
+ return outOps;
+ }
+
+ private boolean createHardLinkToExistingFile(@NonNull File fromFile, @NonNull File toFile)
+ throws IOException {
+ if (!fromFile.exists()) {
+ return false;
+ }
+ Files.createLink(toFile.toPath(), fromFile.toPath());
+ return true;
+ }
+
+ private void handlePersistHistoricalOpsRecursiveDLocked(@NonNull File newBaseDir,
+ @NonNull File oldBaseDir, @Nullable List<HistoricalOps> passedOps, int depth)
+ throws IOException, XmlPullParserException {
+ final long previousIntervalEndMillis = (long) Math.pow(mIntervalCompressionMultiplier,
+ depth) * mBaseSnapshotInterval;
+ final long currentIntervalEndMillis = (long) Math.pow(mIntervalCompressionMultiplier,
+ depth + 1) * mBaseSnapshotInterval;
+
+ if (passedOps == null || passedOps.isEmpty()) {
+ // If there is an old file we need to copy it over to the new state.
+ final File oldFile = generateFile(oldBaseDir, depth);
+ final File newFile = generateFile(newBaseDir, depth);
+ if (createHardLinkToExistingFile(oldFile, newFile)) {
+ handlePersistHistoricalOpsRecursiveDLocked(newBaseDir, oldBaseDir,
+ passedOps, depth + 1);
+ }
+ return;
+ }
+
+ if (DEBUG) {
+ enforceOpsWellFormed(passedOps);
+ }
+
+ // Normalize passed ops time to be based off this interval start
+ final int passedOpCount = passedOps.size();
+ for (int i = 0; i < passedOpCount; i++) {
+ final HistoricalOps passedOp = passedOps.get(i);
+ passedOp.offsetBeginAndEndTime(-previousIntervalEndMillis);
+ }
+
+ if (DEBUG) {
+ enforceOpsWellFormed(passedOps);
+ }
+
+ // Read persisted ops for this interval
+ final List<HistoricalOps> existingOps = readHistoricalOpsLocked(oldBaseDir,
+ previousIntervalEndMillis, currentIntervalEndMillis,
+ Process.INVALID_UID /*filterUid*/, null /*filterPackageName*/,
+ null /*filterOpNames*/, Long.MIN_VALUE /*filterBeginTimeMillis*/,
+ Long.MAX_VALUE /*filterEndTimeMillis*/, null, depth,
+ null /*historyFiles*/);
+
+ if (DEBUG) {
+ enforceOpsWellFormed(existingOps);
+ }
+
+ // Offset existing ops to account for elapsed time
+ final int existingOpCount = existingOps.size();
+ if (existingOpCount > 0) {
+ // Compute elapsed time
+ final long elapsedTimeMillis = passedOps.get(passedOps.size() - 1)
+ .getEndTimeMillis();
+ for (int i = 0; i < existingOpCount; i++) {
+ final HistoricalOps existingOp = existingOps.get(i);
+ existingOp.offsetBeginAndEndTime(elapsedTimeMillis);
+ }
+ }
+
+ if (DEBUG) {
+ enforceOpsWellFormed(existingOps);
+ }
+
+ final long slotDurationMillis = previousIntervalEndMillis;
+
+ // Consolidate passed ops at the current slot duration ensuring each snapshot is
+ // full. To achieve this we put all passed and existing ops in a list and will
+ // merge them to ensure each represents a snapshot at the current granularity.
+ final List<HistoricalOps> allOps = new LinkedList<>();
+ allOps.addAll(passedOps);
+ allOps.addAll(existingOps);
+
+ if (DEBUG) {
+ enforceOpsWellFormed(allOps);
+ }
+
+ // Compute ops to persist and overflow ops
+ List<HistoricalOps> persistedOps = null;
+ List<HistoricalOps> overflowedOps = null;
+
+ // We move a snapshot into the next level only if the start time is
+ // after the end of the current interval. This avoids rewriting all
+ // files to propagate the information added to the history on every
+ // iteration. Instead, we would rewrite the next level file only if
+ // an entire snapshot from the previous level is being propagated.
+ // The trade off is that we need to store how much the last snapshot
+ // of the current interval overflows past the interval end. We write
+ // the overflow data to avoid parsing all snapshots on query.
+ long intervalOverflowMillis = 0;
+ final int opCount = allOps.size();
+ for (int i = 0; i < opCount; i++) {
+ final HistoricalOps op = allOps.get(i);
+ final HistoricalOps persistedOp;
+ final HistoricalOps overflowedOp;
+ if (op.getEndTimeMillis() <= currentIntervalEndMillis) {
+ persistedOp = op;
+ overflowedOp = null;
+ } else if (op.getBeginTimeMillis() < currentIntervalEndMillis) {
+ persistedOp = op;
+ intervalOverflowMillis = op.getEndTimeMillis() - currentIntervalEndMillis;
+ if (intervalOverflowMillis > previousIntervalEndMillis) {
+ final double splitScale = (double) intervalOverflowMillis
+ / op.getDurationMillis();
+ overflowedOp = spliceFromEnd(op, splitScale);
+ intervalOverflowMillis = op.getEndTimeMillis() - currentIntervalEndMillis;
+ } else {
+ overflowedOp = null;
+ }
+ } else {
+ persistedOp = null;
+ overflowedOp = op;
+ }
+ if (persistedOp != null) {
+ if (persistedOps == null) {
+ persistedOps = new ArrayList<>();
+ }
+ persistedOps.add(persistedOp);
+ }
+ if (overflowedOp != null) {
+ if (overflowedOps == null) {
+ overflowedOps = new ArrayList<>();
+ }
+ overflowedOps.add(overflowedOp);
+ }
+ }
+
+ if (DEBUG) {
+ enforceOpsWellFormed(persistedOps);
+ enforceOpsWellFormed(overflowedOps);
+ }
+
+ if (persistedOps != null) {
+ normalizeSnapshotForSlotDuration(persistedOps, slotDurationMillis);
+ final File newFile = generateFile(newBaseDir, depth);
+ writeHistoricalOpsDLocked(persistedOps, intervalOverflowMillis, newFile);
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "Persisted at depth: " + depth
+ + " ops:\n" + opsToDebugString(persistedOps));
+ enforceOpsWellFormed(persistedOps);
+ }
+ }
+
+ handlePersistHistoricalOpsRecursiveDLocked(newBaseDir, oldBaseDir,
+ overflowedOps, depth + 1);
+ }
+
+ private @NonNull List<HistoricalOps> readHistoricalOpsLocked(File baseDir,
+ long intervalBeginMillis, long intervalEndMillis, int filterUid,
+ @Nullable String filterPackageName, @Nullable String[] filterOpNames,
+ long filterBeginTimeMillis, long filterEndTimeMillis,
+ @Nullable long[] cumulativeOverflowMillis, int depth,
+ @NonNull ArraySet<File> historyFiles)
+ throws IOException, XmlPullParserException {
+ final File file = generateFile(baseDir, depth);
+ if (historyFiles != null) {
+ historyFiles.remove(file);
+ }
+ if (filterBeginTimeMillis >= filterEndTimeMillis
+ || filterEndTimeMillis < intervalBeginMillis) {
+ // Don't go deeper
+ return Collections.emptyList();
+ }
+ if (filterBeginTimeMillis >= (intervalEndMillis
+ + ((intervalEndMillis - intervalBeginMillis) / mIntervalCompressionMultiplier)
+ + (cumulativeOverflowMillis != null ? cumulativeOverflowMillis[0] : 0))
+ || !file.exists()) {
+ if (historyFiles == null || historyFiles.isEmpty()) {
+ // Don't go deeper
+ return Collections.emptyList();
+ } else {
+ // Keep diving
+ return null;
+ }
+ }
+ return readHistoricalOpsLocked(file, filterUid, filterPackageName, filterOpNames,
+ filterBeginTimeMillis, filterEndTimeMillis, cumulativeOverflowMillis);
+ }
+
+ private @Nullable List<HistoricalOps> readHistoricalOpsLocked(@NonNull File file,
+ int filterUid, @Nullable String filterPackageName, @Nullable String[] filterOpNames,
+ long filterBeginTimeMillis, long filterEndTimeMillis,
+ @Nullable long[] cumulativeOverflowMillis)
+ throws IOException, XmlPullParserException {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "Reading ops from:" + file);
+ }
+ List<HistoricalOps> allOps = null;
+ try (FileInputStream stream = new FileInputStream(file)) {
+ final XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, StandardCharsets.UTF_8.name());
+ XmlUtils.beginDocument(parser, TAG_HISTORY);
+ final long overflowMillis = XmlUtils.readLongAttribute(parser, ATTR_OVERFLOW, 0);
+ final int depth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, depth)) {
+ if (TAG_OPS.equals(parser.getName())) {
+ final HistoricalOps ops = readeHistoricalOpsDLocked(parser,
+ filterUid, filterPackageName, filterOpNames, filterBeginTimeMillis,
+ filterEndTimeMillis, cumulativeOverflowMillis);
+ if (ops == null) {
+ continue;
+ }
+ if (ops.isEmpty()) {
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ if (allOps == null) {
+ allOps = new ArrayList<>();
+ }
+ allOps.add(ops);
+ }
+ }
+ if (cumulativeOverflowMillis != null) {
+ cumulativeOverflowMillis[0] += overflowMillis;
+ }
+ } catch (FileNotFoundException e) {
+ Slog.i(LOG_TAG, "No history file: " + file.getName());
+ return Collections.emptyList();
+ }
+ if (DEBUG) {
+ if (allOps != null) {
+ Slog.i(LOG_TAG, "Read from file: " + file + "ops:\n"
+ + opsToDebugString(allOps));
+ enforceOpsWellFormed(allOps);
+ }
+ }
+ return allOps;
+ }
+
+ private @Nullable HistoricalOps readeHistoricalOpsDLocked(
+ @NonNull XmlPullParser parser, int filterUid, @Nullable String filterPackageName,
+ @Nullable String[] filterOpNames, long filterBeginTimeMillis,
+ long filterEndTimeMillis, @Nullable long[] cumulativeOverflowMillis)
+ throws IOException, XmlPullParserException {
+ final long beginTimeMillis = XmlUtils.readLongAttribute(parser, ATTR_BEGIN_TIME, 0)
+ + (cumulativeOverflowMillis != null ? cumulativeOverflowMillis[0] : 0);
+ final long endTimeMillis = XmlUtils.readLongAttribute(parser, ATTR_END_TIME, 0)
+ + (cumulativeOverflowMillis != null ? cumulativeOverflowMillis[0] : 0);
+ // Keep reading as subsequent records may start matching
+ if (filterEndTimeMillis < beginTimeMillis) {
+ return null;
+ }
+ // Stop reading as subsequent records will not match
+ if (filterBeginTimeMillis > endTimeMillis) {
+ return new HistoricalOps(0, 0);
+ }
+ final long filteredBeginTimeMillis = Math.max(beginTimeMillis, filterBeginTimeMillis);
+ final long filteredEndTimeMillis = Math.min(endTimeMillis, filterEndTimeMillis);
+ final double filterScale = (double) (filteredEndTimeMillis - filteredBeginTimeMillis)
+ / (double) (endTimeMillis - beginTimeMillis);
+ HistoricalOps ops = null;
+ final int depth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, depth)) {
+ if (TAG_UID.equals(parser.getName())) {
+ final HistoricalOps returnedOps = readHistoricalUidOpsDLocked(ops, parser,
+ filterUid, filterPackageName, filterOpNames, filterScale);
+ if (ops == null) {
+ ops = returnedOps;
+ }
+ }
+ }
+ if (ops != null) {
+ ops.setBeginAndEndTime(filteredBeginTimeMillis, filteredEndTimeMillis);
+ }
+ return ops;
+ }
+
+ private @Nullable HistoricalOps readHistoricalUidOpsDLocked(
+ @Nullable HistoricalOps ops, @NonNull XmlPullParser parser, int filterUid,
+ @Nullable String filterPackageName, @Nullable String[] filterOpNames,
+ double filterScale) throws IOException, XmlPullParserException {
+ final int uid = XmlUtils.readIntAttribute(parser, ATTR_NAME);
+ if (filterUid != Process.INVALID_UID && filterUid != uid) {
+ XmlUtils.skipCurrentTag(parser);
+ return null;
+ }
+ final int depth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, depth)) {
+ if (TAG_PACKAGE.equals(parser.getName())) {
+ final HistoricalOps returnedOps = readHistoricalPackageOpsDLocked(ops,
+ uid, parser, filterPackageName, filterOpNames, filterScale);
+ if (ops == null) {
+ ops = returnedOps;
+ }
+ }
+ }
+ return ops;
+ }
+
+ private @Nullable HistoricalOps readHistoricalPackageOpsDLocked(
+ @Nullable HistoricalOps ops, int uid, @NonNull XmlPullParser parser,
+ @Nullable String filterPackageName, @Nullable String[] filterOpNames,
+ double filterScale) throws IOException, XmlPullParserException {
+ final String packageName = XmlUtils.readStringAttribute(parser, ATTR_NAME);
+ if (filterPackageName != null && !filterPackageName.equals(packageName)) {
+ XmlUtils.skipCurrentTag(parser);
+ return null;
+ }
+ final int depth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, depth)) {
+ if (TAG_OP.equals(parser.getName())) {
+ final HistoricalOps returnedOps = readHistoricalOpDLocked(ops, uid,
+ packageName, parser, filterOpNames, filterScale);
+ if (ops == null) {
+ ops = returnedOps;
+ }
+ }
+ }
+ return ops;
+ }
+
+ private @Nullable HistoricalOps readHistoricalOpDLocked(@Nullable HistoricalOps ops,
+ int uid, String packageName, @NonNull XmlPullParser parser,
+ @Nullable String[] filterOpNames, double filterScale)
+ throws IOException, XmlPullParserException {
+ final int op = XmlUtils.readIntAttribute(parser, ATTR_NAME);
+ if (filterOpNames != null && !ArrayUtils.contains(filterOpNames,
+ AppOpsManager.opToName(op))) {
+ XmlUtils.skipCurrentTag(parser);
+ return null;
+ }
+ final int depth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, depth)) {
+ if (TAG_STATE.equals(parser.getName())) {
+ final HistoricalOps returnedOps = readUidStateDLocked(ops, uid,
+ packageName, op, parser, filterScale);
+ if (ops == null) {
+ ops = returnedOps;
+ }
+ }
+ }
+ return ops;
+ }
+
+ private @Nullable HistoricalOps readUidStateDLocked(@Nullable HistoricalOps ops,
+ int uid, String packageName, int op, @NonNull XmlPullParser parser,
+ double filterScale) throws IOException {
+ final int uidState = XmlUtils.readIntAttribute(parser, ATTR_NAME);
+ long accessCount = XmlUtils.readLongAttribute(parser, ATTR_ACCESS_COUNT, 0);
+ if (accessCount > 0) {
+ if (!Double.isNaN(filterScale)) {
+ accessCount = (long) HistoricalOps.round(
+ (double) accessCount * filterScale);
+ }
+ if (ops == null) {
+ ops = new HistoricalOps(0, 0);
+ }
+ ops.increaseAccessCount(op, uid, packageName, uidState, accessCount);
+ }
+ long rejectCount = XmlUtils.readLongAttribute(parser, ATTR_REJECT_COUNT, 0);
+ if (rejectCount > 0) {
+ if (!Double.isNaN(filterScale)) {
+ rejectCount = (long) HistoricalOps.round(
+ (double) rejectCount * filterScale);
+ }
+ if (ops == null) {
+ ops = new HistoricalOps(0, 0);
+ }
+ ops.increaseRejectCount(op, uid, packageName, uidState, rejectCount);
+ }
+ long accessDuration = XmlUtils.readLongAttribute(parser, ATTR_ACCESS_DURATION, 0);
+ if (accessDuration > 0) {
+ if (!Double.isNaN(filterScale)) {
+ accessDuration = (long) HistoricalOps.round(
+ (double) accessDuration * filterScale);
+ }
+ if (ops == null) {
+ ops = new HistoricalOps(0, 0);
+ }
+ ops.increaseAccessDuration(op, uid, packageName, uidState, accessDuration);
+ }
+ return ops;
+ }
+
+ private void writeHistoricalOpsDLocked(@Nullable List<HistoricalOps> allOps,
+ long intervalOverflowMillis, @NonNull File file) throws IOException {
+ final FileOutputStream output = mHistoricalAppOpsDir.openWrite(file);
+ try {
+ final XmlSerializer serializer = Xml.newSerializer();
+ serializer.setOutput(output, StandardCharsets.UTF_8.name());
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output",
+ true);
+ serializer.startDocument(null, true);
+ serializer.startTag(null, TAG_HISTORY);
+ serializer.attribute(null, ATTR_VERSION, String.valueOf(CURRENT_VERSION));
+ if (intervalOverflowMillis != 0) {
+ serializer.attribute(null, ATTR_OVERFLOW,
+ Long.toString(intervalOverflowMillis));
+ }
+ if (allOps != null) {
+ final int opsCount = allOps.size();
+ for (int i = 0; i < opsCount; i++) {
+ final HistoricalOps ops = allOps.get(i);
+ writeHistoricalOpDLocked(ops, serializer);
+ }
+ }
+ serializer.endTag(null, TAG_HISTORY);
+ serializer.endDocument();
+ mHistoricalAppOpsDir.closeWrite(output);
+ } catch (IOException e) {
+ mHistoricalAppOpsDir.failWrite(output);
+ throw e;
+ }
+ }
+
+ private void writeHistoricalOpDLocked(@NonNull HistoricalOps ops,
+ @NonNull XmlSerializer serializer) throws IOException {
+ serializer.startTag(null, TAG_OPS);
+ serializer.attribute(null, ATTR_BEGIN_TIME, Long.toString(ops.getBeginTimeMillis()));
+ serializer.attribute(null, ATTR_END_TIME, Long.toString(ops.getEndTimeMillis()));
+ final int uidCount = ops.getUidCount();
+ for (int i = 0; i < uidCount; i++) {
+ final HistoricalUidOps uidOp = ops.getUidOpsAt(i);
+ writeHistoricalUidOpsDLocked(uidOp, serializer);
+ }
+ serializer.endTag(null, TAG_OPS);
+ }
+
+ private void writeHistoricalUidOpsDLocked(@NonNull HistoricalUidOps uidOps,
+ @NonNull XmlSerializer serializer) throws IOException {
+ serializer.startTag(null, TAG_UID);
+ serializer.attribute(null, ATTR_NAME, Integer.toString(uidOps.getUid()));
+ final int packageCount = uidOps.getPackageCount();
+ for (int i = 0; i < packageCount; i++) {
+ final HistoricalPackageOps packageOps = uidOps.getPackageOpsAt(i);
+ writeHistoricalPackageOpsDLocked(packageOps, serializer);
+ }
+ serializer.endTag(null, TAG_UID);
+ }
+
+ private void writeHistoricalPackageOpsDLocked(@NonNull HistoricalPackageOps packageOps,
+ @NonNull XmlSerializer serializer) throws IOException {
+ serializer.startTag(null, TAG_PACKAGE);
+ serializer.attribute(null, ATTR_NAME, packageOps.getPackageName());
+ final int opCount = packageOps.getOpCount();
+ for (int i = 0; i < opCount; i++) {
+ final HistoricalOp op = packageOps.getOpAt(i);
+ writeHistoricalOpDLocked(op, serializer);
+ }
+ serializer.endTag(null, TAG_PACKAGE);
+ }
+
+ private void writeHistoricalOpDLocked(@NonNull HistoricalOp op,
+ @NonNull XmlSerializer serializer) throws IOException {
+ serializer.startTag(null, TAG_OP);
+ serializer.attribute(null, ATTR_NAME, Integer.toString(op.getOpCode()));
+ for (int uidState = 0; uidState < AppOpsManager._NUM_UID_STATE; uidState++) {
+ writeUidStateOnLocked(op, uidState, serializer);
+ }
+ serializer.endTag(null, TAG_OP);
+ }
+
+ private void writeUidStateOnLocked(@NonNull HistoricalOp op, @UidState int uidState,
+ @NonNull XmlSerializer serializer) throws IOException {
+ final long accessCount = op.getAccessCount(uidState);
+ final long rejectCount = op.getRejectCount(uidState);
+ final long accessDuration = op.getAccessDuration(uidState);
+ if (accessCount == 0 && rejectCount == 0 && accessDuration == 0) {
+ return;
+ }
+ serializer.startTag(null, TAG_STATE);
+ serializer.attribute(null, ATTR_NAME, Integer.toString(uidState));
+ if (accessCount > 0) {
+ serializer.attribute(null, ATTR_ACCESS_COUNT, Long.toString(accessCount));
+ }
+ if (rejectCount > 0) {
+ serializer.attribute(null, ATTR_REJECT_COUNT, Long.toString(rejectCount));
+ }
+ if (accessDuration > 0) {
+ serializer.attribute(null, ATTR_ACCESS_DURATION, Long.toString(accessDuration));
+ }
+ serializer.endTag(null, TAG_STATE);
+ }
+
+ private static void enforceOpsWellFormed(@NonNull List<HistoricalOps> ops) {
+ if (ops == null) {
+ return;
+ }
+ HistoricalOps previous;
+ HistoricalOps current = null;
+ final int opsCount = ops.size();
+ for (int i = 0; i < opsCount; i++) {
+ previous = current;
+ current = ops.get(i);
+ if (current.isEmpty()) {
+ throw new IllegalStateException("Empty ops:\n"
+ + opsToDebugString(ops));
+ }
+ if (current.getEndTimeMillis() < current.getBeginTimeMillis()) {
+ throw new IllegalStateException("Begin after end:\n"
+ + opsToDebugString(ops));
+ }
+ if (previous != null) {
+ if (previous.getEndTimeMillis() > current.getBeginTimeMillis()) {
+ throw new IllegalStateException("Intersecting ops:\n"
+ + opsToDebugString(ops));
+ }
+ if (previous.getBeginTimeMillis() > current.getBeginTimeMillis()) {
+ throw new IllegalStateException("Non increasing ops:\n"
+ + opsToDebugString(ops));
+ }
+ }
+ }
+ }
+
+ private long computeGlobalIntervalBeginMillis(int depth) {
+ long beginTimeMillis = 0;
+ for (int i = 0; i < depth + 1; i++) {
+ beginTimeMillis += Math.pow(mIntervalCompressionMultiplier, i);
+ }
+ return beginTimeMillis * mBaseSnapshotInterval;
+ }
+
+ private static @NonNull HistoricalOps spliceFromEnd(@NonNull HistoricalOps ops,
+ double spliceRatio) {
+ if (DEBUG) {
+ Slog.w(LOG_TAG, "Splicing from end:" + ops + " ratio:" + spliceRatio);
+ }
+ final HistoricalOps splice = ops.spliceFromEnd(spliceRatio);
+ if (DEBUG) {
+ Slog.w(LOG_TAG, "Spliced into:" + ops + " and:" + splice);
+ }
+ return splice;
+ }
+
+
+ private static @NonNull HistoricalOps spliceFromBeginning(@NonNull HistoricalOps ops,
+ double spliceRatio) {
+ if (DEBUG) {
+ Slog.w(LOG_TAG, "Splicing from beginning:" + ops + " ratio:" + spliceRatio);
+ }
+ final HistoricalOps splice = ops.spliceFromBeginning(spliceRatio);
+ if (DEBUG) {
+ Slog.w(LOG_TAG, "Spliced into:" + ops + " and:" + splice);
+ }
+ return splice;
+ }
+
+ private static void normalizeSnapshotForSlotDuration(@NonNull List<HistoricalOps> ops,
+ long slotDurationMillis) {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "Normalizing for slot duration: " + slotDurationMillis
+ + " ops:\n" + opsToDebugString(ops));
+ enforceOpsWellFormed(ops);
+ }
+ long slotBeginTimeMillis;
+ final int opCount = ops.size();
+ for (int processedIdx = opCount - 1; processedIdx >= 0; processedIdx--) {
+ final HistoricalOps processedOp = ops.get(processedIdx);
+ slotBeginTimeMillis = Math.max(processedOp.getEndTimeMillis()
+ - slotDurationMillis, 0);
+ for (int candidateIdx = processedIdx - 1; candidateIdx >= 0; candidateIdx--) {
+ final HistoricalOps candidateOp = ops.get(candidateIdx);
+ final long candidateSlotIntersectionMillis = candidateOp.getEndTimeMillis()
+ - Math.min(slotBeginTimeMillis, processedOp.getBeginTimeMillis());
+ if (candidateSlotIntersectionMillis <= 0) {
+ break;
+ }
+ final float candidateSplitRatio = candidateSlotIntersectionMillis
+ / (float) candidateOp.getDurationMillis();
+ if (Float.compare(candidateSplitRatio, 1.0f) >= 0) {
+ ops.remove(candidateIdx);
+ processedIdx--;
+ processedOp.merge(candidateOp);
+ } else {
+ final HistoricalOps endSplice = spliceFromEnd(candidateOp,
+ candidateSplitRatio);
+ if (endSplice != null) {
+ processedOp.merge(endSplice);
+ }
+ if (candidateOp.isEmpty()) {
+ ops.remove(candidateIdx);
+ processedIdx--;
+ }
+ }
+ }
+ }
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "Normalized for slot duration: " + slotDurationMillis
+ + " ops:\n" + opsToDebugString(ops));
+ enforceOpsWellFormed(ops);
+ }
+ }
+
+ private static @NonNull String opsToDebugString(@NonNull List<HistoricalOps> ops) {
+ StringBuilder builder = new StringBuilder();
+ final int opCount = ops.size();
+ for (int i = 0; i < opCount; i++) {
+ builder.append(" ");
+ builder.append(ops.get(i));
+ if (i < opCount - 1) {
+ builder.append('\n');
+ }
+ }
+ return builder.toString();
+ }
+ }
+
+ private final class StringDumpVisitor implements AppOpsManager.HistoricalOpsVisitor {
+ private final long mNow = System.currentTimeMillis();
+
+ private final SimpleDateFormat mDateFormatter = new SimpleDateFormat(
+ "yyyy-MM-dd HH:mm:ss.SSS");
+ private final Date mDate = new Date();
+
+ private final @NonNull String mOpsPrefix;
+ private final @NonNull String mUidPrefix;
+ private final @NonNull String mPackagePrefix;
+ private final @NonNull String mEntryPrefix;
+ private final @NonNull String mUidStatePrefix;
+ private final @NonNull PrintWriter mWriter;
+ private final int mFilterUid;
+ private final String mFilterPackage;
+ private final int mFilterOp;
+
+ StringDumpVisitor(@NonNull String prefix, @NonNull PrintWriter writer,
+ int filterUid, String filterPackage, int filterOp) {
+ mOpsPrefix = prefix + " ";
+ mUidPrefix = mOpsPrefix + " ";
+ mPackagePrefix = mUidPrefix + " ";
+ mEntryPrefix = mPackagePrefix + " ";
+ mUidStatePrefix = mEntryPrefix + " ";
+ mWriter = writer;
+ mFilterUid = filterUid;
+ mFilterPackage = filterPackage;
+ mFilterOp = filterOp;
+ }
+
+ @Override
+ public void visitHistoricalOps(HistoricalOps ops) {
+ mWriter.println();
+ mWriter.print(mOpsPrefix);
+ mWriter.println("snapshot:");
+ mWriter.print(mUidPrefix);
+ mWriter.print("begin = ");
+ mDate.setTime(ops.getBeginTimeMillis());
+ mWriter.print(mDateFormatter.format(mDate));
+ mWriter.print(" (");
+ TimeUtils.formatDuration(ops.getBeginTimeMillis() - mNow, mWriter);
+ mWriter.println(")");
+ mWriter.print(mUidPrefix);
+ mWriter.print("end = ");
+ mDate.setTime(ops.getEndTimeMillis());
+ mWriter.print(mDateFormatter.format(mDate));
+ mWriter.print(" (");
+ TimeUtils.formatDuration(ops.getEndTimeMillis() - mNow, mWriter);
+ mWriter.println(")");
+ }
+
+ @Override
+ public void visitHistoricalUidOps(HistoricalUidOps ops) {
+ if (mFilterUid != Process.INVALID_UID && mFilterUid != ops.getUid()) {
+ return;
+ }
+ mWriter.println();
+ mWriter.print(mUidPrefix);
+ mWriter.print("Uid ");
+ UserHandle.formatUid(mWriter, ops.getUid());
+ mWriter.println(":");
+ }
+
+ @Override
+ public void visitHistoricalPackageOps(HistoricalPackageOps ops) {
+ if (mFilterPackage != null && !mFilterPackage.equals(ops.getPackageName())) {
+ return;
+ }
+ mWriter.print(mPackagePrefix);
+ mWriter.print("Package ");
+ mWriter.print(ops.getPackageName());
+ mWriter.println(":");
+ }
+
+ @Override
+ public void visitHistoricalOp(HistoricalOp ops) {
+ if (mFilterOp != AppOpsManager.OP_NONE && mFilterOp != ops.getOpCode()) {
+ return;
+ }
+ mWriter.print(mEntryPrefix);
+ mWriter.print(AppOpsManager.opToName(ops.getOpCode()));
+ mWriter.println(":");
+ for (int uidState = 0; uidState < AppOpsManager._NUM_UID_STATE; uidState++) {
+ boolean printedUidState = false;
+ final long accessCount = ops.getAccessCount(uidState);
+ if (accessCount > 0) {
+ if (!printedUidState) {
+ mWriter.print(mUidStatePrefix);
+ mWriter.print(AppOpsManager.uidStateToString(uidState));
+ mWriter.print("[");
+ printedUidState = true;
+ }
+ mWriter.print("access=");
+ mWriter.print(accessCount);
+ }
+ final long rejectCount = ops.getRejectCount(uidState);
+ if (rejectCount > 0) {
+ if (!printedUidState) {
+ mWriter.print(mUidStatePrefix);
+ mWriter.print(AppOpsManager.uidStateToString(uidState));
+ mWriter.print("[");
+ printedUidState = true;
+ } else {
+ mWriter.print(",");
+ }
+ mWriter.print("reject=");
+ mWriter.print(rejectCount);
+ }
+ final long accessDuration = ops.getAccessDuration(uidState);
+ if (accessDuration > 0) {
+ if (!printedUidState) {
+ mWriter.print(mUidStatePrefix);
+ mWriter.print(AppOpsManager.uidStateToString(uidState));
+ printedUidState = true;
+ } else {
+ mWriter.print(",");
+ }
+ mWriter.print("duration=");
+ mWriter.print(accessDuration);
+ }
+ if (printedUidState) {
+ mWriter.println("]");
+ }
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index fc1e326..41fedc5 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -351,10 +351,7 @@
if (!runningTasks.isEmpty()) {
final String topPackage = runningTasks.get(0).topActivity.getPackageName();
if (mCurrentAuthSession != null
- && !topPackage.contentEquals(mCurrentAuthSession.mOpPackageName)
- && mCurrentAuthSession.mState != STATE_AUTH_STARTED) {
- // We only care about this state, since <Biometric>Service will
- // cancel any client that's still in STATE_AUTH_STARTED
+ && !topPackage.contentEquals(mCurrentAuthSession.mOpPackageName)) {
mStatusBarService.hideBiometricDialog();
mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
mCurrentAuthSession.mClientReceiver.onError(
@@ -464,8 +461,9 @@
if (mCurrentAuthSession != null && mCurrentAuthSession.containsCookie(cookie)) {
if (mCurrentAuthSession.mState == STATE_AUTH_STARTED) {
mStatusBarService.onBiometricError(message);
- mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
+ mActivityTaskManager.unregisterTaskStackListener(
+ mTaskStackListener);
mCurrentAuthSession.mClientReceiver.onError(error, message);
mCurrentAuthSession.mState = STATE_AUTH_IDLE;
mCurrentAuthSession = null;
@@ -474,9 +472,14 @@
// Send errors after the dialog is dismissed.
mHandler.postDelayed(() -> {
try {
- mCurrentAuthSession.mClientReceiver.onError(error, message);
- mCurrentAuthSession.mState = STATE_AUTH_IDLE;
- mCurrentAuthSession = null;
+ if (mCurrentAuthSession != null) {
+ mActivityTaskManager.unregisterTaskStackListener(
+ mTaskStackListener);
+ mCurrentAuthSession.mClientReceiver.onError(error,
+ message);
+ mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+ mCurrentAuthSession = null;
+ }
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
}
@@ -540,6 +543,11 @@
@Override
public void onDialogDismissed(int reason) throws RemoteException {
+ if (mCurrentAuthSession == null) {
+ Slog.e(TAG, "onDialogDismissed: " + reason + ", auth session null");
+ return;
+ }
+
if (reason != BiometricPrompt.DISMISSED_REASON_POSITIVE) {
// Positive button is used by passive modalities as a "confirm" button,
// do not send to client
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index 32219aa..ecc3d2d 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -819,8 +819,6 @@
// Should be done on a handler thread - not on the Binder's thread.
private void startAuthentication(AuthenticationClientImpl client, String opPackageName) {
- updateActiveGroup(client.getGroupId(), opPackageName);
-
if (DEBUG) Slog.v(getTag(), "startAuthentication(" + opPackageName + ")");
int lockoutMode = getLockoutMode();
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index f4d8d4b..5a9c1ac 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -133,10 +133,11 @@
}
@Override // Binder call
- public void authenticate(final IBinder token, final long opId,
+ public void authenticate(final IBinder token, final long opId, int userId,
final IFaceServiceReceiver receiver, final int flags,
final String opPackageName) {
checkPermission(USE_BIOMETRIC_INTERNAL);
+ updateActiveGroup(userId, opPackageName);
final boolean restricted = isRestricted();
final AuthenticationClientImpl client = new FaceAuthClient(getContext(),
mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index 3895ef7..1613dc9 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -159,6 +159,7 @@
public void authenticate(final IBinder token, final long opId, final int groupId,
final IFingerprintServiceReceiver receiver, final int flags,
final String opPackageName) {
+ updateActiveGroup(groupId, opPackageName);
final boolean restricted = isRestricted();
final AuthenticationClientImpl client = new FingerprintAuthClient(getContext(),
mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index 73d3d95..b332c47 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -18,7 +18,9 @@
import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
+import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_SATURATION;
+import android.Manifest;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.TypeEvaluator;
@@ -31,6 +33,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.hardware.display.ColorDisplayManager;
import android.hardware.display.IColorDisplayManager;
@@ -39,6 +42,7 @@
import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
+import android.os.Message;
import android.os.UserHandle;
import android.provider.Settings.Secure;
import android.provider.Settings.System;
@@ -61,6 +65,7 @@
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeParseException;
+import java.util.Arrays;
/**
* Controls the display's color transforms.
@@ -83,6 +88,10 @@
Matrix.setIdentityM(MATRIX_IDENTITY, 0);
}
+ private static final int MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE = 0;
+ private static final int MSG_APPLY_NIGHT_DISPLAY_ANIMATED = 1;
+ private static final int MSG_APPLY_GLOBAL_SATURATION = 2;
+
/**
* Evaluator used to animate color matrix transitions.
*/
@@ -161,6 +170,53 @@
}
};
+ private final TintController mGlobalSaturationTintController = new TintController() {
+
+ private float[] mMatrixGlobalSaturation = new float[16];
+
+ @Override
+ public void setUp(Context context, boolean needsLinear) {
+ }
+
+ @Override
+ public float[] getMatrix() {
+ return Arrays.copyOf(mMatrixGlobalSaturation, mMatrixGlobalSaturation.length);
+ }
+
+ @Override
+ public void setMatrix(int saturationLevel) {
+ if (saturationLevel < 0) {
+ saturationLevel = 0;
+ } else if (saturationLevel > 100) {
+ saturationLevel = 100;
+ }
+ Slog.d(TAG, "Setting saturation level: " + saturationLevel);
+
+ if (saturationLevel == 100) {
+ Matrix.setIdentityM(mMatrixGlobalSaturation, 0);
+ } else {
+ float saturation = saturationLevel * 0.1f;
+ float desaturation = 1.0f - saturation;
+ float[] luminance = {0.231f * desaturation, 0.715f * desaturation,
+ 0.072f * desaturation};
+ mMatrixGlobalSaturation[0] = luminance[0] + saturation;
+ mMatrixGlobalSaturation[1] = luminance[0];
+ mMatrixGlobalSaturation[2] = luminance[0];
+ mMatrixGlobalSaturation[4] = luminance[1];
+ mMatrixGlobalSaturation[5] = luminance[1] + saturation;
+ mMatrixGlobalSaturation[6] = luminance[1];
+ mMatrixGlobalSaturation[8] = luminance[2];
+ mMatrixGlobalSaturation[9] = luminance[2];
+ mMatrixGlobalSaturation[10] = luminance[2] + saturation;
+ }
+ }
+
+ @Override
+ public int getLevel() {
+ return LEVEL_COLOR_MATRIX_SATURATION;
+ }
+ };
+
private final Handler mHandler;
private int mCurrentUser = UserHandle.USER_NULL;
@@ -178,7 +234,7 @@
public ColorDisplayService(Context context) {
super(context);
- mHandler = new Handler(Looper.getMainLooper());
+ mHandler = new TintHandler(Looper.getMainLooper());
}
@Override
@@ -904,6 +960,23 @@
void onDisplayWhiteBalanceStatusChanged(boolean enabled);
}
+ private final class TintHandler extends Handler {
+
+ TintHandler(Looper looper) {
+ super(looper, null, true /* async */);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_APPLY_GLOBAL_SATURATION:
+ mGlobalSaturationTintController.setMatrix(msg.arg1);
+ applyTint(mGlobalSaturationTintController, false);
+ break;
+ }
+ }
+ }
+
private final class BinderService extends IColorDisplayManager.Stub {
@Override
@@ -915,5 +988,27 @@
Binder.restoreCallingIdentity(token);
}
}
+
+ @Override
+ public boolean setSaturationLevel(int level) {
+ final boolean hasTransformsPermission = getContext()
+ .checkCallingPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
+ == PackageManager.PERMISSION_GRANTED;
+ final boolean hasLegacyPermission = getContext()
+ .checkCallingPermission(Manifest.permission.CONTROL_DISPLAY_SATURATION)
+ == PackageManager.PERMISSION_GRANTED;
+ if (!hasTransformsPermission && !hasLegacyPermission) {
+ throw new SecurityException("Permission required to set display saturation level");
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ final Message message = mHandler.obtainMessage(MSG_APPLY_GLOBAL_SATURATION);
+ message.arg1 = level;
+ mHandler.sendMessage(message);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return true;
+ }
}
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index b1ba05c..4a17c65 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -724,27 +724,6 @@
}
}
- private void setSaturationLevelInternal(float level) {
- if (level < 0 || level > 1) {
- throw new IllegalArgumentException("Saturation level must be between 0 and 1");
- }
- float[] matrix = (level == 1.0f ? null : computeSaturationMatrix(level));
- DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
- dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_SATURATION, matrix);
- }
-
- private static float[] computeSaturationMatrix(float saturation) {
- float desaturation = 1.0f - saturation;
- float[] luminance = {0.231f * desaturation, 0.715f * desaturation, 0.072f * desaturation};
- float[] matrix = {
- luminance[0] + saturation, luminance[0], luminance[0], 0,
- luminance[1], luminance[1] + saturation, luminance[1], 0,
- luminance[2], luminance[2], luminance[2] + saturation, 0,
- 0, 0, 0, 1
- };
- return matrix;
- }
-
private int createVirtualDisplayInternal(IVirtualDisplayCallback callback,
IMediaProjection projection, int callingUid, String packageName, String name, int width,
int height, int densityDpi, Surface surface, int flags, String uniqueId) {
@@ -1836,19 +1815,6 @@
}
@Override // Binder call
- public void setSaturationLevel(float level) {
- mContext.enforceCallingOrSelfPermission(
- Manifest.permission.CONTROL_DISPLAY_SATURATION,
- "Permission required to set display saturation level");
- final long token = Binder.clearCallingIdentity();
- try {
- setSaturationLevelInternal(level);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override // Binder call
public int createVirtualDisplay(IVirtualDisplayCallback callback,
IMediaProjection projection, String packageName, String name,
int width, int height, int densityDpi, Surface surface, int flags,
diff --git a/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java b/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java
index ed17de5..18d328d 100644
--- a/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java
@@ -21,14 +21,15 @@
* Feature action that handles Audio Return Channel initiated by AVR devices.
*/
public class ArcInitiationActionFromAvr extends HdmiCecFeatureAction {
- // TODO(shubang): add tests
-
// State in which waits for ARC response.
private static final int STATE_WAITING_FOR_INITIATE_ARC_RESPONSE = 1;
private static final int STATE_ARC_INITIATED = 2;
// the required maximum response time specified in CEC 9.2
private static final int TIMEOUT_MS = 1000;
+ private static final int MAX_RETRY_COUNT = 5;
+
+ private int mSendRequestActiveSourceRetryCount = 0;
ArcInitiationActionFromAvr(HdmiCecLocalDevice source) {
super(source);
@@ -56,7 +57,12 @@
return true;
case Constants.MESSAGE_REPORT_ARC_INITIATED:
mState = STATE_ARC_INITIATED;
- finish();
+ if (audioSystem().getActiveSource().physicalAddress != getSourcePath()
+ && audioSystem().isSystemAudioActivated()) {
+ sendRequestActiveSource();
+ } else {
+ finish();
+ }
return true;
}
return false;
@@ -91,4 +97,19 @@
finish();
}
+ protected void sendRequestActiveSource() {
+ sendCommand(HdmiCecMessageBuilder.buildRequestActiveSource(getSourceAddress()),
+ result -> {
+ if (result != SendMessageResult.SUCCESS) {
+ if (mSendRequestActiveSourceRetryCount < MAX_RETRY_COUNT) {
+ mSendRequestActiveSourceRetryCount++;
+ sendRequestActiveSource();
+ } else {
+ finish();
+ }
+ } else {
+ finish();
+ }
+ });
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java b/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java
index 7e73321..eb7c0cd 100644
--- a/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java
@@ -50,6 +50,9 @@
case Constants.MESSAGE_REPORT_ARC_TERMINATED:
mState = STATE_ARC_TERMINATED;
audioSystem().setArcStatus(false);
+ if (audioSystem().getLocalActivePort() == Constants.CEC_SWITCH_ARC) {
+ audioSystem().routeToInputFromPortId(audioSystem().getRoutingPort());
+ }
finish();
return true;
}
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index 1b0eb19..6f5a196 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -256,6 +256,41 @@
static final int USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON = 1;
static final int NEVER_SYSTEM_AUDIO_CONTROL_ON_POWER_ON = 2;
+ // Port id to record local active port for Routing Control features
+ // They are used to map to corresponding Inputs
+ // Current interface is only implemented for specific device.
+ // Developers can add more port number and map them to corresponding inputs on demand.
+ @IntDef({
+ CEC_SWITCH_HOME,
+ CEC_SWITCH_HDMI1,
+ CEC_SWITCH_HDMI2,
+ CEC_SWITCH_HDMI3,
+ CEC_SWITCH_HDMI4,
+ CEC_SWITCH_HDMI5,
+ CEC_SWITCH_HDMI6,
+ CEC_SWITCH_HDMI7,
+ CEC_SWITCH_HDMI8,
+ CEC_SWITCH_ARC,
+ CEC_SWITCH_BLUETOOTH,
+ CEC_SWITCH_OPTICAL,
+ CEC_SWITCH_AUX
+ })
+ @interface LocalActivePort {}
+ static final int CEC_SWITCH_HOME = 0;
+ static final int CEC_SWITCH_HDMI1 = 1;
+ static final int CEC_SWITCH_HDMI2 = 2;
+ static final int CEC_SWITCH_HDMI3 = 3;
+ static final int CEC_SWITCH_HDMI4 = 4;
+ static final int CEC_SWITCH_HDMI5 = 5;
+ static final int CEC_SWITCH_HDMI6 = 6;
+ static final int CEC_SWITCH_HDMI7 = 7;
+ static final int CEC_SWITCH_HDMI8 = 8;
+ static final int CEC_SWITCH_ARC = 17;
+ static final int CEC_SWITCH_BLUETOOTH = 18;
+ static final int CEC_SWITCH_OPTICAL = 19;
+ static final int CEC_SWITCH_AUX = 20;
+ static final int CEC_SWITCH_PORT_MAX = 21;
+
static final String PROPERTY_PREFERRED_ADDRESS_AUDIO_SYSTEM =
"persist.sys.hdmi.addr.audiosystem";
static final String PROPERTY_PREFERRED_ADDRESS_PLAYBACK = "persist.sys.hdmi.addr.playback";
@@ -274,6 +309,13 @@
static final String PROPERTY_SET_MENU_LANGUAGE = "ro.hdmi.set_menu_language";
/**
+ * Property to save the ARC port id on system audio device.
+ * <p>When ARC is initiated, this port will be used to turn on ARC.
+ */
+ static final String PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT =
+ "ro.hdmi.property_sytem_audio_device_arc_port";
+
+ /**
* Property to disable muting logic in System Audio Control handling. Default is true.
*
* <p>True means enabling muting logic.
@@ -291,6 +333,24 @@
static final String PROPERTY_HDMI_CEC_NEVER_CLAIM_PLAYBACK_LOGICAL_ADDRESS =
"ro.hdmi.property_hdmi_cec_never_claim_playback_logical_address";
+ /**
+ * A comma separated list of logical addresses that HdmiControlService
+ * will never assign local CEC devices to.
+ *
+ * <p> This is useful when HDMI CEC hardware module can't assign multiple logical addresses
+ * in the range same range of 0-7 or 8-15.
+ */
+ static final String PROPERTY_HDMI_CEC_NEVER_ASSIGN_LOGICAL_ADDRESSES =
+ "ro.hdmi.property_hdmi_cec_never_assign_logical_addresses";
+
+ /**
+ * Property to indicate if the current device is a cec switch device.
+ *
+ * <p> Default is false.
+ */
+ static final String PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH =
+ "ro.hdmi.property_is_device_hdmi_cec_switch";
+
// Set to false to allow playback device to go to suspend mode even
// when it's an active source. True by default.
static final String PROPERTY_KEEP_AWAKE = "persist.sys.hdmi.keep_awake";
@@ -331,13 +391,6 @@
"persist.sys.hdmi.property_sytem_audio_mode_audio_port";
/**
- * Property to save the ARC port id on system audio device.
- * <p>When ARC is initiated, this port will be used to turn on ARC.
- */
- static final String PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT =
- "persist.sys.hdmi.property_sytem_audio_device_arc_port";
-
- /**
* Property to indicate if a CEC audio device should forward volume keys when system audio mode
* is off.
*
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index de6cdd4..e777ce8 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -22,20 +22,25 @@
import android.os.Handler;
import android.os.Looper;
import android.os.MessageQueue;
+import android.os.SystemProperties;
import android.util.Slog;
import android.util.SparseArray;
+
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.hdmi.HdmiAnnotations.IoThreadOnly;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import com.android.server.hdmi.HdmiControlService.DevicePollingCallback;
+
+import libcore.util.EmptyArray;
+
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
-import java.util.function.Predicate;
import java.util.concurrent.ArrayBlockingQueue;
-import libcore.util.EmptyArray;
+import java.util.function.Predicate;
+
import sun.util.locale.LanguageTag;
/**
@@ -112,10 +117,18 @@
private final NativeWrapper mNativeWrapperImpl;
+ /** List of logical addresses that should not be assigned to the current device.
+ *
+ * <p>Parsed from {@link Constants#PROPERTY_HDMI_CEC_NEVER_ASSIGN_LOGICAL_ADDRESSES}
+ */
+ private final List<Integer> mNeverAssignLogicalAddresses;
+
// Private constructor. Use HdmiCecController.create().
private HdmiCecController(HdmiControlService service, NativeWrapper nativeWrapper) {
mService = service;
mNativeWrapperImpl = nativeWrapper;
+ mNeverAssignLogicalAddresses = mService.getIntList(SystemProperties.get(
+ Constants.PROPERTY_HDMI_CEC_NEVER_ASSIGN_LOGICAL_ADDRESSES));
}
/**
@@ -208,7 +221,8 @@
for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) {
int curAddress = (startAddress + i) % NUM_LOGICAL_ADDRESS;
if (curAddress != Constants.ADDR_UNREGISTERED
- && deviceType == HdmiUtils.getTypeFromAddress(curAddress)) {
+ && deviceType == HdmiUtils.getTypeFromAddress(curAddress)
+ && !mNeverAssignLogicalAddresses.contains(curAddress)) {
boolean acked = false;
for (int j = 0; j < HdmiConfig.ADDRESS_ALLOCATION_RETRY; ++j) {
if (sendPollMessage(curAddress, curAddress, 1)) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index c338e21..6e1b018 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -18,10 +18,12 @@
import android.annotation.Nullable;
import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.input.InputManager;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Slog;
import android.view.InputDevice;
@@ -30,6 +32,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.hdmi.Constants.LocalActivePort;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
@@ -132,9 +135,6 @@
return s.toString();
}
}
- // Logical address of the active source.
- @GuardedBy("mLock")
- protected final ActiveSource mActiveSource = new ActiveSource();
// Active routing path. Physical address of the active source but not all the time, such as
// when the new active source does not claim itself to be one. Note that we don't keep
@@ -866,9 +866,7 @@
}
ActiveSource getActiveSource() {
- synchronized (mLock) {
- return mActiveSource;
- }
+ return mService.getActiveSource();
}
void setActiveSource(ActiveSource newActive) {
@@ -880,10 +878,7 @@
}
void setActiveSource(int logicalAddress, int physicalAddress) {
- synchronized (mLock) {
- mActiveSource.logicalAddress = logicalAddress;
- mActiveSource.physicalAddress = physicalAddress;
- }
+ mService.setActiveSource(logicalAddress, physicalAddress);
mService.setLastInputForMhl(Constants.INVALID_PORT_ID);
}
@@ -1028,6 +1023,19 @@
return Constants.ADDR_INVALID;
}
+ @ServiceThreadOnly
+ void invokeCallback(IHdmiControlCallback callback, int result) {
+ assertRunOnServiceThread();
+ if (callback == null) {
+ return;
+ }
+ try {
+ callback.onComplete(result);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Invoking callback failed:" + e);
+ }
+ }
+
void sendUserControlPressedAndReleased(int targetAddress, int cecKeycode) {
mService.sendCecCommand(
HdmiCecMessageBuilder.buildUserControlPressed(mAddress, targetAddress, cecKeycode));
@@ -1041,7 +1049,7 @@
pw.println("mAddress: " + mAddress);
pw.println("mPreferredAddress: " + mPreferredAddress);
pw.println("mDeviceInfo: " + mDeviceInfo);
- pw.println("mActiveSource: " + mActiveSource);
+ pw.println("mActiveSource: " + getActiveSource());
pw.println(String.format("mActiveRoutingPath: 0x%04x", mActiveRoutingPath));
}
@@ -1051,7 +1059,7 @@
* <p>This check assumes target address is valid.
* @param targetPhysicalAddress is the physical address of the target device
* @return
- * <p>If the target device is under the current device, return the port number of current device
+ * If the target device is under the current device, return the port number of current device
* that the target device is connected to.
*
* <p>If the target device has the same physical address as the current device, return
@@ -1085,4 +1093,27 @@
}
return TARGET_NOT_UNDER_LOCAL_DEVICE;
}
+
+ /** Calculates the physical address for {@code activePortId}.
+ *
+ * <p>This method assumes current device physical address is valid.
+ * <p>If the current device is already the leaf of the whole CEC system
+ * and can't have devices under it, will return its own physical address.
+ *
+ * @param activePortId is the local active port Id
+ * @return the calculated physical address of the port
+ */
+ protected int getActivePathOnSwitchFromActivePortId(@LocalActivePort int activePortId) {
+ int myPhysicalAddress = mService.getPhysicalAddress();
+ int finalMask = activePortId << 8;
+ int mask;
+ for (mask = 0x0F00; mask > 0x000F; mask >>= 4) {
+ if ((myPhysicalAddress & mask) == 0) {
+ break;
+ } else {
+ finalMask >>= 4;
+ }
+ }
+ return finalMask | myPhysicalAddress;
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 20908b6..8cfe47f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -20,18 +20,23 @@
import static com.android.server.hdmi.Constants.USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON;
import android.annotation.Nullable;
+import android.content.Intent;
+import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.hdmi.IHdmiControlCallback;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.media.AudioSystem;
+import android.media.tv.TvContract;
import android.os.SystemProperties;
-import android.provider.Settings.Global;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.hdmi.Constants.AudioCodec;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
+import java.util.HashMap;
+
/**
* Represent a logical device of type {@link HdmiDeviceInfo#DEVICE_AUDIO_SYSTEM} residing in Android
* system.
@@ -51,25 +56,20 @@
private boolean mTvSystemAudioModeSupport;
- // Whether the auido system will turn TV off when it's powering off
- private boolean mAutoTvOff;
- // Whether the auido system will broadcast standby to the system when it's powering off
- private boolean mAutoDeviceOff;
-
// Whether ARC is available or not. "true" means that ARC is established between TV and
// AVR as audio receiver.
@ServiceThreadOnly private boolean mArcEstablished = false;
- /**
- * Return value of {@link #getLocalPortFromPhysicalAddress(int)}
- */
- private static final int TARGET_NOT_UNDER_LOCAL_DEVICE = -1;
- private static final int TARGET_SAME_PHYSICAL_ADDRESS = 0;
+ // If the current device uses TvInput for ARC. We assume all other inputs also use TvInput
+ // when ARC is using TvInput.
+ private boolean mArcIntentUsed = SystemProperties
+ .get(Constants.PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT, "0").contains("tvinput");
- // Local active port number used for Routing Control.
- // Default 0 means HOME is the current active path. Temp solution only.
- // TODO(amyjojo): adding system constants for Atom inputs port and TIF mapping.
- private int mLocalActivePath = 0;
+ // Keeps the mapping (HDMI port ID to TV input URI) to keep track of the TV inputs ready to
+ // accept input switching request from HDMI devices. Requests for which the corresponding
+ // input ID is not yet registered by TV input framework need to be buffered for delayed
+ // processing.
+ private final HashMap<Integer, String> mTvInputs = new HashMap<>();
protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) {
super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
@@ -77,10 +77,13 @@
// TODO(amyjojo) make System Audio Control controllable by users
/*mSystemAudioControlFeatureEnabled =
mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true);*/
- mAutoDeviceOff = mService.readBooleanSetting(
- Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, true);
- mAutoTvOff = mService.readBooleanSetting(
- Global.HDMI_CONTROL_AUTO_TV_OFF_ENABLED, true);
+ // TODO(amyjojo): make the map ro property.
+ mTvInputs.put(Constants.CEC_SWITCH_HDMI1,
+ "com.droidlogic.tvinput/.services.Hdmi1InputService/HW5");
+ mTvInputs.put(Constants.CEC_SWITCH_HDMI2,
+ "com.droidlogic.tvinput/.services.Hdmi2InputService/HW6");
+ mTvInputs.put(Constants.CEC_SWITCH_HDMI3,
+ "com.droidlogic.tvinput/.services.Hdmi3InputService/HW7");
}
@Override
@@ -95,21 +98,6 @@
mSystemAudioActivated ? "true" : "false");
}
terminateSystemAudioMode();
-
- HdmiLogger.debug(TAG + " onStandby, initiatedByCec:" + initiatedByCec
- + ", mAutoDeviceOff: " + mAutoDeviceOff + ", mAutoTvOff: " + mAutoTvOff);
- if (!mService.isControlEnabled() || initiatedByCec) {
- return;
- }
- if (mAutoDeviceOff) {
- mService.sendCecCommand(
- HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_BROADCAST));
- } else if (mAutoTvOff) {
- mService.sendCecCommand(
- HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV));
- }
- return;
-
}
@Override
@@ -221,6 +209,7 @@
@ServiceThreadOnly
protected boolean handleRequestArcInitiate(HdmiCecMessage message) {
assertRunOnServiceThread();
+ removeAction(ArcInitiationActionFromAvr.class);
if (!SystemProperties.getBoolean(Constants.PROPERTY_ARC_SUPPORT, true)) {
mService.maySendFeatureAbortCommand(message, Constants.ABORT_UNRECOGNIZED_OPCODE);
} else if (!isDirectConnectToTv()) {
@@ -242,6 +231,7 @@
HdmiLogger.debug("ARC is not established between TV and AVR device");
mService.maySendFeatureAbortCommand(message, Constants.ABORT_NOT_IN_CORRECT_MODE);
} else {
+ removeAction(ArcTerminationActionFromAvr.class);
addAndStartAction(new ArcTerminationActionFromAvr(this));
}
return true;
@@ -460,11 +450,17 @@
}
}
// Init arc whenever System Audio Mode is on
- // Since some TV like LG don't request ARC on with System Audio Mode on request
- if (newSystemAudioMode
- && SystemProperties.getBoolean(Constants.PROPERTY_ARC_SUPPORT, true)
- && !isArcEnabled() && isDirectConnectToTv()) {
- addAndStartAction(new ArcInitiationActionFromAvr(this));
+ // Terminate arc when System Audio Mode is off
+ // Since some TVs don't request ARC on with System Audio Mode on request
+ if (SystemProperties.getBoolean(Constants.PROPERTY_ARC_SUPPORT, true)
+ && isDirectConnectToTv()) {
+ if (newSystemAudioMode && !isArcEnabled()) {
+ removeAction(ArcInitiationActionFromAvr.class);
+ addAndStartAction(new ArcInitiationActionFromAvr(this));
+ } else if (!newSystemAudioMode && isArcEnabled()) {
+ removeAction(ArcTerminationActionFromAvr.class);
+ addAndStartAction(new ArcTerminationActionFromAvr(this));
+ }
}
}
@@ -490,6 +486,33 @@
}
}
+ @ServiceThreadOnly
+ void doManualPortSwitching(int portId, IHdmiControlCallback callback) {
+ assertRunOnServiceThread();
+ // TODO: validate port ID
+ if (portId == getLocalActivePort()) {
+ invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
+ return;
+ }
+ getActiveSource().invalidate();
+ if (!mService.isControlEnabled()) {
+ setLocalActivePort(portId);
+ invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
+ return;
+ }
+ int oldPath = getLocalActivePort() != Constants.CEC_SWITCH_HOME
+ ? getActivePathOnSwitchFromActivePortId(getLocalActivePort())
+ : getDeviceInfo().getPhysicalAddress();
+ int newPath = getActivePathOnSwitchFromActivePortId(portId);
+ if (oldPath == newPath) {
+ return;
+ }
+ setLocalActivePort(portId);
+ HdmiCecMessage routingChange =
+ HdmiCecMessageBuilder.buildRoutingChange(mAddress, oldPath, newPath);
+ mService.sendCecCommand(routingChange);
+ }
+
boolean isSystemAudioControlFeatureEnabled() {
synchronized (mLock) {
return mSystemAudioControlFeatureEnabled;
@@ -583,16 +606,123 @@
}
}
- @ServiceThreadOnly
- protected void setAutoTvOff(boolean autoTvOff) {
- assertRunOnServiceThread();
- mAutoTvOff = autoTvOff;
+ @Override
+ protected void switchInputOnReceivingNewActivePath(int physicalAddress) {
+ int port = getLocalPortFromPhysicalAddress(physicalAddress);
+ if (isSystemAudioActivated() && port < 0) {
+ // If system audio mode is on and the new active source is not under the current device,
+ // Will switch to ARC input.
+ // TODO(b/115637145): handle system aduio without ARC
+ routeToInputFromPortId(Constants.CEC_SWITCH_ARC);
+ } else if (mIsSwitchDevice && port >= 0) {
+ // If current device is a switch and the new active source is under it,
+ // will switch to the corresponding active path.
+ routeToInputFromPortId(port);
+ }
+ }
+
+ protected void routeToInputFromPortId(int portId) {
+ if (mArcIntentUsed) {
+ routeToTvInputFromPortId(portId);
+ } else {
+ // TODO(): implement input switching for devices not using TvInput.
+ }
+ }
+
+ protected void routeToTvInputFromPortId(int portId) {
+ if (portId < 0 || portId >= Constants.CEC_SWITCH_PORT_MAX) {
+ HdmiLogger.debug("Invalid port number for Tv Input switching.");
+ return;
+ }
+ // Wake up if the current device if ready to route.
+ if (mService.isPowerStandbyOrTransient()) {
+ mService.wakeUp();
+ }
+ if (portId == Constants.CEC_SWITCH_HOME && mService.isPlaybackDevice()) {
+ switchToHomeTvInput();
+ } else if (portId == Constants.CEC_SWITCH_ARC) {
+ switchToTvInput(SystemProperties.get(Constants.PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT));
+ setLocalActivePort(portId);
+ return;
+ } else {
+ String uri = mTvInputs.get(portId);
+ if (uri != null) {
+ switchToTvInput(mTvInputs.get(portId));
+ } else {
+ HdmiLogger.debug("Port number does not match any Tv Input.");
+ return;
+ }
+ }
+
+ setLocalActivePort(portId);
+ setRoutingPort(portId);
+ }
+
+ // For device to switch to specific TvInput with corresponding URI.
+ private void switchToTvInput(String uri) {
+ mService.getContext().startActivity(new Intent(Intent.ACTION_VIEW,
+ TvContract.buildChannelUriForPassthroughInput(uri))
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ }
+
+ // For device using TvInput to switch to Home.
+ private void switchToHomeTvInput() {
+ Intent activityIntent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME)
+ .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
+ | Intent.FLAG_ACTIVITY_SINGLE_TOP
+ | Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_NO_ANIMATION);
+ mService.getContext().startActivity(activityIntent);
}
@Override
- @ServiceThreadOnly
- void setAutoDeviceOff(boolean autoDeviceOff) {
- assertRunOnServiceThread();
- mAutoDeviceOff = autoDeviceOff;
+ protected void handleRoutingChangeAndInformation(int physicalAddress, HdmiCecMessage message) {
+ int port = getLocalPortFromPhysicalAddress(physicalAddress);
+ // Routing change or information sent from switches under the current device can be ignored.
+ if (port > 0) {
+ return;
+ }
+ // When other switches route to some other devices not under the current device,
+ // check system audio mode status and do ARC switch if needed.
+ if (port < 0 && isSystemAudioActivated()) {
+ handleRoutingChangeAndInformationForSystemAudio();
+ return;
+ }
+ // When other switches route to the current device
+ // and the current device is also a switch.
+ if (port == 0) {
+ handleRoutingChangeAndInformationForSwitch(message);
+ }
+ }
+
+ // Handle the system audio(ARC) part of the logic on receiving routing change or information.
+ private void handleRoutingChangeAndInformationForSystemAudio() {
+ // TODO(b/115637145): handle system aduio without ARC
+ routeToInputFromPortId(Constants.CEC_SWITCH_ARC);
+ }
+
+ // Handle the routing control part of the logic on receiving routing change or information.
+ private void handleRoutingChangeAndInformationForSwitch(HdmiCecMessage message) {
+ if (getRoutingPort() == Constants.CEC_SWITCH_HOME && mService.isPlaybackDevice()) {
+ routeToInputFromPortId(Constants.CEC_SWITCH_HOME);
+ mService.setAndBroadcastActiveSourceFromOneDeviceType(
+ message.getSource(), mService.getPhysicalAddress());
+ return;
+ }
+
+ int routingInformationPath =
+ getActivePathOnSwitchFromActivePortId(getRoutingPort());
+ // If current device is already the leaf of the whole HDMI system, will do nothing.
+ if (routingInformationPath == mService.getPhysicalAddress()) {
+ HdmiLogger.debug("Current device can't assign valid physical address"
+ + "to devices under it any more. "
+ + "It's physical address is " + routingInformationPath);
+ return;
+ }
+ // Otherwise will switch to the current active port and broadcast routing information.
+ mService.sendCecCommand(HdmiCecMessageBuilder.buildRoutingInformation(
+ mAddress, routingInformationPath));
+ routeToInputFromPortId(getRoutingPort());
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index e9dd682..07db971 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -21,7 +21,6 @@
import android.hardware.hdmi.IHdmiControlCallback;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
-import android.os.RemoteException;
import android.os.SystemProperties;
import android.provider.Settings.Global;
import android.util.Slog;
@@ -39,7 +38,7 @@
/**
* Represent a logical device of type Playback residing in Android system.
*/
-final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
+public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
private static final String TAG = "HdmiCecLocalDevicePlayback";
private static final boolean WAKE_ON_HOTPLUG =
@@ -48,8 +47,6 @@
private static final boolean SET_MENU_LANGUAGE =
SystemProperties.getBoolean(Constants.PROPERTY_SET_MENU_LANGUAGE, false);
- private boolean mIsActiveSource = false;
-
// Used to keep the device awake while it is the active source. For devices that
// cannot wake up via CEC commands, this address the inconvenience of having to
// turn them on. True by default, and can be disabled (i.e. device can go to sleep
@@ -122,16 +119,6 @@
addAndStartAction(action);
}
- @ServiceThreadOnly
- private void invokeCallback(IHdmiControlCallback callback, int result) {
- assertRunOnServiceThread();
- try {
- callback.onComplete(result);
- } catch (RemoteException e) {
- Slog.e(TAG, "Invoking callback failed:" + e);
- }
- }
-
@Override
@ServiceThreadOnly
void onHotplug(int portId, boolean connected) {
@@ -174,6 +161,7 @@
}
@ServiceThreadOnly
+ @VisibleForTesting
void setIsActiveSource(boolean on) {
assertRunOnServiceThread();
mIsActiveSource = on;
@@ -220,53 +208,7 @@
}
@Override
- @ServiceThreadOnly
- protected boolean handleSetStreamPath(HdmiCecMessage message) {
- assertRunOnServiceThread();
- int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
- // If current device is the target path, set to Active Source.
- // If the path is under the current device, should switch
- int port = getLocalPortFromPhysicalAddress(physicalAddress);
- if (port == 0) {
- setIsActiveSource(true);
- maySendActiveSource(message.getSource());
- wakeUpIfActiveSource();
- } else if (port > 0) {
- // Wake up the device if the power is in standby mode for routing
- if (mService.isPowerStandbyOrTransient()) {
- mService.wakeUp();
- }
- routeToPort(port);
- }
- return true;
- }
-
- // Samsung model we tested sends <Routing Change> and <Request Active Source>
- // in a row, and then changes the input to the internal source if there is no
- // <Active Source> in response. To handle this, we'll set ActiveSource aggressively.
- @Override
- @ServiceThreadOnly
- protected boolean handleRoutingChange(HdmiCecMessage message) {
- assertRunOnServiceThread();
- int newPath = HdmiUtils.twoBytesToInt(message.getParams(), 2);
- maySetActiveSource(newPath);
- return true; // Broadcast message.
- }
-
- @Override
- @ServiceThreadOnly
- protected boolean handleRoutingInformation(HdmiCecMessage message) {
- assertRunOnServiceThread();
- int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
- maySetActiveSource(physicalAddress);
- return true; // Broadcast message.
- }
-
- private void maySetActiveSource(int physicalAddress) {
- setIsActiveSource(physicalAddress == mService.getPhysicalAddress());
- }
-
- private void wakeUpIfActiveSource() {
+ protected void wakeUpIfActiveSource() {
if (!mIsActiveSource) {
return;
}
@@ -277,7 +219,8 @@
}
}
- private void maySendActiveSource(int dest) {
+ @Override
+ protected void maySendActiveSource(int dest) {
if (mIsActiveSource) {
mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(
mAddress, mService.getPhysicalAddress()));
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
index fed6622..6532e16 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -18,9 +18,12 @@
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.IHdmiControlCallback;
-import android.os.RemoteException;
+import android.os.SystemProperties;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.hdmi.Constants.LocalActivePort;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import java.util.List;
@@ -33,7 +36,32 @@
private static final String TAG = "HdmiCecLocalDeviceSource";
// Indicate if current device is Active Source or not
- private boolean mIsActiveSource = false;
+ @VisibleForTesting
+ protected boolean mIsActiveSource = false;
+
+ // Device has cec switch functionality or not.
+ // Default is false.
+ protected boolean mIsSwitchDevice = SystemProperties.getBoolean(
+ Constants.PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH, false);
+
+ // Routing port number used for Routing Control.
+ // This records the default routing port or the previous valid routing port.
+ // Default is HOME input.
+ // Note that we don't save active path here because for source device,
+ // new Active Source physical address might not match the active path
+ @GuardedBy("mLock")
+ @LocalActivePort
+ private int mRoutingPort = Constants.CEC_SWITCH_HOME;
+
+ // This records the current input of the device.
+ // When device is switched to ARC input, mRoutingPort does not record it
+ // since it's not an HDMI port used for Routing Control.
+ // mLocalActivePort will record whichever input we switch to to keep tracking on
+ // the current input status of the device.
+ // This can help prevent duplicate switching and provide status information.
+ @GuardedBy("mLock")
+ @LocalActivePort
+ protected int mLocalActivePort = Constants.CEC_SWITCH_HOME;
protected HdmiCecLocalDeviceSource(HdmiControlService service, int deviceType) {
super(service, deviceType);
@@ -80,25 +108,16 @@
}
@ServiceThreadOnly
- private void invokeCallback(IHdmiControlCallback callback, int result) {
- assertRunOnServiceThread();
- try {
- callback.onComplete(result);
- } catch (RemoteException e) {
- Slog.e(TAG, "Invoking callback failed:" + e);
- }
- }
-
- @ServiceThreadOnly
protected boolean handleActiveSource(HdmiCecMessage message) {
assertRunOnServiceThread();
int logicalAddress = message.getSource();
int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress);
- if (!mActiveSource.equals(activeSource)) {
+ if (!getActiveSource().equals(activeSource)) {
setActiveSource(activeSource);
}
setIsActiveSource(physicalAddress == mService.getPhysicalAddress());
+ switchInputOnReceivingNewActivePath(physicalAddress);
return true;
}
@@ -106,16 +125,152 @@
@ServiceThreadOnly
protected boolean handleRequestActiveSource(HdmiCecMessage message) {
assertRunOnServiceThread();
- if (mIsActiveSource) {
- mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(
- mAddress, mService.getPhysicalAddress()));
- }
+ maySendActiveSource(message.getSource());
return true;
}
+ @Override
+ @ServiceThreadOnly
+ protected boolean handleSetStreamPath(HdmiCecMessage message) {
+ assertRunOnServiceThread();
+ int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
+ // If current device is the target path, set to Active Source.
+ // If the path is under the current device, should switch
+ if (physicalAddress == mService.getPhysicalAddress() && mService.isPlaybackDevice()) {
+ setAndBroadcastActiveSource(message, physicalAddress);
+ }
+ switchInputOnReceivingNewActivePath(physicalAddress);
+ return true;
+ }
+
+ @Override
+ @ServiceThreadOnly
+ protected boolean handleRoutingChange(HdmiCecMessage message) {
+ assertRunOnServiceThread();
+ int newPath = HdmiUtils.twoBytesToInt(message.getParams(), 2);
+ // if the current device is a pure playback device
+ if (!mIsSwitchDevice
+ && newPath == mService.getPhysicalAddress()
+ && mService.isPlaybackDevice()) {
+ setAndBroadcastActiveSource(message, newPath);
+ }
+ handleRoutingChangeAndInformation(newPath, message);
+ return true;
+ }
+
+ @Override
+ @ServiceThreadOnly
+ protected boolean handleRoutingInformation(HdmiCecMessage message) {
+ assertRunOnServiceThread();
+ int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
+ // if the current device is a pure playback device
+ if (!mIsSwitchDevice
+ && physicalAddress == mService.getPhysicalAddress()
+ && mService.isPlaybackDevice()) {
+ setAndBroadcastActiveSource(message, physicalAddress);
+ }
+ handleRoutingChangeAndInformation(physicalAddress, message);
+ return true;
+ }
+
+ // Method to switch Input with the new Active Path.
+ // All the devices with Switch functionality should implement this.
+ protected void switchInputOnReceivingNewActivePath(int physicalAddress) {
+ // do nothing
+ }
+
+ // Source device with Switch functionality should implement this method.
+ // TODO(): decide which type will handle the routing when multi device type is supported
+ protected void handleRoutingChangeAndInformation(int physicalAddress, HdmiCecMessage message) {
+ // do nothing
+ }
+
+ // Active source claiming needs to be handled in Service
+ // since service can decide who will be the active source when the device supports
+ // multiple device types in this method.
+ // This method should only be called when the device can be the active source.
+ protected void setAndBroadcastActiveSource(HdmiCecMessage message, int physicalAddress) {
+ mService.setAndBroadcastActiveSource(
+ message, physicalAddress, getDeviceInfo().getDeviceType());
+ }
+
@ServiceThreadOnly
void setIsActiveSource(boolean on) {
assertRunOnServiceThread();
mIsActiveSource = on;
}
+
+ protected void wakeUpIfActiveSource() {
+ if (!mIsActiveSource) {
+ return;
+ }
+ // Wake up the device if the power is in standby mode
+ if (mService.isPowerStandbyOrTransient()) {
+ mService.wakeUp();
+ }
+ return;
+ }
+
+ protected void maySendActiveSource(int dest) {
+ if (mIsActiveSource) {
+ mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(
+ mAddress, mService.getPhysicalAddress()));
+ }
+ }
+
+ /**
+ * Set {@link #mRoutingPort} to a specific {@link LocalActivePort} to record the current active
+ * CEC Routing Control related port.
+ *
+ * @param portId The portId of the new routing port.
+ */
+ @VisibleForTesting
+ protected void setRoutingPort(@LocalActivePort int portId) {
+ synchronized (mLock) {
+ mRoutingPort = portId;
+ }
+ }
+
+ /**
+ * Get {@link #mRoutingPort}. This is useful when the device needs to route to the last valid
+ * routing port.
+ */
+ @LocalActivePort
+ protected int getRoutingPort() {
+ synchronized (mLock) {
+ return mRoutingPort;
+ }
+ }
+
+ /**
+ * Get {@link #mLocalActivePort}. This is useful when device needs to know the current active
+ * port.
+ */
+ @LocalActivePort
+ protected int getLocalActivePort() {
+ synchronized (mLock) {
+ return mLocalActivePort;
+ }
+ }
+
+ /**
+ * Set {@link #mLocalActivePort} to a specific {@link LocalActivePort} to record the current
+ * active port.
+ *
+ * <p>It does not have to be a Routing Control related port. For example it can be
+ * set to {@link Constants#CEC_SWITCH_ARC} but this port is System Audio related.
+ *
+ * @param activePort The portId of the new active port.
+ */
+ protected void setLocalActivePort(@LocalActivePort int activePort) {
+ synchronized (mLock) {
+ mLocalActivePort = activePort;
+ }
+ }
+
+ // Check if the device is trying to switch to the same input that is active right now.
+ // This can help avoid redundant port switching.
+ protected boolean isSwitchingToTheSameInput(@LocalActivePort int activePort) {
+ return activePort == getLocalActivePort();
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 25ca278..b91d8c6 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -41,17 +41,18 @@
import android.media.AudioSystem;
import android.media.tv.TvInputInfo;
import android.media.tv.TvInputManager.TvInputCallback;
-import android.os.RemoteException;
import android.provider.Settings.Global;
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
+
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -307,7 +308,7 @@
private void handleSelectInternalSource() {
assertRunOnServiceThread();
// Seq #18
- if (mService.isControlEnabled() && mActiveSource.logicalAddress != mAddress) {
+ if (mService.isControlEnabled() && getActiveSource().logicalAddress != mAddress) {
updateActiveSource(mAddress, mService.getPhysicalAddress());
if (mSkipRoutingControl) {
mSkipRoutingControl = false;
@@ -329,7 +330,7 @@
void updateActiveSource(ActiveSource newActive) {
assertRunOnServiceThread();
// Seq #14
- if (mActiveSource.equals(newActive)) {
+ if (getActiveSource().equals(newActive)) {
return;
}
setActiveSource(newActive);
@@ -402,7 +403,7 @@
invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
return;
}
- mActiveSource.invalidate();
+ getActiveSource().invalidate();
if (!mService.isControlEnabled()) {
setActivePortId(portId);
invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
@@ -452,17 +453,6 @@
return Constants.ADDR_INVALID;
}
- private static void invokeCallback(IHdmiControlCallback callback, int result) {
- if (callback == null) {
- return;
- }
- try {
- callback.onComplete(result);
- } catch (RemoteException e) {
- Slog.e(TAG, "Invoking callback failed:" + e);
- }
- }
-
@Override
@ServiceThreadOnly
protected boolean handleActiveSource(HdmiCecMessage message) {
@@ -518,7 +508,7 @@
} else {
// No HDMI port to switch to was found. Notify the input change listers to
// switch to the lastly shown internal input.
- mActiveSource.invalidate();
+ getActiveSource().invalidate();
setActivePath(Constants.INVALID_PHYSICAL_ADDRESS);
mService.invokeInputChangeListener(HdmiDeviceInfo.INACTIVE_DEVICE);
}
@@ -685,7 +675,7 @@
byte[] params = message.getParams();
int currentPath = HdmiUtils.twoBytesToInt(params);
if (HdmiUtils.isAffectingActiveRoutingPath(getActivePath(), currentPath)) {
- mActiveSource.invalidate();
+ getActiveSource().invalidate();
removeAction(RoutingControlAction.class);
int newPath = HdmiUtils.twoBytesToInt(params, 2);
addAndStartAction(new RoutingControlAction(this, newPath, true, null));
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 7e369598..833091d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -140,6 +140,10 @@
static final int STANDBY_SCREEN_OFF = 0;
static final int STANDBY_SHUTDOWN = 1;
+ // Logical address of the active source.
+ @GuardedBy("mLock")
+ protected final ActiveSource mActiveSource = new ActiveSource();
+
private static final boolean isHdmiCecNeverClaimPlaybackLogicAddr =
SystemProperties.getBoolean(
Constants.PROPERTY_HDMI_CEC_NEVER_CLAIM_PLAYBACK_LOGICAL_ADDRESS, false);
@@ -417,7 +421,7 @@
mSettingsObserver = new SettingsObserver(mHandler);
}
- private static List<Integer> getIntList(String string) {
+ protected static List<Integer> getIntList(String string) {
ArrayList<Integer> list = new ArrayList<>();
TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
splitter.setString(string);
@@ -596,11 +600,6 @@
}
// No need to propagate to HAL.
break;
- case Global.HDMI_CONTROL_AUTO_TV_OFF_ENABLED:
- if (isAudioSystemDevice()) {
- audioSystem().setAutoTvOff(enabled);
- }
- break;
case Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED:
if (isTvDeviceEnabled()) {
tv().setSystemAudioControlFeatureEnabled(enabled);
@@ -1009,6 +1008,10 @@
assertRunOnServiceThread();
if (connected && !isTvDevice()) {
+ if (getPortInfo(portId).getType() == HdmiPortInfo.PORT_OUTPUT && isSwitchDevice()) {
+ initPortInfo();
+ HdmiLogger.debug("initPortInfo for switch device when onHotplug from tx.");
+ }
ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>();
for (int type : mLocalDevices) {
if (type == HdmiDeviceInfo.DEVICE_PLAYBACK
@@ -1394,17 +1397,24 @@
return;
}
HdmiCecLocalDeviceTv tv = tv();
- if (tv == null) {
- if (!mAddressAllocated) {
- mSelectRequestBuffer.set(SelectRequestBuffer.newPortSelect(
- HdmiControlService.this, portId, callback));
- return;
- }
- Slog.w(TAG, "Local tv device not available");
- invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE);
+ if (tv != null) {
+ tv.doManualPortSwitching(portId, callback);
return;
}
- tv.doManualPortSwitching(portId, callback);
+ HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
+ if (audioSystem != null) {
+ audioSystem.doManualPortSwitching(portId, callback);
+ return;
+ }
+
+ if (!mAddressAllocated) {
+ mSelectRequestBuffer.set(SelectRequestBuffer.newPortSelect(
+ HdmiControlService.this, portId, callback));
+ return;
+ }
+ Slog.w(TAG, "Local device not available");
+ invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE);
+ return;
}
});
}
@@ -2114,11 +2124,20 @@
return mLocalDevices.contains(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
}
+ boolean isPlaybackDevice() {
+ return mLocalDevices.contains(HdmiDeviceInfo.DEVICE_PLAYBACK);
+ }
+
+ boolean isSwitchDevice() {
+ return SystemProperties.getBoolean(
+ Constants.PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH, false);
+ }
+
boolean isTvDeviceEnabled() {
return isTvDevice() && tv() != null;
}
- private HdmiCecLocalDevicePlayback playback() {
+ protected HdmiCecLocalDevicePlayback playback() {
return (HdmiCecLocalDevicePlayback)
mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_PLAYBACK);
}
@@ -2489,6 +2508,77 @@
setLastInputForMhl(Constants.INVALID_PORT_ID);
}
+ ActiveSource getActiveSource() {
+ synchronized (mLock) {
+ return mActiveSource;
+ }
+ }
+
+ void setActiveSource(int logicalAddress, int physicalAddress) {
+ synchronized (mLock) {
+ mActiveSource.logicalAddress = logicalAddress;
+ mActiveSource.physicalAddress = physicalAddress;
+ }
+ }
+
+ // This method should only be called when the device can be the active source
+ // and all the device types call into this method.
+ // For example, when receiving broadcast messages, all the device types will call this
+ // method but only one of them will be the Active Source.
+ protected void setAndBroadcastActiveSource(
+ HdmiCecMessage message, int physicalAddress, int deviceType) {
+ // If the device has both playback and audio system logical addresses,
+ // playback will claim active source. Otherwise audio system will.
+ if (deviceType == HdmiDeviceInfo.DEVICE_PLAYBACK) {
+ HdmiCecLocalDevicePlayback playback = playback();
+ playback.setIsActiveSource(true);
+ playback.wakeUpIfActiveSource();
+ playback.maySendActiveSource(message.getSource());
+ setActiveSource(playback.mAddress, physicalAddress);
+ }
+
+ if (deviceType == HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM) {
+ HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
+ if (playback() != null) {
+ audioSystem.setIsActiveSource(false);
+ } else {
+ audioSystem.setIsActiveSource(true);
+ audioSystem.wakeUpIfActiveSource();
+ audioSystem.maySendActiveSource(message.getSource());
+ setActiveSource(audioSystem.mAddress, physicalAddress);
+ }
+ }
+ }
+
+ // This method should only be called when the device can be the active source
+ // and only one of the device types calls into this method.
+ // For example, when receiving One Touch Play, only playback device handles it
+ // and this method updates Active Source in all the device types sharing the same
+ // Physical Address.
+ protected void setAndBroadcastActiveSourceFromOneDeviceType(
+ int sourceAddress, int physicalAddress) {
+ // If the device has both playback and audio system logical addresses,
+ // playback will claim active source. Otherwise audio system will.
+ HdmiCecLocalDevicePlayback playback = playback();
+ HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
+ if (playback != null) {
+ playback.setIsActiveSource(true);
+ playback.wakeUpIfActiveSource();
+ playback.maySendActiveSource(sourceAddress);
+ if (audioSystem != null) {
+ audioSystem.setIsActiveSource(false);
+ }
+ setActiveSource(playback.mAddress, physicalAddress);
+ } else {
+ if (audioSystem != null) {
+ audioSystem.setIsActiveSource(true);
+ audioSystem.wakeUpIfActiveSource();
+ audioSystem.maySendActiveSource(sourceAddress);
+ setActiveSource(audioSystem.mAddress, physicalAddress);
+ }
+ }
+ }
+
@ServiceThreadOnly
void setLastInputForMhl(int portId) {
assertRunOnServiceThread();
diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
index 48c71d8..41bf01f 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
@@ -83,9 +83,17 @@
}
private void broadcastActiveSource() {
- sendCommand(HdmiCecMessageBuilder.buildActiveSource(getSourceAddress(), getSourcePath()));
// Because only source device can create this action, it's safe to cast.
- source().setIsActiveSource(true);
+ HdmiCecLocalDeviceSource source = source();
+ source.mService.setAndBroadcastActiveSourceFromOneDeviceType(
+ mTargetAddress, getSourcePath());
+ // Set local active port to HOME when One Touch Play.
+ // Active Port and Current Input are handled by the switch functionality device.
+ if (source.mService.audioSystem() != null) {
+ source = source.mService.audioSystem();
+ }
+ source.setRoutingPort(Constants.CEC_SWITCH_HOME);
+ source.setLocalActivePort(Constants.CEC_SWITCH_HOME);
}
private void queryDevicePowerStatus() {
diff --git a/services/core/java/com/android/server/hdmi/SelectRequestBuffer.java b/services/core/java/com/android/server/hdmi/SelectRequestBuffer.java
index 75986c7..ba16260 100644
--- a/services/core/java/com/android/server/hdmi/SelectRequestBuffer.java
+++ b/services/core/java/com/android/server/hdmi/SelectRequestBuffer.java
@@ -56,6 +56,10 @@
return mService.tv();
}
+ protected HdmiCecLocalDeviceAudioSystem audioSystem() {
+ return mService.audioSystem();
+ }
+
protected boolean isLocalDeviceReady() {
if (tv() == null) {
Slog.e(TAG, "Local tv device not available");
@@ -105,7 +109,15 @@
public void process() {
if (isLocalDeviceReady()) {
Slog.v(TAG, "calling delayed portSelect id:" + mId);
- tv().doManualPortSwitching(mId, mCallback);
+ HdmiCecLocalDeviceTv tv = tv();
+ if (tv != null) {
+ tv.doManualPortSwitching(mId, mCallback);
+ return;
+ }
+ HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
+ if (audioSystem != null) {
+ audioSystem.doManualPortSwitching(mId, mCallback);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java b/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
index a6e6965..b6ebcd7c 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
@@ -41,7 +41,7 @@
@Override
boolean start() {
- if (audioSystem().mActiveSource.physicalAddress == Constants.INVALID_PHYSICAL_ADDRESS) {
+ if (audioSystem().getActiveSource().physicalAddress == Constants.INVALID_PHYSICAL_ADDRESS) {
mState = STATE_WAITING_FOR_ACTIVE_SOURCE;
addTimer(mState, HdmiConfig.TIMEOUT_MS);
sendRequestActiveSource();
@@ -60,10 +60,8 @@
return false;
}
mActionTimer.clearTimerMessage();
- int physicalAddress = HdmiUtils.twoBytesToInt(cmd.getParams());
- if (physicalAddress != getSourcePath()) {
- audioSystem().setActiveSource(cmd.getSource(), physicalAddress);
- }
+ // Broadcast message is also handled by other device types
+ audioSystem().handleActiveSource(cmd);
mState = STATE_WAITING_FOR_TV_SUPPORT;
queryTvSystemAudioModeSupport();
return true;
@@ -116,7 +114,16 @@
private void handleActiveSourceTimeout() {
HdmiLogger.debug("Cannot get active source.");
- audioSystem().checkSupportAndSetSystemAudioMode(false);
+ // If not able to find Active Source and the current device has playbcak functionality,
+ // claim Active Source and start to query TV system audio mode support.
+ if (audioSystem().mService.isPlaybackDevice()) {
+ audioSystem().mService.setAndBroadcastActiveSourceFromOneDeviceType(
+ Constants.ADDR_BROADCAST, getSourcePath());
+ mState = STATE_WAITING_FOR_TV_SUPPORT;
+ queryTvSystemAudioModeSupport();
+ } else {
+ audioSystem().checkSupportAndSetSystemAudioMode(false);
+ }
finish();
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index e7c3c7b..df28f30 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -213,8 +213,6 @@
private static native void nativeSetFocusedApplication(long ptr,
int displayId, InputApplicationHandle application);
private static native void nativeSetFocusedDisplay(long ptr, int displayId);
- private static native boolean nativeTransferTouchFocus(long ptr,
- InputChannel fromChannel, InputChannel toChannel);
private static native void nativeSetPointerSpeed(long ptr, int speed);
private static native void nativeSetShowTouches(long ptr, boolean enabled);
private static native void nativeSetInteractive(long ptr, boolean interactive);
@@ -1485,29 +1483,6 @@
nativeSetSystemUiVisibility(mPtr, visibility);
}
- /**
- * Atomically transfers touch focus from one window to another as identified by
- * their input channels. It is possible for multiple windows to have
- * touch focus if they support split touch dispatch
- * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
- * method only transfers touch focus of the specified window without affecting
- * other windows that may also have touch focus at the same time.
- * @param fromChannel The channel of a window that currently has touch focus.
- * @param toChannel The channel of the window that should receive touch focus in
- * place of the first.
- * @return True if the transfer was successful. False if the window with the
- * specified channel did not actually have touch focus at the time of the request.
- */
- public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) {
- if (fromChannel == null) {
- throw new IllegalArgumentException("fromChannel must not be null.");
- }
- if (toChannel == null) {
- throw new IllegalArgumentException("toChannel must not be null.");
- }
- return nativeTransferTouchFocus(mPtr, fromChannel, toChannel);
- }
-
@Override // Binder call
public void tryPointerSpeed(int speed) {
if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
@@ -1785,15 +1760,14 @@
}
// Native callback
- private void notifyFocusChanged(IBinder token) {
- if (mFocusedWindow != token) {
- if (mFocusedWindowHasCapture) {
- setPointerCapture(false);
- }
- if (token instanceof IWindow) {
- mFocusedWindow = (IWindow) token;
- }
+ private void notifyFocusChanged(IBinder oldToken, IBinder newToken) {
+ if (mFocusedWindow.asBinder() == newToken) {
+ Log.w(TAG, "notifyFocusChanged called with unchanged mFocusedWindow=" + mFocusedWindow);
+ return;
}
+
+ setPointerCapture(false);
+ mFocusedWindow = IWindow.Stub.asInterface(newToken);
}
// Native callback.
diff --git a/services/core/java/com/android/server/location/LocationRequestStatistics.java b/services/core/java/com/android/server/location/LocationRequestStatistics.java
index b7934d9..b7ccb26 100644
--- a/services/core/java/com/android/server/location/LocationRequestStatistics.java
+++ b/services/core/java/com/android/server/location/LocationRequestStatistics.java
@@ -123,6 +123,9 @@
// in foreground.
private long mForegroundDurationMs;
+ // Time when package last went dormant (stopped requesting location)
+ private long mLastStopElapsedTimeMs;
+
private PackageStatistics() {
mInitialElapsedTimeMs = SystemClock.elapsedRealtime();
mNumActiveRequests = 0;
@@ -131,6 +134,7 @@
mSlowestIntervalMs = 0;
mForegroundDurationMs = 0;
mLastForegroundElapsedTimeMs = 0;
+ mLastStopElapsedTimeMs = 0;
}
private void startRequesting(long intervalMs) {
@@ -167,8 +171,8 @@
mNumActiveRequests--;
if (mNumActiveRequests == 0) {
- long lastDurationMs
- = SystemClock.elapsedRealtime() - mLastActivitationElapsedTimeMs;
+ mLastStopElapsedTimeMs = SystemClock.elapsedRealtime();
+ long lastDurationMs = mLastStopElapsedTimeMs - mLastActivitationElapsedTimeMs;
mTotalDurationMs += lastDurationMs;
updateForeground(false);
}
@@ -206,6 +210,13 @@
}
/**
+ * Returns the time since the last request stopped in ms.
+ */
+ public long getTimeSinceLastRequestStoppedMs() {
+ return SystemClock.elapsedRealtime() - mLastStopElapsedTimeMs;
+ }
+
+ /**
* Returns the fastest interval that has been tracked.
*/
public long getFastestIntervalMs() {
@@ -244,6 +255,10 @@
.append(" minutes");
if (isActive()) {
s.append(": Currently active");
+ } else {
+ s.append(": Last active ")
+ .append((getTimeSinceLastRequestStoppedMs() / 1000) / 60)
+ .append(" minutes ago");
}
return s.toString();
}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 8ecceb9..d611a17 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -19,7 +19,6 @@
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ParceledListSlice;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.AudioManagerInternal;
@@ -27,14 +26,15 @@
import android.media.MediaMetadata;
import android.media.Rating;
import android.media.VolumeProvider;
+import android.media.session.ControllerCallbackLink;
import android.media.session.ISession;
-import android.media.session.ISessionCallback;
import android.media.session.ISessionController;
-import android.media.session.ISessionControllerCallback;
import android.media.session.MediaController;
import android.media.session.MediaController.PlaybackInfo;
import android.media.session.MediaSession;
+import android.media.session.MediaSession.QueueItem;
import android.media.session.PlaybackState;
+import android.media.session.SessionCallbackLink;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -44,7 +44,6 @@
import android.os.Looper;
import android.os.Message;
import android.os.Process;
-import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.SystemClock;
import android.util.Log;
@@ -55,6 +54,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.List;
/**
* This is the system implementation of a Session. Apps will interact with the
@@ -84,7 +84,7 @@
private final Context mContext;
private final Object mLock = new Object();
- private final ArrayList<ISessionControllerCallbackHolder> mControllerCallbackHolders =
+ private final ArrayList<ControllerCallbackLinkHolder> mControllerCallbackHolders =
new ArrayList<>();
private long mFlags;
@@ -97,7 +97,7 @@
// may result in throwing an exception.
private MediaMetadata mMetadata;
private PlaybackState mPlaybackState;
- private ParceledListSlice mQueue;
+ private List<QueueItem> mQueue;
private CharSequence mQueueTitle;
private int mRatingType;
// End TransportPerformer fields
@@ -120,7 +120,7 @@
private String mMetadataDescription;
public MediaSessionRecord(int ownerPid, int ownerUid, int userId, String ownerPackageName,
- ISessionCallback cb, String tag, MediaSessionService service, Looper handlerLooper) {
+ SessionCallbackLink cb, String tag, MediaSessionService service, Looper handlerLooper) {
mOwnerPid = ownerPid;
mOwnerUid = ownerUid;
mUserId = userId;
@@ -249,7 +249,7 @@
* @param useSuggested True to use adjustSuggestedStreamVolume instead of
*/
public void adjustVolume(String packageName, String opPackageName, int pid, int uid,
- ISessionControllerCallback caller, boolean asSystemService, int direction, int flags,
+ ControllerCallbackLink caller, boolean asSystemService, int direction, int flags,
boolean useSuggested) {
int previousFlagPlaySound = flags & AudioManager.FLAG_PLAY_SOUND;
if (isPlaybackActive() || hasFlag(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY)) {
@@ -291,7 +291,7 @@
}
private void setVolumeTo(String packageName, String opPackageName, int pid, int uid,
- ISessionControllerCallback caller, int value, int flags) {
+ ControllerCallbackLink caller, int value, int flags) {
if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
final int volumeValue = value;
@@ -440,7 +440,7 @@
}
}
- public ISessionCallback getCallback() {
+ public SessionCallbackLink getCallback() {
return mSessionCb.mCb;
}
@@ -468,7 +468,7 @@
+ ", max=" + mMaxVolume + ", current=" + mCurrentVolume);
pw.println(indent + "metadata: " + mMetadataDescription);
pw.println(indent + "queueTitle=" + mQueueTitle + ", size="
- + (mQueue == null ? 0 : mQueue.getList().size()));
+ + (mQueue == null ? 0 : mQueue.size()));
}
@Override
@@ -518,7 +518,7 @@
}
private void logCallbackException(
- String msg, ISessionControllerCallbackHolder holder, Exception e) {
+ String msg, ControllerCallbackLinkHolder holder, Exception e) {
Log.v(TAG, msg + ", this=" + this + ", callback package=" + holder.mPackageName
+ ", exception=" + e);
}
@@ -529,16 +529,18 @@
return;
}
for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
- ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
+ ControllerCallbackLinkHolder holder = mControllerCallbackHolders.get(i);
try {
- holder.mCallback.onPlaybackStateChanged(mPlaybackState);
- } catch (DeadObjectException e) {
- mControllerCallbackHolders.remove(i);
- logCallbackException("Removed dead callback in pushPlaybackStateUpdate",
- holder, e);
- } catch (RemoteException e) {
- logCallbackException("unexpected exception in pushPlaybackStateUpdate",
- holder, e);
+ holder.mCallback.notifyPlaybackStateChanged(mPlaybackState);
+ } catch (RuntimeException e) {
+ if (e.getCause() instanceof DeadObjectException) {
+ mControllerCallbackHolders.remove(i);
+ logCallbackException("Removing dead callback in pushPlaybackStateUpdate",
+ holder, e);
+ } else {
+ logCallbackException("unexpected exception in pushPlaybackStateUpdate",
+ holder, e);
+ }
}
}
}
@@ -550,14 +552,18 @@
return;
}
for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
- ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
+ ControllerCallbackLinkHolder holder = mControllerCallbackHolders.get(i);
try {
- holder.mCallback.onMetadataChanged(mMetadata);
- } catch (DeadObjectException e) {
- logCallbackException("Removing dead callback in pushMetadataUpdate", holder, e);
- mControllerCallbackHolders.remove(i);
- } catch (RemoteException e) {
- logCallbackException("unexpected exception in pushMetadataUpdate", holder, e);
+ holder.mCallback.notifyMetadataChanged(mMetadata);
+ } catch (RuntimeException e) {
+ if (e.getCause() instanceof DeadObjectException) {
+ mControllerCallbackHolders.remove(i);
+ logCallbackException("Removing dead callback in pushMetadataUpdate",
+ holder, e);
+ } else {
+ logCallbackException("unexpected exception in pushMetadataUpdate",
+ holder, e);
+ }
}
}
}
@@ -569,14 +575,17 @@
return;
}
for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
- ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
+ ControllerCallbackLinkHolder holder = mControllerCallbackHolders.get(i);
try {
- holder.mCallback.onQueueChanged(mQueue);
- } catch (DeadObjectException e) {
- mControllerCallbackHolders.remove(i);
- logCallbackException("Removed dead callback in pushQueueUpdate", holder, e);
- } catch (RemoteException e) {
- logCallbackException("unexpected exception in pushQueueUpdate", holder, e);
+ holder.mCallback.notifyQueueChanged(mQueue);
+ } catch (RuntimeException e) {
+ if (e.getCause() instanceof DeadObjectException) {
+ mControllerCallbackHolders.remove(i);
+ logCallbackException("Removing dead callback in pushQueueUpdate",
+ holder, e);
+ } else {
+ logCallbackException("unexpected exception in pushQueueUpdate", holder, e);
+ }
}
}
}
@@ -588,16 +597,18 @@
return;
}
for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
- ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
+ ControllerCallbackLinkHolder holder = mControllerCallbackHolders.get(i);
try {
- holder.mCallback.onQueueTitleChanged(mQueueTitle);
- } catch (DeadObjectException e) {
- mControllerCallbackHolders.remove(i);
- logCallbackException("Removed dead callback in pushQueueTitleUpdate",
- holder, e);
- } catch (RemoteException e) {
- logCallbackException("unexpected exception in pushQueueTitleUpdate",
- holder, e);
+ holder.mCallback.notifyQueueTitleChanged(mQueueTitle);
+ } catch (RuntimeException e) {
+ if (e.getCause() instanceof DeadObjectException) {
+ mControllerCallbackHolders.remove(i);
+ logCallbackException("Removing dead callback in pushQueueTitleUpdate",
+ holder, e);
+ } else {
+ logCallbackException("unexpected exception in pushQueueTitleUpdate",
+ holder, e);
+ }
}
}
}
@@ -609,14 +620,17 @@
return;
}
for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
- ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
+ ControllerCallbackLinkHolder holder = mControllerCallbackHolders.get(i);
try {
- holder.mCallback.onExtrasChanged(mExtras);
- } catch (DeadObjectException e) {
- mControllerCallbackHolders.remove(i);
- logCallbackException("Removed dead callback in pushExtrasUpdate", holder, e);
- } catch (RemoteException e) {
- logCallbackException("unexpected exception in pushExtrasUpdate", holder, e);
+ holder.mCallback.notifyExtrasChanged(mExtras);
+ } catch (RuntimeException e) {
+ if (e.getCause() instanceof DeadObjectException) {
+ mControllerCallbackHolders.remove(i);
+ logCallbackException("Removing dead callback in pushExtrasUpdate",
+ holder, e);
+ } else {
+ logCallbackException("unexpected exception in pushExtrasUpdate", holder, e);
+ }
}
}
}
@@ -629,14 +643,17 @@
}
PlaybackInfo info = mController.getVolumeAttributes();
for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
- ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
+ ControllerCallbackLinkHolder holder = mControllerCallbackHolders.get(i);
try {
- holder.mCallback.onVolumeInfoChanged(info);
- } catch (DeadObjectException e) {
- mControllerCallbackHolders.remove(i);
- logCallbackException("Removing dead callback in pushVolumeUpdate", holder, e);
- } catch (RemoteException e) {
- logCallbackException("Unexpected exception in pushVolumeUpdate", holder, e);
+ holder.mCallback.notifyVolumeInfoChanged(info);
+ } catch (RuntimeException e) {
+ if (e.getCause() instanceof DeadObjectException) {
+ mControllerCallbackHolders.remove(i);
+ logCallbackException("Removing dead callback in pushVolumeUpdate",
+ holder, e);
+ } else {
+ logCallbackException("unexpected exception in pushVolumeUpdate", holder, e);
+ }
}
}
}
@@ -648,14 +665,16 @@
return;
}
for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
- ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
+ ControllerCallbackLinkHolder holder = mControllerCallbackHolders.get(i);
try {
- holder.mCallback.onEvent(event, data);
- } catch (DeadObjectException e) {
- mControllerCallbackHolders.remove(i);
- logCallbackException("Removing dead callback in pushEvent", holder, e);
- } catch (RemoteException e) {
- logCallbackException("unexpected exception in pushEvent", holder, e);
+ holder.mCallback.notifyEvent(event, data);
+ } catch (RuntimeException e) {
+ if (e.getCause() instanceof DeadObjectException) {
+ mControllerCallbackHolders.remove(i);
+ logCallbackException("Removing dead callback in pushEvent", holder, e);
+ } else {
+ logCallbackException("unexpected exception in pushEvent", holder, e);
+ }
}
}
}
@@ -669,14 +688,18 @@
return;
}
for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
- ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
+ ControllerCallbackLinkHolder holder = mControllerCallbackHolders.get(i);
try {
- holder.mCallback.onSessionDestroyed();
- } catch (DeadObjectException e) {
- logCallbackException("Removing dead callback in pushEvent", holder, e);
- mControllerCallbackHolders.remove(i);
- } catch (RemoteException e) {
- logCallbackException("unexpected exception in pushEvent", holder, e);
+ holder.mCallback.notifySessionDestroyed();
+ } catch (RuntimeException e) {
+ if (e.getCause() instanceof DeadObjectException) {
+ mControllerCallbackHolders.remove(i);
+ logCallbackException("Removing dead callback in pushSessionDestroyed",
+ holder, e);
+ } else {
+ logCallbackException("unexpected exception in pushSessionDestroyed",
+ holder, e);
+ }
}
}
// After notifying clear all listeners
@@ -716,10 +739,10 @@
return result == null ? state : result;
}
- private int getControllerHolderIndexForCb(ISessionControllerCallback cb) {
- IBinder binder = cb.asBinder();
+ private int getControllerHolderIndexForCb(ControllerCallbackLink cb) {
+ IBinder binder = cb.getBinder();
for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
- if (binder.equals(mControllerCallbackHolders.get(i).mCallback.asBinder())) {
+ if (binder.equals(mControllerCallbackHolders.get(i).mCallback.getBinder())) {
return i;
}
}
@@ -843,7 +866,7 @@
}
@Override
- public void setQueue(ParceledListSlice queue) {
+ public void setQueue(List<QueueItem> queue) {
synchronized (mLock) {
mQueue = queue;
}
@@ -920,9 +943,9 @@
}
class SessionCb {
- private final ISessionCallback mCb;
+ private final SessionCallbackLink mCb;
- public SessionCb(ISessionCallback cb) {
+ SessionCb(SessionCallbackLink cb) {
mCb = cb;
}
@@ -930,224 +953,224 @@
boolean asSystemService, KeyEvent keyEvent, int sequenceId, ResultReceiver cb) {
try {
if (asSystemService) {
- mCb.onMediaButton(mContext.getPackageName(), Process.myPid(),
+ mCb.notifyMediaButton(mContext.getPackageName(), Process.myPid(),
Process.SYSTEM_UID, createMediaButtonIntent(keyEvent), sequenceId, cb);
} else {
- mCb.onMediaButton(packageName, pid, uid,
+ mCb.notifyMediaButton(packageName, pid, uid,
createMediaButtonIntent(keyEvent), sequenceId, cb);
}
return true;
- } catch (RemoteException e) {
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in sendMediaRequest.", e);
}
return false;
}
public boolean sendMediaButton(String packageName, int pid, int uid,
- ISessionControllerCallback caller, boolean asSystemService,
+ ControllerCallbackLink caller, boolean asSystemService,
KeyEvent keyEvent) {
try {
if (asSystemService) {
- mCb.onMediaButton(mContext.getPackageName(), Process.myPid(),
+ mCb.notifyMediaButton(mContext.getPackageName(), Process.myPid(),
Process.SYSTEM_UID, createMediaButtonIntent(keyEvent), 0, null);
} else {
- mCb.onMediaButtonFromController(packageName, pid, uid, caller,
+ mCb.notifyMediaButtonFromController(packageName, pid, uid, caller,
createMediaButtonIntent(keyEvent));
}
return true;
- } catch (RemoteException e) {
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in sendMediaRequest.", e);
}
return false;
}
public void sendCommand(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String command, Bundle args, ResultReceiver cb) {
+ ControllerCallbackLink caller, String command, Bundle args, ResultReceiver cb) {
try {
- mCb.onCommand(packageName, pid, uid, caller, command, args, cb);
- } catch (RemoteException e) {
+ mCb.notifyCommand(packageName, pid, uid, caller, command, args, cb);
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in sendCommand.", e);
}
}
public void sendCustomAction(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String action,
+ ControllerCallbackLink caller, String action,
Bundle args) {
try {
- mCb.onCustomAction(packageName, pid, uid, caller, action, args);
- } catch (RemoteException e) {
+ mCb.notifyCustomAction(packageName, pid, uid, caller, action, args);
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in sendCustomAction.", e);
}
}
public void prepare(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
+ ControllerCallbackLink caller) {
try {
- mCb.onPrepare(packageName, pid, uid, caller);
- } catch (RemoteException e) {
+ mCb.notifyPrepare(packageName, pid, uid, caller);
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in prepare.", e);
}
}
public void prepareFromMediaId(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String mediaId, Bundle extras) {
+ ControllerCallbackLink caller, String mediaId, Bundle extras) {
try {
- mCb.onPrepareFromMediaId(packageName, pid, uid, caller, mediaId, extras);
- } catch (RemoteException e) {
+ mCb.notifyPrepareFromMediaId(packageName, pid, uid, caller, mediaId, extras);
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in prepareFromMediaId.", e);
}
}
public void prepareFromSearch(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String query, Bundle extras) {
+ ControllerCallbackLink caller, String query, Bundle extras) {
try {
- mCb.onPrepareFromSearch(packageName, pid, uid, caller, query, extras);
- } catch (RemoteException e) {
+ mCb.notifyPrepareFromSearch(packageName, pid, uid, caller, query, extras);
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in prepareFromSearch.", e);
}
}
public void prepareFromUri(String packageName, int pid, int uid,
- ISessionControllerCallback caller, Uri uri, Bundle extras) {
+ ControllerCallbackLink caller, Uri uri, Bundle extras) {
try {
- mCb.onPrepareFromUri(packageName, pid, uid, caller, uri, extras);
- } catch (RemoteException e) {
+ mCb.notifyPrepareFromUri(packageName, pid, uid, caller, uri, extras);
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in prepareFromUri.", e);
}
}
- public void play(String packageName, int pid, int uid, ISessionControllerCallback caller) {
+ public void play(String packageName, int pid, int uid, ControllerCallbackLink caller) {
try {
- mCb.onPlay(packageName, pid, uid, caller);
- } catch (RemoteException e) {
+ mCb.notifyPlay(packageName, pid, uid, caller);
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in play.", e);
}
}
public void playFromMediaId(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String mediaId, Bundle extras) {
+ ControllerCallbackLink caller, String mediaId, Bundle extras) {
try {
- mCb.onPlayFromMediaId(packageName, pid, uid, caller, mediaId, extras);
- } catch (RemoteException e) {
+ mCb.notifyPlayFromMediaId(packageName, pid, uid, caller, mediaId, extras);
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in playFromMediaId.", e);
}
}
public void playFromSearch(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String query, Bundle extras) {
+ ControllerCallbackLink caller, String query, Bundle extras) {
try {
- mCb.onPlayFromSearch(packageName, pid, uid, caller, query, extras);
- } catch (RemoteException e) {
+ mCb.notifyPlayFromSearch(packageName, pid, uid, caller, query, extras);
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in playFromSearch.", e);
}
}
public void playFromUri(String packageName, int pid, int uid,
- ISessionControllerCallback caller, Uri uri, Bundle extras) {
+ ControllerCallbackLink caller, Uri uri, Bundle extras) {
try {
- mCb.onPlayFromUri(packageName, pid, uid, caller, uri, extras);
- } catch (RemoteException e) {
+ mCb.notifyPlayFromUri(packageName, pid, uid, caller, uri, extras);
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in playFromUri.", e);
}
}
public void skipToTrack(String packageName, int pid, int uid,
- ISessionControllerCallback caller, long id) {
+ ControllerCallbackLink caller, long id) {
try {
- mCb.onSkipToTrack(packageName, pid, uid, caller, id);
- } catch (RemoteException e) {
+ mCb.notifySkipToTrack(packageName, pid, uid, caller, id);
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in skipToTrack", e);
}
}
- public void pause(String packageName, int pid, int uid, ISessionControllerCallback caller) {
+ public void pause(String packageName, int pid, int uid, ControllerCallbackLink caller) {
try {
- mCb.onPause(packageName, pid, uid, caller);
- } catch (RemoteException e) {
+ mCb.notifyPause(packageName, pid, uid, caller);
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in pause.", e);
}
}
- public void stop(String packageName, int pid, int uid, ISessionControllerCallback caller) {
+ public void stop(String packageName, int pid, int uid, ControllerCallbackLink caller) {
try {
- mCb.onStop(packageName, pid, uid, caller);
- } catch (RemoteException e) {
+ mCb.notifyStop(packageName, pid, uid, caller);
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in stop.", e);
}
}
- public void next(String packageName, int pid, int uid, ISessionControllerCallback caller) {
+ public void next(String packageName, int pid, int uid, ControllerCallbackLink caller) {
try {
- mCb.onNext(packageName, pid, uid, caller);
- } catch (RemoteException e) {
+ mCb.notifyNext(packageName, pid, uid, caller);
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in next.", e);
}
}
public void previous(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
+ ControllerCallbackLink caller) {
try {
- mCb.onPrevious(packageName, pid, uid, caller);
- } catch (RemoteException e) {
+ mCb.notifyPrevious(packageName, pid, uid, caller);
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in previous.", e);
}
}
public void fastForward(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
+ ControllerCallbackLink caller) {
try {
- mCb.onFastForward(packageName, pid, uid, caller);
- } catch (RemoteException e) {
+ mCb.notifyFastForward(packageName, pid, uid, caller);
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in fastForward.", e);
}
}
public void rewind(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
+ ControllerCallbackLink caller) {
try {
- mCb.onRewind(packageName, pid, uid, caller);
- } catch (RemoteException e) {
+ mCb.notifyRewind(packageName, pid, uid, caller);
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in rewind.", e);
}
}
- public void seekTo(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ public void seekTo(String packageName, int pid, int uid, ControllerCallbackLink caller,
long pos) {
try {
- mCb.onSeekTo(packageName, pid, uid, caller, pos);
- } catch (RemoteException e) {
+ mCb.notifySeekTo(packageName, pid, uid, caller, pos);
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in seekTo.", e);
}
}
- public void rate(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ public void rate(String packageName, int pid, int uid, ControllerCallbackLink caller,
Rating rating) {
try {
- mCb.onRate(packageName, pid, uid, caller, rating);
- } catch (RemoteException e) {
+ mCb.notifyRate(packageName, pid, uid, caller, rating);
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in rate.", e);
}
}
public void adjustVolume(String packageName, int pid, int uid,
- ISessionControllerCallback caller, boolean asSystemService, int direction) {
+ ControllerCallbackLink caller, boolean asSystemService, int direction) {
try {
if (asSystemService) {
- mCb.onAdjustVolume(mContext.getPackageName(), Process.myPid(),
+ mCb.notifyAdjustVolume(mContext.getPackageName(), Process.myPid(),
Process.SYSTEM_UID, null, direction);
} else {
- mCb.onAdjustVolume(packageName, pid, uid, caller, direction);
+ mCb.notifyAdjustVolume(packageName, pid, uid, caller, direction);
}
- } catch (RemoteException e) {
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in adjustVolume.", e);
}
}
public void setVolumeTo(String packageName, int pid, int uid,
- ISessionControllerCallback caller, int value) {
+ ControllerCallbackLink caller, int value) {
try {
- mCb.onSetVolumeTo(packageName, pid, uid, caller, value);
- } catch (RemoteException e) {
+ mCb.notifySetVolumeTo(packageName, pid, uid, caller, value);
+ } catch (RuntimeException e) {
Slog.e(TAG, "Remote failure in setVolumeTo.", e);
}
}
@@ -1161,34 +1184,34 @@
class ControllerStub extends ISessionController.Stub {
@Override
- public void sendCommand(String packageName, ISessionControllerCallback caller,
+ public void sendCommand(String packageName, ControllerCallbackLink caller,
String command, Bundle args, ResultReceiver cb) {
mSessionCb.sendCommand(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
caller, command, args, cb);
}
@Override
- public boolean sendMediaButton(String packageName, ISessionControllerCallback cb,
+ public boolean sendMediaButton(String packageName, ControllerCallbackLink cb,
boolean asSystemService, KeyEvent keyEvent) {
return mSessionCb.sendMediaButton(packageName, Binder.getCallingPid(),
Binder.getCallingUid(), cb, asSystemService, keyEvent);
}
@Override
- public void registerCallbackListener(String packageName, ISessionControllerCallback cb) {
+ public void registerCallbackListener(String packageName, ControllerCallbackLink cb) {
synchronized (mLock) {
// If this session is already destroyed tell the caller and
// don't add them.
if (mDestroyed) {
try {
- cb.onSessionDestroyed();
+ cb.notifySessionDestroyed();
} catch (Exception e) {
// ignored
}
return;
}
if (getControllerHolderIndexForCb(cb) < 0) {
- mControllerCallbackHolders.add(new ISessionControllerCallbackHolder(cb,
+ mControllerCallbackHolders.add(new ControllerCallbackLinkHolder(cb,
packageName, Binder.getCallingUid()));
if (DEBUG) {
Log.d(TAG, "registering controller callback " + cb + " from controller"
@@ -1199,14 +1222,14 @@
}
@Override
- public void unregisterCallbackListener(ISessionControllerCallback cb) {
+ public void unregisterCallbackListener(ControllerCallbackLink cb) {
synchronized (mLock) {
int index = getControllerHolderIndexForCb(cb);
if (index != -1) {
mControllerCallbackHolders.remove(index);
}
if (DEBUG) {
- Log.d(TAG, "unregistering callback " + cb.asBinder());
+ Log.d(TAG, "unregistering callback " + cb.getBinder());
}
}
}
@@ -1253,7 +1276,7 @@
@Override
public void adjustVolume(String packageName, String opPackageName,
- ISessionControllerCallback caller, boolean asSystemService, int direction,
+ ControllerCallbackLink caller, boolean asSystemService, int direction,
int flags) {
int pid = Binder.getCallingPid();
int uid = Binder.getCallingUid();
@@ -1268,7 +1291,7 @@
@Override
public void setVolumeTo(String packageName, String opPackageName,
- ISessionControllerCallback caller, int value, int flags) {
+ ControllerCallbackLink caller, int value, int flags) {
int pid = Binder.getCallingPid();
int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
@@ -1281,110 +1304,110 @@
}
@Override
- public void prepare(String packageName, ISessionControllerCallback caller) {
+ public void prepare(String packageName, ControllerCallbackLink caller) {
mSessionCb.prepare(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
}
@Override
- public void prepareFromMediaId(String packageName, ISessionControllerCallback caller,
+ public void prepareFromMediaId(String packageName, ControllerCallbackLink caller,
String mediaId, Bundle extras) {
mSessionCb.prepareFromMediaId(packageName, Binder.getCallingPid(),
Binder.getCallingUid(), caller, mediaId, extras);
}
@Override
- public void prepareFromSearch(String packageName, ISessionControllerCallback caller,
+ public void prepareFromSearch(String packageName, ControllerCallbackLink caller,
String query, Bundle extras) {
mSessionCb.prepareFromSearch(packageName, Binder.getCallingPid(),
Binder.getCallingUid(), caller, query, extras);
}
@Override
- public void prepareFromUri(String packageName, ISessionControllerCallback caller,
+ public void prepareFromUri(String packageName, ControllerCallbackLink caller,
Uri uri, Bundle extras) {
mSessionCb.prepareFromUri(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
caller, uri, extras);
}
@Override
- public void play(String packageName, ISessionControllerCallback caller) {
+ public void play(String packageName, ControllerCallbackLink caller) {
mSessionCb.play(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
}
@Override
- public void playFromMediaId(String packageName, ISessionControllerCallback caller,
+ public void playFromMediaId(String packageName, ControllerCallbackLink caller,
String mediaId, Bundle extras) {
mSessionCb.playFromMediaId(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
caller, mediaId, extras);
}
@Override
- public void playFromSearch(String packageName, ISessionControllerCallback caller,
+ public void playFromSearch(String packageName, ControllerCallbackLink caller,
String query, Bundle extras) {
mSessionCb.playFromSearch(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
caller, query, extras);
}
@Override
- public void playFromUri(String packageName, ISessionControllerCallback caller,
+ public void playFromUri(String packageName, ControllerCallbackLink caller,
Uri uri, Bundle extras) {
mSessionCb.playFromUri(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
caller, uri, extras);
}
@Override
- public void skipToQueueItem(String packageName, ISessionControllerCallback caller,
+ public void skipToQueueItem(String packageName, ControllerCallbackLink caller,
long id) {
mSessionCb.skipToTrack(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
caller, id);
}
@Override
- public void pause(String packageName, ISessionControllerCallback caller) {
+ public void pause(String packageName, ControllerCallbackLink caller) {
mSessionCb.pause(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
}
@Override
- public void stop(String packageName, ISessionControllerCallback caller) {
+ public void stop(String packageName, ControllerCallbackLink caller) {
mSessionCb.stop(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
}
@Override
- public void next(String packageName, ISessionControllerCallback caller) {
+ public void next(String packageName, ControllerCallbackLink caller) {
mSessionCb.next(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
}
@Override
- public void previous(String packageName, ISessionControllerCallback caller) {
+ public void previous(String packageName, ControllerCallbackLink caller) {
mSessionCb.previous(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
caller);
}
@Override
- public void fastForward(String packageName, ISessionControllerCallback caller) {
+ public void fastForward(String packageName, ControllerCallbackLink caller) {
mSessionCb.fastForward(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
caller);
}
@Override
- public void rewind(String packageName, ISessionControllerCallback caller) {
+ public void rewind(String packageName, ControllerCallbackLink caller) {
mSessionCb.rewind(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
}
@Override
- public void seekTo(String packageName, ISessionControllerCallback caller, long pos) {
+ public void seekTo(String packageName, ControllerCallbackLink caller, long pos) {
mSessionCb.seekTo(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller,
pos);
}
@Override
- public void rate(String packageName, ISessionControllerCallback caller, Rating rating) {
+ public void rate(String packageName, ControllerCallbackLink caller, Rating rating) {
mSessionCb.rate(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller,
rating);
}
@Override
- public void sendCustomAction(String packageName, ISessionControllerCallback caller,
+ public void sendCustomAction(String packageName, ControllerCallbackLink caller,
String action, Bundle args) {
mSessionCb.sendCustomAction(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
caller, action, args);
@@ -1403,7 +1426,7 @@
}
@Override
- public ParceledListSlice getQueue() {
+ public List<QueueItem> getQueue() {
synchronized (mLock) {
return mQueue;
}
@@ -1432,12 +1455,12 @@
}
}
- private class ISessionControllerCallbackHolder {
- private final ISessionControllerCallback mCallback;
+ private class ControllerCallbackLinkHolder {
+ private final ControllerCallbackLink mCallback;
private final String mPackageName;
private final int mUid;
- ISessionControllerCallbackHolder(ISessionControllerCallback callback, String packageName,
+ ControllerCallbackLinkHolder(ControllerCallbackLink callback, String packageName,
int uid) {
mCallback = callback;
mPackageName = packageName;
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 7f2e047..ce0e72b 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -48,10 +48,10 @@
import android.media.session.IOnMediaKeyListener;
import android.media.session.IOnVolumeKeyLongPressListener;
import android.media.session.ISession;
-import android.media.session.ISessionCallback;
import android.media.session.ISessionManager;
import android.media.session.MediaSession;
import android.media.session.MediaSessionManager;
+import android.media.session.SessionCallbackLink;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -114,10 +114,11 @@
@GuardedBy("mLock")
private final ArrayList<SessionsListenerRecord> mSessionsListeners
= new ArrayList<SessionsListenerRecord>();
+ // Map user id as index to list of Session2Tokens
// TODO: Keep session2 info in MediaSessionStack for prioritizing both session1 and session2 in
// one place.
@GuardedBy("mLock")
- private final List<Session2Token> mSession2Tokens = new ArrayList<>();
+ private final SparseArray<List<Session2Token>> mSession2TokensPerUser = new SparseArray<>();
private KeyguardManager mKeyguardManager;
private IAudioService mAudioService;
@@ -305,10 +306,13 @@
updateUser();
}
+ // Called when the user with the userId is removed.
@Override
public void onStopUser(int userId) {
if (DEBUG) Log.d(TAG, "onStopUser: " + userId);
synchronized (mLock) {
+ // TODO: Also handle removing user in updateUser() because adding/switching user is
+ // handled in updateUser().
FullUserRecord user = getFullUserRecordLocked(userId);
if (user != null) {
if (user.mFullUserId == userId) {
@@ -318,6 +322,7 @@
user.destroySessionsForUserLocked(userId);
}
}
+ mSession2TokensPerUser.remove(userId);
updateUser();
}
}
@@ -363,6 +368,9 @@
mUserRecords.put(userInfo.id, new FullUserRecord(userInfo.id));
}
}
+ if (mSession2TokensPerUser.get(userInfo.id) == null) {
+ mSession2TokensPerUser.put(userInfo.id, new ArrayList<>());
+ }
}
}
// Ensure that the current full user exists.
@@ -372,6 +380,9 @@
Log.w(TAG, "Cannot find FullUserInfo for the current user " + currentFullUserId);
mCurrentFullUserRecord = new FullUserRecord(currentFullUserId);
mUserRecords.put(currentFullUserId, mCurrentFullUserRecord);
+ if (mSession2TokensPerUser.get(currentFullUserId) == null) {
+ mSession2TokensPerUser.put(currentFullUserId, new ArrayList<>());
+ }
}
mFullUserIds.put(currentFullUserId, currentFullUserId);
}
@@ -425,7 +436,7 @@
}
try {
- session.getCallback().asBinder().unlinkToDeath(session, 0);
+ session.getCallback().getBinder().unlinkToDeath(session, 0);
} catch (Exception e) {
// ignore exceptions while destroying a session.
}
@@ -511,7 +522,7 @@
}
private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId,
- String callerPackageName, ISessionCallback cb, String tag) throws RemoteException {
+ String callerPackageName, SessionCallbackLink cb, String tag) throws RemoteException {
synchronized (mLock) {
return createSessionLocked(callerPid, callerUid, userId, callerPackageName, cb, tag);
}
@@ -525,7 +536,7 @@
* 4. It needs to be added to the relevant user record.
*/
private MediaSessionRecord createSessionLocked(int callerPid, int callerUid, int userId,
- String callerPackageName, ISessionCallback cb, String tag) {
+ String callerPackageName, SessionCallbackLink cb, String tag) {
FullUserRecord user = getFullUserRecordLocked(userId);
if (user == null) {
Log.wtf(TAG, "Request from invalid user: " + userId);
@@ -535,7 +546,7 @@
final MediaSessionRecord session = new MediaSessionRecord(callerPid, callerUid, userId,
callerPackageName, cb, tag, this, mHandler.getLooper());
try {
- cb.asBinder().linkToDeath(session, 0);
+ cb.getBinder().linkToDeath(session, 0);
} catch (RemoteException e) {
throw new RuntimeException("Media Session owner died prematurely.", e);
}
@@ -732,9 +743,15 @@
pw.println(indent + "Restored MediaButtonReceiverComponentType: "
+ mRestoredMediaButtonReceiverComponentType);
mPriorityStack.dump(pw, indent);
- pw.println(indent + "Session2Tokens - " + mSession2Tokens.size());
- for (Session2Token session2Token : mSession2Tokens) {
- pw.println(indent + " " + session2Token);
+ pw.println(indent + "Session2Tokens:");
+ for (int i = 0; i < mSession2TokensPerUser.size(); i++) {
+ List<Session2Token> list = mSession2TokensPerUser.valueAt(i);
+ if (list == null || list.size() == 0) {
+ continue;
+ }
+ for (Session2Token token : list) {
+ pw.println(indent + " " + token);
+ }
}
}
@@ -890,7 +907,7 @@
private boolean mVoiceButtonHandled = false;
@Override
- public ISession createSession(String packageName, ISessionCallback cb, String tag,
+ public ISession createSession(String packageName, SessionCallbackLink cb, String tag,
int userId) throws RemoteException {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
@@ -956,6 +973,34 @@
}
@Override
+ public List<Session2Token> getSession2Tokens(int userId) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+
+ try {
+ // Check that they can make calls on behalf of the user and
+ // get the final user id
+ int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+ true /* allowAll */, true /* requireFull */, "getSession2Tokens",
+ null /* optional packageName */);
+ List<Session2Token> result = new ArrayList<>();
+ synchronized (mLock) {
+ if (resolvedUserId == UserHandle.USER_ALL) {
+ for (int i = 0; i < mSession2TokensPerUser.size(); i++) {
+ result.addAll(mSession2TokensPerUser.valueAt(i));
+ }
+ } else {
+ result.addAll(mSession2TokensPerUser.get(userId));
+ }
+ }
+ return result;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
public void addSessionsListener(IActiveSessionsListener listener,
ComponentName componentName, int userId) throws RemoteException {
final int pid = Binder.getCallingPid();
@@ -1965,14 +2010,16 @@
@Override
public void onConnected(MediaController2 controller, Session2CommandGroup allowedCommands) {
synchronized (mLock) {
- mSession2Tokens.add(mToken);
+ int userId = UserHandle.getUserId(mToken.getUid());
+ mSession2TokensPerUser.get(userId).add(mToken);
}
}
@Override
public void onDisconnected(MediaController2 controller) {
synchronized (mLock) {
- mSession2Tokens.remove(mToken);
+ int userId = UserHandle.getUserId(mToken.getUid());
+ mSession2TokensPerUser.get(userId).remove(mToken);
}
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c68e0f9..7ecdad2 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -77,6 +77,7 @@
import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
+import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER;
import static com.android.server.utils.PriorityDump.PRIORITY_ARG;
import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL;
import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL;
@@ -4452,7 +4453,8 @@
am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
WHITELIST_TOKEN, duration);
am.setPendingIntentAllowBgActivityStarts(pendingIntent.getTarget(),
- WHITELIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER));
+ WHITELIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER
+ | FLAG_SERVICE_SENDER));
}
}
}
diff --git a/services/core/java/com/android/server/os/BugreportManagerService.java b/services/core/java/com/android/server/os/BugreportManagerService.java
new file mode 100644
index 0000000..e241591
--- /dev/null
+++ b/services/core/java/com/android/server/os/BugreportManagerService.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.os;
+
+import android.content.Context;
+
+import com.android.server.SystemService;
+
+/**
+ * Service that provides a privileged API to capture and consume bugreports.
+ *
+ * @hide
+ */
+public class BugreportManagerService extends SystemService {
+ private static final String TAG = "BugreportManagerService";
+
+ private BugreportManagerServiceImpl mService;
+
+ public BugreportManagerService(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ mService = new BugreportManagerServiceImpl(getContext());
+ // TODO(b/111441001): Needs sepolicy to be submitted first.
+ // publishBinderService(Context.BUGREPORT_SERVICE, mService);
+ }
+}
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
new file mode 100644
index 0000000..faa4714
--- /dev/null
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.os;
+
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.os.BugreportParams;
+import android.os.IDumpstate;
+import android.os.IDumpstateListener;
+import android.os.IDumpstateToken;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.util.Slog;
+
+import java.io.FileDescriptor;
+
+// TODO(b/111441001):
+// 1. Handle the case where another bugreport is in progress
+// 2. Make everything threadsafe
+// 3. Pass validation & other errors on listener
+
+/**
+ * Implementation of the service that provides a privileged API to capture and consume bugreports.
+ *
+ * <p>Delegates the actualy generation to a native implementation of {@code Dumpstate}.
+ */
+class BugreportManagerServiceImpl extends IDumpstate.Stub {
+ private static final String TAG = "BugreportManagerService";
+ private static final long DEFAULT_BUGREPORT_SERVICE_TIMEOUT_MILLIS = 30 * 1000;
+
+ private IDumpstate mDs = null;
+ private final Context mContext;
+
+ BugreportManagerServiceImpl(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ @RequiresPermission(android.Manifest.permission.DUMP)
+ public IDumpstateToken setListener(String name, IDumpstateListener listener,
+ boolean getSectionDetails) throws RemoteException {
+ // TODO(b/111441001): Figure out if lazy setting of listener should be allowed
+ // and if so how to handle it.
+ throw new UnsupportedOperationException("setListener is not allowed on this service");
+ }
+
+
+ @Override
+ @RequiresPermission(android.Manifest.permission.DUMP)
+ public void startBugreport(FileDescriptor bugreportFd, FileDescriptor screenshotFd,
+ int bugreportMode, IDumpstateListener listener) throws RemoteException {
+
+ validate(bugreportMode);
+
+ mDs = getDumpstateService();
+ if (mDs == null) {
+ Slog.w(TAG, "Unable to get bugreport service");
+ // TODO(b/111441001): pass error on listener
+ return;
+ }
+ mDs.startBugreport(bugreportFd, screenshotFd, bugreportMode, listener);
+ }
+
+ private boolean validate(@BugreportParams.BugreportMode int mode) {
+ if (mode != BugreportParams.BUGREPORT_MODE_FULL
+ && mode != BugreportParams.BUGREPORT_MODE_INTERACTIVE
+ && mode != BugreportParams.BUGREPORT_MODE_REMOTE
+ && mode != BugreportParams.BUGREPORT_MODE_WEAR
+ && mode != BugreportParams.BUGREPORT_MODE_TELEPHONY
+ && mode != BugreportParams.BUGREPORT_MODE_WIFI) {
+ Slog.w(TAG, "Unknown bugreport mode: " + mode);
+ return false;
+ }
+ return true;
+ }
+
+ /*
+ * Start and get a handle to the native implementation of {@code IDumpstate} which does the
+ * actual bugreport generation.
+ *
+ * <p>Generating bugreports requires root privileges. To limit the footprint
+ * of the root access, the actual generation in Dumpstate binary is accessed as a
+ * oneshot service 'bugreport'.
+ */
+ private IDumpstate getDumpstateService() {
+ // Start bugreport service.
+ SystemProperties.set("ctl.start", "bugreport");
+
+ IDumpstate ds = null;
+ boolean timedOut = false;
+ int totalTimeWaitedMillis = 0;
+ int seedWaitTimeMillis = 500;
+ while (!timedOut) {
+ // Note that the binder service on the native side is "dumpstate".
+ ds = IDumpstate.Stub.asInterface(ServiceManager.getService("dumpstate"));
+ if (ds != null) {
+ Slog.i(TAG, "Got bugreport service handle.");
+ break;
+ }
+ SystemClock.sleep(seedWaitTimeMillis);
+ Slog.i(TAG,
+ "Waiting to get dumpstate service handle (" + totalTimeWaitedMillis + "ms)");
+ totalTimeWaitedMillis += seedWaitTimeMillis;
+ seedWaitTimeMillis *= 2;
+ timedOut = totalTimeWaitedMillis > DEFAULT_BUGREPORT_SERVICE_TIMEOUT_MILLIS;
+ }
+ if (timedOut) {
+ Slog.w(TAG,
+ "Timed out waiting to get dumpstate service handle ("
+ + totalTimeWaitedMillis + "ms)");
+ }
+ return ds;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java
index 3b11525..8facce1 100644
--- a/services/core/java/com/android/server/pm/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/ComponentResolver.java
@@ -42,6 +42,7 @@
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.DebugUtils;
import android.util.Log;
import android.util.LogPrinter;
import android.util.Pair;
@@ -60,6 +61,7 @@
/** Resolves all Android component types [activities, services, providers and receivers]. */
public class ComponentResolver {
+ private static final boolean DEBUG = false;
private static final String TAG = "PackageManager";
private static final boolean DEBUG_FILTERS = false;
private static final boolean DEBUG_SHOW_INFO = false;
@@ -1198,22 +1200,48 @@
return packageName.equals(info.activity.owner.packageName);
}
+ private void log(String reason, ActivityIntentInfo info, int match,
+ int userId) {
+ Slog.w(TAG, reason
+ + "; match: "
+ + DebugUtils.flagsToString(IntentFilter.class, "MATCH_", match)
+ + "; userId: " + userId
+ + "; intent info: " + info);
+ }
+
@Override
protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
int match, int userId) {
- if (!sUserManager.exists(userId)) return null;
+ if (!sUserManager.exists(userId)) {
+ if (DEBUG) {
+ log("User doesn't exist", info, match, userId);
+ }
+ return null;
+ }
if (!sPackageManagerInternal.isEnabledAndMatches(info.activity.info, mFlags, userId)) {
+ if (DEBUG) {
+ log("!PackageManagerInternal.isEnabledAndMatches; mFlags="
+ + DebugUtils.flagsToString(PackageManager.class, "MATCH_", mFlags),
+ info, match, userId);
+ }
return null;
}
final PackageParser.Activity activity = info.activity;
PackageSetting ps = (PackageSetting) activity.owner.mExtras;
if (ps == null) {
+ if (DEBUG) {
+ log("info.activity.owner.mExtras == null", info, match, userId);
+ }
return null;
}
final PackageUserState userState = ps.readUserState(userId);
ActivityInfo ai =
PackageParser.generateActivityInfo(activity, mFlags, userState, userId);
if (ai == null) {
+ if (DEBUG) {
+ log("Failed to create ActivityInfo based on " + info.activity, info, match,
+ userId);
+ }
return null;
}
final boolean matchExplicitlyVisibleOnly =
@@ -1227,15 +1255,31 @@
final boolean matchInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0;
// throw out filters that aren't visible to ephemeral apps
if (matchVisibleToInstantApp && !(componentVisible || userState.instantApp)) {
+ if (DEBUG) {
+ log("Filter(s) not visible to ephemeral apps"
+ + "; matchVisibleToInstantApp=" + matchVisibleToInstantApp
+ + "; matchInstantApp=" + matchInstantApp
+ + "; info.isVisibleToInstantApp()=" + info.isVisibleToInstantApp()
+ + "; matchExplicitlyVisibleOnly=" + matchExplicitlyVisibleOnly
+ + "; info.isExplicitlyVisibleToInstantApp()="
+ + info.isExplicitlyVisibleToInstantApp(),
+ info, match, userId);
+ }
return null;
}
// throw out instant app filters if we're not explicitly requesting them
if (!matchInstantApp && userState.instantApp) {
+ if (DEBUG) {
+ log("Instant app filter is not explicitly requested", info, match, userId);
+ }
return null;
}
// throw out instant app filters if updates are available; will trigger
// instant app resolution
if (userState.instantApp && ps.isUpdateAvailable()) {
+ if (DEBUG) {
+ log("Instant app update is available", info, match, userId);
+ }
return null;
}
final ResolveInfo res = new ResolveInfo();
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 7ca39df..d0b20e8 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -329,6 +329,9 @@
if (valid) {
mSessions.put(session.sessionId, session);
+ if (session.isStaged()) {
+ mStagingManager.restoreSession(session);
+ }
} else {
// Since this is early during boot we don't send
// any observer events about the session, but we
@@ -533,7 +536,7 @@
session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
mInstallThread.getLooper(), mStagingManager, sessionId, userId,
installerPackageName, callingUid, params, createdMillis, stageDir, stageCid, false,
- false, null, SessionInfo.INVALID_ID);
+ false, null, SessionInfo.INVALID_ID, false, false, false, SessionInfo.NO_ERROR);
synchronized (mSessions) {
mSessions.put(sessionId, session);
@@ -1131,7 +1134,9 @@
}
}
synchronized (mSessions) {
- mSessions.remove(session.sessionId);
+ if (!session.isStaged() || !success) {
+ mSessions.remove(session.sessionId);
+ }
addHistoricalSessionLocked(session);
final File appIconFile = buildAppIconFile(session.sessionId);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 5cb6c34..516927f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -151,6 +151,10 @@
private static final String ATTR_MULTI_PACKAGE = "multiPackage";
private static final String ATTR_PARENT_SESSION_ID = "parentSessionId";
private static final String ATTR_STAGED_SESSION = "stagedSession";
+ private static final String ATTR_IS_READY = "isReady";
+ private static final String ATTR_IS_FAILED = "isFailed";
+ private static final String ATTR_IS_APPLIED = "isApplied";
+ private static final String ATTR_STAGED_SESSION_ERROR_CODE = "errorCode";
private static final String ATTR_MODE = "mode";
private static final String ATTR_INSTALL_FLAGS = "installFlags";
private static final String ATTR_INSTALL_LOCATION = "installLocation";
@@ -408,7 +412,8 @@
int sessionId, int userId,
String installerPackageName, int installerUid, SessionParams params, long createdMillis,
File stageDir, String stageCid, boolean prepared, boolean sealed,
- @Nullable int[] childSessionIds, int parentSessionId) {
+ @Nullable int[] childSessionIds, int parentSessionId, boolean isReady,
+ boolean isFailed, boolean isApplied, int stagedSessionErrorCode) {
mCallback = callback;
mContext = context;
mPm = pm;
@@ -438,7 +443,10 @@
}
mPrepared = prepared;
-
+ mStagedSessionReady = isReady;
+ mStagedSessionFailed = isFailed;
+ mStagedSessionApplied = isApplied;
+ mStagedSessionErrorCode = stagedSessionErrorCode;
if (sealed) {
synchronized (mLock) {
try {
@@ -2023,8 +2031,9 @@
private void destroyInternal() {
synchronized (mLock) {
mSealed = true;
- mDestroyed = true;
-
+ if (!params.isStaged) {
+ mDestroyed = true;
+ }
// Force shut down all bridges
for (RevocableFileDescriptor fd : mFds) {
fd.revoke();
@@ -2131,6 +2140,10 @@
writeBooleanAttribute(out, ATTR_MULTI_PACKAGE, params.isMultiPackage);
writeBooleanAttribute(out, ATTR_STAGED_SESSION, params.isStaged);
+ writeBooleanAttribute(out, ATTR_IS_READY, mStagedSessionReady);
+ writeBooleanAttribute(out, ATTR_IS_FAILED, mStagedSessionFailed);
+ writeBooleanAttribute(out, ATTR_IS_APPLIED, mStagedSessionApplied);
+ writeIntAttribute(out, ATTR_STAGED_SESSION_ERROR_CODE, mStagedSessionErrorCode);
// TODO(patb,109941548): avoid writing to xml and instead infer / validate this after
// we've read all sessions.
writeIntAttribute(out, ATTR_PARENT_SESSION_ID, mParentSessionId);
@@ -2269,10 +2282,16 @@
params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath());
params.appIconLastModified = appIconFile.lastModified();
}
+ final boolean isReady = readBooleanAttribute(in, ATTR_IS_READY);
+ final boolean isFailed = readBooleanAttribute(in, ATTR_IS_FAILED);
+ final boolean isApplied = readBooleanAttribute(in, ATTR_IS_APPLIED);
+ final int stagedSessionErrorCode = readIntAttribute(in, ATTR_STAGED_SESSION_ERROR_CODE);
+
return new PackageInstallerSession(callback, context, pm, sessionProvider,
installerThread, stagingManager, sessionId, userId, installerPackageName,
installerUid, params, createdMillis, stageDir, stageCid, prepared, sealed,
- EMPTY_CHILD_SESSION_ARRAY, parentSessionId);
+ EMPTY_CHILD_SESSION_ARRAY, parentSessionId, isReady, isFailed, isApplied,
+ stagedSessionErrorCode);
}
/**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3301962..597f5b3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -13562,7 +13562,8 @@
}
Signature[] callerSignature;
- Object obj = mSettings.getSettingLPr(callingUid);
+ final int appId = UserHandle.getAppId(callingUid);
+ final Object obj = mSettings.getSettingLPr(appId);
if (obj != null) {
if (obj instanceof SharedUserSetting) {
callerSignature =
@@ -16910,19 +16911,29 @@
final String filePath = entry.getKey();
final String signaturePath = entry.getValue();
- final VerityUtils.SetupResult result = VerityUtils.generateApkVeritySetupData(
- filePath, signaturePath, legacyMode);
+ if (!legacyMode) {
+ // fs-verity is optional for now. Only set up if signature is provided.
+ if (new File(signaturePath).exists()) {
+ try {
+ VerityUtils.setUpFsverity(filePath, signaturePath);
+ } catch (IOException | DigestException | NoSuchAlgorithmException
+ | SecurityException e) {
+ throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE,
+ "Failed to enable fs-verity: " + e);
+ }
+ }
+ continue;
+ }
+
+ // In legacy mode, fs-verity can only be enabled by process with CAP_SYS_ADMIN.
+ final VerityUtils.SetupResult result = VerityUtils.generateApkVeritySetupData(filePath);
if (result.isOk()) {
if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling verity to " + filePath);
final FileDescriptor fd = result.getUnownedFileDescriptor();
try {
mInstaller.installApkVerity(filePath, fd, result.getContentSize());
-
- // In legacy mode, fs-verity can only be enabled by process with CAP_SYS_ADMIN.
- if (legacyMode) {
- final byte[] rootHash = VerityUtils.generateApkVerityRootHash(filePath);
- mInstaller.assertFsverityRootHashMatches(filePath, rootHash);
- }
+ final byte[] rootHash = VerityUtils.generateApkVerityRootHash(filePath);
+ mInstaller.assertFsverityRootHashMatches(filePath, rootHash);
} finally {
IoUtils.closeQuietly(fd);
}
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 48ee9dc..c297c62 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -53,9 +53,6 @@
private final PackageManagerService mPm;
private final Handler mBgHandler;
- // STOPSHIP: This is a temporary mock implementation of staged sessions. This variable
- // shouldn't be needed at all.
- // TODO(b/118865310): Implement staged sessions logic.
@GuardedBy("mStagedSessions")
private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();
@@ -191,4 +188,11 @@
mStagedSessions.remove(sessionInfo.sessionId);
}
}
+
+ void restoreSession(@NonNull PackageInstallerSession session) {
+ updateStoredSession(session);
+ // TODO(b/118865310): This method is called when PackageInstaller is re-instantiated, e.g.
+ // at reboot. Staging manager should at this point recover state from apexd and decide what
+ // to do with the session.
+ }
}
diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
new file mode 100644
index 0000000..45c975b
--- /dev/null
+++ b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy.role;
+
+import android.annotation.NonNull;
+import android.app.role.RoleManager;
+import android.content.Context;
+import android.os.Debug;
+import android.provider.Settings;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.telephony.SmsApplication;
+import com.android.internal.util.CollectionUtils;
+import com.android.server.role.RoleManagerService;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Logic to retrieve the various legacy(pre-Q) equivalents of role holders.
+ *
+ * Unlike {@link RoleManagerService} this is meant to be pretty high-level to allow for depending
+ * on all kinds of various systems that are historically involved in legacy role resolution,
+ * e.g. {@link SmsApplication}
+ *
+ * @see RoleManagerService#migrateRoleIfNecessary
+ */
+public class LegacyRoleResolutionPolicy implements RoleManagerService.RoleHoldersResolver {
+
+ private static final boolean DEBUG = false;
+ private static final String LOG_TAG = "LegacyRoleResolutionPol";
+
+ @NonNull
+ private final Context mContext;
+
+ public LegacyRoleResolutionPolicy(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public List<String> getRoleHolders(String roleName, int userId) {
+ switch (roleName) {
+ case RoleManager.ROLE_SMS: {
+ // Moved over from SmsApplication#getApplication
+ String result = Settings.Secure.getStringForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
+
+ if (result == null) {
+ Collection<SmsApplication.SmsApplicationData> applications =
+ SmsApplication.getApplicationCollectionAsUser(mContext, userId);
+ SmsApplication.SmsApplicationData applicationData;
+ String defaultPackage = mContext.getResources()
+ .getString(com.android.internal.R.string.default_sms_application);
+ applicationData =
+ SmsApplication.getApplicationForPackage(applications, defaultPackage);
+
+ if (applicationData == null) {
+ // Are there any applications?
+ if (applications.size() != 0) {
+ applicationData =
+ (SmsApplication.SmsApplicationData) applications.toArray()[0];
+ }
+ }
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Found default sms app: " + applicationData
+ + " among: " + applications + " from " + Debug.getCallers(4));
+ }
+ SmsApplication.SmsApplicationData app = applicationData;
+ result = app == null ? null : app.mPackageName;
+ }
+
+ return CollectionUtils.singletonOrEmpty(result);
+ }
+ default: {
+ Slog.e(LOG_TAG, "Don't know how to find legacy role holders for " + roleName);
+ return Collections.emptyList();
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/power/OWNERS b/services/core/java/com/android/server/power/OWNERS
index 244ccb6..5cbe74c 100644
--- a/services/core/java/com/android/server/power/OWNERS
+++ b/services/core/java/com/android/server/power/OWNERS
@@ -1,6 +1,4 @@
michaelwr@google.com
santoscordon@google.com
-per-file BatterySaverPolicy.java=omakoto@google.com
-per-file ShutdownThread.java=fkupolov@google.com
-per-file ThermalManagerService.java=wvw@google.com
\ No newline at end of file
+per-file ThermalManagerService.java=wvw@google.com
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 565bb706..a027873 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -96,6 +96,7 @@
import com.android.server.lights.LightsManager;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.power.batterysaver.BatterySaverController;
+import com.android.server.power.batterysaver.BatterySaverPolicy;
import com.android.server.power.batterysaver.BatterySaverStateMachine;
import com.android.server.power.batterysaver.BatterySavingStats;
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index 6400c88..1d74350 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -35,13 +35,13 @@
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
-import com.android.server.power.BatterySaverPolicy;
-import com.android.server.power.BatterySaverPolicy.BatterySaverPolicyListener;
import com.android.server.power.PowerManagerService;
+import com.android.server.power.batterysaver.BatterySaverPolicy.BatterySaverPolicyListener;
import com.android.server.power.batterysaver.BatterySavingStats.BatterySaverState;
import com.android.server.power.batterysaver.BatterySavingStats.DozeState;
import com.android.server.power.batterysaver.BatterySavingStats.InteractiveState;
@@ -158,10 +158,9 @@
mBatterySavingStats = batterySavingStats;
// Initialize plugins.
- final ArrayList<Plugin> plugins = new ArrayList<>();
- plugins.add(new BatterySaverLocationPlugin(mContext));
-
- mPlugins = plugins.toArray(new Plugin[plugins.size()]);
+ mPlugins = new Plugin[] {
+ new BatterySaverLocationPlugin(mContext)
+ };
}
/**
@@ -217,7 +216,7 @@
super(looper);
}
- public void postStateChanged(boolean sendBroadcast, int reason) {
+ void postStateChanged(boolean sendBroadcast, int reason) {
obtainMessage(MSG_STATE_CHANGED, sendBroadcast ?
ARG_SEND_BROADCAST : ARG_DONT_SEND_BROADCAST, reason).sendToTarget();
}
@@ -244,9 +243,8 @@
}
}
- /**
- * Called by {@link PowerManagerService} to update the battery saver state.
- */
+ /** Enable or disable full battery saver. */
+ @VisibleForTesting
public void enableBatterySaver(boolean enable, int reason) {
synchronized (mLock) {
if (mEnabled == enable) {
@@ -311,7 +309,7 @@
reason);
mPreviouslyEnabled = mEnabled;
- listeners = mListeners.toArray(new LowPowerModeListener[mListeners.size()]);
+ listeners = mListeners.toArray(new LowPowerModeListener[0]);
enabled = mEnabled;
mIsInteractive = isInteractive;
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
similarity index 98%
rename from services/core/java/com/android/server/power/BatterySaverPolicy.java
rename to services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
index cedb548..48a041e 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.server.power;
+package com.android.server.power.batterysaver;
import android.content.ContentResolver;
import android.content.Context;
@@ -36,21 +36,19 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ConcurrentUtils;
-import com.android.server.power.batterysaver.BatterySavingStats;
-import com.android.server.power.batterysaver.CpuFrequencies;
+import com.android.server.power.PowerManagerService;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
/**
- * Class to decide whether to turn on battery saver mode for specific service
+ * Class to decide whether to turn on battery saver mode for specific services.
*
* IMPORTANT: This class shares the power manager lock, which is very low in the lock hierarchy.
* Do not call out with the lock held, such as AccessibilityManager. (Settings provider is okay.)
*
- * Test:
- atest ${ANDROID_BUILD_TOP}/frameworks/base/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
+ * Test: atest com.android.server.power.batterysaver.BatterySaverPolicyTest.java
*/
public class BatterySaverPolicy extends ContentObserver {
private static final String TAG = "BatterySaverPolicy";
@@ -200,8 +198,10 @@
onChange(true, null);
}
+ @VisibleForTesting
public void addListener(BatterySaverPolicyListener listener) {
synchronized (mLock) {
+ // TODO: set this in the constructor instead
mListeners.add(listener);
}
}
@@ -244,7 +244,7 @@
// Update.
updateConstantsLocked(setting, deviceSpecificSetting);
- listeners = mListeners.toArray(new BatterySaverPolicyListener[mListeners.size()]);
+ listeners = mListeners.toArray(new BatterySaverPolicyListener[0]);
}
// Notify the listeners.
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index a60f16d..b7f28da 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -37,7 +37,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.server.EventLogTags;
-import com.android.server.power.BatterySaverPolicy;
import com.android.server.power.BatterySaverStateMachineProto;
import java.io.PrintWriter;
@@ -229,8 +228,8 @@
}
/**
- * Run a {@link Runnable} on a background handler, but lazily. If the same {@link Runnable},
- * it'll be first removed before a new one is posted.
+ * Run a {@link Runnable} on a background handler, but lazily. If the same {@link Runnable} is
+ * already registered, it'll be first removed before being re-posted.
*/
@VisibleForTesting
void runOnBgThreadLazy(Runnable r, int delayMillis) {
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
index 8213205..79b44eb 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
@@ -29,7 +29,6 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
-import com.android.server.power.BatterySaverPolicy;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index f37ca12..b488337 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -35,6 +35,7 @@
import android.content.IntentFilter;
import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
+import android.os.Binder;
import android.os.Handler;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
@@ -92,6 +93,15 @@
@NonNull
private final Object mLock = new Object();
+ @NonNull
+ private final RoleHoldersResolver mLegacyRoleResolver;
+
+ /** @see #getRoleHolders(String, int) */
+ public interface RoleHoldersResolver {
+ /** @return a list of packages that hold a given role for a given user */
+ List<String> getRoleHolders(String roleName, int userId);
+ }
+
/**
* Maps user id to its state.
*/
@@ -118,9 +128,12 @@
@NonNull
private final Handler mListenerHandler = FgThread.getHandler();
- public RoleManagerService(@NonNull Context context) {
+ public RoleManagerService(@NonNull Context context,
+ @NonNull RoleHoldersResolver legacyRoleResolver) {
super(context);
+ mLegacyRoleResolver = legacyRoleResolver;
+
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
mAppOpsManager = context.getSystemService(AppOpsManager.class);
@@ -175,10 +188,17 @@
private void performInitialGrantsIfNecessary(@UserIdInt int userId) {
RoleUserState userState;
userState = getOrCreateUserState(userId);
+
String packagesHash = computeComponentStateHash(userId);
String oldPackagesHash = userState.getPackagesHash();
boolean needGrant = !Objects.equals(packagesHash, oldPackagesHash);
if (needGrant) {
+
+ //TODO gradually add more role migrations statements here for remaining roles
+ // Make sure to implement LegacyRoleResolutionPolicy#getRoleHolders
+ // for a given role before adding a migration statement for it here
+ migrateRoleIfNecessary(RoleManager.ROLE_SMS, userId);
+
// Some vital packages state has changed since last role grant
// Run grants again
Slog.i(LOG_TAG, "Granting default permissions...");
@@ -205,6 +225,20 @@
}
}
+ private void migrateRoleIfNecessary(String role, @UserIdInt int userId) {
+ // Any role for which we have a record are already migrated
+ RoleUserState userState = getOrCreateUserState(userId);
+ if (!userState.isRoleAvailable(role)) {
+ userState.addRoleName(role);
+ List<String> roleHolders = mLegacyRoleResolver.getRoleHolders(role, userId);
+ Slog.i(LOG_TAG, "Migrating " + role + ", legacy holders: " + roleHolders);
+ int size = roleHolders.size();
+ for (int i = 0; i < size; i++) {
+ userState.addRoleHolder(role, roleHolders.get(i));
+ }
+ }
+ }
+
@Nullable
private static String computeComponentStateHash(@UserIdInt int userId) {
PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
@@ -372,6 +406,7 @@
@Nullable
private ArraySet<String> getRoleHoldersInternal(@NonNull String roleName,
@UserIdInt int userId) {
+ migrateRoleIfNecessary(roleName, userId);
RoleUserState userState = getOrCreateUserState(userId);
return userState.getRoleHolders(roleName);
}
@@ -530,6 +565,17 @@
}
@Override
+ public String getDefaultSmsPackage(int userId) {
+ long identity = Binder.clearCallingIdentity();
+ try {
+ return CollectionUtils.firstOrNull(
+ getRoleHoldersAsUser(RoleManager.ROLE_SMS, userId));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
@Nullable String[] args) {
if (!DumpUtils.checkDumpPermission(getContext(), LOG_TAG, fout)) {
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index 630a39c..69e1449 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -205,6 +205,28 @@
}
/**
+ * Adds the given role, effectively marking it as {@link #isRoleAvailable available}
+ *
+ * @param roleName the name of the role
+ *
+ * @return whether any changes were made
+ */
+ public boolean addRoleName(@NonNull String roleName) {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+
+ if (!mRoles.containsKey(roleName)) {
+ mRoles.put(roleName, new ArraySet<>());
+ Slog.i(LOG_TAG, "Added new role: " + roleName);
+ scheduleWriteFileLocked();
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ /**
* Set the names of all available roles.
*
* @param roleNames the names of all the available roles
@@ -231,13 +253,7 @@
int roleNamesSize = roleNames.size();
for (int i = 0; i < roleNamesSize; i++) {
- String roleName = roleNames.get(i);
-
- if (!mRoles.containsKey(roleName)) {
- mRoles.put(roleName, new ArraySet<>());
- Slog.i(LOG_TAG, "Added new role: " + roleName);
- changed = true;
- }
+ changed |= addRoleName(roleNames.get(i));
}
if (changed) {
diff --git a/services/core/java/com/android/server/security/VerityUtils.java b/services/core/java/com/android/server/security/VerityUtils.java
index 839ed30..b1db46f 100644
--- a/services/core/java/com/android/server/security/VerityUtils.java
+++ b/services/core/java/com/android/server/security/VerityUtils.java
@@ -36,6 +36,7 @@
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -59,6 +60,8 @@
/** The maximum size of signature file. This is just to avoid potential abuse. */
private static final int MAX_SIGNATURE_FILE_SIZE_BYTES = 8192;
+ private static final int COMMON_LINUX_PAGE_SIZE_IN_BYTES = 4096;
+
private static final boolean DEBUG = false;
/** Returns true if the given file looks like containing an fs-verity signature. */
@@ -71,6 +74,48 @@
return filePath + FSVERITY_SIGNATURE_FILE_EXTENSION;
}
+ /** Generates Merkle tree and fs-verity metadata then enables fs-verity. */
+ public static void setUpFsverity(@NonNull String filePath, String signaturePath)
+ throws IOException, DigestException, NoSuchAlgorithmException {
+ final PKCS7 pkcs7 = new PKCS7(Files.readAllBytes(Paths.get(signaturePath)));
+ final byte[] expectedMeasurement = pkcs7.getContentInfo().getContentBytes();
+ if (DEBUG) {
+ Slog.d(TAG, "Enabling fs-verity with signed fs-verity measurement "
+ + bytesToString(expectedMeasurement));
+ Slog.d(TAG, "PKCS#7 info: " + pkcs7);
+ }
+
+ final TrackedBufferFactory bufferFactory = new TrackedBufferFactory();
+ final byte[] actualMeasurement = generateFsverityMetadata(filePath, signaturePath,
+ bufferFactory);
+ try (RandomAccessFile raf = new RandomAccessFile(filePath, "rw")) {
+ FileChannel ch = raf.getChannel();
+ ch.position(roundUpToNextMultiple(ch.size(), COMMON_LINUX_PAGE_SIZE_IN_BYTES));
+ ByteBuffer buffer = bufferFactory.getBuffer();
+
+ long offset = buffer.position();
+ long size = buffer.limit();
+ while (offset < size) {
+ long s = ch.write(buffer);
+ offset += s;
+ size -= s;
+ }
+ }
+
+ if (!Arrays.equals(expectedMeasurement, actualMeasurement)) {
+ throw new SecurityException("fs-verity measurement mismatch: "
+ + bytesToString(actualMeasurement) + " != "
+ + bytesToString(expectedMeasurement));
+ }
+
+ // This can fail if the public key is not already in .fs-verity kernel keyring.
+ int errno = enableFsverityNative(filePath);
+ if (errno != 0) {
+ throw new IOException("Failed to enable fs-verity on " + filePath + ": "
+ + Os.strerror(errno));
+ }
+ }
+
/** Returns whether the file has fs-verity enabled. */
public static boolean hasFsverity(@NonNull String filePath) {
// NB: only measure but not check the actual measurement here. As long as this succeeds,
@@ -87,36 +132,18 @@
}
/**
- * Generates Merkle tree and fs-verity metadata.
+ * Generates legacy Merkle tree and fs-verity metadata with Signing Block skipped.
*
* @return {@code SetupResult} that contains the result code, and when success, the
* {@code FileDescriptor} to read all the data from.
*/
- public static SetupResult generateApkVeritySetupData(@NonNull String apkPath,
- String signaturePath, boolean skipSigningBlock) {
+ public static SetupResult generateApkVeritySetupData(@NonNull String apkPath) {
if (DEBUG) {
- Slog.d(TAG, "Trying to install apk verity to " + apkPath + " with signature file "
- + signaturePath);
+ Slog.d(TAG, "Trying to install legacy apk verity to " + apkPath);
}
SharedMemory shm = null;
try {
- byte[] signedVerityHash;
- if (skipSigningBlock) {
- signedVerityHash = ApkSignatureVerifier.getVerityRootHash(apkPath);
- } else {
- Path path = Paths.get(signaturePath);
- if (Files.exists(path)) {
- // TODO(112037636): fail early if the signing key is not in .fs-verity keyring.
- PKCS7 pkcs7 = new PKCS7(Files.readAllBytes(path));
- signedVerityHash = pkcs7.getContentInfo().getContentBytes();
- if (DEBUG) {
- Slog.d(TAG, "fs-verity measurement = " + bytesToString(signedVerityHash));
- }
- } else {
- signedVerityHash = null;
- }
- }
-
+ final byte[] signedVerityHash = ApkSignatureVerifier.getVerityRootHash(apkPath);
if (signedVerityHash == null) {
if (DEBUG) {
Slog.d(TAG, "Skip verity tree generation since there is no signed root hash");
@@ -124,8 +151,8 @@
return SetupResult.skipped();
}
- Pair<SharedMemory, Integer> result = generateFsVerityIntoSharedMemory(apkPath,
- signaturePath, signedVerityHash, skipSigningBlock);
+ Pair<SharedMemory, Integer> result =
+ generateFsVerityIntoSharedMemory(apkPath, signedVerityHash);
shm = result.first;
int contentSize = result.second;
FileDescriptor rfd = shm.getFileDescriptor();
@@ -156,7 +183,7 @@
* {@see ApkSignatureVerifier#getVerityRootHash(String)}.
*/
public static byte[] getVerityRootHash(@NonNull String apkPath)
- throws IOException, SignatureNotFoundException, SecurityException {
+ throws IOException, SignatureNotFoundException {
return ApkSignatureVerifier.getVerityRootHash(apkPath);
}
@@ -172,9 +199,8 @@
* includes SHA-256 of fs-verity descriptor and authenticated extensions.
*/
private static byte[] generateFsverityMetadata(String filePath, String signaturePath,
- @NonNull TrackedShmBufferFactory trackedBufferFactory)
- throws IOException, SignatureNotFoundException, SecurityException, DigestException,
- NoSuchAlgorithmException {
+ @NonNull ByteBufferFactory trackedBufferFactory)
+ throws IOException, DigestException, NoSuchAlgorithmException {
try (RandomAccessFile file = new RandomAccessFile(filePath, "r")) {
VerityBuilder.VerityResult result = VerityBuilder.generateFsVerityTree(
file, trackedBufferFactory);
@@ -184,6 +210,7 @@
final byte[] measurement = generateFsverityDescriptorAndMeasurement(file,
result.rootHash, signaturePath, buffer);
+ buffer.flip();
return constructFsveritySignedDataNative(measurement);
}
}
@@ -243,6 +270,7 @@
return md.digest();
}
+ private static native int enableFsverityNative(@NonNull String filePath);
private static native int measureFsverityNative(@NonNull String filePath);
private static native byte[] constructFsveritySignedDataNative(@NonNull byte[] measurement);
private static native byte[] constructFsverityDescriptorNative(long fileSize);
@@ -256,18 +284,13 @@
* for fsverity setup. The data is aligned to the beginning of {@code SharedMemory}, and has
* length equals to the returned {@code Integer}.
*/
- private static Pair<SharedMemory, Integer> generateFsVerityIntoSharedMemory(
- String apkPath, String signaturePath, @NonNull byte[] expectedRootHash,
- boolean skipSigningBlock)
- throws IOException, SecurityException, DigestException, NoSuchAlgorithmException,
+ private static Pair<SharedMemory, Integer> generateFsVerityIntoSharedMemory(String apkPath,
+ @NonNull byte[] expectedRootHash)
+ throws IOException, DigestException, NoSuchAlgorithmException,
SignatureNotFoundException {
TrackedShmBufferFactory shmBufferFactory = new TrackedShmBufferFactory();
- byte[] generatedRootHash;
- if (skipSigningBlock) {
- generatedRootHash = ApkSignatureVerifier.generateApkVerity(apkPath, shmBufferFactory);
- } else {
- generatedRootHash = generateFsverityMetadata(apkPath, signaturePath, shmBufferFactory);
- }
+ byte[] generatedRootHash =
+ ApkSignatureVerifier.generateApkVerity(apkPath, shmBufferFactory);
// We only generate Merkle tree once here, so it's important to make sure the root hash
// matches the signed one in the apk.
if (!Arrays.equals(expectedRootHash, generatedRootHash)) {
@@ -345,7 +368,7 @@
private ByteBuffer mBuffer;
@Override
- public ByteBuffer create(int capacity) throws SecurityException {
+ public ByteBuffer create(int capacity) {
try {
if (DEBUG) Slog.d(TAG, "Creating shared memory for apk verity");
// NB: This method is supposed to be called once according to the contract with
@@ -378,4 +401,30 @@
return mBuffer == null ? -1 : mBuffer.limit();
}
}
+
+ /** A {@code ByteBufferFactory} that tracks the {@code ByteBuffer} it creates. */
+ private static class TrackedBufferFactory implements ByteBufferFactory {
+ private ByteBuffer mBuffer;
+
+ @Override
+ public ByteBuffer create(int capacity) {
+ if (mBuffer != null) {
+ throw new IllegalStateException("Multiple instantiation from this factory");
+ }
+ mBuffer = ByteBuffer.allocate(capacity);
+ return mBuffer;
+ }
+
+ public ByteBuffer getBuffer() {
+ return mBuffer;
+ }
+ }
+
+ /** Round up the number to the next multiple of the divisor. */
+ private static long roundUpToNextMultiple(long number, long divisor) {
+ if (number > (Long.MAX_VALUE - divisor)) {
+ throw new IllegalArgumentException("arithmetic overflow");
+ }
+ return ((number + (divisor - 1)) / divisor) * divisor;
+ }
}
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 2cab63a..ef77140 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -510,7 +510,8 @@
Slog.d(LOG_TAG, "Binding to " + serviceIntent.getComponent());
willBind = mContext.bindServiceAsUser(
serviceIntent, mConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
+ | Context.BIND_RESTRICT_ASSOCIATIONS,
UserHandle.of(mUserId));
mBinding = willBind;
} finally {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 410f864..fcc8284 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -84,6 +84,7 @@
import android.system.ErrnoException;
import android.system.Os;
import android.util.EventLog;
+import android.util.FeatureFlagUtils;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -2219,8 +2220,12 @@
synchronized (mLock) {
mInAmbientMode = inAmbientMode;
final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
- if (data != null && data.connection != null && data.connection.mInfo != null
- && data.connection.mInfo.supportsAmbientMode()) {
+ final boolean hasConnection = data != null && data.connection != null;
+ final WallpaperInfo info = hasConnection ? data.connection.mInfo : null;
+
+ // The wallpaper info is null for image wallpaper, also use the engine in this case.
+ if (hasConnection && (info == null && isAodImageWallpaperEnabled()
+ || info != null && info.supportsAmbientMode())) {
// TODO(multi-display) Extends this method with specific display.
engine = data.connection.getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine;
} else {
@@ -2237,6 +2242,10 @@
}
}
+ private boolean isAodImageWallpaperEnabled() {
+ return FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.AOD_IMAGEWALLPAPER_ENABLED);
+ }
+
@Override
public boolean setLockWallpaperCallback(IWallpaperManagerCallback cb) {
checkPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 6f8f85f..f8f0d1c 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -390,6 +390,11 @@
private boolean mTurnScreenOn;
/**
+ * Current sequencing integer of the configuration, for skipping old activity configurations.
+ */
+ private int mConfigurationSeq;
+
+ /**
* Temp configs used in {@link #ensureActivityConfiguration(int, boolean)}
*/
private final Configuration mTmpConfig = new Configuration();
@@ -2568,6 +2573,45 @@
onRequestedOverrideConfigurationChanged(mTmpConfig);
}
+ @Override
+ void resolveOverrideConfiguration(Configuration newParentConfiguration) {
+ super.resolveOverrideConfiguration(newParentConfiguration);
+
+ // Assign configuration sequence number into hierarchy because there is a different way than
+ // ensureActivityConfiguration() in this class that uses configuration in WindowState during
+ // layout traversals.
+ mConfigurationSeq = Math.max(++mConfigurationSeq, 1);
+ getResolvedOverrideConfiguration().seq = mConfigurationSeq;
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newParentConfig) {
+ super.onConfigurationChanged(newParentConfig);
+
+ // Configuration's equality doesn't consider seq so if only seq number changes in resolved
+ // override configuration. Therefore ConfigurationContainer doesn't change merged override
+ // configuration, but it's used to push configuration changes so explicitly update that.
+ if (getMergedOverrideConfiguration().seq != getResolvedOverrideConfiguration().seq) {
+ onMergedOverrideConfigurationChanged();
+ }
+
+ // TODO(b/80414790): Remove code below after unification.
+ // Same as above it doesn't notify configuration listeners, and consequently AppWindowToken
+ // can't get updated seq number. However WindowState's merged override configuration needs
+ // to have this seq number because that's also used for activity config pushes during layout
+ // traversal. Therefore explicitly update them here.
+ if (mAppWindowToken == null) {
+ return;
+ }
+ final Configuration appWindowTokenRequestedOverrideConfig =
+ mAppWindowToken.getRequestedOverrideConfiguration();
+ if (appWindowTokenRequestedOverrideConfig.seq != getResolvedOverrideConfiguration().seq) {
+ appWindowTokenRequestedOverrideConfig.seq =
+ getResolvedOverrideConfiguration().seq;
+ mAppWindowToken.onMergedOverrideConfigurationChanged();
+ }
+ }
+
/** Returns true if the configuration is compatible with this activity. */
boolean isConfigurationCompatible(Configuration config) {
final int orientation = mAppWindowToken != null
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 0f286ce..d8644df 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.ActivityManager;
import android.app.AppProtoEnums;
import android.app.IActivityManager;
import android.app.IApplicationThread;
@@ -479,4 +480,10 @@
public abstract void setProfilerInfo(ProfilerInfo profilerInfo);
public abstract ActivityMetricsLaunchObserverRegistry getLaunchObserverRegistry();
+
+ /**
+ * Gets bitmap snapshot of the provided task id.
+ */
+ public abstract ActivityManager.TaskSnapshot getTaskSnapshot(int taskId,
+ boolean reducedResolution);
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 42121ca..e5bf21a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -245,7 +245,7 @@
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.server.AppOpsService;
+import com.android.server.appop.AppOpsService;
import com.android.server.AttributeCache;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -7012,5 +7012,12 @@
return mStackSupervisor.getActivityMetricsLogger().getLaunchObserverRegistry();
}
}
+
+ @Override
+ public ActivityManager.TaskSnapshot getTaskSnapshot(int taskId, boolean reducedResolution) {
+ synchronized (mGlobalLock) {
+ return ActivityTaskManagerService.this.getTaskSnapshot(taskId, reducedResolution);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/WindowTraceBuffer.java b/services/core/java/com/android/server/wm/WindowTraceBuffer.java
new file mode 100644
index 0000000..936ee85
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowTraceBuffer.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER;
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_H;
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_L;
+
+import android.os.Trace;
+import android.util.proto.ProtoOutputStream;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * Buffer used for window tracing.
+ */
+abstract class WindowTraceBuffer {
+ private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
+
+ final Object mBufferSizeLock = new Object();
+ final BlockingQueue<byte[]> mBuffer;
+ int mBufferSize;
+ private final int mBufferCapacity;
+ private final File mTraceFile;
+
+ WindowTraceBuffer(int size, File traceFile) throws IOException {
+ mBufferCapacity = size;
+ mTraceFile = traceFile;
+ mBuffer = new LinkedBlockingQueue<>();
+
+ initTraceFile();
+ }
+
+ int getAvailableSpace() {
+ return mBufferCapacity - mBufferSize;
+ }
+
+ /**
+ * Inserts the specified element into this buffer.
+ *
+ * This method is synchronized with {@code #take()} and {@code #clear()}
+ * for consistency.
+ *
+ * @param proto the element to add
+ * @return {@code true} if the inserted item was inserted into the buffer
+ * @throws IllegalStateException if the element cannot be added because it is larger
+ * than the buffer size.
+ */
+ boolean add(ProtoOutputStream proto) throws InterruptedException {
+ byte[] protoBytes = proto.getBytes();
+ int protoLength = protoBytes.length;
+ if (protoLength > mBufferCapacity) {
+ throw new IllegalStateException("Trace object too large for the buffer. Buffer size:"
+ + mBufferCapacity + " Object size: " + protoLength);
+ }
+ synchronized (mBufferSizeLock) {
+ boolean canAdd = canAdd(protoBytes);
+ if (canAdd) {
+ mBuffer.offer(protoBytes);
+ mBufferSize += protoLength;
+ }
+ return canAdd;
+ }
+ }
+
+ void writeNextBufferElementToFile() throws IOException {
+ byte[] proto;
+ try {
+ proto = take();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return;
+ }
+
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToFile");
+ try (OutputStream os = new FileOutputStream(mTraceFile, true)) {
+ os.write(proto);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ }
+ }
+
+ /**
+ * Retrieves and removes the head of this queue, waiting if necessary
+ * until an element becomes available.
+ *
+ * This method is synchronized with {@code #add(ProtoOutputStream)} and {@code #clear()}
+ * for consistency.
+ *
+ * @return the head of this buffer, or {@code null} if this buffer is empty
+ */
+ private byte[] take() throws InterruptedException {
+ byte[] item = mBuffer.take();
+ synchronized (mBufferSizeLock) {
+ mBufferSize -= item.length;
+ return item;
+ }
+ }
+
+ private void initTraceFile() throws IOException {
+ mTraceFile.delete();
+ try (OutputStream os = new FileOutputStream(mTraceFile)) {
+ mTraceFile.setReadable(true, false);
+ ProtoOutputStream proto = new ProtoOutputStream(os);
+ proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
+ proto.flush();
+ }
+ }
+
+ /**
+ * Checks if the element can be added to the buffer. The element is already certain to be
+ * smaller than the overall buffer size.
+ *
+ * @param protoBytes byte array representation of the Proto object to add
+ * @return <tt>true<</tt> if the element can be added to the buffer or not
+ */
+ abstract boolean canAdd(byte[] protoBytes) throws InterruptedException;
+
+ /**
+ * Flush all buffer content to the disk.
+ *
+ * @throws IOException if the buffer cannot write its contents to the {@link #mTraceFile}
+ */
+ abstract void writeToDisk() throws IOException, InterruptedException;
+
+ /**
+ * Builder for a {@code WindowTraceBuffer} which creates a {@link WindowTraceQueueBuffer}
+ */
+ static class Builder {
+ private File mTraceFile;
+ private int mBufferCapacity;
+
+
+ Builder setTraceFile(File traceFile) {
+ mTraceFile = traceFile;
+ return this;
+ }
+
+ Builder setBufferCapacity(int size) {
+ mBufferCapacity = size;
+ return this;
+ }
+
+ File getFile() {
+ return mTraceFile;
+ }
+
+ WindowTraceBuffer build() throws IOException {
+ if (mBufferCapacity <= 0) {
+ throw new IllegalStateException("Buffer capacity must be greater than 0.");
+ }
+
+ if (mTraceFile == null) {
+ throw new IllegalArgumentException("A valid trace file must be specified.");
+ }
+
+ return new WindowTraceQueueBuffer(mBufferCapacity, mTraceFile);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java b/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java
new file mode 100644
index 0000000..b7fc7ac
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.os.Build.IS_USER;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * A buffer structure backed by a {@link java.util.concurrent.BlockingQueue} to store the first
+ * {@code #size size} bytes of window trace elements.
+ * Once the buffer is full it will no longer accepts new elements.
+ */
+class WindowTraceQueueBuffer extends WindowTraceBuffer {
+ private Thread mWriterThread;
+ private boolean mCancel;
+
+ @VisibleForTesting
+ WindowTraceQueueBuffer(int size, File traceFile, boolean startWriterThread) throws IOException {
+ super(size, traceFile);
+ if (startWriterThread) {
+ initializeWriterThread();
+ }
+ }
+
+ WindowTraceQueueBuffer(int size, File traceFile) throws IOException {
+ this(size, traceFile, !IS_USER);
+ }
+
+ private void initializeWriterThread() {
+ mCancel = false;
+ mWriterThread = new Thread(() -> {
+ try {
+ loop();
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to execute trace write loop thread", e);
+ }
+ }, "window_tracing");
+ mWriterThread.start();
+ }
+
+ private void loop() throws IOException {
+ while (!mCancel) {
+ writeNextBufferElementToFile();
+ }
+ }
+
+ private void restartWriterThread() throws InterruptedException {
+ if (mWriterThread != null) {
+ mCancel = true;
+ mWriterThread.interrupt();
+ mWriterThread.join();
+ initializeWriterThread();
+ }
+ }
+
+ @Override
+ boolean canAdd(byte[] protoBytes) {
+ long availableSpace = getAvailableSpace();
+ return availableSpace >= protoBytes.length;
+ }
+
+ @Override
+ void writeToDisk() throws InterruptedException {
+ while (!mBuffer.isEmpty()) {
+ mBufferSizeLock.wait();
+ mBufferSizeLock.notify();
+ }
+ restartWriterThread();
+ }
+}
diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
index 8fa56bb..63539c4 100644
--- a/services/core/java/com/android/server/wm/WindowTracing.java
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -17,31 +17,23 @@
package com.android.server.wm;
import static android.os.Build.IS_USER;
+
import static com.android.server.wm.WindowManagerTraceFileProto.ENTRY;
-import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER;
-import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_H;
-import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_L;
import static com.android.server.wm.WindowManagerTraceProto.ELAPSED_REALTIME_NANOS;
import static com.android.server.wm.WindowManagerTraceProto.WHERE;
import static com.android.server.wm.WindowManagerTraceProto.WINDOW_MANAGER_SERVICE;
+import android.annotation.Nullable;
import android.content.Context;
import android.os.ShellCommand;
import android.os.SystemClock;
import android.os.Trace;
-import android.annotation.Nullable;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
-import com.android.internal.annotations.VisibleForTesting;
-
import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.OutputStream;
import java.io.PrintWriter;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.BlockingQueue;
/**
* A class that allows window manager to dump its state continuously to a trace file, such that a
@@ -49,35 +41,42 @@
*/
class WindowTracing {
+ /**
+ * Maximum buffer size, currently defined as 512 KB
+ * Size was experimentally defined to fit between 100 to 150 elements.
+ */
+ private static final int WINDOW_TRACE_BUFFER_SIZE = 512 * 1024;
private static final String TAG = "WindowTracing";
- private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
private final Object mLock = new Object();
- private final File mTraceFile;
- private final BlockingQueue<ProtoOutputStream> mWriteQueue = new ArrayBlockingQueue<>(200);
+ private final WindowTraceBuffer.Builder mBufferBuilder;
+
+ private WindowTraceBuffer mTraceBuffer;
private boolean mEnabled;
private volatile boolean mEnabledLockFree;
WindowTracing(File file) {
- mTraceFile = file;
+ mBufferBuilder = new WindowTraceBuffer.Builder()
+ .setTraceFile(file)
+ .setBufferCapacity(WINDOW_TRACE_BUFFER_SIZE);
}
void startTrace(@Nullable PrintWriter pw) throws IOException {
- if (IS_USER){
+ if (IS_USER) {
logAndPrintln(pw, "Error: Tracing is not supported on user builds.");
return;
}
synchronized (mLock) {
- logAndPrintln(pw, "Start tracing to " + mTraceFile + ".");
- mWriteQueue.clear();
- mTraceFile.delete();
- try (OutputStream os = new FileOutputStream(mTraceFile)) {
- mTraceFile.setReadable(true, false);
- ProtoOutputStream proto = new ProtoOutputStream(os);
- proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
- proto.flush();
+ logAndPrintln(pw, "Start tracing to " + mBufferBuilder.getFile() + ".");
+ if (mTraceBuffer != null) {
+ try {
+ mTraceBuffer.writeToDisk();
+ } catch (InterruptedException e) {
+ logAndPrintln(pw, "Error: Unable to flush the previous buffer.");
+ }
}
+ mTraceBuffer = mBufferBuilder.build();
mEnabled = mEnabledLockFree = true;
}
}
@@ -91,67 +90,42 @@
}
void stopTrace(@Nullable PrintWriter pw) {
- if (IS_USER){
+ if (IS_USER) {
logAndPrintln(pw, "Error: Tracing is not supported on user builds.");
return;
}
synchronized (mLock) {
- logAndPrintln(pw, "Stop tracing to " + mTraceFile + ". Waiting for traces to flush.");
+ logAndPrintln(pw, "Stop tracing to " + mBufferBuilder.getFile()
+ + ". Waiting for traces to flush.");
mEnabled = mEnabledLockFree = false;
- while (!mWriteQueue.isEmpty()) {
+
+ synchronized (mLock) {
if (mEnabled) {
logAndPrintln(pw, "ERROR: tracing was re-enabled while waiting for flush.");
throw new IllegalStateException("tracing enabled while waiting for flush.");
}
try {
- mLock.wait();
- mLock.notify();
+ mTraceBuffer.writeToDisk();
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to write buffer to file", e);
} catch (InterruptedException e) {
- Thread.currentThread().interrupt();
+ Log.e(TAG, "Unable to interrupt window tracing file write thread", e);
}
}
- logAndPrintln(pw, "Trace written to " + mTraceFile + ".");
+ logAndPrintln(pw, "Trace written to " + mBufferBuilder.getFile() + ".");
}
}
- void appendTraceEntry(ProtoOutputStream proto) {
+ private void appendTraceEntry(ProtoOutputStream proto) {
if (!mEnabledLockFree) {
return;
}
- if (!mWriteQueue.offer(proto)) {
- Log.e(TAG, "Dropping window trace entry, queue full");
- }
- }
-
- void loop() {
- for (;;) {
- loopOnce();
- }
- }
-
- @VisibleForTesting
- void loopOnce() {
- ProtoOutputStream proto;
try {
- proto = mWriteQueue.take();
+ mTraceBuffer.add(proto);
} catch (InterruptedException e) {
+ Log.e(TAG, "Unable to add element to trace", e);
Thread.currentThread().interrupt();
- return;
- }
-
- synchronized (mLock) {
- try {
- Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToFile");
- try (OutputStream os = new FileOutputStream(mTraceFile, true /* append */)) {
- os.write(proto.getBytes());
- }
- } catch (IOException e) {
- Log.e(TAG, "Failed to write file " + mTraceFile, e);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
- }
- mLock.notify();
}
}
@@ -161,11 +135,7 @@
static WindowTracing createDefaultAndStartLooper(Context context) {
File file = new File("/data/misc/wmtrace/wm_trace.pb");
- WindowTracing windowTracing = new WindowTracing(file);
- if (!IS_USER){
- new Thread(windowTracing::loop, "window_tracing").start();
- }
- return windowTracing;
+ return new WindowTracing(file);
}
int onShellCommand(ShellCommand shell, String cmd) {
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 0929e20..64120076 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -244,7 +244,7 @@
const sp<IBinder>& token,
const std::string& reason);
virtual void notifyInputChannelBroken(const sp<IBinder>& token);
- virtual void notifyFocusChanged(const sp<IBinder>& token);
+ virtual void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken);
virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags);
virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig);
virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags);
@@ -738,7 +738,8 @@
}
}
-void NativeInputManager::notifyFocusChanged(const sp<IBinder>& token) {
+void NativeInputManager::notifyFocusChanged(const sp<IBinder>& oldToken,
+ const sp<IBinder>& newToken) {
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("notifyFocusChanged");
#endif
@@ -746,12 +747,11 @@
JNIEnv* env = jniEnv();
- jobject tokenObj = javaObjectForIBinder(env, token);
- if (tokenObj) {
- env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyFocusChanged,
- tokenObj);
- checkAndClearExceptionFromCallback(env, "notifyFocusChanged");
- }
+ jobject oldTokenObj = javaObjectForIBinder(env, oldToken);
+ jobject newTokenObj = javaObjectForIBinder(env, newToken);
+ env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyFocusChanged,
+ oldTokenObj, newTokenObj);
+ checkAndClearExceptionFromCallback(env, "notifyFocusChanged");
}
void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
@@ -1500,27 +1500,6 @@
im->setSystemUiVisibility(visibility);
}
-static jboolean nativeTransferTouchFocus(JNIEnv* env,
- jclass /* clazz */, jlong ptr, jobject fromChannelObj, jobject toChannelObj) {
- NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
-
- sp<InputChannel> fromChannel =
- android_view_InputChannel_getInputChannel(env, fromChannelObj);
- sp<InputChannel> toChannel =
- android_view_InputChannel_getInputChannel(env, toChannelObj);
-
- if (fromChannel == nullptr || toChannel == nullptr) {
- return JNI_FALSE;
- }
-
- if (im->getInputManager()->getDispatcher()->
- transferTouchFocus(fromChannel, toChannel)) {
- return JNI_TRUE;
- } else {
- return JNI_FALSE;
- }
-}
-
static void nativeSetPointerSpeed(JNIEnv* /* env */,
jclass /* clazz */, jlong ptr, jint speed) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
@@ -1708,8 +1687,6 @@
(void*) nativeSetInputDispatchMode },
{ "nativeSetSystemUiVisibility", "(JI)V",
(void*) nativeSetSystemUiVisibility },
- { "nativeTransferTouchFocus", "(JLandroid/view/InputChannel;Landroid/view/InputChannel;)Z",
- (void*) nativeTransferTouchFocus },
{ "nativeSetPointerSpeed", "(JI)V",
(void*) nativeSetPointerSpeed },
{ "nativeSetShowTouches", "(JZ)V",
@@ -1785,7 +1762,7 @@
"notifyInputChannelBroken", "(Landroid/os/IBinder;)V");
GET_METHOD_ID(gServiceClassInfo.notifyFocusChanged, clazz,
- "notifyFocusChanged", "(Landroid/os/IBinder;)V");
+ "notifyFocusChanged", "(Landroid/os/IBinder;Landroid/os/IBinder;)V");
GET_METHOD_ID(gServiceClassInfo.notifyANR, clazz,
"notifyANR",
diff --git a/services/core/jni/com_android_server_security_VerityUtils.cpp b/services/core/jni/com_android_server_security_VerityUtils.cpp
index 3c87e42..7dd30bd 100644
--- a/services/core/jni/com_android_server_security_VerityUtils.cpp
+++ b/services/core/jni/com_android_server_security_VerityUtils.cpp
@@ -75,6 +75,23 @@
jbyte* mElements;
};
+int enableFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) {
+#if HAS_FSVERITY
+ const char* path = env->GetStringUTFChars(filePath, nullptr);
+ ::android::base::unique_fd rfd(open(path, O_RDONLY | O_CLOEXEC));
+ if (rfd.get() < 0) {
+ return errno;
+ }
+ if (ioctl(rfd.get(), FS_IOC_ENABLE_VERITY, nullptr) < 0) {
+ return errno;
+ }
+ return 0;
+#else
+ LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
+ return ENOSYS;
+#endif // HAS_FSVERITY
+}
+
int measureFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) {
#if HAS_FSVERITY
auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_digest) + kSha256Bytes);
@@ -82,14 +99,17 @@
data->digest_size = kSha256Bytes; // the only input/output parameter
const char* path = env->GetStringUTFChars(filePath, nullptr);
- ::android::base::unique_fd rfd(open(path, O_RDONLY));
+ ::android::base::unique_fd rfd(open(path, O_RDONLY | O_CLOEXEC));
+ if (rfd.get() < 0) {
+ return errno;
+ }
if (ioctl(rfd.get(), FS_IOC_MEASURE_VERITY, data) < 0) {
return errno;
}
return 0;
#else
LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
- return -1;
+ return ENOSYS;
#endif // HAS_FSVERITY
}
@@ -172,6 +192,7 @@
}
const JNINativeMethod sMethods[] = {
+ { "enableFsverityNative", "(Ljava/lang/String;)I", (void *)enableFsverity },
{ "measureFsverityNative", "(Ljava/lang/String;)I", (void *)measureFsverity },
{ "constructFsveritySignedDataNative", "([B)[B", (void *)constructFsveritySignedData },
{ "constructFsverityDescriptorNative", "(J)[B", (void *)constructFsverityDescriptor },
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f78f6ed..76ae5cc 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5323,6 +5323,7 @@
}
final int callingUserId = mInjector.userHandleGetCallingUserId();
+ ComponentName adminComponent = null;
synchronized (getLockObject()) {
// Make sure the caller has any active admin with the right policy or
// the required permission.
@@ -5333,8 +5334,7 @@
android.Manifest.permission.LOCK_DEVICE);
final long ident = mInjector.binderClearCallingIdentity();
try {
- final ComponentName adminComponent = admin == null ?
- null : admin.info.getComponent();
+ adminComponent = admin == null ? null : admin.info.getComponent();
if (adminComponent != null) {
// For Profile Owners only, callers with only permission not allowed.
if ((flags & DevicePolicyManager.FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY) != 0) {
@@ -5386,6 +5386,7 @@
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.LOCK_NOW)
+ .setAdmin(adminComponent)
.setInt(flags)
.write();
}
@@ -6102,7 +6103,9 @@
synchronized (getLockObject()) {
delegates = getDelegatePackagesInternalLocked(scope, userId);
}
- if (delegates.size() != 1) {
+ if (delegates.size() == 0) {
+ return null;
+ } else if (delegates.size() > 1) {
Slog.wtf(LOG_TAG, "More than one delegate holds " + scope);
return null;
}
diff --git a/services/ipmemorystore/Android.bp b/services/ipmemorystore/Android.bp
new file mode 100644
index 0000000..013cf56
--- /dev/null
+++ b/services/ipmemorystore/Android.bp
@@ -0,0 +1,4 @@
+java_library_static {
+ name: "services.ipmemorystore",
+ srcs: ["java/**/*.java"],
+}
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
new file mode 100644
index 0000000..c9759bf
--- /dev/null
+++ b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
@@ -0,0 +1,151 @@
+/*
+ * 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.ipmemorystore;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.net.IIpMemoryStore;
+import android.net.ipmemorystore.Blob;
+import android.net.ipmemorystore.IOnBlobRetrievedListener;
+import android.net.ipmemorystore.IOnL2KeyResponseListener;
+import android.net.ipmemorystore.IOnNetworkAttributesRetrieved;
+import android.net.ipmemorystore.IOnSameNetworkResponseListener;
+import android.net.ipmemorystore.IOnStatusListener;
+import android.net.ipmemorystore.NetworkAttributesParcelable;
+
+/**
+ * Implementation for the IP memory store.
+ * This component offers specialized services for network components to store and retrieve
+ * knowledge about networks, and provides intelligence that groups level 2 networks together
+ * into level 3 networks.
+ *
+ * @hide
+ */
+public class IpMemoryStoreService extends IIpMemoryStore.Stub {
+ final Context mContext;
+
+ public IpMemoryStoreService(@NonNull final Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Store network attributes for a given L2 key.
+ *
+ * @param l2Key The L2 key for the L2 network. Clients that don't know or care about the L2
+ * key and only care about grouping can pass a unique ID here like the ones
+ * generated by {@code java.util.UUID.randomUUID()}, but keep in mind the low
+ * relevance of such a network will lead to it being evicted soon if it's not
+ * refreshed. Use findL2Key to try and find a similar L2Key to these attributes.
+ * @param attributes The attributes for this network.
+ * @param listener A listener to inform of the completion of this call, or null if the client
+ * is not interested in learning about success/failure.
+ * Through the listener, returns the L2 key. This is useful if the L2 key was not specified.
+ * If the call failed, the L2 key will be null.
+ */
+ @Override
+ public void storeNetworkAttributes(@NonNull final String l2Key,
+ @NonNull final NetworkAttributesParcelable attributes,
+ @Nullable final IOnStatusListener listener) {
+ // TODO : implement this
+ }
+
+ /**
+ * Store a binary blob associated with an L2 key and a name.
+ *
+ * @param l2Key The L2 key for this network.
+ * @param clientId The ID of the client.
+ * @param name The name of this data.
+ * @param data The data to store.
+ * @param listener The listener that will be invoked to return the answer, or null if the
+ * is not interested in learning about success/failure.
+ * Through the listener, returns a status to indicate success or failure.
+ */
+ @Override
+ public void storeBlob(@NonNull final String l2Key, @NonNull final String clientId,
+ @NonNull final String name, @NonNull final Blob data,
+ @Nullable final IOnStatusListener listener) {
+ // TODO : implement this
+ }
+
+ /**
+ * Returns the best L2 key associated with the attributes.
+ *
+ * This will find a record that would be in the same group as the passed attributes. This is
+ * useful to choose the key for storing a sample or private data when the L2 key is not known.
+ * If multiple records are group-close to these attributes, the closest match is returned.
+ * If multiple records have the same closeness, the one with the smaller (unicode codepoint
+ * order) L2 key is returned.
+ * If no record matches these attributes, null is returned.
+ *
+ * @param attributes The attributes of the network to find.
+ * @param listener The listener that will be invoked to return the answer.
+ * Through the listener, returns the L2 key if one matched, or null.
+ */
+ @Override
+ public void findL2Key(@NonNull final NetworkAttributesParcelable attributes,
+ @NonNull final IOnL2KeyResponseListener listener) {
+ // TODO : implement this
+ }
+
+ /**
+ * Returns whether, to the best of the store's ability to tell, the two specified L2 keys point
+ * to the same L3 network. Group-closeness is used to determine this.
+ *
+ * @param l2Key1 The key for the first network.
+ * @param l2Key2 The key for the second network.
+ * @param listener The listener that will be invoked to return the answer.
+ * Through the listener, a SameL3NetworkResponse containing the answer and confidence.
+ */
+ @Override
+ public void isSameNetwork(@NonNull final String l2Key1, @NonNull final String l2Key2,
+ @NonNull final IOnSameNetworkResponseListener listener) {
+ // TODO : implement this
+ }
+
+ /**
+ * Retrieve the network attributes for a key.
+ * If no record is present for this key, this will return null attributes.
+ *
+ * @param l2Key The key of the network to query.
+ * @param listener The listener that will be invoked to return the answer.
+ * Through the listener, returns the network attributes and the L2 key associated with
+ * the query.
+ */
+ @Override
+ public void retrieveNetworkAttributes(@NonNull final String l2Key,
+ @NonNull final IOnNetworkAttributesRetrieved listener) {
+ // TODO : implement this.
+ }
+
+ /**
+ * Retrieve previously stored private data.
+ * If no data was stored for this L2 key and name this will return null.
+ *
+ * @param l2Key The L2 key.
+ * @param clientId The id of the client that stored this data.
+ * @param name The name of the data.
+ * @param listener The listener that will be invoked to return the answer.
+ * Through the listener, returns the private data if any or null if none, with the L2 key
+ * and the name of the data associated with the query.
+ */
+ @Override
+ public void retrieveBlob(@NonNull final String l2Key, @NonNull final String clientId,
+ @NonNull final String name, @NonNull final IOnBlobRetrievedListener listener) {
+ // TODO : implement this.
+ }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 8084c2b..fef2db9 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -102,10 +102,12 @@
import com.android.server.media.projection.MediaProjectionManagerService;
import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.net.NetworkStatsService;
+import com.android.server.net.ipmemorystore.IpMemoryStoreService;
import com.android.server.net.watchlist.NetworkWatchlistService;
import com.android.server.notification.NotificationManagerService;
import com.android.server.oemlock.OemLockService;
import com.android.server.om.OverlayManagerService;
+import com.android.server.os.BugreportManagerService;
import com.android.server.os.DeviceIdentifiersPolicyService;
import com.android.server.os.SchedulingPolicyService;
import com.android.server.pm.BackgroundDexOptService;
@@ -118,6 +120,7 @@
import com.android.server.pm.ShortcutService;
import com.android.server.pm.UserManagerService;
import com.android.server.policy.PhoneWindowManager;
+import com.android.server.policy.role.LegacyRoleResolutionPolicy;
import com.android.server.power.PowerManagerService;
import com.android.server.power.ShutdownThread;
import com.android.server.power.ThermalManagerService;
@@ -260,6 +263,10 @@
"com.android.server.accessibility.AccessibilityManagerService$Lifecycle";
private static final String ADB_SERVICE_CLASS =
"com.android.server.adb.AdbService$Lifecycle";
+ private static final String APP_PREDICTION_MANAGER_SERVICE_CLASS =
+ "com.android.server.appprediction.AppPredictionManagerService";
+ private static final String CONTENT_SUGGESTIONS_SERVICE_CLASS =
+ "com.android.server.contentsuggestions.ContentSuggestionsManagerService";
private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
@@ -786,6 +793,11 @@
traceBeginAndSlog("StartRollbackManagerService");
mSystemServiceManager.startService(RollbackManagerService.class);
traceEnd();
+
+ // Service to capture bugreports.
+ traceBeginAndSlog("StartBugreportManagerService");
+ mSystemServiceManager.startService(BugreportManagerService.class);
+ traceEnd();
}
/**
@@ -1165,6 +1177,16 @@
startContentCaptureService(context);
+ // App prediction manager service
+ traceBeginAndSlog("StartAppPredictionService");
+ mSystemServiceManager.startService(APP_PREDICTION_MANAGER_SERVICE_CLASS);
+ traceEnd();
+
+ // Content suggestions manager service
+ traceBeginAndSlog("StartContentSuggestionsService");
+ mSystemServiceManager.startService(CONTENT_SUGGESTIONS_SERVICE_CLASS);
+ traceEnd();
+
// NOTE: ClipboardService indirectly depends on IntelligenceService
traceBeginAndSlog("StartClipboardService");
mSystemServiceManager.startService(ClipboardService.class);
@@ -1179,6 +1201,15 @@
}
traceEnd();
+ traceBeginAndSlog("StartIpMemoryStoreService");
+ try {
+ ServiceManager.addService(Context.IP_MEMORY_STORE_SERVICE,
+ new IpMemoryStoreService(context));
+ } catch (Throwable e) {
+ reportWtf("starting IP Memory Store Service", e);
+ }
+ traceEnd();
+
traceBeginAndSlog("StartIpSecService");
try {
ipSecService = IpSecService.create(context);
@@ -1961,7 +1992,8 @@
// Grants default permissions and defines roles
traceBeginAndSlog("StartRoleManagerService");
- mSystemServiceManager.startService(RoleManagerService.class);
+ mSystemServiceManager.startService(new RoleManagerService(
+ mSystemContext, new LegacyRoleResolutionPolicy(mSystemContext)));
traceEnd();
// No dependency on Webview preparation in system server. But this should
@@ -2202,7 +2234,7 @@
windowManager.onSystemUiStarted();
}
- private static void traceBeginAndSlog(String name) {
+ private static void traceBeginAndSlog(@NonNull String name) {
Slog.i(TAG, name);
BOOT_TIMINGS_TRACE_LOG.traceBegin(name);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index 148faad..6a153d5 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -60,6 +60,7 @@
import android.os.Looper;
import android.os.PowerManager;
import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
import android.util.Log;
import android.util.SparseArray;
@@ -81,6 +82,7 @@
import java.util.ArrayList;
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class AlarmManagerServiceTest {
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index 6a10ff4..2cc338c 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -70,7 +70,7 @@
import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;
-import com.android.server.AppOpsService;
+import com.android.server.appop.AppOpsService;
import com.android.server.am.ProcessList.IsolatedUidRange;
import com.android.server.am.ProcessList.IsolatedUidRangeAllocator;
import com.android.server.wm.ActivityTaskManagerService;
diff --git a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
index 05cb48b..8109b1c 100644
--- a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
@@ -25,7 +25,7 @@
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
-import com.android.server.AppOpsService;
+import com.android.server.appop.AppOpsService;
import org.junit.Before;
import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java b/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
index 9626990..cbdc6c3 100644
--- a/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
@@ -34,7 +34,7 @@
import androidx.test.filters.SmallTest;
import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.AppOpsService;
+import com.android.server.appop.AppOpsService;
import org.junit.AfterClass;
import org.junit.Before;
diff --git a/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsActiveWatcherTest.java
similarity index 99%
rename from services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java
rename to services/tests/servicestests/src/com/android/server/appop/AppOpsActiveWatcherTest.java
index 7e0dfcf..65c5781 100644
--- a/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsActiveWatcherTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.appops;
+package com.android.server.appop;
import static com.google.common.truth.Truth.assertThat;
diff --git a/services/tests/servicestests/src/com/android/server/appops/AppOpsNotedWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/appops/AppOpsNotedWatcherTest.java
rename to services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
diff --git a/services/tests/servicestests/src/com/android/server/appops/AppOpsServiceTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java
similarity index 98%
rename from services/tests/servicestests/src/com/android/server/appops/AppOpsServiceTest.java
rename to services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java
index 4ae9bea..36f84d0 100644
--- a/services/tests/servicestests/src/com/android/server/appops/AppOpsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.appop;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_ERRORED;
@@ -36,6 +36,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.appop.AppOpsService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/AppOpsUpgradeTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
similarity index 99%
rename from services/tests/servicestests/src/com/android/server/AppOpsUpgradeTest.java
rename to services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
index aac96a1..eb0c627 100644
--- a/services/tests/servicestests/src/com/android/server/AppOpsUpgradeTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.appop;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
new file mode 100644
index 0000000..8b0e8ab
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
@@ -0,0 +1,163 @@
+/*
+ * 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.hdmi;
+
+import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.annotation.Nullable;
+import android.app.Instrumentation;
+import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
+import android.os.Looper;
+import android.os.test.TestLooper;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+
+/** Tests for {@link ArcInitiationActionFromAvrTest} */
+@SmallTest
+@RunWith(JUnit4.class)
+public class ArcInitiationActionFromAvrTest {
+
+ private HdmiDeviceInfo mDeviceInfoForTests;
+ private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem;
+ private HdmiCecController mHdmiCecController;
+ private HdmiControlService mHdmiControlService;
+ private FakeNativeWrapper mNativeWrapper;
+ private ArcInitiationActionFromAvr mAction;
+
+ private TestLooper mTestLooper = new TestLooper();
+ private boolean mSendCecCommandSuccess;
+ private boolean mShouldDispatchARCInitiated;
+ private boolean mArcInitSent;
+ private boolean mRequestActiveSourceSent;
+ private Instrumentation mInstrumentation;
+ private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
+
+ @Before
+ public void setUp() {
+ mDeviceInfoForTests = new HdmiDeviceInfo(1000, 1);
+
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+
+ mHdmiControlService =
+ new HdmiControlService(mInstrumentation.getTargetContext()) {
+ @Override
+ void sendCecCommand(
+ HdmiCecMessage command, @Nullable SendMessageCallback callback) {
+ switch (command.getOpcode()) {
+ case Constants.MESSAGE_REQUEST_ACTIVE_SOURCE:
+ if (callback != null) {
+ callback.onSendCompleted(
+ mSendCecCommandSuccess
+ ? SendMessageResult.SUCCESS
+ : SendMessageResult.NACK);
+ }
+ mRequestActiveSourceSent = true;
+ break;
+ case Constants.MESSAGE_INITIATE_ARC:
+ if (callback != null) {
+ callback.onSendCompleted(
+ mSendCecCommandSuccess
+ ? SendMessageResult.SUCCESS
+ : SendMessageResult.NACK);
+ }
+ mArcInitSent = true;
+ if (mShouldDispatchARCInitiated) {
+ mHdmiCecLocalDeviceAudioSystem.dispatchMessage(
+ HdmiCecMessageBuilder.buildReportArcInitiated(
+ Constants.ADDR_TV,
+ Constants.ADDR_AUDIO_SYSTEM));
+ }
+ break;
+ default:
+ }
+ }
+
+ @Override
+ boolean isPowerStandby() {
+ return false;
+ }
+
+ @Override
+ boolean isAddressAllocated() {
+ return true;
+ }
+
+ @Override
+ Looper getServiceLooper() {
+ return mTestLooper.getLooper();
+ }
+ };
+
+ mHdmiCecLocalDeviceAudioSystem =
+ new HdmiCecLocalDeviceAudioSystem(mHdmiControlService) {
+ @Override
+ HdmiDeviceInfo getDeviceInfo() {
+ return mDeviceInfoForTests;
+ }
+
+ @Override
+ void setArcStatus(boolean enabled) {
+ // do nothing
+ }
+
+ @Override
+ protected boolean isSystemAudioActivated() {
+ return true;
+ }
+ };
+
+ mHdmiCecLocalDeviceAudioSystem.init();
+ Looper looper = mTestLooper.getLooper();
+ mHdmiControlService.setIoLooper(looper);
+ mNativeWrapper = new FakeNativeWrapper();
+ mHdmiCecController =
+ HdmiCecController.createWithNativeWrapper(this.mHdmiControlService, mNativeWrapper);
+ mHdmiControlService.setCecController(mHdmiCecController);
+ mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
+ mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
+ mHdmiControlService.initPortInfo();
+ mAction = new ArcInitiationActionFromAvr(mHdmiCecLocalDeviceAudioSystem);
+
+ mLocalDevices.add(mHdmiCecLocalDeviceAudioSystem);
+ mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ mTestLooper.dispatchAll();
+ }
+
+ @Test
+ public void arcInitiation_requestActiveSource() {
+ mSendCecCommandSuccess = true;
+ mShouldDispatchARCInitiated = true;
+ mRequestActiveSourceSent = false;
+ mArcInitSent = false;
+
+ mHdmiCecLocalDeviceAudioSystem.addAndStartAction(mAction);
+ mTestLooper.dispatchAll();
+
+ assertThat(mArcInitSent).isTrue();
+ assertThat(mRequestActiveSourceSent).isTrue();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
index da840be..93a09dc 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
@@ -18,6 +18,7 @@
import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM;
import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_PLAYBACK;
import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_TV;
+
import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_2;
@@ -25,16 +26,21 @@
import static com.android.server.hdmi.Constants.ADDR_SPECIFIC_USE;
import static com.android.server.hdmi.Constants.ADDR_TV;
import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED;
+
import static junit.framework.Assert.assertEquals;
import android.content.Context;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.os.Looper;
import android.os.test.TestLooper;
+
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+
import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback;
+
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -136,6 +142,7 @@
assertEquals(ADDR_UNREGISTERED, mLogicalAddress);
}
+ @Ignore("b/110413065 Support multiple device types 4 and 5.")
@Test
public void testAllocatLogicalAddress_PlaybackPreferredNotOccupied() {
mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_PLAYBACK_1, mCallback);
@@ -151,6 +158,7 @@
assertEquals(ADDR_PLAYBACK_2, mLogicalAddress);
}
+ @Ignore("b/110413065 Support multiple device types 4 and 5.")
@Test
public void testAllocatLogicalAddress_PlaybackNoPreferredNotOcuppied() {
mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index 7049b21..b47f269 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -17,6 +17,7 @@
import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
import static com.android.server.hdmi.Constants.ADDR_TUNER_1;
import static com.android.server.hdmi.Constants.ADDR_TV;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
@@ -35,6 +36,7 @@
import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -53,6 +55,7 @@
private HdmiControlService mHdmiControlService;
private HdmiCecController mHdmiCecController;
private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem;
+ private HdmiCecLocalDevicePlayback mHdmiCecLocalDevicePlayback;
private FakeNativeWrapper mNativeWrapper;
private Looper mMyLooper;
private TestLooper mTestLooper = new TestLooper();
@@ -124,16 +127,18 @@
@Override
void wakeUp() {}
-
- @Override
- boolean isControlEnabled() {
- return true;
- }
};
mMyLooper = mTestLooper.getLooper();
mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(mHdmiControlService);
+ mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService) {
+ @Override
+ void setIsActiveSource(boolean on) {
+ mIsActiveSource = on;
+ }
+ };
mHdmiCecLocalDeviceAudioSystem.init();
+ mHdmiCecLocalDevicePlayback.init();
mHdmiControlService.setIoLooper(mMyLooper);
mNativeWrapper = new FakeNativeWrapper();
mHdmiCecController =
@@ -142,6 +147,7 @@
mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
mLocalDevices.add(mHdmiCecLocalDeviceAudioSystem);
+ mLocalDevices.add(mHdmiCecLocalDevicePlayback);
mHdmiControlService.initPortInfo();
// No TV device interacts with AVR so system audio control won't be turned on here
mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
@@ -292,8 +298,6 @@
@Test
public void onStandbyAudioSystem_currentSystemAudioControlOn() throws Exception {
- mHdmiCecLocalDeviceAudioSystem.setAutoDeviceOff(false);
- mHdmiCecLocalDeviceAudioSystem.setAutoTvOff(false);
// Set system audio control on first
mHdmiCecLocalDeviceAudioSystem.checkSupportAndSetSystemAudioMode(true);
// Check if standby correctly turns off the feature
@@ -513,17 +517,6 @@
assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
}
- @Test
- public void onStandby_setAutoDeviceOff_true() throws Exception {
- HdmiCecMessage expectedMessage =
- HdmiCecMessageBuilder.buildStandby(ADDR_AUDIO_SYSTEM, ADDR_BROADCAST);
- mHdmiCecLocalDeviceAudioSystem.setAutoDeviceOff(true);
- mHdmiCecLocalDeviceAudioSystem.onStandby(false, STANDBY_SCREEN_OFF);
-
- mTestLooper.dispatchAll();
- assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
- }
-
public void handleSystemAudioModeRequest_fromNonTV_tVNotSupport() {
HdmiCecMessage message =
HdmiCecMessageBuilder.buildSystemAudioModeRequest(
@@ -557,4 +550,65 @@
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
}
+
+ @Test
+ public void handleActiveSource_activeSourceFromTV_swithToArc() {
+ mHdmiCecLocalDeviceAudioSystem.setArcStatus(true);
+ HdmiCecMessage message =
+ HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
+
+ ActiveSource expectedActiveSource = ActiveSource.of(ADDR_TV, 0x0000);
+
+ assertThat(mHdmiCecLocalDeviceAudioSystem.handleActiveSource(message)).isTrue();
+ mTestLooper.dispatchAll();
+ assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource())
+ .isEqualTo(expectedActiveSource);
+ }
+
+ @Ignore("b/110413065 Support multiple device types 4 and 5.")
+ @Test
+ public void handleRoutingChange_currentActivePortIsHome() {
+ HdmiCecMessage message =
+ HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x3000, mAvrPhysicalAddress);
+
+ HdmiCecMessage expectedMessage =
+ HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, mAvrPhysicalAddress);
+ ActiveSource expectedActiveSource = ActiveSource.of(ADDR_PLAYBACK_1, mAvrPhysicalAddress);
+ int expectedLocalActivePort = Constants.CEC_SWITCH_HOME;
+
+ assertThat(mHdmiCecLocalDeviceAudioSystem.handleRoutingChange(message)).isTrue();
+ mTestLooper.dispatchAll();
+ assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource())
+ .isEqualTo(expectedActiveSource);
+ assertThat(mHdmiCecLocalDeviceAudioSystem.getRoutingPort())
+ .isEqualTo(expectedLocalActivePort);
+ assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
+ }
+
+ @Test
+ public void handleRoutingInformation_currentActivePortIsHDMI1() {
+ HdmiCecMessage message =
+ HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, 0x2000);
+ mHdmiCecLocalDeviceAudioSystem.setRoutingPort(Constants.CEC_SWITCH_HDMI1);
+ HdmiCecMessage expectedMessage =
+ HdmiCecMessageBuilder.buildRoutingInformation(ADDR_AUDIO_SYSTEM, 0x2100);
+
+ assertThat(mHdmiCecLocalDeviceAudioSystem.handleRoutingInformation(message)).isTrue();
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
+ }
+
+ @Ignore("b/110413065 Support multiple device types 4 and 5.")
+ @Test
+ public void handleRoutingChange_homeIsActive_playbackSendActiveSource() {
+ HdmiCecMessage message =
+ HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000, 0x2000);
+
+ HdmiCecMessage expectedMessage =
+ HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, 0x2000);
+
+ assertThat(mHdmiCecLocalDeviceAudioSystem.handleRoutingChange(message)).isTrue();
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 76f638c..792c617 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -27,6 +27,7 @@
import androidx.test.filters.SmallTest;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -80,12 +81,14 @@
mNativeWrapper.setPhysicalAddress(mPlaybackPhysicalAddress);
}
+ @Ignore
@Test
public void handleSetStreamPath_underCurrentDevice() {
assertThat(mHdmiCecLocalDevicePlayback.getLocalActivePath()).isEqualTo(0);
HdmiCecMessage message =
HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x2100);
assertThat(mHdmiCecLocalDevicePlayback.handleSetStreamPath(message)).isTrue();
+ // TODO(amyjojo): Move set and get LocalActivePath to Control Service.
assertThat(mHdmiCecLocalDevicePlayback.getLocalActivePath()).isEqualTo(1);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
index d914b9a..bd297ee 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
@@ -26,8 +26,10 @@
import android.media.AudioManager;
import android.os.Looper;
import android.os.test.TestLooper;
+
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -49,6 +51,9 @@
private int mMsgRequestActiveSourceCount;
private int mMsgSetSystemAudioModeCount;
private int mQueryTvSystemAudioModeSupportCount;
+ private boolean mArcEnabled;
+ private boolean mIsPlaybackDevice;
+ private boolean mBroadcastActiveSource;
@Before
public void SetUp() {
@@ -80,6 +85,8 @@
callback.onSendCompleted(SendMessageResult.NACK);
}
break;
+ case Constants.MESSAGE_INITIATE_ARC:
+ break;
default:
throw new IllegalArgumentException("Unexpected message");
}
@@ -132,6 +139,17 @@
int getPhysicalAddress() {
return 0;
}
+
+ @Override
+ boolean isPlaybackDevice() {
+ return mIsPlaybackDevice;
+ }
+
+ @Override
+ public void setAndBroadcastActiveSourceFromOneDeviceType(
+ int sourceAddress, int physicalAddress) {
+ mBroadcastActiveSource = true;
+ }
};
mHdmiCecLocalDeviceAudioSystem =
new HdmiCecLocalDeviceAudioSystem(hdmiControlService) {
@@ -148,6 +166,11 @@
HdmiDeviceInfo getDeviceInfo() {
return mDeviceInfoForTests;
}
+
+ @Override
+ void setArcStatus(boolean enabled) {
+ mArcEnabled = enabled;
+ }
};
mHdmiCecLocalDeviceAudioSystem.init();
Looper looper = mTestLooper.getLooper();
@@ -159,7 +182,7 @@
resetTestVariables();
mShouldDispatchActiveSource = false;
- assertThat(mHdmiCecLocalDeviceAudioSystem.mActiveSource.physicalAddress)
+ assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource().physicalAddress)
.isEqualTo(Constants.INVALID_PHYSICAL_ADDRESS);
mHdmiCecLocalDeviceAudioSystem.addAndStartAction(
@@ -171,7 +194,7 @@
assertThat(mQueryTvSystemAudioModeSupportCount).isEqualTo(0);
assertFalse(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated());
- assertThat(mHdmiCecLocalDeviceAudioSystem.mActiveSource.physicalAddress)
+ assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource().physicalAddress)
.isEqualTo(Constants.INVALID_PHYSICAL_ADDRESS);
}
@@ -206,14 +229,15 @@
assertThat(mQueryTvSystemAudioModeSupportCount).isEqualTo(1);
assertTrue(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated());
- assertThat(mHdmiCecLocalDeviceAudioSystem.mActiveSource.physicalAddress).isEqualTo(1002);
+ assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource().physicalAddress)
+ .isEqualTo(1002);
}
@Test
public void testKnownActiveSource() {
resetTestVariables();
mTvSystemAudioModeSupport = true;
- mHdmiCecLocalDeviceAudioSystem.mActiveSource.physicalAddress = 1001;
+ mHdmiCecLocalDeviceAudioSystem.getActiveSource().physicalAddress = 1001;
mHdmiCecLocalDeviceAudioSystem.addAndStartAction(
new SystemAudioInitiationActionFromAvr(mHdmiCecLocalDeviceAudioSystem));
@@ -233,7 +257,7 @@
mTryCountBeforeSucceed = 3;
assertThat(mTryCountBeforeSucceed)
.isAtMost(SystemAudioInitiationActionFromAvr.MAX_RETRY_COUNT);
- assertThat(mHdmiCecLocalDeviceAudioSystem.mActiveSource.physicalAddress)
+ assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource().physicalAddress)
.isEqualTo(Constants.INVALID_PHYSICAL_ADDRESS);
mHdmiCecLocalDeviceAudioSystem.addAndStartAction(
@@ -246,12 +270,32 @@
assertTrue(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated());
}
+ @Test
+ public void testIsPlaybackDevice_cannotReceiveActiveSource() {
+ resetTestVariables();
+ mIsPlaybackDevice = true;
+ assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource().physicalAddress)
+ .isEqualTo(Constants.INVALID_PHYSICAL_ADDRESS);
+
+ mHdmiCecLocalDeviceAudioSystem.addAndStartAction(
+ new SystemAudioInitiationActionFromAvr(mHdmiCecLocalDeviceAudioSystem));
+ mTestLooper.dispatchAll();
+
+ assertThat(mMsgRequestActiveSourceCount).isEqualTo(1);
+ assertThat(mMsgSetSystemAudioModeCount).isEqualTo(1);
+ assertThat(mQueryTvSystemAudioModeSupportCount).isEqualTo(1);
+ assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isTrue();
+ assertThat(mBroadcastActiveSource).isTrue();
+ }
+
private void resetTestVariables() {
mMsgRequestActiveSourceCount = 0;
mMsgSetSystemAudioModeCount = 0;
mQueryTvSystemAudioModeSupportCount = 0;
mTryCountBeforeSucceed = 0;
- mHdmiCecLocalDeviceAudioSystem.mActiveSource.physicalAddress =
+ mIsPlaybackDevice = false;
+ mBroadcastActiveSource = false;
+ mHdmiCecLocalDeviceAudioSystem.getActiveSource().physicalAddress =
Constants.INVALID_PHYSICAL_ADDRESS;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 561c61f..0dff03f 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -47,6 +47,7 @@
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.power.PowerManagerService.Injector;
import com.android.server.power.PowerManagerService.NativeWrapper;
+import com.android.server.power.batterysaver.BatterySaverPolicy;
import com.android.server.power.batterysaver.BatterySavingStats;
import org.junit.Rule;
diff --git a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
similarity index 94%
rename from services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
rename to services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
index acf511e..73eefcf 100644
--- a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.server.power;
+package com.android.server.power.batterysaver;
import static com.google.common.truth.Truth.assertThat;
@@ -31,13 +31,12 @@
import com.android.frameworks.servicestests.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
-import com.android.server.power.batterysaver.BatterySavingStats;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/**
- * Tests for {@link com.android.server.power.BatterySaverPolicy}
+ * Tests for {@link com.android.server.power.batterysaver.BatterySaverPolicy}
*/
public class BatterySaverPolicyTest extends AndroidTestCase {
private static final boolean BATTERY_SAVER_ON = true;
@@ -62,7 +61,7 @@
private static final String BATTERY_SAVER_INCORRECT_CONSTANTS = "vi*,!=,,true";
private class BatterySaverPolicyForTest extends BatterySaverPolicy {
- public BatterySaverPolicyForTest(Object lock, Context context,
+ BatterySaverPolicyForTest(Object lock, Context context,
BatterySavingStats batterySavingStats) {
super(lock, context, batterySavingStats);
}
@@ -269,15 +268,15 @@
mBatterySaverPolicy.onChange();
assertThat(mBatterySaverPolicy.getFileValues(true).toString()).isEqualTo("{}");
assertThat(mBatterySaverPolicy.getFileValues(false).toString())
- .isEqualTo("{/sys/devices/system/cpu/cpu1/cpufreq/scaling_max_freq=123, " +
- "/sys/devices/system/cpu/cpu2/cpufreq/scaling_max_freq=456}");
+ .isEqualTo("{/sys/devices/system/cpu/cpu1/cpufreq/scaling_max_freq=123, "
+ + "/sys/devices/system/cpu/cpu2/cpufreq/scaling_max_freq=456}");
mDeviceSpecificConfigResId = R.string.config_batterySaverDeviceSpecificConfig_3;
mBatterySaverPolicy.onChange();
assertThat(mBatterySaverPolicy.getFileValues(true).toString())
- .isEqualTo("{/sys/devices/system/cpu/cpu3/cpufreq/scaling_max_freq=333, " +
- "/sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq=444}");
+ .isEqualTo("{/sys/devices/system/cpu/cpu3/cpufreq/scaling_max_freq=333, "
+ + "/sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq=444}");
assertThat(mBatterySaverPolicy.getFileValues(false).toString())
.isEqualTo("{/sys/devices/system/cpu/cpu2/cpufreq/scaling_max_freq=222}");
@@ -287,9 +286,9 @@
mBatterySaverPolicy.onChange();
assertThat(mBatterySaverPolicy.getFileValues(true).toString())
- .isEqualTo("{/sys/devices/system/cpu/cpu3/cpufreq/scaling_max_freq=1234567890, " +
- "/sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq=14, " +
- "/sys/devices/system/cpu/cpu5/cpufreq/scaling_max_freq=15}");
+ .isEqualTo("{/sys/devices/system/cpu/cpu3/cpufreq/scaling_max_freq=1234567890, "
+ + "/sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq=14, "
+ + "/sys/devices/system/cpu/cpu5/cpufreq/scaling_max_freq=15}");
assertThat(mBatterySaverPolicy.getFileValues(false).toString()).isEqualTo("{}");
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index b6f1817..8f9d2ba 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -20,6 +20,9 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT;
@@ -38,6 +41,7 @@
import android.app.ActivityOptions;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.PauseActivityItem;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.util.MutableBoolean;
@@ -210,4 +214,41 @@
assertNull(mActivity.pendingOptions);
assertNotNull(activity2.pendingOptions);
}
+
+ @Test
+ public void testNewOverrideConfigurationIncrementsSeq() {
+ final Configuration newConfig = new Configuration();
+
+ final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
+ mActivity.onRequestedOverrideConfigurationChanged(newConfig);
+ assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
+ }
+
+ @Test
+ public void testNewParentConfigurationIncrementsSeq() {
+ final Configuration newConfig = new Configuration(
+ mTask.getRequestedOverrideConfiguration());
+ newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
+ ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
+
+ final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
+ mTask.onRequestedOverrideConfigurationChanged(newConfig);
+ assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
+ }
+
+ @Test
+ public void testNotifiesSeqIncrementToAppToken() {
+ final Configuration appWindowTokenRequestedOrientation = mock(Configuration.class);
+ mActivity.mAppWindowToken = mock(AppWindowToken.class);
+ doReturn(appWindowTokenRequestedOrientation).when(mActivity.mAppWindowToken)
+ .getRequestedOverrideConfiguration();
+
+ final Configuration newConfig = new Configuration();
+ newConfig.orientation = Configuration.ORIENTATION_PORTRAIT;
+
+ final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
+ mActivity.onRequestedOverrideConfigurationChanged(newConfig);
+ assertEquals(prevSeq + 1, appWindowTokenRequestedOrientation.seq);
+ verify(mActivity.mAppWindowToken).onMergedOverrideConfigurationChanged();
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index bd29d2a..5589ca1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -66,7 +66,7 @@
import android.view.DisplayInfo;
import com.android.internal.app.IVoiceInteractor;
-import com.android.server.AppOpsService;
+import com.android.server.appop.AppOpsService;
import com.android.server.AttributeCache;
import com.android.server.ServiceThread;
import com.android.server.am.ActivityManagerService;
@@ -264,6 +264,8 @@
.setOrientation(anyInt(), any(), any());
doCallRealMethod().when(activity.mAppWindowToken).setOrientation(anyInt());
doNothing().when(activity).removeWindowContainer();
+ doReturn(mock(Configuration.class)).when(activity.mAppWindowToken)
+ .getRequestedOverrideConfiguration();
if (mTaskRecord != null) {
mTaskRecord.addActivityToTop(activity);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index f1c6eab..bb3ab35 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -20,11 +20,9 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -125,7 +123,6 @@
mDisplayContent = spy(mDisplayContent);
mWindow = createDropTargetWindow("Drag test window", 0);
doReturn(mWindow).when(mDisplayContent).getTouchableWinAtPointLocked(0, 0);
- when(mWm.mInputManager.transferTouchFocus(any(), any())).thenReturn(true);
synchronized (mWm.mGlobalLock) {
mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
@@ -176,7 +173,6 @@
.setFormat(PixelFormat.TRANSLUCENT)
.build();
- assertTrue(mWm.mInputManager.transferTouchFocus(null, null));
mToken = mTarget.performDrag(
new SurfaceSession(), 0, 0, mWindow.mClient, flag, surface, 0, 0, 0, 0, 0,
data);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
index c343fe7..8c6ac23 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -18,7 +18,6 @@
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
@@ -58,10 +57,6 @@
assertNotNull(mWm.mTaskPositioningController);
mTarget = mWm.mTaskPositioningController;
- when(mWm.mInputManager.transferTouchFocus(
- any(InputChannel.class),
- any(InputChannel.class))).thenReturn(true);
-
mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
mWindow.mInputChannel = new InputChannel();
synchronized (mWm.mGlobalLock) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java
new file mode 100644
index 0000000..8d83497
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER;
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_H;
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_L;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.platform.test.annotations.Presubmit;
+import android.util.proto.ProtoOutputStream;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+
+
+/**
+ * Test class for {@link WindowTraceBuffer} and {@link WindowTraceQueueBuffer}.
+ *
+ * Build/Install/Run:
+ * atest WmTests:WindowTraceBufferTest
+ */
+@SmallTest
+@Presubmit
+public class WindowTraceBufferTest {
+ private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
+
+ private File mFile;
+
+ @Before
+ public void setUp() throws Exception {
+ final Context testContext = getInstrumentation().getContext();
+ mFile = testContext.getFileStreamPath("tracing_test.dat");
+ mFile.delete();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mFile.delete();
+ }
+
+ @Test
+ public void testTraceQueueBuffer_addItem() throws Exception {
+ ProtoOutputStream toWrite1 = getDummy(1);
+ ProtoOutputStream toWrite2 = getDummy(2);
+ ProtoOutputStream toWrite3 = getDummy(3);
+ byte[] toWrite1Bytes = toWrite1.getBytes();
+ byte[] toWrite2Bytes = toWrite2.getBytes();
+ byte[] toWrite3Bytes = toWrite3.getBytes();
+
+ final int objectSize = toWrite1.getBytes().length;
+ final int bufferCapacity = objectSize * 2;
+
+ final WindowTraceBuffer buffer = buildQueueBuffer(bufferCapacity);
+
+ buffer.add(toWrite1);
+ assertTrue("First element should be in the list",
+ buffer.mBuffer.stream().anyMatch(p -> Arrays.equals(p, toWrite1Bytes)));
+
+ buffer.add(toWrite2);
+ assertTrue("First element should be in the list",
+ buffer.mBuffer.stream().anyMatch(p -> Arrays.equals(p, toWrite1Bytes)));
+ assertTrue("Second element should be in the list",
+ buffer.mBuffer.stream().anyMatch(p -> Arrays.equals(p, toWrite2Bytes)));
+
+ buffer.add(toWrite3);
+
+ assertTrue("Third element should not be in the list",
+ buffer.mBuffer.stream().noneMatch(p -> Arrays.equals(p, toWrite3Bytes)));
+
+ assertEquals("Buffer should have 2 elements", buffer.mBuffer.size(), 2);
+ assertEquals(String.format("Buffer is full, used space should be %d", bufferCapacity),
+ buffer.mBufferSize, bufferCapacity);
+ assertEquals("Buffer is full, available space should be 0",
+ buffer.getAvailableSpace(), 0);
+ }
+
+ private ProtoOutputStream getDummy(int value) {
+ ProtoOutputStream toWrite = new ProtoOutputStream();
+ toWrite.write(MAGIC_NUMBER, value);
+ toWrite.flush();
+
+ return toWrite;
+ }
+
+ private WindowTraceBuffer buildQueueBuffer(int size) throws IOException {
+ return new WindowTraceQueueBuffer(size, mFile, false);
+ }
+}
diff --git a/telephony/java/android/telephony/DataSpecificRegistrationStates.java b/telephony/java/android/telephony/DataSpecificRegistrationStates.java
index 5d809d0..d6a8065 100644
--- a/telephony/java/android/telephony/DataSpecificRegistrationStates.java
+++ b/telephony/java/android/telephony/DataSpecificRegistrationStates.java
@@ -44,13 +44,19 @@
*/
public final boolean isEnDcAvailable;
+ /**
+ * Provides network support info for LTE VoPS and LTE Emergency bearer support
+ */
+ public final LteVopsSupportInfo lteVopsSupportInfo;
+
DataSpecificRegistrationStates(
int maxDataCalls, boolean isDcNrRestricted, boolean isNrAvailable,
- boolean isEnDcAvailable) {
+ boolean isEnDcAvailable, LteVopsSupportInfo lteVops) {
this.maxDataCalls = maxDataCalls;
this.isDcNrRestricted = isDcNrRestricted;
this.isNrAvailable = isNrAvailable;
this.isEnDcAvailable = isEnDcAvailable;
+ this.lteVopsSupportInfo = lteVops;
}
private DataSpecificRegistrationStates(Parcel source) {
@@ -58,6 +64,7 @@
isDcNrRestricted = source.readBoolean();
isNrAvailable = source.readBoolean();
isEnDcAvailable = source.readBoolean();
+ lteVopsSupportInfo = LteVopsSupportInfo.CREATOR.createFromParcel(source);
}
@Override
@@ -66,6 +73,7 @@
dest.writeBoolean(isDcNrRestricted);
dest.writeBoolean(isNrAvailable);
dest.writeBoolean(isEnDcAvailable);
+ lteVopsSupportInfo.writeToParcel(dest, flags);
}
@Override
@@ -81,13 +89,15 @@
.append(" isDcNrRestricted = " + isDcNrRestricted)
.append(" isNrAvailable = " + isNrAvailable)
.append(" isEnDcAvailable = " + isEnDcAvailable)
+ .append(lteVopsSupportInfo.toString())
.append(" }")
.toString();
}
@Override
public int hashCode() {
- return Objects.hash(maxDataCalls, isDcNrRestricted, isNrAvailable, isEnDcAvailable);
+ return Objects.hash(maxDataCalls, isDcNrRestricted, isNrAvailable, isEnDcAvailable,
+ lteVopsSupportInfo);
}
@Override
@@ -100,7 +110,8 @@
return this.maxDataCalls == other.maxDataCalls
&& this.isDcNrRestricted == other.isDcNrRestricted
&& this.isNrAvailable == other.isNrAvailable
- && this.isEnDcAvailable == other.isEnDcAvailable;
+ && this.isEnDcAvailable == other.isEnDcAvailable
+ && this.lteVopsSupportInfo.equals(other.lteVopsSupportInfo);
}
public static final Parcelable.Creator<DataSpecificRegistrationStates> CREATOR =
@@ -115,4 +126,4 @@
return new DataSpecificRegistrationStates[size];
}
};
-}
\ No newline at end of file
+}
diff --git a/telephony/java/android/telephony/LteVopsSupportInfo.aidl b/telephony/java/android/telephony/LteVopsSupportInfo.aidl
new file mode 100644
index 0000000..5984598
--- /dev/null
+++ b/telephony/java/android/telephony/LteVopsSupportInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 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.telephony;
+
+parcelable LteVopsSupportInfo;
diff --git a/telephony/java/android/telephony/LteVopsSupportInfo.java b/telephony/java/android/telephony/LteVopsSupportInfo.java
new file mode 100644
index 0000000..0ae85c0
--- /dev/null
+++ b/telephony/java/android/telephony/LteVopsSupportInfo.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.telephony;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Class stores information related to LTE network VoPS support
+ * @hide
+ */
+@SystemApi
+public final class LteVopsSupportInfo implements Parcelable {
+
+ /**@hide*/
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ value = {LTE_STATUS_NOT_AVAILABLE, LTE_STATUS_SUPPORTED,
+ LTE_STATUS_NOT_SUPPORTED}, prefix = "LTE_STATUS_")
+ public @interface LteVopsStatus {}
+ /**
+ * Indicates information not available from modem.
+ */
+ public static final int LTE_STATUS_NOT_AVAILABLE = 1;
+
+ /**
+ * Indicates network support the feature.
+ */
+ public static final int LTE_STATUS_SUPPORTED = 2;
+
+ /**
+ * Indicates network does not support the feature.
+ */
+ public static final int LTE_STATUS_NOT_SUPPORTED = 3;
+
+ @LteVopsStatus
+ private final int mVopsSupport;
+ @LteVopsStatus
+ private final int mEmcBearerSupport;
+
+ public LteVopsSupportInfo(@LteVopsStatus int vops, @LteVopsStatus int emergency) {
+ mVopsSupport = vops;
+ mEmcBearerSupport = emergency;
+ }
+
+ /**
+ * Provides the LTE VoPS support capability as described in:
+ * 3GPP 24.301 EPS network feature support -> IMS VoPS
+ */
+ public @LteVopsStatus int getVopsSupport() {
+ return mVopsSupport;
+ }
+
+ /**
+ * Provides the LTE Emergency bearer support capability as described in:
+ * 3GPP 24.301 EPS network feature support -> EMC BS
+ * 25.331 LTE RRC SIB1 : ims-EmergencySupport-r9
+ */
+ public @LteVopsStatus int getEmcBearerSupport() {
+ return mEmcBearerSupport;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mVopsSupport);
+ out.writeInt(mEmcBearerSupport);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || !(o instanceof LteVopsSupportInfo)) {
+ return false;
+ }
+ if (this == o) return true;
+ LteVopsSupportInfo other = (LteVopsSupportInfo) o;
+ return mVopsSupport == other.mVopsSupport
+ && mEmcBearerSupport == other.mEmcBearerSupport;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mVopsSupport, mEmcBearerSupport);
+ }
+
+ /**
+ * @return string representation.
+ */
+ @Override
+ public String toString() {
+ return ("LteVopsSupportInfo : "
+ + " mVopsSupport = " + mVopsSupport
+ + " mEmcBearerSupport = " + mEmcBearerSupport);
+ }
+
+ public static final Creator<LteVopsSupportInfo> CREATOR =
+ new Creator<LteVopsSupportInfo>() {
+ @Override
+ public LteVopsSupportInfo createFromParcel(Parcel in) {
+ return new LteVopsSupportInfo(in);
+ }
+
+ @Override
+ public LteVopsSupportInfo[] newArray(int size) {
+ return new LteVopsSupportInfo[size];
+ }
+ };
+
+ private LteVopsSupportInfo(Parcel in) {
+ mVopsSupport = in.readInt();
+ mEmcBearerSupport = in.readInt();
+ }
+}
diff --git a/telephony/java/android/telephony/NetworkRegistrationState.java b/telephony/java/android/telephony/NetworkRegistrationState.java
index b00665e..ceb76b5 100644
--- a/telephony/java/android/telephony/NetworkRegistrationState.java
+++ b/telephony/java/android/telephony/NetworkRegistrationState.java
@@ -219,12 +219,13 @@
public NetworkRegistrationState(int domain, int transportType, int regState,
int accessNetworkTechnology, int rejectCause, boolean emergencyOnly,
int[] availableServices, @Nullable CellIdentity cellIdentity, int maxDataCalls,
- boolean isDcNrRestricted, boolean isNrAvailable, boolean isEndcAvailable) {
+ boolean isDcNrRestricted, boolean isNrAvailable, boolean isEndcAvailable,
+ LteVopsSupportInfo lteVopsSupportInfo) {
this(domain, transportType, regState, accessNetworkTechnology, rejectCause, emergencyOnly,
availableServices, cellIdentity);
mDataSpecificStates = new DataSpecificRegistrationStates(
- maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable);
+ maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable, lteVopsSupportInfo);
updateNrStatus(mDataSpecificStates);
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 9fc1b6f..bf9bf9a 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -170,7 +170,8 @@
RIL_RADIO_TECHNOLOGY_GSM,
RIL_RADIO_TECHNOLOGY_TD_SCDMA,
RIL_RADIO_TECHNOLOGY_IWLAN,
- RIL_RADIO_TECHNOLOGY_LTE_CA})
+ RIL_RADIO_TECHNOLOGY_LTE_CA,
+ RIL_RADIO_TECHNOLOGY_NR})
public @interface RilRadioTechnology {}
/**
* Available radio technologies for GSM, UMTS and CDMA.
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 4e04ef2..34f7abd 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1172,17 +1172,33 @@
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public List<SubscriptionInfo> getActiveSubscriptionInfoList() {
- List<SubscriptionInfo> result = null;
+ return getActiveSubscriptionInfoList(false);
+ }
+
+ /**
+ * This is similar to {@link #getActiveSubscriptionInfoList()}, but if userVisibleOnly
+ * is true, it will filter out the hidden subscriptions.
+ *
+ * @hide
+ */
+ public List<SubscriptionInfo> getActiveSubscriptionInfoList(boolean userVisibleOnly) {
+ List<SubscriptionInfo> activeList = null;
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
if (iSub != null) {
- result = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName());
+ activeList = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName());
}
} catch (RemoteException ex) {
// ignore it
}
- return result;
+
+ if (!userVisibleOnly || activeList == null) {
+ return activeList;
+ } else {
+ return activeList.stream().filter(subInfo -> !shouldHideSubscription(subInfo))
+ .collect(Collectors.toList());
+ }
}
/**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 6484005..b48a1ce 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -76,8 +76,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telecom.ITelecomService;
import com.android.internal.telephony.CellNetworkScanResult;
-import com.android.internal.telephony.IAns;
import com.android.internal.telephony.INumberVerificationCallback;
+import com.android.internal.telephony.IOns;
import com.android.internal.telephony.IPhoneSubInfo;
import com.android.internal.telephony.ITelephony;
import com.android.internal.telephony.ITelephonyRegistry;
@@ -4651,8 +4651,8 @@
return ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));
}
- private IAns getIAns() {
- return IAns.Stub.asInterface(ServiceManager.getService("ians"));
+ private IOns getIOns() {
+ return IOns.Stub.asInterface(ServiceManager.getService("ions"));
}
//
@@ -9456,10 +9456,10 @@
}
/**
- * Enable or disable AlternativeNetworkService.
+ * Enable or disable OpportunisticNetworkService.
*
* This method should be called to enable or disable
- * AlternativeNetwork service on the device.
+ * OpportunisticNetwork service on the device.
*
* <p>
* Requires Permission:
@@ -9470,25 +9470,25 @@
* @hide
*/
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public boolean setAlternativeNetworkState(boolean enable) {
+ public boolean setOpportunisticNetworkState(boolean enable) {
String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
boolean ret = false;
try {
- IAns iAlternativeNetworkService = getIAns();
- if (iAlternativeNetworkService != null) {
- ret = iAlternativeNetworkService.setEnable(enable, pkgForDebug);
+ IOns iOpportunisticNetworkService = getIOns();
+ if (iOpportunisticNetworkService != null) {
+ ret = iOpportunisticNetworkService.setEnable(enable, pkgForDebug);
}
} catch (RemoteException ex) {
- Rlog.e(TAG, "enableAlternativeNetwork RemoteException", ex);
+ Rlog.e(TAG, "enableOpportunisticNetwork RemoteException", ex);
}
return ret;
}
/**
- * is AlternativeNetworkService enabled
+ * is OpportunisticNetworkService enabled
*
- * This method should be called to determine if the AlternativeNetworkService is
+ * This method should be called to determine if the OpportunisticNetworkService is
* enabled
*
* <p>
@@ -9497,17 +9497,17 @@
* @hide
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public boolean isAlternativeNetworkEnabled() {
+ public boolean isOpportunisticNetworkEnabled() {
String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
boolean isEnabled = false;
try {
- IAns iAlternativeNetworkService = getIAns();
- if (iAlternativeNetworkService != null) {
- isEnabled = iAlternativeNetworkService.isEnabled(pkgForDebug);
+ IOns iOpportunisticNetworkService = getIOns();
+ if (iOpportunisticNetworkService != null) {
+ isEnabled = iOpportunisticNetworkService.isEnabled(pkgForDebug);
}
} catch (RemoteException ex) {
- Rlog.e(TAG, "enableAlternativeNetwork RemoteException", ex);
+ Rlog.e(TAG, "enableOpportunisticNetwork RemoteException", ex);
}
return isEnabled;
@@ -9862,9 +9862,9 @@
public boolean setPreferredOpportunisticDataSubscription(int subId) {
String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
try {
- IAns iAlternativeNetworkService = getIAns();
- if (iAlternativeNetworkService != null) {
- return iAlternativeNetworkService.setPreferredData(subId, pkgForDebug);
+ IOns iOpportunisticNetworkService = getIOns();
+ if (iOpportunisticNetworkService != null) {
+ return iOpportunisticNetworkService.setPreferredData(subId, pkgForDebug);
}
} catch (RemoteException ex) {
Rlog.e(TAG, "setPreferredData RemoteException", ex);
@@ -9886,9 +9886,9 @@
String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
try {
- IAns iAlternativeNetworkService = getIAns();
- if (iAlternativeNetworkService != null) {
- subId = iAlternativeNetworkService.getPreferredData(pkgForDebug);
+ IOns iOpportunisticNetworkService = getIOns();
+ if (iOpportunisticNetworkService != null) {
+ subId = iOpportunisticNetworkService.getPreferredData(pkgForDebug);
}
} catch (RemoteException ex) {
Rlog.e(TAG, "getPreferredData RemoteException", ex);
@@ -9899,8 +9899,8 @@
/**
* Update availability of a list of networks in the current location.
*
- * This api should be called to inform AlternativeNetwork Service about the availability
- * of a network at the current location. This information will be used by AlternativeNetwork
+ * This api should be called to inform OpportunisticNetwork Service about the availability
+ * of a network at the current location. This information will be used by OpportunisticNetwork
* service to decide to attach to the network opportunistically. If an empty list is passed,
* it is assumed that no network is available.
* Requires that the calling app has carrier privileges on both primary and
@@ -9915,9 +9915,9 @@
String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
boolean ret = false;
try {
- IAns iAlternativeNetworkService = getIAns();
- if (iAlternativeNetworkService != null) {
- ret = iAlternativeNetworkService.updateAvailableNetworks(availableNetworks,
+ IOns iOpportunisticNetworkService = getIOns();
+ if (iOpportunisticNetworkService != null) {
+ ret = iOpportunisticNetworkService.updateAvailableNetworks(availableNetworks,
pkgForDebug);
}
} catch (RemoteException ex) {
diff --git a/telephony/java/com/android/internal/telephony/IAns.aidl b/telephony/java/com/android/internal/telephony/IOns.aidl
similarity index 92%
rename from telephony/java/com/android/internal/telephony/IAns.aidl
rename to telephony/java/com/android/internal/telephony/IOns.aidl
index 98bcd41..d6779f1 100755
--- a/telephony/java/com/android/internal/telephony/IAns.aidl
+++ b/telephony/java/com/android/internal/telephony/IOns.aidl
@@ -18,13 +18,13 @@
import android.telephony.AvailableNetworkInfo;
-interface IAns {
+interface IOns {
/**
- * Enable or disable Alternative Network service.
+ * Enable or disable Opportunistic Network service.
*
* This method should be called to enable or disable
- * AlternativeNetwork service on the device.
+ * OpportunisticNetwork service on the device.
*
* <p>
* Requires Permission:
@@ -38,9 +38,9 @@
boolean setEnable(boolean enable, String callingPackage);
/**
- * is Alternative Network service enabled
+ * is Opportunistic Network service enabled
*
- * This method should be called to determine if the Alternative Network service is enabled
+ * This method should be called to determine if the Opportunistic Network service is enabled
*
* <p>
* Requires Permission:
@@ -84,7 +84,7 @@
* Update availability of a list of networks in the current location.
*
* This api should be called if the caller is aware of the availability of a network
- * at the current location. This information will be used by AlternativeNetwork service
+ * at the current location. This information will be used by OpportunisticNetwork service
* to decide to attach to the network. If an empty list is passed,
* it is assumed that no network is available.
* Requires that the calling app has carrier privileges on both primary and
diff --git a/telephony/java/com/android/internal/telephony/SmsApplication.java b/telephony/java/com/android/internal/telephony/SmsApplication.java
index 9874f80..a508b06 100644
--- a/telephony/java/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/java/com/android/internal/telephony/SmsApplication.java
@@ -18,6 +18,8 @@
import android.Manifest.permission;
import android.app.AppOpsManager;
+import android.app.role.RoleManager;
+import android.app.role.RoleManagerCallback;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -29,13 +31,12 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
-import android.content.res.Resources;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Binder;
import android.os.Debug;
import android.os.Process;
import android.os.UserHandle;
-import android.provider.Settings;
import android.provider.Telephony;
import android.provider.Telephony.Sms.Intents;
import android.telephony.Rlog;
@@ -50,6 +51,10 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* Class for managing the primary application that we will deliver SMS/MMS messages to
@@ -67,6 +72,7 @@
private static final String SCHEME_SMSTO = "smsto";
private static final String SCHEME_MMS = "mms";
private static final String SCHEME_MMSTO = "mmsto";
+ private static final boolean DEBUG = false;
private static final boolean DEBUG_MULTIUSER = false;
private static final int[] DEFAULT_APP_EXCLUSIVE_APPOPS = {
@@ -240,7 +246,11 @@
// Get the list of apps registered for SMS
Intent intent = new Intent(Intents.SMS_DELIVER_ACTION);
- List<ResolveInfo> smsReceivers = packageManager.queryBroadcastReceiversAsUser(intent, 0,
+ if (DEBUG) {
+ intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
+ }
+ List<ResolveInfo> smsReceivers = packageManager.queryBroadcastReceiversAsUser(intent,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
userId);
HashMap<String, SmsApplicationData> receivers = new HashMap<String, SmsApplicationData>();
@@ -266,7 +276,8 @@
// Update any existing entries with mms receiver class
intent = new Intent(Intents.WAP_PUSH_DELIVER_ACTION);
intent.setDataAndType(null, "application/vnd.wap.mms-message");
- List<ResolveInfo> mmsReceivers = packageManager.queryBroadcastReceiversAsUser(intent, 0,
+ List<ResolveInfo> mmsReceivers = packageManager.queryBroadcastReceiversAsUser(intent,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
userId);
for (ResolveInfo resolveInfo : mmsReceivers) {
final ActivityInfo activityInfo = resolveInfo.activityInfo;
@@ -286,7 +297,8 @@
// Update any existing entries with respond via message intent class.
intent = new Intent(TelephonyManager.ACTION_RESPOND_VIA_MESSAGE,
Uri.fromParts(SCHEME_SMSTO, "", null));
- List<ResolveInfo> respondServices = packageManager.queryIntentServicesAsUser(intent, 0,
+ List<ResolveInfo> respondServices = packageManager.queryIntentServicesAsUser(intent,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
userId);
for (ResolveInfo resolveInfo : respondServices) {
final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
@@ -306,7 +318,8 @@
// Update any existing entries with supports send to.
intent = new Intent(Intent.ACTION_SENDTO,
Uri.fromParts(SCHEME_SMSTO, "", null));
- List<ResolveInfo> sendToActivities = packageManager.queryIntentActivitiesAsUser(intent, 0,
+ List<ResolveInfo> sendToActivities = packageManager.queryIntentActivitiesAsUser(intent,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
userId);
for (ResolveInfo resolveInfo : sendToActivities) {
final ActivityInfo activityInfo = resolveInfo.activityInfo;
@@ -323,7 +336,9 @@
// Update any existing entries with the default sms changed handler.
intent = new Intent(Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED);
List<ResolveInfo> smsAppChangedReceivers =
- packageManager.queryBroadcastReceiversAsUser(intent, 0, userId);
+ packageManager.queryBroadcastReceiversAsUser(intent,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
if (DEBUG_MULTIUSER) {
Log.i(LOG_TAG, "getApplicationCollectionInternal smsAppChangedActivities=" +
smsAppChangedReceivers);
@@ -348,7 +363,9 @@
// Update any existing entries with the external provider changed handler.
intent = new Intent(Telephony.Sms.Intents.ACTION_EXTERNAL_PROVIDER_CHANGE);
List<ResolveInfo> providerChangedReceivers =
- packageManager.queryBroadcastReceiversAsUser(intent, 0, userId);
+ packageManager.queryBroadcastReceiversAsUser(intent,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
if (DEBUG_MULTIUSER) {
Log.i(LOG_TAG, "getApplicationCollectionInternal providerChangedActivities=" +
providerChangedReceivers);
@@ -373,7 +390,9 @@
// Update any existing entries with the sim full handler.
intent = new Intent(Intents.SIM_FULL_ACTION);
List<ResolveInfo> simFullReceivers =
- packageManager.queryBroadcastReceiversAsUser(intent, 0, userId);
+ packageManager.queryBroadcastReceiversAsUser(intent,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
if (DEBUG_MULTIUSER) {
Log.i(LOG_TAG, "getApplicationCollectionInternal simFullReceivers="
+ simFullReceivers);
@@ -406,7 +425,8 @@
if (smsApplicationData != null) {
if (!smsApplicationData.isComplete()) {
Log.w(LOG_TAG, "Package " + packageName
- + " lacks required manifest declarations to be a default sms app");
+ + " lacks required manifest declarations to be a default sms app: "
+ + smsApplicationData);
receivers.remove(packageName);
}
}
@@ -418,7 +438,7 @@
* Checks to see if we have a valid installed SMS application for the specified package name
* @return Data for the specified package name or null if there isn't one
*/
- private static SmsApplicationData getApplicationForPackage(
+ public static SmsApplicationData getApplicationForPackage(
Collection<SmsApplicationData> applications, String packageName) {
if (packageName == null) {
return null;
@@ -456,8 +476,7 @@
Log.i(LOG_TAG, "getApplication userId=" + userId);
}
// Determine which application receives the broadcast
- String defaultApplication = Settings.Secure.getStringForUser(context.getContentResolver(),
- Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
+ String defaultApplication = getDefaultSmsPackage(context, userId);
if (DEBUG_MULTIUSER) {
Log.i(LOG_TAG, "getApplication defaultApp=" + defaultApplication);
}
@@ -469,27 +488,6 @@
if (DEBUG_MULTIUSER) {
Log.i(LOG_TAG, "getApplication appData=" + applicationData);
}
- // Picking a new SMS app requires AppOps and Settings.Secure permissions, so we only do
- // this if the caller asked us to.
- if (updateIfNeeded && applicationData == null) {
- // Try to find the default SMS package for this device
- Resources r = context.getResources();
- String defaultPackage =
- r.getString(com.android.internal.R.string.default_sms_application);
- applicationData = getApplicationForPackage(applications, defaultPackage);
-
- if (applicationData == null) {
- // Are there any applications?
- if (applications.size() != 0) {
- applicationData = (SmsApplicationData)applications.toArray()[0];
- }
- }
-
- // If we found a new default app, update the setting
- if (applicationData != null) {
- setDefaultApplicationInternal(applicationData.mPackageName, context, userId);
- }
- }
// If we found a package, make sure AppOps permissions are set up correctly
if (applicationData != null) {
@@ -513,7 +511,7 @@
// current SMS app will already be the preferred activity - but checking whether or
// not this is true is just as expensive as reconfiguring the preferred activity so
// we just reconfigure every time.
- updateDefaultSmsApp(context, userId, applicationData);
+ defaultSmsAppChanged(context);
}
}
if (DEBUG_MULTIUSER) {
@@ -522,16 +520,17 @@
return applicationData;
}
- private static void updateDefaultSmsApp(Context context, int userId,
- SmsApplicationData applicationData) {
+ private static String getDefaultSmsPackage(Context context, int userId) {
+ return context.getSystemService(RoleManager.class).getDefaultSmsPackage(userId);
+ }
+
+ /**
+ * Grants various permissions and appops on sms app change
+ */
+ private static void defaultSmsAppChanged(Context context) {
PackageManager packageManager = context.getPackageManager();
AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
- // Configure this as the preferred activity for SENDTO sms/mms intents
- configurePreferredActivity(packageManager, new ComponentName(
- applicationData.mPackageName, applicationData.mSendToClass),
- userId);
-
// Assign permission to special system apps
assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
PHONE_PACKAGE_NAME);
@@ -603,8 +602,7 @@
final UserHandle userHandle = UserHandle.of(userId);
// Get old package name
- String oldPackageName = Settings.Secure.getStringForUser(context.getContentResolver(),
- Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
+ String oldPackageName = getDefaultSmsPackage(context, userId);
if (DEBUG_MULTIUSER) {
Log.i(LOG_TAG, "setDefaultApplicationInternal old=" + oldPackageName +
@@ -636,16 +634,29 @@
}
}
- // Update the secure setting.
- Settings.Secure.putStringForUser(context.getContentResolver(),
- Settings.Secure.SMS_DEFAULT_APPLICATION, applicationData.mPackageName,
- userId);
+ // Update the setting.
+ CompletableFuture<Void> res = new CompletableFuture<>();
+ context.getSystemService(RoleManager.class).addRoleHolderAsUser(
+ RoleManager.ROLE_SMS, applicationData.mPackageName, UserHandle.of(userId),
+ AsyncTask.THREAD_POOL_EXECUTOR, new RoleManagerCallback() {
+ @Override
+ public void onSuccess() {
+ res.complete(null);
+ }
- // Allow relevant appops for the newly configured default SMS app.
- setExclusiveAppops(applicationData.mPackageName, appOps, applicationData.mUid,
- AppOpsManager.MODE_ALLOWED);
+ @Override
+ public void onFailure() {
+ res.completeExceptionally(new RuntimeException());
+ }
+ });
+ try {
+ res.get(5, TimeUnit.SECONDS);
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ Log.e(LOG_TAG, "Exception while adding sms role holder " + applicationData, e);
+ return;
+ }
- updateDefaultSmsApp(context, userId, applicationData);
+ defaultSmsAppChanged(context);
if (DEBUG_MULTIUSER) {
Log.i(LOG_TAG, "setDefaultApplicationInternal oldAppData=" + oldAppData);
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index 37158e5..e1d6e01 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -25,7 +25,8 @@
"android.test.mock",
],
+ srcs_lib: "framework",
+ srcs_lib_whitelist_dirs: ["core/java"],
srcs_lib_whitelist_pkgs: ["android"],
- metalava_enabled: false,
compile_dex: true,
}
diff --git a/tests/PackageWatchdog/Android.mk b/tests/PackageWatchdog/Android.mk
new file mode 100644
index 0000000..b53f27d
--- /dev/null
+++ b/tests/PackageWatchdog/Android.mk
@@ -0,0 +1,34 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+# PackageWatchdogTest
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_PACKAGE_NAME := PackageWatchdogTest
+LOCAL_MODULE_TAGS := tests
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ junit \
+ frameworks-base-testutils \
+ android-support-test \
+ services
+
+LOCAL_JAVA_LIBRARIES := \
+ android.test.runner
+
+LOCAL_PRIVATE_PLATFORM_APIS := true
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
+include $(BUILD_PACKAGE)
diff --git a/tests/PackageWatchdog/AndroidManifest.xml b/tests/PackageWatchdog/AndroidManifest.xml
new file mode 100644
index 0000000..fa89528
--- /dev/null
+++ b/tests/PackageWatchdog/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?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.tests.packagewatchdog" >
+
+ <application android:debuggable="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.tests.packagewatchdog"
+ android:label="PackageWatchdog Test"/>
+</manifest>
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
new file mode 100644
index 0000000..ec07037
--- /dev/null
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static com.android.server.PackageWatchdog.TRIGGER_FAILURE_COUNT;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.os.test.TestLooper;
+import android.support.test.InstrumentationRegistry;
+
+import com.android.server.PackageWatchdog.PackageHealthObserver;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+// TODO(zezeozue): Write test without using PackageWatchdog#getPackages. Just rely on
+// behavior of observers receiving crash notifications or not to determine if it's registered
+/**
+ * Test PackageWatchdog.
+ */
+public class PackageWatchdogTest {
+ private static final String APP_A = "com.package.a";
+ private static final String APP_B = "com.package.b";
+ private static final String OBSERVER_NAME_1 = "observer1";
+ private static final String OBSERVER_NAME_2 = "observer2";
+ private static final String OBSERVER_NAME_3 = "observer3";
+ private static final long SHORT_DURATION = TimeUnit.SECONDS.toMillis(1);
+ private static final long LONG_DURATION = TimeUnit.SECONDS.toMillis(5);
+ private TestLooper mTestLooper;
+
+ @Before
+ public void setUp() throws Exception {
+ mTestLooper = new TestLooper();
+ mTestLooper.startAutoDispatch();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ new File(InstrumentationRegistry.getContext().getFilesDir(),
+ "package-watchdog.xml").delete();
+ }
+
+ /**
+ * Test registration, unregistration, package expiry and duration reduction
+ */
+ @Test
+ public void testRegistration() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver observer1 = new TestObserver(OBSERVER_NAME_1);
+ TestObserver observer2 = new TestObserver(OBSERVER_NAME_2);
+ TestObserver observer3 = new TestObserver(OBSERVER_NAME_3);
+
+ // Start observing for observer1 which will be unregistered
+ watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
+ // Start observing for observer2 which will expire
+ watchdog.startObservingHealth(observer2, Arrays.asList(APP_A, APP_B), SHORT_DURATION);
+ // Start observing for observer3 which will have expiry duration reduced
+ watchdog.startObservingHealth(observer3, Arrays.asList(APP_A), LONG_DURATION);
+
+ // Verify packages observed at start
+ // 1
+ assertEquals(1, watchdog.getPackages(observer1).size());
+ assertTrue(watchdog.getPackages(observer1).contains(APP_A));
+ // 2
+ assertEquals(2, watchdog.getPackages(observer2).size());
+ assertTrue(watchdog.getPackages(observer2).contains(APP_A));
+ assertTrue(watchdog.getPackages(observer2).contains(APP_B));
+ // 3
+ assertEquals(1, watchdog.getPackages(observer3).size());
+ assertTrue(watchdog.getPackages(observer3).contains(APP_A));
+
+ // Then unregister observer1
+ watchdog.unregisterHealthObserver(observer1);
+
+ // Verify observer2 and observer3 left
+ // 1
+ assertNull(watchdog.getPackages(observer1));
+ // 2
+ assertEquals(2, watchdog.getPackages(observer2).size());
+ assertTrue(watchdog.getPackages(observer2).contains(APP_A));
+ assertTrue(watchdog.getPackages(observer2).contains(APP_B));
+ // 3
+ assertEquals(1, watchdog.getPackages(observer3).size());
+ assertTrue(watchdog.getPackages(observer3).contains(APP_A));
+
+ // Then advance time a little and run messages in Handlers so observer2 expires
+ Thread.sleep(SHORT_DURATION);
+ mTestLooper.dispatchAll();
+
+ // Verify observer3 left with reduced expiry duration
+ // 1
+ assertNull(watchdog.getPackages(observer1));
+ // 2
+ assertNull(watchdog.getPackages(observer2));
+ // 3
+ assertEquals(1, watchdog.getPackages(observer3).size());
+ assertTrue(watchdog.getPackages(observer3).contains(APP_A));
+
+ // Then advance time some more and run messages in Handlers so observer3 expires
+ Thread.sleep(LONG_DURATION);
+ mTestLooper.dispatchAll();
+
+ // Verify observer3 expired
+ // 1
+ assertNull(watchdog.getPackages(observer1));
+ // 2
+ assertNull(watchdog.getPackages(observer2));
+ // 3
+ assertNull(watchdog.getPackages(observer3));
+ }
+
+ /**
+ * Test package observers are persisted and loaded on startup
+ */
+ @Test
+ public void testPersistence() throws Exception {
+ PackageWatchdog watchdog1 = createWatchdog();
+ TestObserver observer1 = new TestObserver(OBSERVER_NAME_1);
+ TestObserver observer2 = new TestObserver(OBSERVER_NAME_2);
+
+ watchdog1.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
+ watchdog1.startObservingHealth(observer2, Arrays.asList(APP_A, APP_B), SHORT_DURATION);
+
+ // Verify 2 observers are registered and saved internally
+ // 1
+ assertEquals(1, watchdog1.getPackages(observer1).size());
+ assertTrue(watchdog1.getPackages(observer1).contains(APP_A));
+ // 2
+ assertEquals(2, watchdog1.getPackages(observer2).size());
+ assertTrue(watchdog1.getPackages(observer2).contains(APP_A));
+ assertTrue(watchdog1.getPackages(observer2).contains(APP_B));
+
+
+ // Then advance time and run IO Handler so file is saved
+ mTestLooper.dispatchAll();
+
+ // Then start a new watchdog
+ PackageWatchdog watchdog2 = createWatchdog();
+
+ // Verify the new watchdog loads observers on startup but nothing registered
+ assertEquals(0, watchdog2.getPackages(observer1).size());
+ assertEquals(0, watchdog2.getPackages(observer2).size());
+ // Verify random observer not saved returns null
+ assertNull(watchdog2.getPackages(new TestObserver(OBSERVER_NAME_3)));
+
+ // Then regiser observer1
+ watchdog2.registerHealthObserver(observer1);
+ watchdog2.registerHealthObserver(observer2);
+
+ // Verify 2 observers are registered after reload
+ // 1
+ assertEquals(1, watchdog1.getPackages(observer1).size());
+ assertTrue(watchdog1.getPackages(observer1).contains(APP_A));
+ // 2
+ assertEquals(2, watchdog1.getPackages(observer2).size());
+ assertTrue(watchdog1.getPackages(observer2).contains(APP_A));
+ assertTrue(watchdog1.getPackages(observer2).contains(APP_B));
+ }
+
+ /**
+ * Test package failure under threshold does not notify observers
+ */
+ @Test
+ public void testNoPackageFailureBeforeThreshold() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver observer1 = new TestObserver(OBSERVER_NAME_1);
+ TestObserver observer2 = new TestObserver(OBSERVER_NAME_2);
+
+ watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION);
+ watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
+
+ // Then fail APP_A below the threshold
+ for (int i = 0; i < TRIGGER_FAILURE_COUNT - 1; i++) {
+ watchdog.onPackageFailure(new String[]{APP_A});
+ }
+
+ // Verify that observers are not notified
+ assertEquals(0, observer1.mFailedPackages.size());
+ assertEquals(0, observer2.mFailedPackages.size());
+ }
+
+ /**
+ * Test package failure and notifies all observer since none handles the failure
+ */
+ @Test
+ public void testPackageFailureNotifyAll() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver observer1 = new TestObserver(OBSERVER_NAME_1);
+ TestObserver observer2 = new TestObserver(OBSERVER_NAME_2);
+
+ // Start observing for observer1 and observer2 without handling failures
+ watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION);
+ watchdog.startObservingHealth(observer1, Arrays.asList(APP_A, APP_B), SHORT_DURATION);
+
+ // Then fail APP_A and APP_B above the threshold
+ for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+ watchdog.onPackageFailure(new String[]{APP_A, APP_B});
+ }
+
+ // Verify all observers are notifed of all package failures
+ List<String> observer1Packages = observer1.mFailedPackages;
+ List<String> observer2Packages = observer2.mFailedPackages;
+ assertEquals(2, observer1Packages.size());
+ assertEquals(1, observer2Packages.size());
+ assertEquals(APP_A, observer1Packages.get(0));
+ assertEquals(APP_B, observer1Packages.get(1));
+ assertEquals(APP_A, observer2Packages.get(0));
+ }
+
+ /**
+ * Test package failure and notifies only one observer because it handles the failure
+ */
+ @Test
+ public void testPackageFailureNotifyOne() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver observer1 = new TestObserver(OBSERVER_NAME_1, true /* shouldHandle */);
+ TestObserver observer2 = new TestObserver(OBSERVER_NAME_2, true /* shouldHandle */);
+
+ // Start observing for observer1 and observer2 with failure handling
+ watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION);
+ watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
+
+ // Then fail APP_A above the threshold
+ for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+ watchdog.onPackageFailure(new String[]{APP_A});
+ }
+
+ // Verify only one observer is notifed
+ assertEquals(1, observer1.mFailedPackages.size());
+ assertEquals(APP_A, observer1.mFailedPackages.get(0));
+ assertEquals(0, observer2.mFailedPackages.size());
+ }
+
+ private PackageWatchdog createWatchdog() {
+ return new PackageWatchdog(InstrumentationRegistry.getContext(),
+ mTestLooper.getLooper());
+ }
+
+ private static class TestObserver implements PackageHealthObserver {
+ private final String mName;
+ private boolean mShouldHandle;
+ final List<String> mFailedPackages = new ArrayList<>();
+
+ TestObserver(String name) {
+ mName = name;
+ }
+
+ TestObserver(String name, boolean shouldHandle) {
+ mName = name;
+ mShouldHandle = shouldHandle;
+ }
+
+ public boolean onHealthCheckFailed(String packageName) {
+ mFailedPackages.add(packageName);
+ return mShouldHandle;
+ }
+
+ public String getName() {
+ return mName;
+ }
+ }
+}
diff --git a/tests/net/Android.mk b/tests/net/Android.mk
index 9d1edbf..f6f35fd 100644
--- a/tests/net/Android.mk
+++ b/tests/net/Android.mk
@@ -18,6 +18,7 @@
mockito-target-minus-junit4 \
platform-test-annotations \
services.core \
+ services.ipmemorystore \
services.net
LOCAL_JAVA_LIBRARIES := \
diff --git a/tests/net/java/android/net/IpMemoryStoreTest.java b/tests/net/java/android/net/IpMemoryStoreTest.java
new file mode 100644
index 0000000..eae9710
--- /dev/null
+++ b/tests/net/java/android/net/IpMemoryStoreTest.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.net;
+
+import android.content.Context;
+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 org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IpMemoryStoreTest {
+ @Mock
+ Context mMockContext;
+ @Mock
+ IIpMemoryStore mMockService;
+ IpMemoryStore mStore;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mStore = new IpMemoryStore(mMockContext, mMockService);
+ }
+
+ @Test
+ public void testNetworkAttributes() {
+ // TODO : implement this
+ }
+
+ @Test
+ public void testPrivateData() {
+ // TODO : implement this
+ }
+
+ @Test
+ public void testFindL2Key() {
+ // TODO : implement this
+ }
+
+ @Test
+ public void testIsSameNetwork() {
+ // TODO : implement this
+ }
+
+}
diff --git a/tests/net/java/android/net/ipmemorystore/ParcelableTests.java b/tests/net/java/android/net/ipmemorystore/ParcelableTests.java
new file mode 100644
index 0000000..a9f9758
--- /dev/null
+++ b/tests/net/java/android/net/ipmemorystore/ParcelableTests.java
@@ -0,0 +1,113 @@
+/*
+ * 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.net.ipmemorystore;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.util.Arrays;
+import java.util.Collections;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ParcelableTests {
+ @Test
+ public void testNetworkAttributesParceling() throws Exception {
+ final NetworkAttributes.Builder builder = new NetworkAttributes.Builder();
+ NetworkAttributes in = builder.build();
+ assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
+
+ builder.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
+ // groupHint stays null this time around
+ builder.setDnsAddresses(Collections.emptyList());
+ builder.setMtu(18);
+ in = builder.build();
+ assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
+
+ builder.setAssignedV4Address((Inet4Address) Inet4Address.getByName("6.7.8.9"));
+ builder.setGroupHint("groupHint");
+ builder.setDnsAddresses(Arrays.asList(
+ InetAddress.getByName("ACA1:652B:0911:DE8F:1200:115E:913B:AA2A"),
+ InetAddress.getByName("6.7.8.9")));
+ builder.setMtu(1_000_000);
+ in = builder.build();
+ assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
+
+ builder.setMtu(null);
+ in = builder.build();
+ assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
+ }
+
+ @Test
+ public void testPrivateDataParceling() throws Exception {
+ final Blob in = new Blob();
+ in.data = new byte[] {89, 111, 108, 111};
+ final Blob out = parcelingRoundTrip(in);
+ // Object.equals on byte[] tests the references
+ assertEquals(in.data.length, out.data.length);
+ assertTrue(Arrays.equals(in.data, out.data));
+ }
+
+ @Test
+ public void testSameL3NetworkResponseParceling() throws Exception {
+ final SameL3NetworkResponseParcelable parcelable = new SameL3NetworkResponseParcelable();
+ parcelable.l2Key1 = "key 1";
+ parcelable.l2Key2 = "key 2";
+ parcelable.confidence = 0.43f;
+
+ final SameL3NetworkResponse in = new SameL3NetworkResponse(parcelable);
+ assertEquals("key 1", in.l2Key1);
+ assertEquals("key 2", in.l2Key2);
+ assertEquals(0.43f, in.confidence, 0.01f /* delta */);
+
+ final SameL3NetworkResponse out =
+ new SameL3NetworkResponse(parcelingRoundTrip(in.toParcelable()));
+
+ assertEquals(in, out);
+ assertEquals(in.l2Key1, out.l2Key1);
+ assertEquals(in.l2Key2, out.l2Key2);
+ assertEquals(in.confidence, out.confidence, 0.01f /* delta */);
+ }
+
+ private <T extends Parcelable> T parcelingRoundTrip(final T in) throws Exception {
+ final Parcel p = Parcel.obtain();
+ in.writeToParcel(p, /* flags */ 0);
+ p.setDataPosition(0);
+ final byte[] marshalledData = p.marshall();
+ p.recycle();
+
+ final Parcel q = Parcel.obtain();
+ q.unmarshall(marshalledData, 0, marshalledData.length);
+ q.setDataPosition(0);
+
+ final Parcelable.Creator<T> creator = (Parcelable.Creator<T>)
+ in.getClass().getField("CREATOR").get(null); // static object, so null receiver
+ final T unmarshalled = (T) creator.createFromParcel(q);
+ q.recycle();
+ return unmarshalled;
+ }
+}
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java b/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
new file mode 100644
index 0000000..859a54d
--- /dev/null
+++ b/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.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 com.android.server.net.ipmemorystore;
+
+import android.content.Context;
+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 org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Unit tests for {@link IpMemoryStoreServiceTest}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class IpMemoryStoreServiceTest {
+ @Mock
+ Context mMockContext;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testNetworkAttributes() {
+ final IpMemoryStoreService service = new IpMemoryStoreService(mMockContext);
+ // TODO : implement this
+ }
+
+ @Test
+ public void testPrivateData() {
+ final IpMemoryStoreService service = new IpMemoryStoreService(mMockContext);
+ // TODO : implement this
+ }
+
+ @Test
+ public void testFindL2Key() {
+ final IpMemoryStoreService service = new IpMemoryStoreService(mMockContext);
+ // TODO : implement this
+ }
+
+ @Test
+ public void testIsSameNetwork() {
+ final IpMemoryStoreService service = new IpMemoryStoreService(mMockContext);
+ // TODO : implement this
+ }
+}
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index c42a888..0580df6 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -58,6 +58,7 @@
"libprotobuf-cpp-lite",
"libz",
],
+ stl: "libc++_static",
group_static_libs: true,
}
diff --git a/tools/bit/command.h b/tools/bit/command.h
index fb44900..dd7103e 100644
--- a/tools/bit/command.h
+++ b/tools/bit/command.h
@@ -25,7 +25,7 @@
struct Command
{
- Command(const string& prog);
+ explicit Command(const string& prog);
~Command();
void AddArg(const string& arg);
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 9968bda..4491a85 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -67,7 +67,7 @@
case JAVA_TYPE_STRING:
return "char const*";
case JAVA_TYPE_BYTE_ARRAY:
- return "char const*";
+ return "const BytesField&";
default:
return "UNKNOWN";
}
@@ -270,10 +270,6 @@
chainField.name.c_str(), chainField.name.c_str());
}
}
- } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
- fprintf(out, ", %s arg%d, size_t arg%d_length",
- cpp_type_name(*arg), argIndex, argIndex);
-
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
fprintf(out, ", const std::map<int, int32_t>& arg%d_1, "
"const std::map<int, int64_t>& arg%d_2, "
@@ -355,7 +351,8 @@
fprintf(out, " event.end();\n\n");
} else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
fprintf(out,
- " event.AppendCharArray(arg%d, arg%d_length);\n",
+ " event.AppendCharArray(arg%d.arg, "
+ "arg%d.arg_length);\n",
argIndex, argIndex);
} else {
if (*arg == JAVA_TYPE_STRING) {
@@ -397,10 +394,6 @@
chainField.name.c_str(), chainField.name.c_str());
}
}
- } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
- fprintf(out, ", %s arg%d, size_t arg%d_length",
- cpp_type_name(*arg), argIndex, argIndex);
-
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
fprintf(out,
", const std::map<int, int32_t>& arg%d_1, "
@@ -434,8 +427,6 @@
chainField.name.c_str(), chainField.name.c_str());
}
}
- } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
- fprintf(out, ", arg%d, arg%d_length", argIndex, argIndex);
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", argIndex,
argIndex, argIndex, argIndex);
@@ -494,7 +485,14 @@
fprintf(out, " arg%d = \"\";\n", argIndex);
fprintf(out, " }\n");
}
- fprintf(out, " event << arg%d;\n", argIndex);
+ if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+ fprintf(out,
+ " event.AppendCharArray(arg%d.arg, "
+ "arg%d.arg_length);",
+ argIndex, argIndex);
+ } else {
+ fprintf(out, " event << arg%d;\n", argIndex);
+ }
if (argIndex == 2) {
fprintf(out, " event.end();\n\n");
fprintf(out, " event.end();\n\n");
@@ -577,7 +575,9 @@
static void write_cpp_usage(
FILE* out, const string& method_name, const string& atom_code_name,
const AtomDecl& atom, const AtomDecl &attributionDecl) {
- fprintf(out, " * Usage: %s(StatsLog.%s", method_name.c_str(), atom_code_name.c_str());
+ fprintf(out, " * Usage: %s(StatsLog.%s", method_name.c_str(),
+ atom_code_name.c_str());
+
for (vector<AtomField>::const_iterator field = atom.fields.begin();
field != atom.fields.end(); field++) {
if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
@@ -601,11 +601,6 @@
field->name.c_str(),
field->name.c_str(),
field->name.c_str());
- } else if (field->javaType == JAVA_TYPE_BYTE_ARRAY) {
- fprintf(out, ", %s %s, size_t %s_length",
- cpp_type_name(field->javaType), field->name.c_str(),
- field->name.c_str());
-
} else {
fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
}
@@ -639,9 +634,6 @@
"const std::map<int, char const*>& arg%d_3, "
"const std::map<int, float>& arg%d_4",
argIndex, argIndex, argIndex, argIndex);
- } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
- fprintf(out, ", %s arg%d, size_t arg%d_length",
- cpp_type_name(*arg), argIndex, argIndex);
} else {
fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
}
@@ -708,6 +700,15 @@
fprintf(out, "};\n");
fprintf(out, "\n");
+ fprintf(out, "struct BytesField {\n");
+ fprintf(out,
+ " BytesField(char const* array, size_t len) : arg(array), "
+ "arg_length(len) {}\n");
+ fprintf(out, " char const* arg;\n");
+ fprintf(out, " size_t arg_length;\n");
+ fprintf(out, "};\n");
+ fprintf(out, "\n");
+
fprintf(out, "struct StateAtomFieldOptions {\n");
fprintf(out, " std::vector<int> primaryFields;\n");
fprintf(out, " int exclusiveField;\n");
@@ -1183,6 +1184,11 @@
fprintf(out, " str%d = NULL;\n", argIndex);
fprintf(out, " }\n");
+ fprintf(out,
+ " android::util::BytesField bytesField%d(str%d, "
+ "str%d_length);",
+ argIndex, argIndex, argIndex);
+
} else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
hadStringOrChain = true;
for (auto chainField : attributionDecl.fields) {
@@ -1240,7 +1246,8 @@
// stats_write call
argIndex = 1;
- fprintf(out, "\n int ret = android::util::%s(code", cpp_method_name.c_str());
+ fprintf(out, "\n int ret = android::util::%s(code",
+ cpp_method_name.c_str());
for (vector<java_type_t>::const_iterator arg = signature->begin();
arg != signature->end(); arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
@@ -1255,16 +1262,12 @@
}
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
fprintf(out, ", int32_t_map, int64_t_map, string_map, float_map");
+ } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+ fprintf(out, ", bytesField%d", argIndex);
} else {
- const char* argName = (*arg == JAVA_TYPE_STRING ||
- *arg == JAVA_TYPE_BYTE_ARRAY)
- ? "str"
- : "arg";
+ const char* argName =
+ (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
-
- if (*arg == JAVA_TYPE_BYTE_ARRAY) {
- fprintf(out, ", %s%d_length", argName, argIndex);
- }
}
argIndex++;
}
diff --git a/tools/streaming_proto/Errors.h b/tools/streaming_proto/Errors.h
index f14bbfd..bddd981 100644
--- a/tools/streaming_proto/Errors.h
+++ b/tools/streaming_proto/Errors.h
@@ -11,7 +11,7 @@
struct Error
{
Error();
- explicit Error(const Error& that);
+ Error(const Error& that);
Error(const string& filename, int lineno, const char* message);
string filename;
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index a809cad..28dd9b4 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -27,7 +27,6 @@
import android.net.ProxyInfo;
import android.net.StaticIpConfiguration;
import android.net.Uri;
-import android.net.wifi.WifiInfo;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -491,7 +490,7 @@
* The set of group management ciphers supported by this configuration.
* See {@link GroupMgmtCipher} for descriptions of the values.
*/
- public BitSet allowedGroupMgmtCiphers;
+ public BitSet allowedGroupManagementCiphers;
/**
* The set of SuiteB ciphers supported by this configuration.
* To be used for WPA3-Enterprise mode.
@@ -1642,7 +1641,7 @@
allowedAuthAlgorithms = new BitSet();
allowedPairwiseCiphers = new BitSet();
allowedGroupCiphers = new BitSet();
- allowedGroupMgmtCiphers = new BitSet();
+ allowedGroupManagementCiphers = new BitSet();
allowedSuiteBCiphers = new BitSet();
wepKeys = new String[4];
for (int i = 0; i < wepKeys.length; i++) {
@@ -1835,8 +1834,8 @@
}
sbuf.append('\n');
sbuf.append(" GroupMgmtCiphers:");
- for (int gmc = 0; gmc < this.allowedGroupMgmtCiphers.size(); gmc++) {
- if (this.allowedGroupMgmtCiphers.get(gmc)) {
+ for (int gmc = 0; gmc < this.allowedGroupManagementCiphers.size(); gmc++) {
+ if (this.allowedGroupManagementCiphers.get(gmc)) {
sbuf.append(" ");
if (gmc < GroupMgmtCipher.strings.length) {
sbuf.append(GroupMgmtCipher.strings[gmc]);
@@ -2235,7 +2234,7 @@
allowedAuthAlgorithms = (BitSet) source.allowedAuthAlgorithms.clone();
allowedPairwiseCiphers = (BitSet) source.allowedPairwiseCiphers.clone();
allowedGroupCiphers = (BitSet) source.allowedGroupCiphers.clone();
- allowedGroupMgmtCiphers = (BitSet) source.allowedGroupMgmtCiphers.clone();
+ allowedGroupManagementCiphers = (BitSet) source.allowedGroupManagementCiphers.clone();
allowedSuiteBCiphers = (BitSet) source.allowedSuiteBCiphers.clone();
enterpriseConfig = new WifiEnterpriseConfig(source.enterpriseConfig);
@@ -2317,7 +2316,7 @@
writeBitSet(dest, allowedAuthAlgorithms);
writeBitSet(dest, allowedPairwiseCiphers);
writeBitSet(dest, allowedGroupCiphers);
- writeBitSet(dest, allowedGroupMgmtCiphers);
+ writeBitSet(dest, allowedGroupManagementCiphers);
writeBitSet(dest, allowedSuiteBCiphers);
dest.writeParcelable(enterpriseConfig, flags);
@@ -2389,7 +2388,7 @@
config.allowedAuthAlgorithms = readBitSet(in);
config.allowedPairwiseCiphers = readBitSet(in);
config.allowedGroupCiphers = readBitSet(in);
- config.allowedGroupMgmtCiphers = readBitSet(in);
+ config.allowedGroupManagementCiphers = readBitSet(in);
config.allowedSuiteBCiphers = readBitSet(in);
config.enterpriseConfig = in.readParcelable(null);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 7f56a01..517bf3b 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -189,6 +189,7 @@
*/
public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID = 5;
+ /** @hide */
@IntDef(prefix = { "STATUS_NETWORK_SUGGESTIONS_" }, value = {
STATUS_NETWORK_SUGGESTIONS_SUCCESS,
STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL,
@@ -1652,7 +1653,7 @@
* suggestion back using this API.</li>
*
* @param networkSuggestions List of network suggestions provided by the app.
- * @return Status code corresponding to the values in {@link NetworkSuggestionsStatusCode}.
+ * @return Status code for the operation. One of the STATUS_NETWORK_SUGGESTIONS_ values.
* {@link WifiNetworkSuggestion#equals(Object)} any previously provided suggestions by the app.
* @throws {@link SecurityException} if the caller is missing required permissions.
*/
@@ -1673,8 +1674,7 @@
*
* @param networkSuggestions List of network suggestions to be removed. Pass an empty list
* to remove all the previous suggestions provided by the app.
- * @return Status code corresponding to the values in
- * {@link NetworkSuggestionsStatusCode}.
+ * @return Status code for the operation. One of the STATUS_NETWORK_SUGGESTIONS_ values.
* Any matching suggestions are removed from the device and will not be considered for any
* further connection attempts.
*/
diff --git a/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java b/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java
index f73b9e5..ecee5ff 100644
--- a/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java
+++ b/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java
@@ -412,7 +412,7 @@
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
// TODO (b/113878056): Verify these params once we verify SuiteB configuration.
- configuration.allowedGroupMgmtCiphers.set(
+ configuration.allowedGroupManagementCiphers.set(
WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256);
configuration.allowedSuiteBCiphers.set(
WifiConfiguration.SuiteBCipher.ECDHE_ECDSA);
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
index 6631fa8..f931ad2 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
@@ -223,7 +223,8 @@
private MacAddress mDeviceAddress = MAC_ANY_ADDRESS;
private String mNetworkName = "";
private String mPassphrase = "";
- private int mGroupOwnerBand = GROUP_OWNER_BAND_AUTO;
+ private int mGroupOperatingBand = GROUP_OWNER_BAND_AUTO;
+ private int mGroupOperatingFrequency = GROUP_OWNER_BAND_AUTO;
private int mNetId = WifiP2pGroup.TEMPORARY_NET_ID;
/**
@@ -285,22 +286,84 @@
}
/**
- * Specify the band to use for creating the group. This method only applies when
- * creating a group as Group Owner using {@link WifiP2pManager#createGroup}.
- * The band should be {@link #GROUP_OWNER_BAND_2GHZ} or {@link #GROUP_OWNER_BAND_5GHZ},
- * or allow the system to pick the band by specifying {@link #GROUP_OWNER_BAND_AUTO}.
+ * Specify the band to use for creating the group or joining the group. The band should
+ * be {@link #GROUP_OWNER_BAND_2GHZ}, {@link #GROUP_OWNER_BAND_5GHZ} or
+ * {@link #GROUP_OWNER_BAND_AUTO}.
+ * <p>
+ * When creating a group as Group Owner using {@link
+ * WifiP2pManager#createGroup(WifiP2pManager.Channel,
+ * WifiP2pConfig, WifiP2pManager.ActionListener)},
+ * specifying {@link #GROUP_OWNER_BAND_AUTO} allows the system to pick the operating
+ * frequency from all supported bands.
+ * Specifying {@link #GROUP_OWNER_BAND_2GHZ} or {@link #GROUP_OWNER_BAND_5GHZ}
+ * only allows the system to pick the operating frequency in the specified band.
* If the Group Owner cannot create a group in the specified band, the operation will fail.
* <p>
+ * When joining a group as Group Client using {@link
+ * WifiP2pManager#connect(WifiP2pManager.Channel, WifiP2pConfig,
+ * WifiP2pManager.ActionListener)},
+ * specifying {@link #GROUP_OWNER_BAND_AUTO} allows the system to scan all supported
+ * frequencies to find the desired group. Specifying {@link #GROUP_OWNER_BAND_2GHZ} or
+ * {@link #GROUP_OWNER_BAND_5GHZ} only allows the system to scan the specified band.
+ * <p>
+ * {@link #setGroupOperatingBand(int)} and {@link #setGroupOperatingFrequency(int)} are
+ * mutually exclusive. Setting operating band and frequency both is invalid.
+ * <p>
* Optional. {@link #GROUP_OWNER_BAND_AUTO} by default.
*
- * @param band the required band of group owner.
+ * @param band the operating band of the group.
* This should be one of {@link #GROUP_OWNER_BAND_AUTO},
* {@link #GROUP_OWNER_BAND_2GHZ}, {@link #GROUP_OWNER_BAND_5GHZ}.
* @return The builder to facilitate chaining
* {@code builder.setXXX(..).setXXX(..)}.
*/
- public Builder setGroupOwnerBand(int band) {
- mGroupOwnerBand = band;
+ public Builder setGroupOperatingBand(@GroupOwnerBandType int band) {
+ switch (band) {
+ case GROUP_OWNER_BAND_AUTO:
+ case GROUP_OWNER_BAND_2GHZ:
+ case GROUP_OWNER_BAND_5GHZ:
+ mGroupOperatingBand = band;
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Invalid constant for the group operating band!");
+ }
+ return this;
+ }
+
+ /**
+ * Specify the frequency to use for creating the group or joining the group.
+ * <p>
+ * When creating a group as Group Owner using {@link WifiP2pManager#createGroup(
+ * WifiP2pManager.Channel, WifiP2pConfig, WifiP2pManager.ActionListener)},
+ * specifying a frequency only allows the system to pick the specified frequency.
+ * If the Group Owner cannot create a group at the specified frequency,
+ * the operation will fail.
+ * When not specifying a frequency, it allows the system to pick operating frequency
+ * from all supported bands.
+ * <p>
+ * When joining a group as Group Client using {@link WifiP2pManager#connect(
+ * WifiP2pManager.Channel, WifiP2pConfig, WifiP2pManager.ActionListener)},
+ * specifying a frequency only allows the system to scan the specified frequency.
+ * If the frequency is not supported or invalid, the operation will fail.
+ * When not specifying a frequency, it allows the system to scan all supported
+ * frequencies to find the desired group.
+ * <p>
+ * {@link #setGroupOperatingBand(int)} and {@link #setGroupOperatingFrequency(int)} are
+ * mutually exclusive. Setting operating band and frequency both is invalid.
+ * <p>
+ * Optional. 0 by default.
+ *
+ * @param frequency the operating frequency of the group.
+ * @return The builder to facilitate chaining
+ * {@code builder.setXXX(..).setXXX(..)}.
+ */
+ public Builder setGroupOperatingFrequency(int frequency) {
+ if (frequency < 0) {
+ throw new IllegalArgumentException(
+ "Invalid group operating frequency!");
+ }
+ mGroupOperatingFrequency = frequency;
return this;
}
@@ -337,11 +400,21 @@
"passphrase must be non-empty.");
}
+ if (mGroupOperatingFrequency > 0 && mGroupOperatingBand > 0) {
+ throw new IllegalStateException(
+ "Preferred frequency and band are mutually exclusive.");
+ }
+
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = mDeviceAddress.toString();
config.networkName = mNetworkName;
config.passphrase = mPassphrase;
- config.groupOwnerBand = mGroupOwnerBand;
+ config.groupOwnerBand = GROUP_OWNER_BAND_AUTO;
+ if (mGroupOperatingFrequency > 0) {
+ config.groupOwnerBand = mGroupOperatingFrequency;
+ } else if (mGroupOperatingBand > 0) {
+ config.groupOwnerBand = mGroupOperatingBand;
+ }
config.netId = mNetId;
return config;
}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
index 83627ad..dd6e2c9 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
@@ -518,7 +518,7 @@
.get(WifiConfiguration.KeyMgmt.SUITE_B_192));
assertTrue(suggestion.wifiConfiguration.allowedGroupCiphers
.get(WifiConfiguration.GroupCipher.GCMP_256));
- assertTrue(suggestion.wifiConfiguration.allowedGroupMgmtCiphers
+ assertTrue(suggestion.wifiConfiguration.allowedGroupManagementCiphers
.get(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256));
assertTrue(suggestion.wifiConfiguration.allowedSuiteBCiphers
.get(WifiConfiguration.SuiteBCipher.ECDHE_ECDSA));