Merge "Fix statsd ble scan logging" into pi-dev
diff --git a/Android.bp b/Android.bp
index 4d5d998..ce93568 100644
--- a/Android.bp
+++ b/Android.bp
@@ -145,11 +145,11 @@
":libcamera_client_framework_aidl",
"core/java/android/hardware/IConsumerIrService.aidl",
"core/java/android/hardware/ISerialManager.aidl",
+ "core/java/android/hardware/biometrics/IBiometricDialogReceiver.aidl",
"core/java/android/hardware/display/IDisplayManager.aidl",
"core/java/android/hardware/display/IDisplayManagerCallback.aidl",
"core/java/android/hardware/display/IVirtualDisplayCallback.aidl",
"core/java/android/hardware/fingerprint/IFingerprintClientActiveCallback.aidl",
- "core/java/android/hardware/fingerprint/IFingerprintDialogReceiver.aidl",
"core/java/android/hardware/fingerprint/IFingerprintService.aidl",
"core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl",
"core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl",
diff --git a/Android.mk b/Android.mk
index b630c3f..e219661 100644
--- a/Android.mk
+++ b/Android.mk
@@ -861,14 +861,11 @@
# ==== hiddenapi lists =======================================
-# Copy blacklist and light greylist over into the build folder.
+# Copy light and dark greylist over into the build folder.
# This is for ART buildbots which need to mock these lists and have alternative
# rules for building them. Other rules in the build system should depend on the
# files in the build folder.
-$(eval $(call copy-one-file,frameworks/base/config/hiddenapi-blacklist.txt,\
- $(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST)))
-
# Automatically add all methods which match the following signatures.
# These need to be greylisted in order to allow applications to write their
# own serializers.
@@ -891,25 +888,31 @@
<(grep -E "\->("$(subst $(space),"|",$(REGEX_SERIALIZATION))")$$" $(PRIVATE_API)) \
> $@
+$(eval $(call copy-one-file,frameworks/base/config/hiddenapi-dark-greylist.txt,\
+ $(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST)))
+
# Generate dark greylist as private API minus (blacklist plus light greylist).
-$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST): PRIVATE_API := $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE)
-$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST): BLACKLIST := $(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST)
-$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST): LIGHT_GREYLIST := $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST)
-$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST): $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE) \
- $(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST) \
- $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST)
- if [ ! -z "`comm -12 <(sort $(BLACKLIST)) <(sort $(LIGHT_GREYLIST))`" ]; then \
- echo "There should be no overlap between $(BLACKLIST) and $(LIGHT_GREYLIST)" 1>&2; \
+$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST): PRIVATE_API := $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE)
+$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST): LIGHT_GREYLIST := $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST)
+$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST): DARK_GREYLIST := $(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST)
+$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST): $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE) \
+ $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST) \
+ $(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST)
+ if [ ! -z "`comm -12 <(sort $(LIGHT_GREYLIST)) <(sort $(DARK_GREYLIST))`" ]; then \
+ echo "There should be no overlap between $(LIGHT_GREYLIST) and $(DARK_GREYLIST)" 1>&2; \
+ comm -12 <(sort $(LIGHT_GREYLIST)) <(sort $(DARK_GREYLIST)) 1>&2; \
exit 1; \
- elif [ ! -z "`comm -13 <(sort $(PRIVATE_API)) <(sort $(BLACKLIST))`" ]; then \
- echo "$(BLACKLIST) must be a subset of $(PRIVATE_API)" 1>&2; \
- exit 2; \
elif [ ! -z "`comm -13 <(sort $(PRIVATE_API)) <(sort $(LIGHT_GREYLIST))`" ]; then \
echo "$(LIGHT_GREYLIST) must be a subset of $(PRIVATE_API)" 1>&2; \
+ comm -13 <(sort $(PRIVATE_API)) <(sort $(LIGHT_GREYLIST)) 1>&2; \
+ exit 2; \
+ elif [ ! -z "`comm -13 <(sort $(PRIVATE_API)) <(sort $(DARK_GREYLIST))`" ]; then \
+ echo "$(DARK_GREYLIST) must be a subset of $(PRIVATE_API)" 1>&2; \
+ comm -13 <(sort $(PRIVATE_API)) <(sort $(DARK_GREYLIST)) 1>&2; \
exit 3; \
fi
- comm -23 <(sort $(PRIVATE_API)) <(sort $(BLACKLIST) $(LIGHT_GREYLIST)) > $@
+ comm -23 <(sort $(PRIVATE_API)) <(sort $(LIGHT_GREYLIST) $(DARK_GREYLIST)) > $@
# Include subdirectory makefiles
# ============================================================
diff --git a/api/current.txt b/api/current.txt
index 2b6ac8d..79f328e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -142,7 +142,8 @@
field public static final java.lang.String TRANSMIT_IR = "android.permission.TRANSMIT_IR";
field public static final java.lang.String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT";
field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
- field public static final java.lang.String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
+ field public static final java.lang.String USE_BIOMETRIC = "android.permission.USE_BIOMETRIC";
+ field public static final deprecated java.lang.String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
field public static final java.lang.String USE_SIP = "android.permission.USE_SIP";
field public static final java.lang.String VIBRATE = "android.permission.VIBRATE";
field public static final java.lang.String WAKE_LOCK = "android.permission.WAKE_LOCK";
@@ -5877,6 +5878,8 @@
method public java.lang.CharSequence getTitle();
method public boolean isEnabled();
method public void setEnabled(boolean);
+ method public void setShouldShowIcon(boolean);
+ method public boolean shouldShowIcon();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.RemoteAction> CREATOR;
}
@@ -6261,6 +6264,7 @@
method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener, android.os.Handler);
method public void clear() throws java.io.IOException;
method public void clear(int) throws java.io.IOException;
+ method public void clearWallpaper();
method public void clearWallpaperOffsets(android.os.IBinder);
method public void forgetLoadedWallpaper();
method public android.graphics.drawable.Drawable getBuiltInDrawable();
@@ -6287,6 +6291,7 @@
method public void setBitmap(android.graphics.Bitmap) throws java.io.IOException;
method public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
method public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean, int) throws java.io.IOException;
+ method public void setDisplayPadding(android.graphics.Rect);
method public void setResource(int) throws java.io.IOException;
method public int setResource(int, int) throws java.io.IOException;
method public void setStream(java.io.InputStream) throws java.io.IOException;
@@ -6680,9 +6685,12 @@
field public static final int ID_TYPE_IMEI = 4; // 0x4
field public static final int ID_TYPE_MEID = 8; // 0x8
field public static final int ID_TYPE_SERIAL = 2; // 0x2
+ field public static final int KEYGUARD_DISABLE_BIOMETRICS = 416; // 0x1a0
+ field public static final int KEYGUARD_DISABLE_FACE = 128; // 0x80
field public static final int KEYGUARD_DISABLE_FEATURES_ALL = 2147483647; // 0x7fffffff
field public static final int KEYGUARD_DISABLE_FEATURES_NONE = 0; // 0x0
field public static final int KEYGUARD_DISABLE_FINGERPRINT = 32; // 0x20
+ field public static final int KEYGUARD_DISABLE_IRIS = 256; // 0x100
field public static final int KEYGUARD_DISABLE_REMOTE_INPUT = 64; // 0x40
field public static final int KEYGUARD_DISABLE_SECURE_CAMERA = 2; // 0x2
field public static final int KEYGUARD_DISABLE_SECURE_NOTIFICATIONS = 4; // 0x4
@@ -7283,7 +7291,7 @@
public class SliceMetrics {
ctor public SliceMetrics(android.content.Context, android.net.Uri);
method public void logHidden();
- method public void logTouch(android.net.Uri);
+ method public void logTouch(int, android.net.Uri);
method public void logVisible();
}
@@ -7332,6 +7340,20 @@
field public static final android.os.Parcelable.Creator<android.app.usage.ConfigurationStats> CREATOR;
}
+ public final class EventStats implements android.os.Parcelable {
+ ctor public EventStats(android.app.usage.EventStats);
+ method public void add(android.app.usage.EventStats);
+ method public int describeContents();
+ method public int getCount();
+ method public int getEventType();
+ method public long getFirstTimeStamp();
+ method public long getLastTimeStamp();
+ method public long getLastTimeUsed();
+ method public long getTotalTime();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.usage.EventStats> CREATOR;
+ }
+
public final class ExternalStorageStats implements android.os.Parcelable {
method public int describeContents();
method public long getAppBytes();
@@ -7437,6 +7459,8 @@
field public static final int MOVE_TO_BACKGROUND = 2; // 0x2
field public static final int MOVE_TO_FOREGROUND = 1; // 0x1
field public static final int NONE = 0; // 0x0
+ field public static final int SCREEN_INTERACTIVE = 15; // 0xf
+ field public static final int SCREEN_NON_INTERACTIVE = 16; // 0x10
field public static final int SHORTCUT_INVOCATION = 8; // 0x8
field public static final int STANDBY_BUCKET_CHANGED = 11; // 0xb
field public static final int USER_INTERACTION = 7; // 0x7
@@ -7460,6 +7484,7 @@
method public boolean isAppInactive(java.lang.String);
method public java.util.Map<java.lang.String, android.app.usage.UsageStats> queryAndAggregateUsageStats(long, long);
method public java.util.List<android.app.usage.ConfigurationStats> queryConfigurations(int, long, long);
+ method public java.util.List<android.app.usage.EventStats> queryEventStats(int, long, long);
method public android.app.usage.UsageEvents queryEvents(long, long);
method public android.app.usage.UsageEvents queryEventsForSelf(long, long);
method public java.util.List<android.app.usage.UsageStats> queryUsageStats(int, long, long);
@@ -9886,6 +9911,8 @@
field public static final java.lang.String ACTION_MEDIA_UNMOUNTABLE = "android.intent.action.MEDIA_UNMOUNTABLE";
field public static final java.lang.String ACTION_MEDIA_UNMOUNTED = "android.intent.action.MEDIA_UNMOUNTED";
field public static final java.lang.String ACTION_MY_PACKAGE_REPLACED = "android.intent.action.MY_PACKAGE_REPLACED";
+ field public static final java.lang.String ACTION_MY_PACKAGE_SUSPENDED = "android.intent.action.MY_PACKAGE_SUSPENDED";
+ field public static final java.lang.String ACTION_MY_PACKAGE_UNSUSPENDED = "android.intent.action.MY_PACKAGE_UNSUSPENDED";
field public static final java.lang.String ACTION_NEW_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL";
field public static final java.lang.String ACTION_OPEN_DOCUMENT = "android.intent.action.OPEN_DOCUMENT";
field public static final java.lang.String ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE";
@@ -10046,6 +10073,7 @@
field public static final java.lang.String EXTRA_SPLIT_NAME = "android.intent.extra.SPLIT_NAME";
field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
field public static final java.lang.String EXTRA_SUBJECT = "android.intent.extra.SUBJECT";
+ field public static final java.lang.String EXTRA_SUSPENDED_PACKAGE_EXTRAS = "android.intent.extra.SUSPENDED_PACKAGE_EXTRAS";
field public static final java.lang.String EXTRA_TEMPLATE = "android.intent.extra.TEMPLATE";
field public static final java.lang.String EXTRA_TEXT = "android.intent.extra.TEXT";
field public static final java.lang.String EXTRA_TITLE = "android.intent.extra.TITLE";
@@ -11159,7 +11187,7 @@
method public abstract android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int);
- method public android.os.PersistableBundle getSuspendedPackageAppExtras();
+ method public android.os.Bundle getSuspendedPackageAppExtras();
method public abstract android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
method public abstract java.lang.String[] getSystemSharedLibraryNames();
method public abstract java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo);
@@ -15701,6 +15729,62 @@
}
+package android.hardware.biometrics {
+
+ public class BiometricDialog {
+ method public void authenticate(android.hardware.biometrics.BiometricDialog.CryptoObject, android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.biometrics.BiometricDialog.AuthenticationCallback);
+ method public void authenticate(android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.biometrics.BiometricDialog.AuthenticationCallback);
+ field public static final int BIOMETRIC_ACQUIRED_GOOD = 0; // 0x0
+ field public static final int BIOMETRIC_ACQUIRED_IMAGER_DIRTY = 3; // 0x3
+ field public static final int BIOMETRIC_ACQUIRED_INSUFFICIENT = 2; // 0x2
+ field public static final int BIOMETRIC_ACQUIRED_PARTIAL = 1; // 0x1
+ field public static final int BIOMETRIC_ACQUIRED_TOO_FAST = 5; // 0x5
+ field public static final int BIOMETRIC_ACQUIRED_TOO_SLOW = 4; // 0x4
+ field public static final int BIOMETRIC_ERROR_CANCELED = 5; // 0x5
+ field public static final int BIOMETRIC_ERROR_HW_NOT_PRESENT = 12; // 0xc
+ field public static final int BIOMETRIC_ERROR_HW_UNAVAILABLE = 1; // 0x1
+ field public static final int BIOMETRIC_ERROR_LOCKOUT = 7; // 0x7
+ field public static final int BIOMETRIC_ERROR_LOCKOUT_PERMANENT = 9; // 0x9
+ field public static final int BIOMETRIC_ERROR_NO_BIOMETRICS = 11; // 0xb
+ field public static final int BIOMETRIC_ERROR_NO_SPACE = 4; // 0x4
+ field public static final int BIOMETRIC_ERROR_TIMEOUT = 3; // 0x3
+ field public static final int BIOMETRIC_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
+ field public static final int BIOMETRIC_ERROR_USER_CANCELED = 10; // 0xa
+ field public static final int BIOMETRIC_ERROR_VENDOR = 8; // 0x8
+ }
+
+ public static abstract class BiometricDialog.AuthenticationCallback {
+ ctor public BiometricDialog.AuthenticationCallback();
+ method public void onAuthenticationError(int, java.lang.CharSequence);
+ method public void onAuthenticationFailed();
+ method public void onAuthenticationHelp(int, java.lang.CharSequence);
+ method public void onAuthenticationSucceeded(android.hardware.biometrics.BiometricDialog.AuthenticationResult);
+ }
+
+ public static class BiometricDialog.AuthenticationResult {
+ method public android.hardware.biometrics.BiometricDialog.CryptoObject getCryptoObject();
+ }
+
+ public static class BiometricDialog.Builder {
+ ctor public BiometricDialog.Builder(android.content.Context);
+ method public android.hardware.biometrics.BiometricDialog build();
+ method public android.hardware.biometrics.BiometricDialog.Builder setDescription(java.lang.CharSequence);
+ method public android.hardware.biometrics.BiometricDialog.Builder setNegativeButton(java.lang.CharSequence, java.util.concurrent.Executor, android.content.DialogInterface.OnClickListener);
+ method public android.hardware.biometrics.BiometricDialog.Builder setSubtitle(java.lang.CharSequence);
+ method public android.hardware.biometrics.BiometricDialog.Builder setTitle(java.lang.CharSequence);
+ }
+
+ public static final class BiometricDialog.CryptoObject {
+ ctor public BiometricDialog.CryptoObject(java.security.Signature);
+ ctor public BiometricDialog.CryptoObject(javax.crypto.Cipher);
+ ctor public BiometricDialog.CryptoObject(javax.crypto.Mac);
+ method public javax.crypto.Cipher getCipher();
+ method public javax.crypto.Mac getMac();
+ method public java.security.Signature getSignature();
+ }
+
+}
+
package android.hardware.camera2 {
public class CameraAccessException extends android.util.AndroidException {
@@ -16072,6 +16156,7 @@
field public static final int REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA = 11; // 0xb
field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING = 2; // 0x2
field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 1; // 0x1
+ field public static final int REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME = 12; // 0xc
field public static final int REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING = 10; // 0xa
field public static final int REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING = 4; // 0x4
field public static final int REQUEST_AVAILABLE_CAPABILITIES_RAW = 3; // 0x3
@@ -16536,58 +16621,6 @@
package android.hardware.fingerprint {
- public class FingerprintDialog {
- method public void authenticate(android.hardware.fingerprint.FingerprintDialog.CryptoObject, android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.fingerprint.FingerprintDialog.AuthenticationCallback);
- method public void authenticate(android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.fingerprint.FingerprintDialog.AuthenticationCallback);
- field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
- field public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3; // 0x3
- field public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2
- field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1
- field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5
- field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4
- field public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5
- field public static final int FINGERPRINT_ERROR_HW_NOT_PRESENT = 12; // 0xc
- field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
- field public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7
- field public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9; // 0x9
- field public static final int FINGERPRINT_ERROR_NO_FINGERPRINTS = 11; // 0xb
- field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
- field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
- field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
- field public static final int FINGERPRINT_ERROR_USER_CANCELED = 10; // 0xa
- field public static final int FINGERPRINT_ERROR_VENDOR = 8; // 0x8
- }
-
- public static abstract class FingerprintDialog.AuthenticationCallback {
- ctor public FingerprintDialog.AuthenticationCallback();
- method public void onAuthenticationError(int, java.lang.CharSequence);
- method public void onAuthenticationFailed();
- method public void onAuthenticationHelp(int, java.lang.CharSequence);
- method public void onAuthenticationSucceeded(android.hardware.fingerprint.FingerprintDialog.AuthenticationResult);
- }
-
- public static class FingerprintDialog.AuthenticationResult {
- method public android.hardware.fingerprint.FingerprintDialog.CryptoObject getCryptoObject();
- }
-
- public static class FingerprintDialog.Builder {
- ctor public FingerprintDialog.Builder();
- method public android.hardware.fingerprint.FingerprintDialog build(android.content.Context);
- method public android.hardware.fingerprint.FingerprintDialog.Builder setDescription(java.lang.CharSequence);
- method public android.hardware.fingerprint.FingerprintDialog.Builder setNegativeButton(java.lang.CharSequence, java.util.concurrent.Executor, android.content.DialogInterface.OnClickListener);
- method public android.hardware.fingerprint.FingerprintDialog.Builder setSubtitle(java.lang.CharSequence);
- method public android.hardware.fingerprint.FingerprintDialog.Builder setTitle(java.lang.CharSequence);
- }
-
- public static final class FingerprintDialog.CryptoObject {
- ctor public FingerprintDialog.CryptoObject(java.security.Signature);
- ctor public FingerprintDialog.CryptoObject(javax.crypto.Cipher);
- ctor public FingerprintDialog.CryptoObject(javax.crypto.Mac);
- method public javax.crypto.Cipher getCipher();
- method public javax.crypto.Mac getMac();
- method public java.security.Signature getSignature();
- }
-
public deprecated class FingerprintManager {
method public deprecated void authenticate(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.CancellationSignal, int, android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, android.os.Handler);
method public deprecated boolean hasEnrolledFingerprints();
@@ -23687,6 +23720,8 @@
field public static final java.lang.String MIMETYPE_AUDIO_VORBIS = "audio/vorbis";
field public static final java.lang.String MIMETYPE_IMAGE_ANDROID_HEIC = "image/vnd.android.heic";
field public static final java.lang.String MIMETYPE_TEXT_CEA_608 = "text/cea-608";
+ field public static final java.lang.String MIMETYPE_TEXT_CEA_708 = "text/cea-708";
+ field public static final java.lang.String MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
field public static final java.lang.String MIMETYPE_TEXT_VTT = "text/vtt";
field public static final java.lang.String MIMETYPE_VIDEO_AVC = "video/avc";
field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision";
@@ -23868,6 +23903,8 @@
method public void addTimedTextSource(java.io.FileDescriptor, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void addTimedTextSource(java.io.FileDescriptor, long, long, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void attachAuxEffect(int);
+ method public void clearOnMediaTimeDiscontinuityListener();
+ method public void clearOnSubtitleDataListener();
method public static android.media.MediaPlayer create(android.content.Context, android.net.Uri);
method public static android.media.MediaPlayer create(android.content.Context, android.net.Uri, android.view.SurfaceHolder);
method public static android.media.MediaPlayer create(android.content.Context, android.net.Uri, android.view.SurfaceHolder, android.media.AudioAttributes, int);
@@ -23932,8 +23969,12 @@
method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener, android.os.Handler);
method public void setOnErrorListener(android.media.MediaPlayer.OnErrorListener);
method public void setOnInfoListener(android.media.MediaPlayer.OnInfoListener);
+ method public void setOnMediaTimeDiscontinuityListener(android.media.MediaPlayer.OnMediaTimeDiscontinuityListener, android.os.Handler);
+ method public void setOnMediaTimeDiscontinuityListener(android.media.MediaPlayer.OnMediaTimeDiscontinuityListener);
method public void setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener);
method public void setOnSeekCompleteListener(android.media.MediaPlayer.OnSeekCompleteListener);
+ method public void setOnSubtitleDataListener(android.media.MediaPlayer.OnSubtitleDataListener, android.os.Handler);
+ method public void setOnSubtitleDataListener(android.media.MediaPlayer.OnSubtitleDataListener);
method public void setOnTimedMetaDataAvailableListener(android.media.MediaPlayer.OnTimedMetaDataAvailableListener);
method public void setOnTimedTextListener(android.media.MediaPlayer.OnTimedTextListener);
method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener);
@@ -23966,7 +24007,7 @@
field public static final int MEDIA_INFO_VIDEO_NOT_PLAYING = 805; // 0x325
field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3
field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc
- field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
+ field public static final deprecated java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
field public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3; // 0x3
field public static final int PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR = 1; // 0x1
field public static final int PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR = 2; // 0x2
@@ -24031,6 +24072,10 @@
method public abstract boolean onInfo(android.media.MediaPlayer, int, int);
}
+ public static abstract interface MediaPlayer.OnMediaTimeDiscontinuityListener {
+ method public abstract void onMediaTimeDiscontinuity(android.media.MediaPlayer, android.media.MediaTimestamp);
+ }
+
public static abstract interface MediaPlayer.OnPreparedListener {
method public abstract void onPrepared(android.media.MediaPlayer);
}
@@ -24039,6 +24084,10 @@
method public abstract void onSeekComplete(android.media.MediaPlayer);
}
+ public static abstract interface MediaPlayer.OnSubtitleDataListener {
+ method public abstract void onSubtitleData(android.media.MediaPlayer, android.media.SubtitleData);
+ }
+
public static abstract interface MediaPlayer.OnTimedMetaDataAvailableListener {
method public abstract void onTimedMetaDataAvailable(android.media.MediaPlayer, android.media.TimedMetaData);
}
@@ -24391,6 +24440,7 @@
method public long getAnchorMediaTimeUs();
method public long getAnchorSytemNanoTime();
method public float getMediaClockRate();
+ field public static final android.media.MediaTimestamp TIMESTAMP_UNKNOWN;
}
public final class MicrophoneInfo {
@@ -24651,6 +24701,13 @@
method public abstract void onLoadComplete(android.media.SoundPool, int, int);
}
+ public final class SubtitleData {
+ method public byte[] getData();
+ method public long getDurationUs();
+ method public long getStartTimeUs();
+ method public int getTrackIndex();
+ }
+
public final class SyncParams {
ctor public SyncParams();
method public android.media.SyncParams allowDefaults();
@@ -28586,6 +28643,8 @@
method public int getDistanceMm();
method public int getDistanceStdDevMm();
method public android.net.MacAddress getMacAddress();
+ method public int getNumAttemptedMeasurements();
+ method public int getNumSuccessfulMeasurements();
method public android.net.wifi.aware.PeerHandle getPeerHandle();
method public long getRangingTimestampMillis();
method public int getRssi();
@@ -32036,7 +32095,6 @@
field public static final java.lang.String BASE_OS;
field public static final java.lang.String CODENAME;
field public static final java.lang.String INCREMENTAL;
- field public static final int MIN_SUPPORTED_TARGET_SDK_INT;
field public static final int PREVIEW_SDK_INT;
field public static final java.lang.String RELEASE;
field public static final deprecated java.lang.String SDK;
@@ -38323,10 +38381,8 @@
method public void shutdown();
}
- public static abstract class SEService.SecureElementListener extends android.os.Binder {
- ctor public SEService.SecureElementListener();
- method public android.os.IBinder asBinder();
- method public void serviceConnected();
+ public static abstract interface SEService.SecureElementListener {
+ method public abstract void onServiceConnected();
}
public class Session {
@@ -38336,9 +38392,7 @@
method public android.se.omapi.Reader getReader();
method public boolean isClosed();
method public android.se.omapi.Channel openBasicChannel(byte[], byte) throws java.io.IOException;
- method public android.se.omapi.Channel openBasicChannel(byte[]) throws java.io.IOException;
method public android.se.omapi.Channel openLogicalChannel(byte[], byte) throws java.io.IOException;
- method public android.se.omapi.Channel openLogicalChannel(byte[]) throws java.io.IOException;
}
}
@@ -38606,6 +38660,7 @@
method public boolean isDigestsSpecified();
method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isRandomizedEncryptionRequired();
+ method public boolean isTrustedUserPresenceRequired();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationValidWhileOnBody();
method public boolean isUserConfirmationRequired();
@@ -38624,6 +38679,7 @@
method public android.security.keystore.KeyProtection.Builder setKeyValidityStart(java.util.Date);
method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
+ method public android.security.keystore.KeyProtection.Builder setTrustedUserPresenceRequired(boolean);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int);
@@ -42361,12 +42417,11 @@
method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String);
method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
method public boolean isConcurrentVoiceAndDataSupported();
- method public deprecated boolean isDataEnabled();
+ method public boolean isDataEnabled();
method public boolean isHearingAidCompatibilitySupported();
method public boolean isNetworkRoaming();
method public boolean isSmsCapable();
method public deprecated boolean isTtyModeSupported();
- method public boolean isUserMobileDataEnabled();
method public boolean isVoiceCapable();
method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle);
method public boolean isWorldPhone();
@@ -42377,13 +42432,12 @@
method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
method public void sendVisualVoicemailSms(java.lang.String, int, java.lang.String, android.app.PendingIntent);
- method public deprecated void setDataEnabled(boolean);
+ method public void setDataEnabled(boolean);
method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
method public void setNetworkSelectionModeAutomatic();
method public boolean setNetworkSelectionModeManual(java.lang.String, boolean);
method public boolean setOperatorBrandOverride(java.lang.String);
method public boolean setPreferredNetworkTypeToGlobal();
- method public void setUserMobileDataEnabled(boolean);
method public void setVisualVoicemailSmsFilterSettings(android.telephony.VisualVoicemailSmsFilterSettings);
method public boolean setVoiceMailNumber(java.lang.String, java.lang.String);
method public deprecated void setVoicemailRingtoneUri(android.telecom.PhoneAccountHandle, android.net.Uri);
@@ -42658,6 +42712,7 @@
field public static final int EMBEDDED_SUBSCRIPTION_RESULT_OK = 0; // 0x0
field public static final int EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR = 1; // 0x1
field public static final java.lang.String EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DETAILED_CODE";
+ field public static final java.lang.String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION";
field public static final java.lang.String META_DATA_CARRIER_ICON = "android.telephony.euicc.carriericon";
}
@@ -50263,38 +50318,13 @@
package android.view.textclassifier {
- public abstract class Logger {
- ctor public Logger(android.view.textclassifier.Logger.Config);
- method public java.text.BreakIterator getTokenIterator(java.util.Locale);
- method public boolean isSmartSelection(java.lang.String);
- method public final void logSelectionActionEvent(int, int, int);
- method public final void logSelectionActionEvent(int, int, int, android.view.textclassifier.TextClassification);
- method public final void logSelectionModifiedEvent(int, int);
- method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextClassification);
- method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextSelection);
- method public final void logSelectionStartedEvent(int, int);
- method public abstract void writeEvent(android.view.textclassifier.SelectionEvent);
- field public static final int OUT_OF_BOUNDS = 2147483647; // 0x7fffffff
- field public static final int OUT_OF_BOUNDS_NEGATIVE = -2147483648; // 0x80000000
- field public static final java.lang.String WIDGET_CUSTOM_EDITTEXT = "customedit";
- field public static final java.lang.String WIDGET_CUSTOM_TEXTVIEW = "customview";
- field public static final java.lang.String WIDGET_CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview";
- field public static final java.lang.String WIDGET_EDITTEXT = "edittext";
- field public static final java.lang.String WIDGET_EDIT_WEBVIEW = "edit-webview";
- field public static final java.lang.String WIDGET_TEXTVIEW = "textview";
- field public static final java.lang.String WIDGET_UNKNOWN = "unknown";
- field public static final java.lang.String WIDGET_UNSELECTABLE_TEXTVIEW = "nosel-textview";
- field public static final java.lang.String WIDGET_WEBVIEW = "webview";
- }
-
- public static final class Logger.Config {
- ctor public Logger.Config(android.content.Context, java.lang.String, java.lang.String);
- method public java.lang.String getPackageName();
- method public java.lang.String getWidgetType();
- method public java.lang.String getWidgetVersion();
- }
-
public final class SelectionEvent implements android.os.Parcelable {
+ method public static android.view.textclassifier.SelectionEvent createSelectionActionEvent(int, int, int);
+ method public static android.view.textclassifier.SelectionEvent createSelectionActionEvent(int, int, int, android.view.textclassifier.TextClassification);
+ method public static android.view.textclassifier.SelectionEvent createSelectionModifiedEvent(int, int);
+ method public static android.view.textclassifier.SelectionEvent createSelectionModifiedEvent(int, int, android.view.textclassifier.TextClassification);
+ method public static android.view.textclassifier.SelectionEvent createSelectionModifiedEvent(int, int, android.view.textclassifier.TextSelection);
+ method public static android.view.textclassifier.SelectionEvent createSelectionStartedEvent(int, int);
method public int describeContents();
method public long getDurationSincePreviousEvent();
method public long getDurationSinceSessionStart();
@@ -50305,13 +50335,14 @@
method public int getEventType();
method public int getInvocationMethod();
method public java.lang.String getPackageName();
- method public java.lang.String getSessionId();
+ method public android.view.textclassifier.TextClassificationSessionId getSessionId();
method public java.lang.String getSignature();
method public int getSmartEnd();
method public int getSmartStart();
method public int getStart();
method public java.lang.String getWidgetType();
method public java.lang.String getWidgetVersion();
+ method public static boolean isTerminal(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final int ACTION_ABANDON = 107; // 0x6b
field public static final int ACTION_COPY = 101; // 0x65
@@ -50332,21 +50363,19 @@
field public static final int EVENT_SMART_SELECTION_SINGLE = 3; // 0x3
field public static final int INVOCATION_LINK = 2; // 0x2
field public static final int INVOCATION_MANUAL = 1; // 0x1
+ field public static final int INVOCATION_UNKNOWN = 0; // 0x0
}
public final class TextClassification implements android.os.Parcelable {
method public int describeContents();
+ method public java.util.List<android.app.RemoteAction> getActions();
method public float getConfidenceScore(java.lang.String);
method public java.lang.String getEntity(int);
method public int getEntityCount();
- method public android.graphics.drawable.Drawable getIcon();
- method public android.content.Intent getIntent();
- method public java.lang.CharSequence getLabel();
- method public android.view.View.OnClickListener getOnClickListener();
- method public int getSecondaryActionsCount();
- method public android.graphics.drawable.Drawable getSecondaryIcon(int);
- method public android.content.Intent getSecondaryIntent(int);
- method public java.lang.CharSequence getSecondaryLabel(int);
+ method public deprecated android.graphics.drawable.Drawable getIcon();
+ method public deprecated android.content.Intent getIntent();
+ method public deprecated java.lang.CharSequence getLabel();
+ method public deprecated android.view.View.OnClickListener getOnClickListener();
method public java.lang.String getSignature();
method public java.lang.String getText();
method public void writeToParcel(android.os.Parcel, int);
@@ -50355,15 +50384,13 @@
public static final class TextClassification.Builder {
ctor public TextClassification.Builder();
- method public android.view.textclassifier.TextClassification.Builder addSecondaryAction(android.content.Intent, java.lang.String, android.graphics.drawable.Drawable);
+ method public android.view.textclassifier.TextClassification.Builder addAction(android.app.RemoteAction);
method public android.view.textclassifier.TextClassification build();
- method public android.view.textclassifier.TextClassification.Builder clearSecondaryActions();
method public android.view.textclassifier.TextClassification.Builder setEntityType(java.lang.String, float);
- method public android.view.textclassifier.TextClassification.Builder setIcon(android.graphics.drawable.Drawable);
- method public android.view.textclassifier.TextClassification.Builder setIntent(android.content.Intent);
- method public android.view.textclassifier.TextClassification.Builder setLabel(java.lang.String);
- method public android.view.textclassifier.TextClassification.Builder setOnClickListener(android.view.View.OnClickListener);
- method public android.view.textclassifier.TextClassification.Builder setPrimaryAction(android.content.Intent, java.lang.String, android.graphics.drawable.Drawable);
+ method public deprecated android.view.textclassifier.TextClassification.Builder setIcon(android.graphics.drawable.Drawable);
+ method public deprecated android.view.textclassifier.TextClassification.Builder setIntent(android.content.Intent);
+ method public deprecated android.view.textclassifier.TextClassification.Builder setLabel(java.lang.String);
+ method public deprecated android.view.textclassifier.TextClassification.Builder setOnClickListener(android.view.View.OnClickListener);
method public android.view.textclassifier.TextClassification.Builder setSignature(java.lang.String);
method public android.view.textclassifier.TextClassification.Builder setText(java.lang.String);
}
@@ -50379,19 +50406,45 @@
field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassification.Options> CREATOR;
}
+ public final class TextClassificationContext {
+ method public java.lang.String getPackageName();
+ method public java.lang.String getWidgetType();
+ method public java.lang.String getWidgetVersion();
+ }
+
+ public static final class TextClassificationContext.Builder {
+ ctor public TextClassificationContext.Builder(java.lang.String, java.lang.String);
+ method public android.view.textclassifier.TextClassificationContext build();
+ method public android.view.textclassifier.TextClassificationContext.Builder setWidgetVersion(java.lang.String);
+ }
+
public final class TextClassificationManager {
+ method public android.view.textclassifier.TextClassifier createTextClassificationSession(android.view.textclassifier.TextClassificationContext);
method public android.view.textclassifier.TextClassifier getTextClassifier();
+ method public void setTextClassificationSessionFactory(android.view.textclassifier.TextClassificationSessionFactory);
method public void setTextClassifier(android.view.textclassifier.TextClassifier);
}
+ public abstract interface TextClassificationSessionFactory {
+ method public abstract android.view.textclassifier.TextClassifier createTextClassificationSession(android.view.textclassifier.TextClassificationContext);
+ }
+
+ public final class TextClassificationSessionId 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.view.textclassifier.TextClassificationSessionId> CREATOR;
+ }
+
public abstract interface TextClassifier {
method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.view.textclassifier.TextClassification.Options);
method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int);
method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
+ method public default void destroy();
method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence, android.view.textclassifier.TextLinks.Options);
method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence);
- method public default android.view.textclassifier.Logger getLogger(android.view.textclassifier.Logger.Config);
method public default int getMaxGenerateLinksTextLength();
+ method public default boolean isDestroyed();
+ method public default void onSelectionEvent(android.view.textclassifier.SelectionEvent);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.view.textclassifier.TextSelection.Options);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
@@ -50407,6 +50460,15 @@
field public static final java.lang.String TYPE_PHONE = "phone";
field public static final java.lang.String TYPE_UNKNOWN = "";
field public static final java.lang.String TYPE_URL = "url";
+ field public static final java.lang.String WIDGET_TYPE_CUSTOM_EDITTEXT = "customedit";
+ field public static final java.lang.String WIDGET_TYPE_CUSTOM_TEXTVIEW = "customview";
+ field public static final java.lang.String WIDGET_TYPE_CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview";
+ field public static final java.lang.String WIDGET_TYPE_EDITTEXT = "edittext";
+ field public static final java.lang.String WIDGET_TYPE_EDIT_WEBVIEW = "edit-webview";
+ field public static final java.lang.String WIDGET_TYPE_TEXTVIEW = "textview";
+ field public static final java.lang.String WIDGET_TYPE_UNKNOWN = "unknown";
+ field public static final java.lang.String WIDGET_TYPE_UNSELECTABLE_TEXTVIEW = "nosel-textview";
+ field public static final java.lang.String WIDGET_TYPE_WEBVIEW = "webview";
}
public static final class TextClassifier.EntityConfig implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index e049f53..5568dba 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -400,10 +400,8 @@
}
public class WallpaperManager {
- method public void clearWallpaper();
method public void clearWallpaper(int, int);
method public void setDisplayOffset(android.os.IBinder, int, int);
- method public void setDisplayPadding(android.graphics.Rect);
method public boolean setWallpaperComponent(android.content.ComponentName);
}
@@ -5503,7 +5501,6 @@
field public static final int EUICC_OTA_NOT_NEEDED = 4; // 0x4
field public static final int EUICC_OTA_STATUS_UNAVAILABLE = 5; // 0x5
field public static final int EUICC_OTA_SUCCEEDED = 3; // 0x3
- field public static final java.lang.String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION";
field public static final java.lang.String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS";
}
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index ece3083..3b57d34 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -20,7 +20,6 @@
#include <dirent.h>
#include <errno.h>
-#include <wait.h>
#include <mutex>
#include <set>
@@ -53,49 +52,15 @@
const int FIELD_ID_INCIDENT_METADATA = 2;
// incident section parameters
-const int WAIT_MAX = 5;
-const struct timespec WAIT_INTERVAL_NS = {0, 200 * 1000 * 1000};
const char INCIDENT_HELPER[] = "/system/bin/incident_helper";
-const char GZIP[] = "/system/bin/gzip";
+const char* GZIP[] = {"/system/bin/gzip", NULL};
static pid_t fork_execute_incident_helper(const int id, Fpipe* p2cPipe, Fpipe* c2pPipe) {
const char* ihArgs[]{INCIDENT_HELPER, "-s", String8::format("%d", id).string(), NULL};
- return fork_execute_cmd(INCIDENT_HELPER, const_cast<char**>(ihArgs), p2cPipe, c2pPipe);
+ return fork_execute_cmd(const_cast<char**>(ihArgs), p2cPipe, c2pPipe);
}
// ================================================================================
-static status_t statusCode(int status) {
- if (WIFSIGNALED(status)) {
- VLOG("return by signal: %s", strerror(WTERMSIG(status)));
- return -WTERMSIG(status);
- } else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) {
- VLOG("return by exit: %s", strerror(WEXITSTATUS(status)));
- return -WEXITSTATUS(status);
- }
- return NO_ERROR;
-}
-
-static status_t kill_child(pid_t pid) {
- int status;
- VLOG("try to kill child process %d", pid);
- kill(pid, SIGKILL);
- if (waitpid(pid, &status, 0) == -1) return -1;
- return statusCode(status);
-}
-
-static status_t wait_child(pid_t pid) {
- int status;
- bool died = false;
- // wait for child to report status up to 1 seconds
- for (int loop = 0; !died && loop < WAIT_MAX; loop++) {
- if (waitpid(pid, &status, WNOHANG) == pid) died = true;
- // sleep for 0.2 second
- nanosleep(&WAIT_INTERVAL_NS, NULL);
- }
- if (!died) return kill_child(pid);
- return statusCode(status);
-}
-// ================================================================================
static status_t write_section_header(int fd, int sectionId, size_t size) {
uint8_t buf[20];
uint8_t* p = write_length_delimited_tag_header(buf, sectionId, size);
@@ -328,12 +293,15 @@
}
// ================================================================================
GZipSection::GZipSection(int id, const char* filename, ...) : Section(id) {
- name = "gzip ";
- name += filename;
va_list args;
va_start(args, filename);
mFilenames = varargs(filename, args);
va_end(args);
+ name = "gzip";
+ for (int i = 0; mFilenames[i] != NULL; i++) {
+ name += " ";
+ name += mFilenames[i];
+ }
}
GZipSection::~GZipSection() {}
@@ -362,8 +330,7 @@
return -errno;
}
- const char* gzipArgs[]{GZIP, NULL};
- pid_t pid = fork_execute_cmd(GZIP, const_cast<char**>(gzipArgs), &p2cPipe, &c2pPipe);
+ pid_t pid = fork_execute_cmd((char* const*)GZIP, &p2cPipe, &c2pPipe);
if (pid == -1) {
ALOGW("GZipSection '%s' failed to fork", this->name.string());
return -errno;
@@ -559,19 +526,27 @@
// ================================================================================
CommandSection::CommandSection(int id, const int64_t timeoutMs, const char* command, ...)
: Section(id, timeoutMs) {
- name = command;
va_list args;
va_start(args, command);
mCommand = varargs(command, args);
va_end(args);
+ name = "cmd";
+ for (int i = 0; mCommand[i] != NULL; i++) {
+ name += " ";
+ name += mCommand[i];
+ }
}
CommandSection::CommandSection(int id, const char* command, ...) : Section(id) {
- name = command;
va_list args;
va_start(args, command);
mCommand = varargs(command, args);
va_end(args);
+ name = "cmd";
+ for (int i = 0; mCommand[i] != NULL; i++) {
+ name += " ";
+ name += mCommand[i];
+ }
}
CommandSection::~CommandSection() { free(mCommand); }
@@ -586,26 +561,11 @@
return -errno;
}
- pid_t cmdPid = fork();
+ pid_t cmdPid = fork_execute_cmd((char* const*)mCommand, NULL, &cmdPipe);
if (cmdPid == -1) {
ALOGW("CommandSection '%s' failed to fork", this->name.string());
return -errno;
}
- // child process to execute the command as root
- if (cmdPid == 0) {
- // replace command's stdout with ihPipe's write Fd
- if (dup2(cmdPipe.writeFd().get(), STDOUT_FILENO) != 1 || !ihPipe.close() ||
- !cmdPipe.close()) {
- ALOGW("CommandSection '%s' failed to set up stdout: %s", this->name.string(),
- strerror(errno));
- _exit(EXIT_FAILURE);
- }
- execvp(this->mCommand[0], (char* const*)this->mCommand);
- int err = errno; // record command error code
- ALOGW("CommandSection '%s' failed in executing command: %s", this->name.string(),
- strerror(errno));
- _exit(err); // exit with command error code
- }
pid_t ihPid = fork_execute_incident_helper(this->id, &cmdPipe, &ihPipe);
if (ihPid == -1) {
ALOGW("CommandSection '%s' failed to fork", this->name.string());
diff --git a/cmds/incidentd/src/incidentd_util.cpp b/cmds/incidentd/src/incidentd_util.cpp
index d799513..7db1fa7 100644
--- a/cmds/incidentd/src/incidentd_util.cpp
+++ b/cmds/incidentd/src/incidentd_util.cpp
@@ -19,6 +19,7 @@
#include "incidentd_util.h"
#include <sys/prctl.h>
+#include <wait.h>
#include "section_list.h"
@@ -57,27 +58,28 @@
unique_fd& Fpipe::writeFd() { return mWrite; }
-pid_t fork_execute_cmd(const char* cmd, char* const argv[], Fpipe* input, Fpipe* output) {
+pid_t fork_execute_cmd(char* const argv[], Fpipe* input, Fpipe* output) {
// fork used in multithreaded environment, avoid adding unnecessary code in child process
pid_t pid = fork();
if (pid == 0) {
- if (TEMP_FAILURE_RETRY(dup2(input->readFd().get(), STDIN_FILENO)) < 0 || !input->close() ||
- TEMP_FAILURE_RETRY(dup2(output->writeFd().get(), STDOUT_FILENO)) < 0 ||
- !output->close()) {
- ALOGW("Can't setup stdin and stdout for command %s", cmd);
+ VLOG("[In child]cmd %s", argv[0]);
+ if (input != NULL && (TEMP_FAILURE_RETRY(dup2(input->readFd().get(), STDIN_FILENO)) < 0 ||
+ !input->close())) {
+ ALOGW("Failed to dup2 stdin.");
_exit(EXIT_FAILURE);
}
-
+ if (TEMP_FAILURE_RETRY(dup2(output->writeFd().get(), STDOUT_FILENO)) < 0 ||
+ !output->close()) {
+ ALOGW("Failed to dup2 stdout.");
+ _exit(EXIT_FAILURE);
+ }
/* make sure the child dies when incidentd dies */
prctl(PR_SET_PDEATHSIG, SIGKILL);
-
- execv(cmd, argv);
-
- ALOGW("%s failed in the child process: %s", cmd, strerror(errno));
- _exit(EXIT_FAILURE); // always exits with failure if any
+ execvp(argv[0], argv);
+ _exit(errno); // always exits with failure if any
}
// close the fds used in child process.
- input->readFd().reset();
+ if (input != NULL) input->readFd().reset();
output->writeFd().reset();
return pid;
}
@@ -111,3 +113,39 @@
clock_gettime(CLOCK_MONOTONIC, &ts);
return static_cast<uint64_t>(ts.tv_sec * NANOS_PER_SEC + ts.tv_nsec);
}
+
+// ================================================================================
+const int WAIT_MAX = 5;
+const struct timespec WAIT_INTERVAL_NS = {0, 200 * 1000 * 1000};
+
+static status_t statusCode(int status) {
+ if (WIFSIGNALED(status)) {
+ VLOG("return by signal: %s", strerror(WTERMSIG(status)));
+ return -WTERMSIG(status);
+ } else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) {
+ VLOG("return by exit: %s", strerror(WEXITSTATUS(status)));
+ return -WEXITSTATUS(status);
+ }
+ return NO_ERROR;
+}
+
+status_t kill_child(pid_t pid) {
+ int status;
+ VLOG("try to kill child process %d", pid);
+ kill(pid, SIGKILL);
+ if (waitpid(pid, &status, 0) == -1) return -1;
+ return statusCode(status);
+}
+
+status_t wait_child(pid_t pid) {
+ int status;
+ bool died = false;
+ // wait for child to report status up to 1 seconds
+ for (int loop = 0; !died && loop < WAIT_MAX; loop++) {
+ if (waitpid(pid, &status, WNOHANG) == pid) died = true;
+ // sleep for 0.2 second
+ nanosleep(&WAIT_INTERVAL_NS, NULL);
+ }
+ if (!died) return kill_child(pid);
+ return statusCode(status);
+}
diff --git a/cmds/incidentd/src/incidentd_util.h b/cmds/incidentd/src/incidentd_util.h
index 228d776..b5f6e21 100644
--- a/cmds/incidentd/src/incidentd_util.h
+++ b/cmds/incidentd/src/incidentd_util.h
@@ -18,12 +18,15 @@
#ifndef INCIDENTD_UTIL_H
#define INCIDENTD_UTIL_H
-#include <android-base/unique_fd.h>
-
#include <stdarg.h>
+#include <unistd.h>
+
+#include <android-base/unique_fd.h>
+#include <utils/Errors.h>
#include "Privacy.h"
+using namespace android;
using namespace android::base;
/**
@@ -52,8 +55,9 @@
/**
* Forks and exec a command with two pipes, one connects stdin for input,
* one connects stdout for output. It returns the pid of the child.
+ * Input pipe can be NULL to indicate child process doesn't read stdin.
*/
-pid_t fork_execute_cmd(const char* cmd, char* const argv[], Fpipe* input, Fpipe* output);
+pid_t fork_execute_cmd(char* const argv[], Fpipe* input, Fpipe* output);
/**
* Grabs varargs from stack and stores them in heap with NULL-terminated array.
@@ -65,4 +69,10 @@
*/
uint64_t Nanotime();
+/**
+ * Methods to wait or kill child process, return exit status code.
+ */
+status_t kill_child(pid_t pid);
+status_t wait_child(pid_t pid);
+
#endif // INCIDENTD_UTIL_H
diff --git a/cmds/incidentd/tests/Section_test.cpp b/cmds/incidentd/tests/Section_test.cpp
index 55192d0..f93839b 100644
--- a/cmds/incidentd/tests/Section_test.cpp
+++ b/cmds/incidentd/tests/Section_test.cpp
@@ -173,12 +173,12 @@
CommandSection cs3(1, 3123, "echo", "\"this is a test\"", "ooo", NULL);
CommandSection cs4(2, 43214, "single_command", NULL);
- EXPECT_THAT(cs1.name.string(), StrEq("echo"));
- EXPECT_THAT(cs2.name.string(), StrEq("single_command"));
+ EXPECT_THAT(cs1.name.string(), StrEq("cmd echo \"this is a test\" ooo"));
+ EXPECT_THAT(cs2.name.string(), StrEq("cmd single_command"));
EXPECT_EQ(3123, cs3.timeoutMs);
EXPECT_EQ(43214, cs4.timeoutMs);
- EXPECT_THAT(cs3.name.string(), StrEq("echo"));
- EXPECT_THAT(cs4.name.string(), StrEq("single_command"));
+ EXPECT_THAT(cs3.name.string(), StrEq("cmd echo \"this is a test\" ooo"));
+ EXPECT_THAT(cs4.name.string(), StrEq("cmd single_command"));
}
TEST_F(SectionTest, CommandSectionEcho) {
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index a35570b..a458c07 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -199,11 +199,6 @@
sp<MetricsManager> newMetricsManager =
new MetricsManager(key, config, mTimeBaseSec, mUidMap,
mAnomalyAlarmMonitor, mPeriodicAlarmMonitor);
- auto it = mMetricsManagers.find(key);
- if (it == mMetricsManagers.end() && mMetricsManagers.size() > StatsdStats::kMaxConfigCount) {
- ALOGE("Can't accept more configs!");
- return;
- }
if (newMetricsManager->isConfigValid()) {
mUidMap->OnConfigUpdated(key);
@@ -213,7 +208,6 @@
mUidMap->addListener(newMetricsManager.get());
}
mMetricsManagers[key] = newMetricsManager;
- // Why doesn't this work? mMetricsManagers.insert({key, std::move(newMetricsManager)});
VLOG("StatsdConfig valid");
} else {
// If there is any error in the config, don't use it.
diff --git a/cmds/statsd/src/anomaly/subscriber_util.cpp b/cmds/statsd/src/anomaly/subscriber_util.cpp
index e796d19..3f69a2c 100644
--- a/cmds/statsd/src/anomaly/subscriber_util.cpp
+++ b/cmds/statsd/src/anomaly/subscriber_util.cpp
@@ -55,8 +55,9 @@
}
break;
case Subscription::SubscriberInformationCase::kPerfettoDetails:
- if (!CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details())) {
- ALOGW("Failed to generate prefetto traces.");
+ if (!CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details(),
+ rule_id, configKey)) {
+ ALOGW("Failed to generate perfetto traces.");
}
break;
case Subscription::SubscriberInformationCase::kBroadcastSubscriberDetails:
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index d5a6e0e..5e75359 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -1340,10 +1340,10 @@
optional string launch_token = 13;
// The compiler filter used when when the package was optimized.
- optional string package_optimization_compilation_filter = 14;
+ optional int32 package_optimization_compilation_filter = 14;
// The reason why the package was optimized.
- optional string package_optimization_compilation_reason = 15;
+ optional int32 package_optimization_compilation_reason = 15;
}
message AppStartCancelChanged {
@@ -1936,7 +1936,8 @@
}
/**
- * Pulls the temperature of various parts of the device, in Celsius.
+ * Pulls the temperature of various parts of the device.
+ * The units are tenths of a degree Celsius. Eg: 30.3C is reported as 303.
*
* Pulled from:
* frameworks/base/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp
@@ -1948,6 +1949,6 @@
// The name of the temperature source. Eg. CPU0
optional string sensor_name = 2;
- // Temperature in degrees C.
- optional float temperature_C = 3;
+ // Temperature in tenths of a degree C.
+ optional int32 temperature_dC = 3;
}
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index aece141..ff25091 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -14,9 +14,13 @@
* limitations under the License.
*/
+#define DEBUG false // STOPSHIP if true
+#include "Log.h"
+
#include "config/ConfigManager.h"
#include "storage/StorageManager.h"
+#include "guardrail/StatsdStats.h"
#include "stats_util.h"
#include <android-base/file.h>
@@ -68,24 +72,37 @@
{
lock_guard <mutex> lock(mMutex);
- auto it = mConfigs.find(key);
-
const int numBytes = config.ByteSize();
vector<uint8_t> buffer(numBytes);
config.SerializeToArray(&buffer[0], numBytes);
- const bool isDuplicate =
- it != mConfigs.end() &&
- StorageManager::hasIdenticalConfig(key, buffer);
+ auto uidIt = mConfigs.find(key.GetUid());
+ // GuardRail: Limit the number of configs per uid.
+ if (uidIt != mConfigs.end()) {
+ auto it = uidIt->second.find(key);
+ if (it == uidIt->second.end() &&
+ uidIt->second.size() >= StatsdStats::kMaxConfigCountPerUid) {
+ ALOGE("ConfigManager: uid %d has exceeded the config count limit", key.GetUid());
+ return;
+ }
+ }
- // Update saved file on disk. We still update timestamp of file when
- // there exists a duplicate configuration to avoid garbage collection.
+ // Check if it's a duplicate config.
+ if (uidIt != mConfigs.end() && uidIt->second.find(key) != uidIt->second.end() &&
+ StorageManager::hasIdenticalConfig(key, buffer)) {
+ // This is a duplicate config.
+ ALOGI("ConfigManager This is a duplicate config %s", key.ToString().c_str());
+ // Update saved file on disk. We still update timestamp of file when
+ // there exists a duplicate configuration to avoid garbage collection.
+ update_saved_configs_locked(key, buffer, numBytes);
+ return;
+ }
+
+ // Update saved file on disk.
update_saved_configs_locked(key, buffer, numBytes);
- if (isDuplicate) return;
-
- // Add to set
- mConfigs.insert(key);
+ // Add to set.
+ mConfigs[key.GetUid()].insert(key);
for (sp<ConfigListener> listener : mListeners) {
broadcastList.push_back(listener);
@@ -113,11 +130,10 @@
{
lock_guard <mutex> lock(mMutex);
- auto it = mConfigs.find(key);
- if (it != mConfigs.end()) {
+ auto uidIt = mConfigs.find(key.GetUid());
+ if (uidIt != mConfigs.end() && uidIt->second.find(key) != uidIt->second.end()) {
// Remove from map
- mConfigs.erase(it);
-
+ uidIt->second.erase(key);
for (sp<ConfigListener> listener : mListeners) {
broadcastList.push_back(listener);
}
@@ -150,18 +166,20 @@
{
lock_guard <mutex> lock(mMutex);
- for (auto it = mConfigs.begin(); it != mConfigs.end();) {
+ auto uidIt = mConfigs.find(uid);
+ if (uidIt == mConfigs.end()) {
+ return;
+ }
+
+ for (auto it = uidIt->second.begin(); it != uidIt->second.end(); ++it) {
// Remove from map
- if (it->GetUid() == uid) {
remove_saved_configs(*it);
removed.push_back(*it);
mConfigReceivers.erase(*it);
- it = mConfigs.erase(it);
- } else {
- it++;
- }
}
+ mConfigs.erase(uidIt);
+
for (sp<ConfigListener> listener : mListeners) {
broadcastList.push_back(listener);
}
@@ -182,17 +200,16 @@
{
lock_guard <mutex> lock(mMutex);
-
- for (auto it = mConfigs.begin(); it != mConfigs.end();) {
- // Remove from map
- removed.push_back(*it);
- auto receiverIt = mConfigReceivers.find(*it);
- if (receiverIt != mConfigReceivers.end()) {
- mConfigReceivers.erase(*it);
+ for (auto uidIt = mConfigs.begin(); uidIt != mConfigs.end();) {
+ for (auto it = uidIt->second.begin(); it != uidIt->second.end();) {
+ // Remove from map
+ removed.push_back(*it);
+ it = uidIt->second.erase(it);
}
- it = mConfigs.erase(it);
+ uidIt = mConfigs.erase(uidIt);
}
+ mConfigReceivers.clear();
for (sp<ConfigListener> listener : mListeners) {
broadcastList.push_back(listener);
}
@@ -211,8 +228,10 @@
lock_guard<mutex> lock(mMutex);
vector<ConfigKey> ret;
- for (auto it = mConfigs.cbegin(); it != mConfigs.cend(); ++it) {
- ret.push_back(*it);
+ for (auto uidIt = mConfigs.cbegin(); uidIt != mConfigs.cend(); ++uidIt) {
+ for (auto it = uidIt->second.cbegin(); it != uidIt->second.cend(); ++it) {
+ ret.push_back(*it);
+ }
}
return ret;
}
@@ -231,13 +250,15 @@
void ConfigManager::Dump(FILE* out) {
lock_guard<mutex> lock(mMutex);
- fprintf(out, "CONFIGURATIONS (%d)\n", (int)mConfigs.size());
+ fprintf(out, "CONFIGURATIONS\n");
fprintf(out, " uid name\n");
- for (const auto& key : mConfigs) {
- fprintf(out, " %6d %lld\n", key.GetUid(), (long long)key.GetId());
- auto receiverIt = mConfigReceivers.find(key);
- if (receiverIt != mConfigReceivers.end()) {
- fprintf(out, " -> received by PendingIntent as binder\n");
+ for (auto uidIt = mConfigs.cbegin(); uidIt != mConfigs.cend(); ++uidIt) {
+ for (auto it = uidIt->second.cbegin(); it != uidIt->second.cend(); ++it) {
+ fprintf(out, " %6d %lld\n", it->GetUid(), (long long)it->GetId());
+ auto receiverIt = mConfigReceivers.find(*it);
+ if (receiverIt != mConfigReceivers.end()) {
+ fprintf(out, " -> received by PendingIntent as binder\n");
+ }
}
}
}
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
index 9a38188a..611c342 100644
--- a/cmds/statsd/src/config/ConfigManager.h
+++ b/cmds/statsd/src/config/ConfigManager.h
@@ -36,9 +36,6 @@
/**
* Keeps track of which configurations have been set from various sources.
- *
- * TODO: Store the configs persistently too.
- * TODO: Dump method for debugging.
*/
class ConfigManager : public virtual android::RefBase {
public:
@@ -125,9 +122,9 @@
void remove_saved_configs(const ConfigKey& key);
/**
- * Config keys that have been set.
+ * Maps from uid to the config keys that have been set.
*/
- std::set<ConfigKey> mConfigs;
+ std::map<int, std::set<ConfigKey>> mConfigs;
/**
* Each config key can be subscribed by up to one receiver, specified as IBinder from
diff --git a/cmds/statsd/src/external/Perfetto.cpp b/cmds/statsd/src/external/Perfetto.cpp
index b09d373..0554483 100644
--- a/cmds/statsd/src/external/Perfetto.cpp
+++ b/cmds/statsd/src/external/Perfetto.cpp
@@ -15,6 +15,7 @@
*/
#define DEBUG false // STOPSHIP if true
+#include "config/ConfigKey.h"
#include "Log.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert
@@ -22,6 +23,7 @@
#include <android-base/unique_fd.h>
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
@@ -36,7 +38,9 @@
namespace os {
namespace statsd {
-bool CollectPerfettoTraceAndUploadToDropbox(const PerfettoDetails& config) {
+bool CollectPerfettoTraceAndUploadToDropbox(const PerfettoDetails& config,
+ int64_t alert_id,
+ const ConfigKey& configKey) {
VLOG("Starting trace collection through perfetto");
if (!config.has_trace_config()) {
@@ -44,6 +48,13 @@
return false;
}
+ char alertId[20];
+ char configId[20];
+ char configUid[20];
+ snprintf(alertId, sizeof(alertId), "%" PRId64, alert_id);
+ snprintf(configId, sizeof(configId), "%" PRId64, configKey.GetId());
+ snprintf(configUid, sizeof(configUid), "%d", configKey.GetUid());
+
android::base::unique_fd readPipe;
android::base::unique_fd writePipe;
if (!android::base::Pipe(&readPipe, &writePipe)) {
@@ -82,7 +93,8 @@
}
execl("/system/bin/perfetto", "perfetto", "--background", "--config", "-", "--dropbox",
- kDropboxTag, nullptr);
+ kDropboxTag, "--alert-id", alertId, "--config-id", configId, "--config-uid",
+ configUid, nullptr);
// execl() doesn't return in case of success, if we get here something
// failed.
diff --git a/cmds/statsd/src/external/Perfetto.h b/cmds/statsd/src/external/Perfetto.h
index 2a5679c..1e7f728 100644
--- a/cmds/statsd/src/external/Perfetto.h
+++ b/cmds/statsd/src/external/Perfetto.h
@@ -24,13 +24,16 @@
namespace os {
namespace statsd {
+class ConfigKey;
class PerfettoDetails; // Declared in statsd_config.pb.h
// Starts the collection of a Perfetto trace with the given |config|.
// The trace is uploaded to Dropbox by the perfetto cmdline util once done.
// This method returns immediately after passing the config and does NOT wait
// for the full duration of the trace.
-bool CollectPerfettoTraceAndUploadToDropbox(const PerfettoDetails& config);
+bool CollectPerfettoTraceAndUploadToDropbox(const PerfettoDetails& config,
+ int64_t alert_id,
+ const ConfigKey& configKey);
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp b/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp
index b3acdfc..33a17de 100644
--- a/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp
+++ b/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp
@@ -120,7 +120,9 @@
wallClockTimestampNs, elapsedTimestampNs);
ptr->write((static_cast<int>(temps[i].type)));
ptr->write(temps[i].name);
- ptr->write(temps[i].currentValue);
+ // Convert the temperature to an int.
+ int32_t temp = static_cast<int>(temps[i].currentValue * 10);
+ ptr->write(temp);
ptr->init();
data->push_back(ptr);
}
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 7675888..7f8755b 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -78,17 +78,17 @@
~StatsdStats(){};
// TODO: set different limit if the device is low ram.
- const static int kDimensionKeySizeSoftLimit = 300;
- const static int kDimensionKeySizeHardLimit = 500;
+ const static int kDimensionKeySizeSoftLimit = 500;
+ const static int kDimensionKeySizeHardLimit = 800;
// Per atom dimension key size limit
static const std::map<int, std::pair<size_t, size_t>> kAtomDimensionKeySizeLimitMap;
- const static int kMaxConfigCount = 10;
+ const static int kMaxConfigCountPerUid = 10;
const static int kMaxAlertCountPerConfig = 100;
- const static int kMaxConditionCountPerConfig = 200;
- const static int kMaxMetricCountPerConfig = 300;
- const static int kMaxMatcherCountPerConfig = 500;
+ const static int kMaxConditionCountPerConfig = 300;
+ const static int kMaxMetricCountPerConfig = 1000;
+ const static int kMaxMatcherCountPerConfig = 800;
// The max number of old config stats we keep.
const static int kMaxIceBoxSize = 20;
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 8e2e43c..3af6105 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -369,6 +369,7 @@
Landroid/bluetooth/BluetoothGatt;->mAuthRetryState:I
Landroid/bluetooth/BluetoothGatt;->refresh()Z
Landroid/bluetooth/BluetoothHeadset;->close()V
+Landroid/bluetooth/BluetoothMapClient;->sendMessage(Landroid/bluetooth/BluetoothDevice;[Landroid/net/Uri;Ljava/lang/String;Landroid/app/PendingIntent;Landroid/app/PendingIntent;)Z
Landroid/bluetooth/BluetoothPan;->isTetheringOn()Z
Landroid/bluetooth/BluetoothPan;->setBluetoothTethering(Z)V
Landroid/bluetooth/BluetoothUuid;->RESERVED_UUIDS:[Landroid/os/ParcelUuid;
@@ -1109,6 +1110,7 @@
Landroid/net/wifi/p2p/WifiP2pManager;->deletePersistentGroup(Landroid/net/wifi/p2p/WifiP2pManager$Channel;ILandroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V
Landroid/net/wifi/p2p/WifiP2pManager;->requestPersistentGroupInfo(Landroid/net/wifi/p2p/WifiP2pManager$Channel;Landroid/net/wifi/p2p/WifiP2pManager$PersistentGroupInfoListener;)V
Landroid/net/wifi/p2p/WifiP2pManager;->setDeviceName(Landroid/net/wifi/p2p/WifiP2pManager$Channel;Ljava/lang/String;Landroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V
+Landroid/net/wifi/p2p/WifiP2pManager;->setWifiP2pChannels(Landroid/net/wifi/p2p/WifiP2pManager$Channel;IILandroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V
Landroid/net/wifi/ScanResult;->anqpDomainId:I
Landroid/net/wifi/ScanResult;->anqpLines:Ljava/util/List;
Landroid/net/wifi/ScanResult;->distanceCm:I
diff --git a/config/hiddenapi-vendor-list.txt b/config/hiddenapi-vendor-list.txt
index 2f0bba1..77bb0bb 100644
--- a/config/hiddenapi-vendor-list.txt
+++ b/config/hiddenapi-vendor-list.txt
@@ -32,6 +32,7 @@
Landroid/app/IActivityManager;->getTaskSnapshot(IZ)Landroid/app/ActivityManager$TaskSnapshot;
Landroid/app/IActivityManager;->registerTaskStackListener(Landroid/app/ITaskStackListener;)V
Landroid/app/IActivityManager;->removeTask(I)Z
+Landroid/app/IActivityManager;->requestBugReport(I)V
Landroid/app/IActivityManager;->startActivityAsUser(Landroid/app/IApplicationThread;Ljava/lang/String;Landroid/content/Intent;Ljava/lang/String;Landroid/os/IBinder;Ljava/lang/String;IILandroid/app/ProfilerInfo;Landroid/os/Bundle;I)I
Landroid/app/IActivityManager;->startActivityFromRecents(ILandroid/os/Bundle;)I
Landroid/app/IActivityManager;->startActivity(Landroid/app/IApplicationThread;Ljava/lang/String;Landroid/content/Intent;Ljava/lang/String;Landroid/os/IBinder;Ljava/lang/String;IILandroid/app/ProfilerInfo;Landroid/os/Bundle;)I
@@ -42,6 +43,7 @@
Landroid/app/IAssistDataReceiver;->onHandleAssistScreenshot(Landroid/graphics/Bitmap;)V
Landroid/app/IAssistDataReceiver$Stub;-><init>()V
Landroid/app/KeyguardManager;->isDeviceLocked(I)Z
+Landroid/app/NotificationManager;->cancelAsUser(Ljava/lang/String;ILandroid/os/UserHandle;)V
Landroid/app/StatusBarManager;->removeIcon(Ljava/lang/String;)V
Landroid/app/StatusBarManager;->setIcon(Ljava/lang/String;IILjava/lang/String;)V
Landroid/app/TaskStackListener;->onActivityDismissingDockedStack()V
@@ -106,6 +108,11 @@
Landroid/graphics/Bitmap;->createHardwareBitmap(Landroid/graphics/GraphicBuffer;)Landroid/graphics/Bitmap;
Landroid/graphics/Canvas;->clipRegion(Landroid/graphics/Region;Landroid/graphics/Region$Op;)Z
Landroid/graphics/Canvas;->clipRegion(Landroid/graphics/Region;)Z
+Landroid/graphics/Canvas;->save(I)I
+Landroid/graphics/Canvas;->saveLayerAlpha(FFFFII)I
+Landroid/graphics/Canvas;->saveLayerAlpha(Landroid/graphics/RectF;II)I
+Landroid/graphics/Canvas;->saveLayer(FFFFLandroid/graphics/Paint;I)I
+Landroid/graphics/Canvas;->saveLayer(Landroid/graphics/RectF;Landroid/graphics/Paint;I)I
Landroid/graphics/drawable/Drawable;->isProjected()Z
Landroid/graphics/drawable/Drawable;->updateTintFilter(Landroid/graphics/PorterDuffColorFilter;Landroid/content/res/ColorStateList;Landroid/graphics/PorterDuff$Mode;)Landroid/graphics/PorterDuffColorFilter;
Landroid/hardware/camera2/CaptureRequest$Key;-><init>(Ljava/lang/String;Ljava/lang/Class;)V
@@ -308,6 +315,7 @@
Landroid/net/SntpClient;->getNtpTime()J
Landroid/net/SntpClient;->getNtpTimeReference()J
Landroid/net/SntpClient;->getRoundTripTime()J
+Landroid/net/SntpClient;->requestTime(Ljava/lang/String;I)Z
Landroid/net/StaticIpConfiguration;->dnsServers:Ljava/util/ArrayList;
Landroid/net/StaticIpConfiguration;->domains:Ljava/lang/String;
Landroid/net/StaticIpConfiguration;->gateway:Ljava/net/InetAddress;
@@ -402,6 +410,9 @@
Landroid/service/dreams/DreamService;->isDozing()Z
Landroid/service/dreams/DreamService;->startDozing()V
Landroid/service/dreams/DreamService;->stopDozing()V
+Landroid/service/euicc/EuiccProfileInfo;-><init>(Ljava/lang/String;[Landroid/telephony/UiccAccessRule;Ljava/lang/String;)V
+Landroid/service/euicc/GetDefaultDownloadableSubscriptionListResult;->result:I
+Landroid/service/euicc/GetDownloadableSubscriptionMetadataResult;->result:I
Landroid/service/vr/VrListenerService;->onCurrentVrActivityChanged(Landroid/content/ComponentName;ZI)V
Landroid/system/NetlinkSocketAddress;-><init>(II)V
Landroid/system/Os;->bind(Ljava/io/FileDescriptor;Ljava/net/SocketAddress;)V
@@ -418,16 +429,42 @@
Landroid/telecom/ParcelableCall;->getId()Ljava/lang/String;
Landroid/telecom/TelecomManager;->from(Landroid/content/Context;)Landroid/telecom/TelecomManager;
Landroid/telecom/VideoProfile$CameraCapabilities;-><init>(IIZF)V
+Landroid/telephony/euicc/DownloadableSubscription;->encodedActivationCode:Ljava/lang/String;
+Landroid/telephony/euicc/DownloadableSubscription;->setAccessRules([Landroid/telephony/UiccAccessRule;)V
+Landroid/telephony/euicc/DownloadableSubscription;->setCarrierName(Ljava/lang/String;)V
+Landroid/telephony/ims/compat/feature/ImsFeature;->getFeatureState()I
+Landroid/telephony/ims/compat/feature/ImsFeature;->setFeatureState(I)V
Landroid/telephony/ims/compat/feature/MMTelFeature;-><init>()V
Landroid/telephony/ims/compat/ImsService;-><init>()V
+Landroid/telephony/ims/compat/ImsService;->mImsServiceController:Landroid/os/IBinder;
Landroid/telephony/ims/compat/stub/ImsCallSessionImplBase;-><init>()V
+Landroid/telephony/ims/compat/stub/ImsConfigImplBase;->getIImsConfig()Lcom/android/ims/internal/IImsConfig;
Landroid/telephony/ims/compat/stub/ImsConfigImplBase;-><init>(Landroid/content/Context;)V
Landroid/telephony/ims/compat/stub/ImsUtListenerImplBase;-><init>()V
Landroid/telephony/ims/ImsCallForwardInfo;-><init>()V
+Landroid/telephony/ims/ImsCallForwardInfo;->mCondition:I
+Landroid/telephony/ims/ImsCallForwardInfo;->mNumber:Ljava/lang/String;
+Landroid/telephony/ims/ImsCallForwardInfo;->mServiceClass:I
+Landroid/telephony/ims/ImsCallForwardInfo;->mStatus:I
+Landroid/telephony/ims/ImsCallForwardInfo;->mTimeSeconds:I
+Landroid/telephony/ims/ImsCallForwardInfo;->mToA:I
+Landroid/telephony/ims/ImsCallProfile;->mCallExtras:Landroid/os/Bundle;
+Landroid/telephony/ims/ImsCallProfile;->mCallType:I
+Landroid/telephony/ims/ImsCallProfile;->mMediaProfile:Landroid/telephony/ims/ImsStreamMediaProfile;
+Landroid/telephony/ims/ImsCallProfile;->mRestrictCause:I
Landroid/telephony/ims/ImsCallProfile;->presentationToOIR(I)I
Landroid/telephony/ims/ImsExternalCallState;-><init>(ILandroid/net/Uri;ZIIZ)V
Landroid/telephony/ims/ImsReasonInfo;-><init>(II)V
+Landroid/telephony/ims/ImsReasonInfo;->mCode:I
+Landroid/telephony/ims/ImsReasonInfo;->mExtraCode:I
+Landroid/telephony/ims/ImsReasonInfo;->mExtraMessage:Ljava/lang/String;
+Landroid/telephony/ims/ImsSsInfo;->mIcbNum:Ljava/lang/String;
+Landroid/telephony/ims/ImsSsInfo;->mStatus:I
Landroid/telephony/ims/ImsStreamMediaProfile;-><init>()V
+Landroid/telephony/ims/ImsStreamMediaProfile;->mAudioDirection:I
+Landroid/telephony/ims/ImsStreamMediaProfile;->mAudioQuality:I
+Landroid/telephony/ims/ImsStreamMediaProfile;->mVideoDirection:I
+Landroid/telephony/ims/ImsVideoCallProvider;->getInterface()Lcom/android/ims/internal/IImsVideoCallProvider;
Landroid/telephony/mbms/IMbmsStreamingSessionCallback$Stub;-><init>()V
Landroid/telephony/mbms/IStreamingServiceCallback$Stub;-><init>()V
Landroid/telephony/mbms/vendor/IMbmsStreamingService;->getPlaybackUri(ILjava/lang/String;)Landroid/net/Uri;
@@ -449,6 +486,7 @@
Landroid/telephony/Rlog;->e(Ljava/lang/String;Ljava/lang/String;)I
Landroid/telephony/Rlog;->e(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I
Landroid/telephony/Rlog;->i(Ljava/lang/String;Ljava/lang/String;)I
+Landroid/telephony/ServiceState;->bitmaskHasTech(II)Z
Landroid/telephony/ServiceState;->getDataRegState()I
Landroid/telephony/ServiceState;->getDataRoaming()Z
Landroid/telephony/ServiceState;->getRilDataRadioTechnology()I
@@ -475,12 +513,19 @@
Landroid/telephony/SubscriptionManager;->setDisplayName(Ljava/lang/String;IJ)I
Landroid/telephony/SubscriptionManager;->setIconTint(II)I
Landroid/telephony/TelephonyManager;->getIntAtIndex(Landroid/content/ContentResolver;Ljava/lang/String;I)I
+Landroid/telephony/TelephonyManager;->getIsimDomain()Ljava/lang/String;
Landroid/telephony/TelephonyManager;->getNetworkTypeName()Ljava/lang/String;
+Landroid/telephony/TelephonyManager;->getPreferredNetworkType(I)I
+Landroid/telephony/TelephonyManager;->getServiceStateForSubscriber(I)Landroid/telephony/ServiceState;
Landroid/telephony/TelephonyManager;->getVoiceMessageCount()I
Landroid/telephony/TelephonyManager;->getVoiceNetworkType(I)I
+Landroid/telephony/TelephonyManager;->isImsRegistered()Z
+Landroid/telephony/TelephonyManager;->isWifiCallingAvailable()Z
Landroid/telephony/TelephonyManager$MultiSimVariants;->DSDA:Landroid/telephony/TelephonyManager$MultiSimVariants;
Landroid/telephony/TelephonyManager$MultiSimVariants;->DSDS:Landroid/telephony/TelephonyManager$MultiSimVariants;
+Landroid/telephony/TelephonyManager;->nvResetConfig(I)Z
Landroid/telephony/TelephonyManager;->putIntAtIndex(Landroid/content/ContentResolver;Ljava/lang/String;II)Z
+Landroid/telephony/TelephonyManager;->setPreferredNetworkType(II)Z
Landroid/text/TextUtils;->isPrintableAsciiOnly(Ljava/lang/CharSequence;)Z
Landroid/util/FloatMath;->ceil(F)F
Landroid/util/FloatMath;->cos(F)F
@@ -498,6 +543,8 @@
Landroid/util/LongArray;->get(I)J
Landroid/util/LongArray;-><init>()V
Landroid/util/LongArray;->size()I
+Landroid/util/RecurrenceRule;->buildRecurringMonthly(ILjava/time/ZoneId;)Landroid/util/RecurrenceRule;
+Landroid/util/RecurrenceRule;->start:Ljava/time/ZonedDateTime;
Landroid/util/Slog;->e(Ljava/lang/String;Ljava/lang/String;)I
Landroid/util/Slog;->e(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I
Landroid/util/Slog;->println(ILjava/lang/String;Ljava/lang/String;)I
@@ -586,6 +633,7 @@
Lcom/android/ims/internal/IImsCallSessionListener;->callSessionTtyModeReceived(Lcom/android/ims/internal/IImsCallSession;I)V
Lcom/android/ims/internal/IImsCallSessionListener;->callSessionUpdated(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsCallProfile;)V
Lcom/android/ims/internal/IImsRegistrationListener;->registrationAssociatedUriChanged([Landroid/net/Uri;)V
+Lcom/android/ims/internal/IImsRegistrationListener;->registrationChangeFailed(ILandroid/telephony/ims/ImsReasonInfo;)V
Lcom/android/ims/internal/IImsRegistrationListener;->registrationConnectedWithRadioTech(I)V
Lcom/android/ims/internal/IImsRegistrationListener;->registrationDisconnected(Landroid/telephony/ims/ImsReasonInfo;)V
Lcom/android/ims/internal/IImsRegistrationListener;->registrationFeatureCapabilityChanged(I[I[I)V
@@ -598,6 +646,27 @@
Lcom/android/ims/internal/IImsUtListener;->utConfigurationQueryFailed(Lcom/android/ims/internal/IImsUt;ILandroid/telephony/ims/ImsReasonInfo;)V
Lcom/android/ims/internal/IImsUtListener;->utConfigurationUpdated(Lcom/android/ims/internal/IImsUt;I)V
Lcom/android/ims/internal/IImsUtListener;->utConfigurationUpdateFailed(Lcom/android/ims/internal/IImsUt;ILandroid/telephony/ims/ImsReasonInfo;)V
+Lcom/android/ims/internal/uce/common/CapInfo;->getCapTimestamp()J
+Lcom/android/ims/internal/uce/common/CapInfo;->isCdViaPresenceSupported()Z
+Lcom/android/ims/internal/uce/common/CapInfo;->isFtHttpSupported()Z
+Lcom/android/ims/internal/uce/common/CapInfo;->isFtSnFSupported()Z
+Lcom/android/ims/internal/uce/common/CapInfo;->isFtSupported()Z
+Lcom/android/ims/internal/uce/common/CapInfo;->isFtThumbSupported()Z
+Lcom/android/ims/internal/uce/common/CapInfo;->isFullSnFGroupChatSupported()Z
+Lcom/android/ims/internal/uce/common/CapInfo;->isGeoPullFtSupported()Z
+Lcom/android/ims/internal/uce/common/CapInfo;->isGeoPullSupported()Z
+Lcom/android/ims/internal/uce/common/CapInfo;->isGeoPushSupported()Z
+Lcom/android/ims/internal/uce/common/CapInfo;->isImSupported()Z
+Lcom/android/ims/internal/uce/common/CapInfo;->isIpVideoSupported()Z
+Lcom/android/ims/internal/uce/common/CapInfo;->isIpVoiceSupported()Z
+Lcom/android/ims/internal/uce/common/CapInfo;->isIsSupported()Z
+Lcom/android/ims/internal/uce/common/CapInfo;->isRcsIpVideoCallSupported()Z
+Lcom/android/ims/internal/uce/common/CapInfo;->isRcsIpVideoOnlyCallSupported()Z
+Lcom/android/ims/internal/uce/common/CapInfo;->isRcsIpVoiceCallSupported()Z
+Lcom/android/ims/internal/uce/common/CapInfo;->isSmSupported()Z
+Lcom/android/ims/internal/uce/common/CapInfo;->isSpSupported()Z
+Lcom/android/ims/internal/uce/common/CapInfo;->isVsDuringCSSupported()Z
+Lcom/android/ims/internal/uce/common/CapInfo;->isVsSupported()Z
Lcom/android/ims/internal/uce/common/StatusCode;->getStatusCode()I
Lcom/android/ims/internal/uce/common/UceLong;->getClientId()I
Lcom/android/ims/internal/uce/common/UceLong;-><init>()V
@@ -617,6 +686,24 @@
Lcom/android/ims/internal/uce/options/IOptionsService;->responseIncomingOptions(IIILjava/lang/String;Lcom/android/ims/internal/uce/options/OptionsCapInfo;Z)Lcom/android/ims/internal/uce/common/StatusCode;
Lcom/android/ims/internal/uce/options/IOptionsService;->setMyInfo(ILcom/android/ims/internal/uce/common/CapInfo;I)Lcom/android/ims/internal/uce/common/StatusCode;
Lcom/android/ims/internal/uce/options/IOptionsService$Stub;-><init>()V
+Lcom/android/ims/internal/uce/options/OptionsCapInfo;->getCapInfo()Lcom/android/ims/internal/uce/common/CapInfo;
+Lcom/android/ims/internal/uce/options/OptionsCapInfo;->getSdp()Ljava/lang/String;
+Lcom/android/ims/internal/uce/options/OptionsCapInfo;-><init>()V
+Lcom/android/ims/internal/uce/options/OptionsCapInfo;->setCapInfo(Lcom/android/ims/internal/uce/common/CapInfo;)V
+Lcom/android/ims/internal/uce/options/OptionsCapInfo;->setSdp(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/options/OptionsCmdId;-><init>()V
+Lcom/android/ims/internal/uce/options/OptionsCmdId;->setCmdId(I)V
+Lcom/android/ims/internal/uce/options/OptionsCmdStatus;-><init>()V
+Lcom/android/ims/internal/uce/options/OptionsCmdStatus;->setCapInfo(Lcom/android/ims/internal/uce/common/CapInfo;)V
+Lcom/android/ims/internal/uce/options/OptionsCmdStatus;->setCmdId(Lcom/android/ims/internal/uce/options/OptionsCmdId;)V
+Lcom/android/ims/internal/uce/options/OptionsCmdStatus;->setStatus(Lcom/android/ims/internal/uce/common/StatusCode;)V
+Lcom/android/ims/internal/uce/options/OptionsCmdStatus;->setUserData(I)V
+Lcom/android/ims/internal/uce/options/OptionsSipResponse;-><init>()V
+Lcom/android/ims/internal/uce/options/OptionsSipResponse;->setCmdId(Lcom/android/ims/internal/uce/options/OptionsCmdId;)V
+Lcom/android/ims/internal/uce/options/OptionsSipResponse;->setReasonPhrase(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/options/OptionsSipResponse;->setRequestId(I)V
+Lcom/android/ims/internal/uce/options/OptionsSipResponse;->setRetryAfter(I)V
+Lcom/android/ims/internal/uce/options/OptionsSipResponse;->setSipResponseCode(I)V
Lcom/android/ims/internal/uce/presence/IPresenceListener;->capInfoReceived(Ljava/lang/String;[Lcom/android/ims/internal/uce/presence/PresTupleInfo;)V
Lcom/android/ims/internal/uce/presence/IPresenceListener;->cmdStatus(Lcom/android/ims/internal/uce/presence/PresCmdStatus;)V
Lcom/android/ims/internal/uce/presence/IPresenceListener;->getVersionCb(Ljava/lang/String;)V
@@ -635,6 +722,12 @@
Lcom/android/ims/internal/uce/presence/IPresenceService;->removeListener(ILcom/android/ims/internal/uce/common/UceLong;)Lcom/android/ims/internal/uce/common/StatusCode;
Lcom/android/ims/internal/uce/presence/IPresenceService;->setNewFeatureTag(ILjava/lang/String;Lcom/android/ims/internal/uce/presence/PresServiceInfo;I)Lcom/android/ims/internal/uce/common/StatusCode;
Lcom/android/ims/internal/uce/presence/IPresenceService$Stub;-><init>()V
+Lcom/android/ims/internal/uce/presence/PresCapInfo;->getCapInfo()Lcom/android/ims/internal/uce/common/CapInfo;
+Lcom/android/ims/internal/uce/presence/PresCapInfo;->getContactUri()Ljava/lang/String;
+Lcom/android/ims/internal/uce/presence/PresServiceInfo;->getMediaType()I
+Lcom/android/ims/internal/uce/presence/PresServiceInfo;->getServiceDesc()Ljava/lang/String;
+Lcom/android/ims/internal/uce/presence/PresServiceInfo;->getServiceId()Ljava/lang/String;
+Lcom/android/ims/internal/uce/presence/PresServiceInfo;->getServiceVer()Ljava/lang/String;
Lcom/android/ims/internal/uce/presence/PresSipResponse;->getCmdId()Lcom/android/ims/internal/uce/presence/PresCmdId;
Lcom/android/ims/internal/uce/presence/PresSipResponse;->getReasonPhrase()Ljava/lang/String;
Lcom/android/ims/internal/uce/presence/PresSipResponse;->getRequestId()I
@@ -684,6 +777,9 @@
Lcom/android/internal/os/BatteryStatsImpl;->getPhoneSignalStrengthTime(IJI)J
Lcom/android/internal/os/BatteryStatsImpl;->getScreenBrightnessTime(IJI)J
Lcom/android/internal/os/BatteryStatsImpl;->getWifiOnTime(JI)J
+Lcom/android/internal/os/SomeArgs;->arg1:Ljava/lang/Object;
+Lcom/android/internal/os/SomeArgs;->arg2:Ljava/lang/Object;
+Lcom/android/internal/os/SomeArgs;->arg3:Ljava/lang/Object;
Lcom/android/internal/os/SomeArgs;->obtain()Lcom/android/internal/os/SomeArgs;
Lcom/android/internal/os/SomeArgs;->recycle()V
Lcom/android/internal/R$styleable;->NumberPicker:[I
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 3047cdb..289a4dd 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -959,8 +959,10 @@
* @hide
*/
static public boolean isHighEndGfx() {
- return !isLowRamDeviceStatic() &&
- !Resources.getSystem().getBoolean(com.android.internal.R.bool.config_avoidGfxAccel);
+ return !isLowRamDeviceStatic()
+ && !RoSystemProperties.CONFIG_AVOID_GFX_ACCEL
+ && !Resources.getSystem()
+ .getBoolean(com.android.internal.R.bool.config_avoidGfxAccel);
}
/**
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index f38c80c..a68136b 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2167,15 +2167,16 @@
@Override
public PersistableBundle getSuspendedPackageAppExtras(String packageName) {
try {
- return mPM.getPackageSuspendedAppExtras(packageName, mContext.getUserId());
+ return mPM.getSuspendedPackageAppExtras(packageName, mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
@Override
- public PersistableBundle getSuspendedPackageAppExtras() {
- return getSuspendedPackageAppExtras(mContext.getOpPackageName());
+ public Bundle getSuspendedPackageAppExtras() {
+ final PersistableBundle extras = getSuspendedPackageAppExtras(mContext.getOpPackageName());
+ return extras != null ? new Bundle(extras.deepCopy()) : null;
}
@Override
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 99efecd..e1a02fa 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -94,6 +94,7 @@
void registerUidObserver(in IUidObserver observer, int which, int cutpoint,
String callingPackage);
void unregisterUidObserver(in IUidObserver observer);
+ boolean isUidActive(int uid, String callingPackage);
// =============== End of transactions used on native side as well ============================
// Special low-level communication with activity manager.
@@ -322,12 +323,14 @@
/**
* Informs ActivityManagerService that the keyguard is showing.
*
- * @param showing True if the keyguard is showing, false otherwise.
+ * @param showingKeyguard True if the keyguard is showing, false otherwise.
+ * @param showingAod True if AOD is showing, false otherwise.
* @param secondaryDisplayShowing The displayId of the secondary display on which the keyguard
* is showing, or INVALID_DISPLAY if there is no such display. Only meaningful if
* showing is true.
*/
- void setLockScreenShown(boolean showing, int secondaryDisplayShowing);
+ void setLockScreenShown(boolean showingKeyguard, boolean showingAod,
+ int secondaryDisplayShowing);
boolean finishActivityAffinity(in IBinder token);
// This is not public because you need to be very careful in how you
// manage your activity to make sure it is always the uid you expect.
diff --git a/core/java/android/app/RemoteAction.java b/core/java/android/app/RemoteAction.java
index e7fe407..47741c0 100644
--- a/core/java/android/app/RemoteAction.java
+++ b/core/java/android/app/RemoteAction.java
@@ -18,14 +18,9 @@
import android.annotation.NonNull;
import android.graphics.drawable.Icon;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.RemoteException;
import android.text.TextUtils;
-import android.util.Log;
import java.io.PrintWriter;
@@ -42,6 +37,7 @@
private final CharSequence mContentDescription;
private final PendingIntent mActionIntent;
private boolean mEnabled;
+ private boolean mShouldShowIcon;
RemoteAction(Parcel in) {
mIcon = Icon.CREATOR.createFromParcel(in);
@@ -49,6 +45,7 @@
mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
mActionIntent = PendingIntent.CREATOR.createFromParcel(in);
mEnabled = in.readBoolean();
+ mShouldShowIcon = in.readBoolean();
}
public RemoteAction(@NonNull Icon icon, @NonNull CharSequence title,
@@ -62,6 +59,7 @@
mContentDescription = contentDescription;
mActionIntent = intent;
mEnabled = true;
+ mShouldShowIcon = true;
}
/**
@@ -79,6 +77,20 @@
}
/**
+ * Sets whether the icon should be shown.
+ */
+ public void setShouldShowIcon(boolean shouldShowIcon) {
+ mShouldShowIcon = shouldShowIcon;
+ }
+
+ /**
+ * Return whether the icon should be shown.
+ */
+ public boolean shouldShowIcon() {
+ return mShouldShowIcon;
+ }
+
+ /**
* Return an icon representing the action.
*/
public @NonNull Icon getIcon() {
@@ -125,6 +137,7 @@
TextUtils.writeToParcel(mContentDescription, out, flags);
mActionIntent.writeToParcel(out, flags);
out.writeBoolean(mEnabled);
+ out.writeBoolean(mShouldShowIcon);
}
public void dump(String prefix, PrintWriter pw) {
@@ -134,6 +147,7 @@
pw.print(" contentDescription=" + mContentDescription);
pw.print(" icon=" + mIcon);
pw.print(" action=" + mActionIntent.getIntent());
+ pw.print(" shouldShowIcon=" + mShouldShowIcon);
pw.println();
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 19240e2..465340f 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -57,10 +57,7 @@
import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.service.wallpaper.WallpaperService;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -444,6 +441,9 @@
synchronized (this) {
mCachedWallpaper = null;
mCachedWallpaperUserId = 0;
+ if (mDefaultWallpaper != null) {
+ mDefaultWallpaper.recycle();
+ }
mDefaultWallpaper = null;
}
}
@@ -915,9 +915,14 @@
/**
* Get the primary colors of a wallpaper.
*
- * <p>You can expect null if:
- * • Colors are still being processed by the system.
- * • A live wallpaper doesn't implement {@link WallpaperService.Engine#onComputeColors()}.
+ * <p>This method can return {@code null} when:
+ * <ul>
+ * <li>Colors are still being processed by the system.</li>
+ * <li>The user has chosen to use a live wallpaper: live wallpapers might not
+ * implement
+ * {@link android.service.wallpaper.WallpaperService.Engine#onComputeColors()
+ * WallpaperService.Engine#onComputeColors()}.</li>
+ * </ul>
*
* @param which Wallpaper type. Must be either {@link #FLAG_SYSTEM} or
* {@link #FLAG_LOCK}.
@@ -929,7 +934,7 @@
}
/**
- * Get the primary colors of a wallpaper
+ * Get the primary colors of the wallpaper configured in the given user.
* @param which wallpaper type. Must be either {@link #FLAG_SYSTEM} or
* {@link #FLAG_LOCK}
* @param userId Owner of the wallpaper.
@@ -1559,11 +1564,13 @@
* Specify extra padding that the wallpaper should have outside of the display.
* That is, the given padding supplies additional pixels the wallpaper should extend
* outside of the display itself.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#SET_WALLPAPER_HINTS}.
+ *
* @param padding The number of pixels the wallpaper should extend beyond the display,
* on its left, top, right, and bottom sides.
- * @hide
*/
- @SystemApi
@RequiresPermission(android.Manifest.permission.SET_WALLPAPER_HINTS)
public void setDisplayPadding(Rect padding) {
try {
@@ -1600,11 +1607,11 @@
}
/**
- * Clear the wallpaper.
+ * Reset all wallpaper to the factory default.
*
- * @hide
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#SET_WALLPAPER}.
*/
- @SystemApi
@RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
public void clearWallpaper() {
clearWallpaper(FLAG_LOCK, mContext.getUserId());
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 3015398..436947f 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3742,7 +3742,7 @@
public static final int KEYGUARD_DISABLE_TRUST_AGENTS = 1 << 4;
/**
- * Disable fingerprint sensor on keyguard secure screens (e.g. PIN/Pattern/Password).
+ * Disable fingerprint authentication on keyguard secure screens (e.g. PIN/Pattern/Password).
*/
public static final int KEYGUARD_DISABLE_FINGERPRINT = 1 << 5;
@@ -3752,6 +3752,25 @@
public static final int KEYGUARD_DISABLE_REMOTE_INPUT = 1 << 6;
/**
+ * Disable face authentication on keyguard secure screens (e.g. PIN/Pattern/Password).
+ */
+ public static final int KEYGUARD_DISABLE_FACE = 1 << 7;
+
+ /**
+ * Disable iris authentication on keyguard secure screens (e.g. PIN/Pattern/Password).
+ */
+ public static final int KEYGUARD_DISABLE_IRIS = 1 << 8;
+
+ /**
+ * Disable all biometric authentication on keyguard secure screens (e.g. PIN/Pattern/Password).
+ */
+ public static final int KEYGUARD_DISABLE_BIOMETRICS =
+ DevicePolicyManager.KEYGUARD_DISABLE_FACE
+ | DevicePolicyManager.KEYGUARD_DISABLE_IRIS
+ | DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
+
+
+ /**
* Disable all current and future keyguard customizations.
*/
public static final int KEYGUARD_DISABLE_FEATURES_ALL = 0x7fffffff;
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index fb1c2d0..b7a8da5 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -84,6 +84,8 @@
public static final String FLAG_REQUIRED_CLIENT_SIDE_ENCRYPTION = "clientSideEncryption";
public static final String FLAG_REQUIRED_DEVICE_TO_DEVICE_TRANSFER = "deviceToDeviceTransfer";
+ public static final String FLAG_REQUIRED_FAKE_CLIENT_SIDE_ENCRYPTION =
+ "fakeClientSideEncryption";
/**
* @hide
@@ -600,6 +602,8 @@
case FLAG_REQUIRED_DEVICE_TO_DEVICE_TRANSFER:
flags |= BackupAgent.FLAG_DEVICE_TO_DEVICE_TRANSFER;
break;
+ case FLAG_REQUIRED_FAKE_CLIENT_SIDE_ENCRYPTION:
+ flags |= BackupAgent.FLAG_FAKE_CLIENT_SIDE_ENCRYPTION_ENABLED;
default:
Log.w(TAG, "Unrecognized requiredFlag provided, value: \"" + f + "\"");
}
diff --git a/core/java/android/app/slice/SliceMetrics.java b/core/java/android/app/slice/SliceMetrics.java
index a7069bc..20c1390 100644
--- a/core/java/android/app/slice/SliceMetrics.java
+++ b/core/java/android/app/slice/SliceMetrics.java
@@ -25,7 +25,7 @@
/**
* Metrics interface for slices.
*
- * This is called by SliceView, so Slice develoers should
+ * This is called by SliceView, so Slice developers should
* not need to reference this class.
*
* @see androidx.slice.widget.SliceView
@@ -55,9 +55,18 @@
}
/**
- * To be called whenever the use interacts with a slice.
- *@param subSlice The URI of the sub-slice that is the subject of the interaction.
+ * To be called whenever the user invokes a discrete action via a slice.
+ *
+ * <P>
+ * Use this for discrete events like a tap or the end of a drag,
+ * not for a continuous streams of events, such as the motion during a gesture.
+ * </P>
+ *
+ * @see androidx.slice.widget.EventInfo#actionType
+ *
+ * @param actionType The type of the event.
+ * @param subSlice The URI of the sub-slice that is the subject of the interaction.
*/
- public void logTouch(@NonNull Uri subSlice) {
+ public void logTouch(int actionType, @NonNull Uri subSlice) {
}
}
diff --git a/core/java/android/app/usage/EventStats.java b/core/java/android/app/usage/EventStats.java
new file mode 100644
index 0000000..b799de9
--- /dev/null
+++ b/core/java/android/app/usage/EventStats.java
@@ -0,0 +1,182 @@
+/**
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package android.app.usage;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Contains usage statistics for an event type for a specific
+ * time range.
+ */
+public final class EventStats implements Parcelable {
+
+ /**
+ * {@hide}
+ */
+ public int mEventType;
+
+ /**
+ * {@hide}
+ */
+ public long mBeginTimeStamp;
+
+ /**
+ * {@hide}
+ */
+ public long mEndTimeStamp;
+
+ /**
+ * Last time used by the user with an explicit action (notification, activity launch).
+ * {@hide}
+ */
+ public long mLastTimeUsed;
+
+ /**
+ * {@hide}
+ */
+ public long mTotalTime;
+
+ /**
+ * {@hide}
+ */
+ public int mCount;
+
+ /**
+ * {@hide}
+ */
+ public EventStats() {
+ }
+
+ public EventStats(EventStats stats) {
+ mEventType = stats.mEventType;
+ mBeginTimeStamp = stats.mBeginTimeStamp;
+ mEndTimeStamp = stats.mEndTimeStamp;
+ mLastTimeUsed = stats.mLastTimeUsed;
+ mTotalTime = stats.mTotalTime;
+ mCount = stats.mCount;
+ }
+
+ /**
+ * Return the type of event this is usage for. May be one of the event
+ * constants in {@link UsageEvents.Event}.
+ */
+ public int getEventType() {
+ return mEventType;
+ }
+
+ /**
+ * Get the beginning of the time range this {@link android.app.usage.EventStats} represents,
+ * measured in milliseconds since the epoch.
+ * <p/>
+ * See {@link System#currentTimeMillis()}.
+ */
+ public long getFirstTimeStamp() {
+ return mBeginTimeStamp;
+ }
+
+ /**
+ * Get the end of the time range this {@link android.app.usage.EventStats} represents,
+ * measured in milliseconds since the epoch.
+ * <p/>
+ * See {@link System#currentTimeMillis()}.
+ */
+ public long getLastTimeStamp() {
+ return mEndTimeStamp;
+ }
+
+ /**
+ * Get the last time this event was used, measured in milliseconds since the epoch.
+ * <p/>
+ * See {@link System#currentTimeMillis()}.
+ */
+ public long getLastTimeUsed() {
+ return mLastTimeUsed;
+ }
+
+ /**
+ * Return the number of times that this event occurred over the interval.
+ */
+ public int getCount() {
+ return mCount;
+ }
+
+ /**
+ * Get the total time this event was active, measured in milliseconds.
+ */
+ public long getTotalTime() {
+ return mTotalTime;
+ }
+
+ /**
+ * Add the statistics from the right {@link EventStats} to the left. The event type for
+ * both {@link UsageStats} objects must be the same.
+ * @param right The {@link EventStats} object to merge into this one.
+ * @throws java.lang.IllegalArgumentException if the event types of the two
+ * {@link UsageStats} objects are different.
+ */
+ public void add(EventStats right) {
+ if (mEventType != right.mEventType) {
+ throw new IllegalArgumentException("Can't merge EventStats for event #"
+ + mEventType + " with EventStats for event #" + right.mEventType);
+ }
+
+ // We use the mBeginTimeStamp due to a bug where UsageStats files can overlap with
+ // regards to their mEndTimeStamp.
+ if (right.mBeginTimeStamp > mBeginTimeStamp) {
+ mLastTimeUsed = Math.max(mLastTimeUsed, right.mLastTimeUsed);
+ }
+ mBeginTimeStamp = Math.min(mBeginTimeStamp, right.mBeginTimeStamp);
+ mEndTimeStamp = Math.max(mEndTimeStamp, right.mEndTimeStamp);
+ mTotalTime += right.mTotalTime;
+ mCount += right.mCount;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mEventType);
+ dest.writeLong(mBeginTimeStamp);
+ dest.writeLong(mEndTimeStamp);
+ dest.writeLong(mLastTimeUsed);
+ dest.writeLong(mTotalTime);
+ dest.writeInt(mCount);
+ }
+
+ public static final Creator<EventStats> CREATOR = new Creator<EventStats>() {
+ @Override
+ public EventStats createFromParcel(Parcel in) {
+ EventStats stats = new EventStats();
+ stats.mEventType = in.readInt();
+ stats.mBeginTimeStamp = in.readLong();
+ stats.mEndTimeStamp = in.readLong();
+ stats.mLastTimeUsed = in.readLong();
+ stats.mTotalTime = in.readLong();
+ stats.mCount = in.readInt();
+ return stats;
+ }
+
+ @Override
+ public EventStats[] newArray(int size) {
+ return new EventStats[size];
+ }
+ };
+}
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index d52bd37..00d8711 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -32,6 +32,8 @@
String callingPackage);
ParceledListSlice queryConfigurationStats(int bucketType, long beginTime, long endTime,
String callingPackage);
+ ParceledListSlice queryEventStats(int bucketType, long beginTime, long endTime,
+ String callingPackage);
UsageEvents queryEvents(long beginTime, long endTime, String callingPackage);
UsageEvents queryEventsForPackage(long beginTime, long endTime, String callingPackage);
void setAppInactive(String packageName, boolean inactive, int userId);
diff --git a/core/java/android/app/usage/TimeSparseArray.java b/core/java/android/app/usage/TimeSparseArray.java
index 5764fa8..9ef88e4 100644
--- a/core/java/android/app/usage/TimeSparseArray.java
+++ b/core/java/android/app/usage/TimeSparseArray.java
@@ -81,12 +81,17 @@
@Override
public void put(long key, E value) {
final long origKey = key;
- while (indexOfKey(key) >= 0) {
- key++;
- }
- if (origKey != key) {
- Slog.w(TAG, "Value " + value + " supposed to be inserted at " + origKey
- + " displaced to " + key);
+ int keyIndex = indexOfKey(key);
+ if (keyIndex >= 0) {
+ final long sz = size();
+ while (keyIndex < sz && keyAt(keyIndex) == key) {
+ key++;
+ keyIndex++;
+ }
+ if (key >= origKey + 10) {
+ Slog.w(TAG, "Value " + value + " supposed to be inserted at " + origKey
+ + " displaced to " + key);
+ }
}
super.put(key, value);
}
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index b354e81..a665652 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -139,6 +139,19 @@
@SystemApi
public static final int SLICE_PINNED = 14;
+ /**
+ * An event type denoting that the screen has gone in to an interactive state (turned
+ * on for full user interaction, not ambient display or other non-interactive state).
+ */
+ public static final int SCREEN_INTERACTIVE = 15;
+
+ /**
+ * An event type denoting that the screen has gone in to a non-interactive state
+ * (completely turned off or turned on only in a non-interactive state like ambient
+ * display).
+ */
+ public static final int SCREEN_NON_INTERACTIVE = 16;
+
/** @hide */
public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0;
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 4744147..6feb527 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -301,6 +301,44 @@
}
/**
+ * Gets aggregated event stats for the given time range, aggregated by the specified interval.
+ * <p>The returned list will contain a {@link EventStats} object for each event type that
+ * is being aggregated and has data for an interval that is a subset of the time range given.
+ *
+ * <p>The current event types that will be aggregated here are:</p>
+ * <ul>
+ * <li>{@link UsageEvents.Event#SCREEN_INTERACTIVE}</li>
+ * <li>{@link UsageEvents.Event#SCREEN_NON_INTERACTIVE}</li>
+ * </ul>
+ *
+ * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p>
+ *
+ * @param intervalType The time interval by which the stats are aggregated.
+ * @param beginTime The inclusive beginning of the range of stats to include in the results.
+ * @param endTime The exclusive end of the range of stats to include in the results.
+ * @return A list of {@link EventStats}
+ *
+ * @see #INTERVAL_DAILY
+ * @see #INTERVAL_WEEKLY
+ * @see #INTERVAL_MONTHLY
+ * @see #INTERVAL_YEARLY
+ * @see #INTERVAL_BEST
+ */
+ public List<EventStats> queryEventStats(int intervalType, long beginTime, long endTime) {
+ try {
+ @SuppressWarnings("unchecked")
+ ParceledListSlice<EventStats> slice = mService.queryEventStats(intervalType, beginTime,
+ endTime, mContext.getOpPackageName());
+ if (slice != null) {
+ return slice.getList();
+ }
+ } catch (RemoteException e) {
+ // fallthrough and return the empty list.
+ }
+ return Collections.emptyList();
+ }
+
+ /**
* Query for events in the given time range. Events are only kept by the system for a few
* days.
* <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p>
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index ce32278..02f0ded 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1814,6 +1814,17 @@
public static final String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
/**
+ * Intent extra: A {@link Bundle} of extras for a package being suspended. Will be sent with
+ * {@link #ACTION_MY_PACKAGE_SUSPENDED}.
+ *
+ * @see #ACTION_MY_PACKAGE_SUSPENDED
+ * @see #ACTION_MY_PACKAGE_UNSUSPENDED
+ * @see PackageManager#isPackageSuspended()
+ * @see PackageManager#getSuspendedPackageAppExtras()
+ */
+ public static final String EXTRA_SUSPENDED_PACKAGE_EXTRAS = "android.intent.extra.SUSPENDED_PACKAGE_EXTRAS";
+
+ /**
* Intent extra: An app split name.
* <p>
* Type: String
@@ -2237,6 +2248,43 @@
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGES_UNSUSPENDED = "android.intent.action.PACKAGES_UNSUSPENDED";
+
+ /**
+ * Broadcast Action: Sent to a package that has been suspended by the system. This is sent
+ * whenever a package is put into a suspended state or any of it's app extras change while
+ * in the suspended state.
+ * <p> Optionally includes the following extras:
+ * <ul>
+ * <li> {@link #EXTRA_SUSPENDED_PACKAGE_EXTRAS} which is a {@link Bundle} which will contain
+ * useful information for the app being suspended.
+ * </ul>
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system. <em>This will be delivered to {@link BroadcastReceiver} components declared in
+ * the manifest.</em>
+ *
+ * @see #ACTION_MY_PACKAGE_UNSUSPENDED
+ * @see #EXTRA_SUSPENDED_PACKAGE_EXTRAS
+ * @see PackageManager#isPackageSuspended()
+ * @see PackageManager#getSuspendedPackageAppExtras()
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_MY_PACKAGE_SUSPENDED = "android.intent.action.MY_PACKAGE_SUSPENDED";
+
+ /**
+ * Broadcast Action: Sent to a package that has been unsuspended.
+ *
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system. <em>This will be delivered to {@link BroadcastReceiver} components declared in
+ * the manifest.</em>
+ *
+ * @see #ACTION_MY_PACKAGE_SUSPENDED
+ * @see #EXTRA_SUSPENDED_PACKAGE_EXTRAS
+ * @see PackageManager#isPackageSuspended()
+ * @see PackageManager#getSuspendedPackageAppExtras()
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_MY_PACKAGE_UNSUSPENDED = "android.intent.action.MY_PACKAGE_UNSUSPENDED";
+
/**
* Broadcast Action: A user ID has been removed from the system. The user
* ID number is stored in the extra data under {@link #EXTRA_UID}.
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index d43d80f..277738b 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -278,7 +278,7 @@
boolean isPackageSuspendedForUser(String packageName, int userId);
- PersistableBundle getPackageSuspendedAppExtras(String pacakgeName, int userId);
+ PersistableBundle getSuspendedPackageAppExtras(String packageName, int userId);
void setSuspendedPackageAppExtras(String packageName, in PersistableBundle appExtras,
int userId);
@@ -619,6 +619,8 @@
in String[] packageNames, int userId);
void revokeDefaultPermissionsFromDisabledTelephonyDataServices(
in String[] packageNames, int userId);
+ void grantDefaultPermissionsToActiveLuiApp(in String packageName, int userId);
+ void revokeDefaultPermissionsFromLuiApps(in String[] packageNames, int userId);
boolean isPermissionRevokedByPolicy(String permission, String packageName, int userId);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 314eb98..491f0af 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -5513,7 +5513,7 @@
* Puts the package in a suspended state, where attempts at starting activities are denied.
*
* <p>It doesn't remove the data or the actual package file. The application's notifications
- * will be hidden, any of the it's started activities will be stopped and it will not be able to
+ * will be hidden, any of its started activities will be stopped and it will not be able to
* show toasts or dialogs or ring the device. When the user tries to launch a suspended app, a
* system dialog with the given {@code dialogMessage} will be shown instead.</p>
*
@@ -5577,11 +5577,26 @@
}
/**
- * Apps can query this to know if they have been suspended.
+ * Apps can query this to know if they have been suspended. A system app with the permission
+ * {@code android.permission.SUSPEND_APPS} can put any app on the device into a suspended state.
+ *
+ * <p>While in this state, the application's notifications will be hidden, any of its started
+ * activities will be stopped and it will not be able to show toasts or dialogs or ring the
+ * device. When the user tries to launch a suspended app, the system will, instead, show a
+ * dialog to the user informing them that they cannot use this app while it is suspended.
+ *
+ * <p>When an app is put into this state, the broadcast action
+ * {@link Intent#ACTION_MY_PACKAGE_SUSPENDED} will be delivered to any of its broadcast
+ * receivers that included this action in their intent-filters, <em>including manifest
+ * receivers.</em> Similarly, a broadcast action {@link Intent#ACTION_MY_PACKAGE_UNSUSPENDED}
+ * is delivered when a previously suspended app is taken out of this state.
+ * </p>
*
* @return {@code true} if the calling package has been suspended, {@code false} otherwise.
*
* @see #getSuspendedPackageAppExtras()
+ * @see Intent#ACTION_MY_PACKAGE_SUSPENDED
+ * @see Intent#ACTION_MY_PACKAGE_UNSUSPENDED
*/
public boolean isPackageSuspended() {
throw new UnsupportedOperationException("isPackageSuspended not implemented");
@@ -5602,7 +5617,7 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.SUSPEND_APPS)
- public PersistableBundle getSuspendedPackageAppExtras(String packageName) {
+ public @Nullable PersistableBundle getSuspendedPackageAppExtras(String packageName) {
throw new UnsupportedOperationException("getSuspendedPackageAppExtras not implemented");
}
@@ -5631,15 +5646,17 @@
* Returns any extra information supplied as {@code appExtras} to the system when the calling
* app was suspended.
*
- * <p> Note: This just returns whatever {@link PersistableBundle} was passed to the system via
- * {@code setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle,
- * String)} when suspending the package, <em> which might be {@code null}. </em></p>
+ * <p>Note: If no extras were supplied to the system, this method will return {@code null}, even
+ * when the calling app has been suspended.</p>
*
- * @return A {@link PersistableBundle} containing the extras for the app, or {@code null} if the
+ * @return A {@link Bundle} containing the extras for the app, or {@code null} if the
* package is not currently suspended.
+ *
* @see #isPackageSuspended()
+ * @see Intent#ACTION_MY_PACKAGE_UNSUSPENDED
+ * @see Intent#ACTION_MY_PACKAGE_SUSPENDED
*/
- public @Nullable PersistableBundle getSuspendedPackageAppExtras() {
+ public @Nullable Bundle getSuspendedPackageAppExtras() {
throw new UnsupportedOperationException("getSuspendedPackageAppExtras not implemented");
}
diff --git a/core/java/android/content/pm/dex/PackageOptimizationInfo.java b/core/java/android/content/pm/dex/PackageOptimizationInfo.java
index b650457..7e7d29e 100644
--- a/core/java/android/content/pm/dex/PackageOptimizationInfo.java
+++ b/core/java/android/content/pm/dex/PackageOptimizationInfo.java
@@ -22,19 +22,19 @@
* @hide
*/
public class PackageOptimizationInfo {
- private final String mCompilationFilter;
- private final String mCompilationReason;
+ private final int mCompilationFilter;
+ private final int mCompilationReason;
- public PackageOptimizationInfo(String compilerFilter, String compilationReason) {
+ public PackageOptimizationInfo(int compilerFilter, int compilationReason) {
this.mCompilationReason = compilationReason;
this.mCompilationFilter = compilerFilter;
}
- public String getCompilationReason() {
+ public int getCompilationReason() {
return mCompilationReason;
}
- public String getCompilationFilter() {
+ public int getCompilationFilter() {
return mCompilationFilter;
}
@@ -42,6 +42,6 @@
* Create a default optimization info object for the case when we have no information.
*/
public static PackageOptimizationInfo createWithNoInfo() {
- return new PackageOptimizationInfo("no-info", "no-info");
+ return new PackageOptimizationInfo(-1, -1);
}
}
diff --git a/core/java/android/hardware/biometrics/BiometricConstants.java b/core/java/android/hardware/biometrics/BiometricConstants.java
new file mode 100644
index 0000000..a037289
--- /dev/null
+++ b/core/java/android/hardware/biometrics/BiometricConstants.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics;
+
+
+/**
+ * Interface containing all of the biometric modality agnostic constants.
+ * @hide
+ */
+public interface BiometricConstants {
+ //
+ // Error messages from biometric hardware during initilization, enrollment, authentication or
+ // removal.
+ //
+
+ /**
+ * The hardware is unavailable. Try again later.
+ */
+ int BIOMETRIC_ERROR_HW_UNAVAILABLE = 1;
+
+ /**
+ * Error state returned when the sensor was unable to process the current image.
+ */
+ int BIOMETRIC_ERROR_UNABLE_TO_PROCESS = 2;
+
+ /**
+ * Error state returned when the current request has been running too long. This is intended to
+ * prevent programs from waiting for the biometric sensor indefinitely. The timeout is platform
+ * and sensor-specific, but is generally on the order of 30 seconds.
+ */
+ int BIOMETRIC_ERROR_TIMEOUT = 3;
+
+ /**
+ * Error state returned for operations like enrollment; the operation cannot be completed
+ * because there's not enough storage remaining to complete the operation.
+ */
+ int BIOMETRIC_ERROR_NO_SPACE = 4;
+
+ /**
+ * The operation was canceled because the biometric sensor is unavailable. For example, this may
+ * happen when the user is switched, the device is locked or another pending operation prevents
+ * or disables it.
+ */
+ int BIOMETRIC_ERROR_CANCELED = 5;
+
+ /**
+ * The {@link BiometricManager#remove} call failed. Typically this will happen when the provided
+ * biometric id was incorrect.
+ *
+ * @hide
+ */
+ int BIOMETRIC_ERROR_UNABLE_TO_REMOVE = 6;
+
+ /**
+ * The operation was canceled because the API is locked out due to too many attempts.
+ * This occurs after 5 failed attempts, and lasts for 30 seconds.
+ */
+ int BIOMETRIC_ERROR_LOCKOUT = 7;
+
+ /**
+ * Hardware vendors may extend this list if there are conditions that do not fall under one of
+ * the above categories. Vendors are responsible for providing error strings for these errors.
+ * These messages are typically reserved for internal operations such as enrollment, but may be
+ * used to express vendor errors not otherwise covered. Applications are expected to show the
+ * error message string if they happen, but are advised not to rely on the message id since they
+ * will be device and vendor-specific
+ */
+ int BIOMETRIC_ERROR_VENDOR = 8;
+
+ /**
+ * The operation was canceled because BIOMETRIC_ERROR_LOCKOUT occurred too many times.
+ * Biometric authentication is disabled until the user unlocks with strong authentication
+ * (PIN/Pattern/Password)
+ */
+ int BIOMETRIC_ERROR_LOCKOUT_PERMANENT = 9;
+
+ /**
+ * The user canceled the operation. Upon receiving this, applications should use alternate
+ * authentication (e.g. a password). The application should also provide the means to return to
+ * biometric authentication, such as a "use <biometric>" button.
+ */
+ int BIOMETRIC_ERROR_USER_CANCELED = 10;
+
+ /**
+ * The user does not have any biometrics enrolled.
+ */
+ int BIOMETRIC_ERROR_NO_BIOMETRICS = 11;
+
+ /**
+ * The device does not have a biometric sensor.
+ */
+ int BIOMETRIC_ERROR_HW_NOT_PRESENT = 12;
+
+ /**
+ * @hide
+ */
+ int BIOMETRIC_ERROR_VENDOR_BASE = 1000;
+
+ //
+ // Image acquisition messages.
+ //
+
+ /**
+ * The image acquired was good.
+ */
+ int BIOMETRIC_ACQUIRED_GOOD = 0;
+
+ /**
+ * Only a partial biometric image was detected. During enrollment, the user should be informed
+ * on what needs to happen to resolve this problem, e.g. "press firmly on sensor." (for
+ * fingerprint)
+ */
+ int BIOMETRIC_ACQUIRED_PARTIAL = 1;
+
+ /**
+ * The biometric image was too noisy to process due to a detected condition or a possibly dirty
+ * sensor (See {@link #BIOMETRIC_ACQUIRED_IMAGER_DIRTY}).
+ */
+ int BIOMETRIC_ACQUIRED_INSUFFICIENT = 2;
+
+ /**
+ * The biometric image was too noisy due to suspected or detected dirt on the sensor. For
+ * example, it's reasonable return this after multiple {@link #BIOMETRIC_ACQUIRED_INSUFFICIENT}
+ * or actual detection of dirt on the sensor (stuck pixels, swaths, etc.). The user is expected
+ * to take action to clean the sensor when this is returned.
+ */
+ int BIOMETRIC_ACQUIRED_IMAGER_DIRTY = 3;
+
+ /**
+ * The biometric image was unreadable due to lack of motion.
+ */
+ int BIOMETRIC_ACQUIRED_TOO_SLOW = 4;
+
+ /**
+ * The biometric image was incomplete due to quick motion. For example, this could also happen
+ * if the user moved during acquisition. The user should be asked to repeat the operation more
+ * slowly.
+ */
+ int BIOMETRIC_ACQUIRED_TOO_FAST = 5;
+
+ /**
+ * Hardware vendors may extend this list if there are conditions that do not fall under one of
+ * the above categories. Vendors are responsible for providing error strings for these errors.
+ * @hide
+ */
+ int BIOMETRIC_ACQUIRED_VENDOR = 6;
+ /**
+ * @hide
+ */
+ int BIOMETRICT_ACQUIRED_VENDOR_BASE = 1000;
+}
diff --git a/core/java/android/hardware/fingerprint/FingerprintDialog.java b/core/java/android/hardware/biometrics/BiometricDialog.java
similarity index 73%
rename from core/java/android/hardware/fingerprint/FingerprintDialog.java
rename to core/java/android/hardware/biometrics/BiometricDialog.java
index 13b7064..dd848a3 100644
--- a/core/java/android/hardware/fingerprint/FingerprintDialog.java
+++ b/core/java/android/hardware/biometrics/BiometricDialog.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package android.hardware.fingerprint;
+package android.hardware.biometrics;
-import static android.Manifest.permission.USE_FINGERPRINT;
+import static android.Manifest.permission.USE_BIOMETRIC;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
@@ -24,10 +24,7 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
-import android.hardware.biometrics.BiometricAuthenticator;
-import android.hardware.biometrics.BiometricFingerprintConstants;
-import android.hardware.biometrics.CryptoObject;
-import android.hardware.fingerprint.IFingerprintDialogReceiver;
+import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.text.TextUtils;
@@ -39,9 +36,9 @@
import javax.crypto.Mac;
/**
- * A class that manages a system-provided fingerprint dialog.
+ * A class that manages a system-provided biometric dialog.
*/
-public class FingerprintDialog implements BiometricAuthenticator, BiometricFingerprintConstants {
+public class BiometricDialog implements BiometricAuthenticator, BiometricConstants {
/**
* @hide
@@ -97,18 +94,21 @@
}
/**
- * A builder that collects arguments, to be shown on the system-provided fingerprint dialog.
+ * A builder that collects arguments to be shown on the system-provided biometric dialog.
**/
public static class Builder {
- private final Bundle bundle;
- private ButtonInfo positiveButtonInfo;
- private ButtonInfo negativeButtonInfo;
+ private final Bundle mBundle;
+ private ButtonInfo mPositiveButtonInfo;
+ private ButtonInfo mNegativeButtonInfo;
+ private Context mContext;
/**
- * Creates a builder for a fingerprint dialog.
+ * Creates a builder for a biometric dialog.
+ * @param context
*/
- public Builder() {
- bundle = new Bundle();
+ public Builder(Context context) {
+ mBundle = new Bundle();
+ mContext = context;
}
/**
@@ -117,7 +117,7 @@
* @return
*/
public Builder setTitle(@NonNull CharSequence title) {
- bundle.putCharSequence(KEY_TITLE, title);
+ mBundle.putCharSequence(KEY_TITLE, title);
return this;
}
@@ -127,7 +127,7 @@
* @return
*/
public Builder setSubtitle(@NonNull CharSequence subtitle) {
- bundle.putCharSequence(KEY_SUBTITLE, subtitle);
+ mBundle.putCharSequence(KEY_SUBTITLE, subtitle);
return this;
}
@@ -137,7 +137,7 @@
* @return
*/
public Builder setDescription(@NonNull CharSequence description) {
- bundle.putCharSequence(KEY_DESCRIPTION, description);
+ mBundle.putCharSequence(KEY_DESCRIPTION, description);
return this;
}
@@ -160,8 +160,8 @@
if (listener == null) {
throw new IllegalArgumentException("Listener must not be null");
}
- bundle.putCharSequence(KEY_POSITIVE_TEXT, text);
- positiveButtonInfo = new ButtonInfo(executor, listener);
+ mBundle.putCharSequence(KEY_POSITIVE_TEXT, text);
+ mPositiveButtonInfo = new ButtonInfo(executor, listener);
return this;
}
@@ -184,27 +184,26 @@
if (listener == null) {
throw new IllegalArgumentException("Listener must not be null");
}
- bundle.putCharSequence(KEY_NEGATIVE_TEXT, text);
- negativeButtonInfo = new ButtonInfo(executor, listener);
+ mBundle.putCharSequence(KEY_NEGATIVE_TEXT, text);
+ mNegativeButtonInfo = new ButtonInfo(executor, listener);
return this;
}
/**
- * Creates a {@link FingerprintDialog} with the arguments supplied to this builder.
- * @param context
- * @return a {@link FingerprintDialog}
+ * Creates a {@link BiometricDialog}.
+ * @return a {@link BiometricDialog}
* @throws IllegalArgumentException if any of the required fields are not set.
*/
- public FingerprintDialog build(Context context) {
- final CharSequence title = bundle.getCharSequence(KEY_TITLE);
- final CharSequence negative = bundle.getCharSequence(KEY_NEGATIVE_TEXT);
+ public BiometricDialog build() {
+ final CharSequence title = mBundle.getCharSequence(KEY_TITLE);
+ final CharSequence negative = mBundle.getCharSequence(KEY_NEGATIVE_TEXT);
if (TextUtils.isEmpty(title)) {
throw new IllegalArgumentException("Title must be set and non-empty");
} else if (TextUtils.isEmpty(negative)) {
throw new IllegalArgumentException("Negative text must be set and non-empty");
}
- return new FingerprintDialog(context, bundle, positiveButtonInfo, negativeButtonInfo);
+ return new BiometricDialog(mContext, mBundle, mPositiveButtonInfo, mNegativeButtonInfo);
}
}
@@ -214,7 +213,7 @@
private ButtonInfo mPositiveButtonInfo;
private ButtonInfo mNegativeButtonInfo;
- IFingerprintDialogReceiver mDialogReceiver = new IFingerprintDialogReceiver.Stub() {
+ IBiometricDialogReceiver mDialogReceiver = new IBiometricDialogReceiver.Stub() {
@Override
public void onDialogDismissed(int reason) {
// Check the reason and invoke OnClickListener(s) if necessary
@@ -230,7 +229,7 @@
}
};
- private FingerprintDialog(Context context, Bundle bundle,
+ private BiometricDialog(Context context, Bundle bundle,
ButtonInfo positiveButtonInfo, ButtonInfo negativeButtonInfo) {
mBundle = bundle;
mPositiveButtonInfo = positiveButtonInfo;
@@ -240,8 +239,8 @@
}
/**
- * A wrapper class for the crypto objects supported by FingerprintManager. Currently the
- * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
+ * A wrapper class for the crypto objects supported by BiometricDialog. Currently the framework
+ * supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
*/
public static final class CryptoObject extends android.hardware.biometrics.CryptoObject {
public CryptoObject(@NonNull Signature signature) {
@@ -282,9 +281,8 @@
}
/**
- * Container for callback data from {@link #authenticate(
- * CancellationSignal, Executor, AuthenticationCallback)} and
- * {@link #authenticate(CryptoObject, CancellationSignal, Executor,
+ * Container for callback data from {@link #authenticate( CancellationSignal, Executor,
+ * AuthenticationCallback)} and {@link #authenticate(CryptoObject, CancellationSignal, Executor,
* AuthenticationCallback)}
*/
public static class AuthenticationResult extends BiometricAuthenticator.AuthenticationResult {
@@ -301,8 +299,8 @@
}
/**
* Obtain the crypto object associated with this transaction
- * @return crypto object provided to {@link #authenticate(
- * CryptoObject, CancellationSignal, Executor, AuthenticationCallback)}
+ * @return crypto object provided to {@link #authenticate( CryptoObject, CancellationSignal,
+ * Executor, AuthenticationCallback)}
*/
public CryptoObject getCryptoObject() {
return (CryptoObject) super.getCryptoObject();
@@ -310,12 +308,12 @@
}
/**
- * Callback structure provided to {@link FingerprintDialog#authenticate(CancellationSignal,
- * Executor, AuthenticationCallback)} or {@link FingerprintDialog#authenticate(CryptoObject,
+ * Callback structure provided to {@link BiometricDialog#authenticate(CancellationSignal,
+ * Executor, AuthenticationCallback)} or {@link BiometricDialog#authenticate(CryptoObject,
* CancellationSignal, Executor, AuthenticationCallback)}. Users must provide an implementation
* of this for listening to authentication events.
*/
- public static abstract class AuthenticationCallback extends
+ public abstract static class AuthenticationCallback extends
BiometricAuthenticator.AuthenticationCallback {
/**
* Called when an unrecoverable error has been encountered and the operation is complete.
@@ -368,7 +366,6 @@
}
}
-
/**
* @param crypto Object associated with the call
* @param cancel An object that can be used to cancel authentication
@@ -381,7 +378,7 @@
@NonNull CancellationSignal cancel,
@NonNull @CallbackExecutor Executor executor,
@NonNull BiometricAuthenticator.AuthenticationCallback callback) {
- if (!(callback instanceof FingerprintDialog.AuthenticationCallback)) {
+ if (!(callback instanceof BiometricDialog.AuthenticationCallback)) {
throw new IllegalArgumentException("Callback cannot be casted");
}
authenticate(crypto, cancel, executor, (AuthenticationCallback) callback);
@@ -398,30 +395,26 @@
public void authenticate(@NonNull CancellationSignal cancel,
@NonNull @CallbackExecutor Executor executor,
@NonNull BiometricAuthenticator.AuthenticationCallback callback) {
- if (!(callback instanceof FingerprintDialog.AuthenticationCallback)) {
+ if (!(callback instanceof BiometricDialog.AuthenticationCallback)) {
throw new IllegalArgumentException("Callback cannot be casted");
}
authenticate(cancel, executor, (AuthenticationCallback) callback);
}
-
/**
- * This call warms up the fingerprint hardware, displays a system-provided dialog,
- * and starts scanning for a fingerprint. It terminates when
- * {@link AuthenticationCallback#onAuthenticationError(int,
- * CharSequence)} is called, when
- * {@link AuthenticationCallback#onAuthenticationSucceeded(
- * AuthenticationResult)}, or when the user dismisses the system-provided dialog, at which point
- * the crypto object becomes invalid. This operation can be canceled by using the provided
- * cancel object. The application will receive authentication errors through
- * {@link AuthenticationCallback}, and button events through the
- * corresponding callback set in {@link Builder#setNegativeButton(CharSequence,
- * Executor, DialogInterface.OnClickListener)}. It is safe to reuse the
- * {@link FingerprintDialog} object, and calling {@link FingerprintDialog#authenticate(
- * CancellationSignal, Executor, AuthenticationCallback)} while an
- * existing authentication attempt is occurring will stop the previous client and start a
- * new authentication. The interrupted client will receive a cancelled notification through
- * {@link AuthenticationCallback#onAuthenticationError(int,
+ * This call warms up the fingerprint hardware, displays a system-provided dialog, and starts
+ * scanning for a fingerprint. It terminates when {@link
+ * AuthenticationCallback#onAuthenticationError(int, CharSequence)} is called, when {@link
+ * AuthenticationCallback#onAuthenticationSucceeded( AuthenticationResult)}, or when the user
+ * dismisses the system-provided dialog, at which point the crypto object becomes invalid. This
+ * operation can be canceled by using the provided cancel object. The application will receive
+ * authentication errors through {@link AuthenticationCallback}, and button events through the
+ * corresponding callback set in {@link Builder#setNegativeButton(CharSequence, Executor,
+ * DialogInterface.OnClickListener)}. It is safe to reuse the {@link BiometricDialog} object,
+ * and calling {@link BiometricDialog#authenticate( CancellationSignal, Executor,
+ * AuthenticationCallback)} while an existing authentication attempt is occurring will stop the
+ * previous client and start a new authentication. The interrupted client will receive a
+ * cancelled notification through {@link AuthenticationCallback#onAuthenticationError(int,
* CharSequence)}.
*
* @throws IllegalArgumentException If any of the arguments are null
@@ -431,7 +424,7 @@
* @param executor An executor to handle callback events
* @param callback An object to receive authentication events
*/
- @RequiresPermission(USE_FINGERPRINT)
+ @RequiresPermission(USE_BIOMETRIC)
public void authenticate(@NonNull CryptoObject crypto,
@NonNull CancellationSignal cancel,
@NonNull @CallbackExecutor Executor executor,
@@ -444,23 +437,19 @@
}
/**
- * This call warms up the fingerprint hardware, displays a system-provided dialog,
- * and starts scanning for a fingerprint. It terminates when
- * {@link AuthenticationCallback#onAuthenticationError(int,
- * CharSequence)} is called, when
- * {@link AuthenticationCallback#onAuthenticationSucceeded(
- * AuthenticationResult)} is called, or when the user dismisses the system-provided dialog.
- * This operation can be canceled by using the provided cancel object. The application will
- * receive authentication errors through {@link AuthenticationCallback},
- * and button events through the corresponding callback set in
- * {@link Builder#setNegativeButton(CharSequence, Executor, DialogInterface.OnClickListener)}.
- * It is safe to reuse the {@link FingerprintDialog} object, and calling
- * {@link FingerprintDialog#authenticate(CancellationSignal, Executor,
- * AuthenticationCallback)} while an existing authentication attempt is
- * occurring will stop the previous client and start a new authentication. The interrupted
- * client will receive a cancelled notification through
- * {@link AuthenticationCallback#onAuthenticationError(int,
- * CharSequence)}.
+ * This call warms up the fingerprint hardware, displays a system-provided dialog, and starts
+ * scanning for a fingerprint. It terminates when {@link
+ * AuthenticationCallback#onAuthenticationError(int, CharSequence)} is called, when {@link
+ * AuthenticationCallback#onAuthenticationSucceeded( AuthenticationResult)} is called, or when
+ * the user dismisses the system-provided dialog. This operation can be canceled by using the
+ * provided cancel object. The application will receive authentication errors through {@link
+ * AuthenticationCallback}, and button events through the corresponding callback set in {@link
+ * Builder#setNegativeButton(CharSequence, Executor, DialogInterface.OnClickListener)}. It is
+ * safe to reuse the {@link BiometricDialog} object, and calling {@link
+ * BiometricDialog#authenticate(CancellationSignal, Executor, AuthenticationCallback)} while
+ * an existing authentication attempt is occurring will stop the previous client and start a new
+ * authentication. The interrupted client will receive a cancelled notification through {@link
+ * AuthenticationCallback#onAuthenticationError(int, CharSequence)}.
*
* @throws IllegalArgumentException If any of the arguments are null
*
@@ -468,7 +457,7 @@
* @param executor An executor to handle callback events
* @param callback An object to receive authentication events
*/
- @RequiresPermission(USE_FINGERPRINT)
+ @RequiresPermission(USE_BIOMETRIC)
public void authenticate(@NonNull CancellationSignal cancel,
@NonNull @CallbackExecutor Executor executor,
@NonNull AuthenticationCallback callback) {
@@ -481,13 +470,16 @@
private boolean handlePreAuthenticationErrors(AuthenticationCallback callback,
Executor executor) {
if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
- sendError(FINGERPRINT_ERROR_HW_NOT_PRESENT, callback, executor);
+ sendError(BiometricDialog.BIOMETRIC_ERROR_HW_NOT_PRESENT, callback,
+ executor);
return true;
} else if (!mFingerprintManager.isHardwareDetected()) {
- sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, callback, executor);
+ sendError(BiometricDialog.BIOMETRIC_ERROR_HW_UNAVAILABLE, callback,
+ executor);
return true;
} else if (!mFingerprintManager.hasEnrolledFingerprints()) {
- sendError(FINGERPRINT_ERROR_NO_FINGERPRINTS, callback, executor);
+ sendError(BiometricDialog.BIOMETRIC_ERROR_NO_BIOMETRICS, callback,
+ executor);
return true;
}
return false;
diff --git a/core/java/android/hardware/fingerprint/IFingerprintDialogReceiver.aidl b/core/java/android/hardware/biometrics/IBiometricDialogReceiver.aidl
similarity index 76%
rename from core/java/android/hardware/fingerprint/IFingerprintDialogReceiver.aidl
rename to core/java/android/hardware/biometrics/IBiometricDialogReceiver.aidl
index 13e7974..e528aa7 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintDialogReceiver.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricDialogReceiver.aidl
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.hardware.fingerprint;
+package android.hardware.biometrics;
-import android.hardware.fingerprint.Fingerprint;
import android.os.Bundle;
import android.os.UserHandle;
/**
- * Communication channel from the FingerprintDialog (SysUI) back to AuthenticationClient.
+ * Communication channel from the BiometricDialog (SysUI) back to AuthenticationClient.
* @hide
*/
-oneway interface IFingerprintDialogReceiver {
+oneway interface IBiometricDialogReceiver {
void onDialogDismissed(int reason);
}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index e6aaab1..4279b19 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1708,6 +1708,7 @@
* <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO CONSTRAINED_HIGH_SPEED_VIDEO}</li>
* <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING MOTION_TRACKING}</li>
* <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA LOGICAL_MULTI_CAMERA}</li>
+ * <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME MONOCHROME}</li>
* </ul></p>
* <p>This key is available on all devices.</p>
*
@@ -1724,6 +1725,7 @@
* @see #REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO
* @see #REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING
* @see #REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
+ * @see #REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME
*/
@PublicKey
public static final Key<int[]> REQUEST_AVAILABLE_CAPABILITIES =
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 7467c3a..1a5d3ac 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -862,6 +862,13 @@
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA = 11;
+ /**
+ * <p>The camera device is a monochrome camera that doesn't contain a color filter array,
+ * and the pixel values on U and Y planes are all 128.</p>
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ */
+ public static final int REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME = 12;
+
//
// Enumeration values for CameraCharacteristics#SCALER_CROPPING_TYPE
//
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index d36785a..2252571 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -2853,6 +2853,8 @@
* of points can be less than max (that is, the request doesn't have to
* always provide a curve with number of points equivalent to
* {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}).</p>
+ * <p>For devices with MONOCHROME capability, only red channel is used. Green and blue channels
+ * are ignored.</p>
* <p>A few examples, and their corresponding graphical mappings; these
* only specify the red channel and the precision is limited to 4
* digits, for conciseness.</p>
@@ -2915,6 +2917,8 @@
* of points can be less than max (that is, the request doesn't have to
* always provide a curve with number of points equivalent to
* {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}).</p>
+ * <p>For devices with MONOCHROME capability, only red channel is used. Green and blue channels
+ * are ignored.</p>
* <p>A few examples, and their corresponding graphical mappings; these
* only specify the red channel and the precision is limited to 4
* digits, for conciseness.</p>
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index bb82260..8df5447 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -4096,6 +4096,8 @@
* of points can be less than max (that is, the request doesn't have to
* always provide a curve with number of points equivalent to
* {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}).</p>
+ * <p>For devices with MONOCHROME capability, only red channel is used. Green and blue channels
+ * are ignored.</p>
* <p>A few examples, and their corresponding graphical mappings; these
* only specify the red channel and the precision is limited to 4
* digits, for conciseness.</p>
@@ -4158,6 +4160,8 @@
* of points can be less than max (that is, the request doesn't have to
* always provide a curve with number of points equivalent to
* {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}).</p>
+ * <p>For devices with MONOCHROME capability, only red channel is used. Green and blue channels
+ * are ignored.</p>
* <p>A few examples, and their corresponding graphical mappings; these
* only specify the red channel and the precision is limited to 4
* digits, for conciseness.</p>
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index a19ba19..5e28570 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.MANAGE_FINGERPRINT;
+import static android.Manifest.permission.USE_BIOMETRIC;
import static android.Manifest.permission.USE_FINGERPRINT;
import android.annotation.CallbackExecutor;
@@ -30,7 +31,9 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricDialog;
import android.hardware.biometrics.BiometricFingerprintConstants;
+import android.hardware.biometrics.IBiometricDialogReceiver;
import android.os.Binder;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -54,10 +57,10 @@
/**
* A class that coordinates access to the fingerprint hardware.
- * @deprecated See {@link FingerprintDialog} which shows a system-provided dialog upon starting
- * authentication. In a world where devices may have in-display fingerprint sensors, it's much
- * more realistic to have a system-provided authentication dialog since the in-display sensor
- * location may vary by vendor/device.
+ * @deprecated See {@link BiometricDialog} which shows a system-provided dialog upon starting
+ * authentication. In a world where devices may have different types of biometric authentication,
+ * it's much more realistic to have a system-provided authentication dialog since the method may
+ * vary by vendor/device.
*/
@Deprecated
@SystemService(Context.FINGERPRINT_SERVICE)
@@ -108,7 +111,7 @@
/**
* A wrapper class for the crypto objects supported by FingerprintManager. Currently the
* framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
- * @deprecated See {@link android.hardware.fingerprint.FingerprintDialog.CryptoObject}
+ * @deprecated See {@link android.hardware.biometrics.BiometricDialog.CryptoObject}
*/
@Deprecated
public static final class CryptoObject extends android.hardware.biometrics.CryptoObject {
@@ -152,7 +155,7 @@
/**
* Container for callback data from {@link FingerprintManager#authenticate(CryptoObject,
* CancellationSignal, int, AuthenticationCallback, Handler)}.
- * @deprecated See {@link android.hardware.fingerprint.FingerprintDialog.AuthenticationResult}
+ * @deprecated See {@link android.hardware.biometrics.BiometricDialog.AuthenticationResult}
*/
@Deprecated
public static class AuthenticationResult {
@@ -201,7 +204,7 @@
* FingerprintManager#authenticate(CryptoObject, CancellationSignal,
* int, AuthenticationCallback, Handler) } must provide an implementation of this for listening to
* fingerprint events.
- * @deprecated See {@link android.hardware.fingerprint.FingerprintDialog.AuthenticationCallback}
+ * @deprecated See {@link android.hardware.biometrics.BiometricDialog.AuthenticationCallback}
*/
@Deprecated
public static abstract class AuthenticationCallback
@@ -375,13 +378,13 @@
* by <a href="{@docRoot}training/articles/keystore.html">Android Keystore
* facility</a>.
* @throws IllegalStateException if the crypto primitive is not initialized.
- * @deprecated See {@link FingerprintDialog#authenticate(CancellationSignal, Executor,
- * FingerprintDialog.AuthenticationCallback)} and {@link FingerprintDialog#authenticate(
- * FingerprintDialog.CryptoObject, CancellationSignal, Executor,
- * FingerprintDialog.AuthenticationCallback)}
+ * @deprecated See {@link BiometricDialog#authenticate(CancellationSignal, Executor,
+ * BiometricDialog.AuthenticationCallback)} and {@link BiometricDialog#authenticate(
+ * BiometricDialog.CryptoObject, CancellationSignal, Executor,
+ * BiometricDialog.AuthenticationCallback)}
*/
@Deprecated
- @RequiresPermission(USE_FINGERPRINT)
+ @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
authenticate(crypto, cancel, flags, callback, handler, mContext.getUserId());
@@ -405,7 +408,7 @@
* @param userId the user ID that the fingerprint hardware will authenticate for.
* @hide
*/
- @RequiresPermission(USE_FINGERPRINT)
+ @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) {
if (callback == null) {
@@ -441,7 +444,7 @@
/**
* Per-user version, see {@link FingerprintManager#authenticate(CryptoObject,
- * CancellationSignal, Bundle, Executor, IFingerprintDialogReceiver, AuthenticationCallback)}
+ * CancellationSignal, Bundle, Executor, IBiometricDialogReceiver, AuthenticationCallback)}
* @param userId the user ID that the fingerprint hardware will authenticate for.
*/
private void authenticate(int userId,
@@ -449,7 +452,7 @@
@NonNull CancellationSignal cancel,
@NonNull Bundle bundle,
@NonNull @CallbackExecutor Executor executor,
- @NonNull IFingerprintDialogReceiver receiver,
+ @NonNull IBiometricDialogReceiver receiver,
@NonNull BiometricAuthenticator.AuthenticationCallback callback) {
mCryptoObject = crypto;
if (cancel.isCanceled()) {
@@ -477,8 +480,8 @@
}
/**
- * Private method, see {@link FingerprintDialog#authenticate(CancellationSignal, Executor,
- * AuthenticationCallback)}
+ * Private method, see {@link BiometricDialog#authenticate(CancellationSignal, Executor,
+ * BiometricDialog.AuthenticationCallback)}
* @param cancel
* @param executor
* @param callback
@@ -488,7 +491,7 @@
@NonNull CancellationSignal cancel,
@NonNull Bundle bundle,
@NonNull @CallbackExecutor Executor executor,
- @NonNull IFingerprintDialogReceiver receiver,
+ @NonNull IBiometricDialogReceiver receiver,
@NonNull BiometricAuthenticator.AuthenticationCallback callback) {
if (cancel == null) {
throw new IllegalArgumentException("Must supply a cancellation signal");
@@ -509,8 +512,8 @@
}
/**
- * Private method, see {@link FingerprintDialog#authenticate(CryptoObject, CancellationSignal,
- * Executor, AuthenticationCallback)}
+ * Private method, see {@link BiometricDialog#authenticate(BiometricDialog.CryptoObject,
+ * CancellationSignal, Executor, BiometricDialog.AuthenticationCallback)}
* @param crypto
* @param cancel
* @param executor
@@ -521,7 +524,7 @@
@NonNull CancellationSignal cancel,
@NonNull Bundle bundle,
@NonNull @CallbackExecutor Executor executor,
- @NonNull IFingerprintDialogReceiver receiver,
+ @NonNull IBiometricDialogReceiver receiver,
@NonNull BiometricAuthenticator.AuthenticationCallback callback) {
if (crypto == null) {
throw new IllegalArgumentException("Must supply a crypto object");
@@ -740,8 +743,8 @@
* Determine if there is at least one fingerprint enrolled.
*
* @return true if at least one fingerprint is enrolled, false otherwise
- * @deprecated See {@link FingerprintDialog} and
- * {@link FingerprintDialog#FINGERPRINT_ERROR_NO_FINGERPRINTS}
+ * @deprecated See {@link BiometricDialog} and
+ * {@link FingerprintManager#FINGERPRINT_ERROR_NO_FINGERPRINTS}
*/
@Deprecated
@RequiresPermission(USE_FINGERPRINT)
@@ -774,8 +777,8 @@
* Determine if fingerprint hardware is present and functional.
*
* @return true if hardware is present and functional, false otherwise.
- * @deprecated See {@link FingerprintDialog} and
- * {@link FingerprintDialog#FINGERPRINT_ERROR_HW_UNAVAILABLE}
+ * @deprecated See {@link BiometricDialog} and
+ * {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE}
*/
@Deprecated
@RequiresPermission(USE_FINGERPRINT)
@@ -1155,14 +1158,14 @@
@Override // binder call
public void onError(long deviceId, int error, int vendorCode) {
if (mExecutor != null) {
- // FingerprintDialog case, post a delayed runnable on the FingerprintManager handler
+ // BiometricDialog case, post a delayed runnable on the FingerprintManager handler
// that sends the error message after FingerprintDialog.HIDE_DIALOG_DELAY to send
// the error to the application.
mHandler.postDelayed(() -> {
mExecutor.execute(() -> {
sendErrorResult(deviceId, error, vendorCode);
});
- }, FingerprintDialog.HIDE_DIALOG_DELAY);
+ }, BiometricDialog.HIDE_DIALOG_DELAY);
} else {
mHandler.obtainMessage(MSG_ERROR, error, vendorCode, deviceId).sendToTarget();
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index f1502e4..78d01e5 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -16,8 +16,8 @@
package android.hardware.fingerprint;
import android.os.Bundle;
+import android.hardware.biometrics.IBiometricDialogReceiver;
import android.hardware.fingerprint.IFingerprintClientActiveCallback;
-import android.hardware.fingerprint.IFingerprintDialogReceiver;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
import android.hardware.fingerprint.Fingerprint;
@@ -31,7 +31,7 @@
// Authenticate the given sessionId with a fingerprint
void authenticate(IBinder token, long sessionId, int userId,
IFingerprintServiceReceiver receiver, int flags, String opPackageName,
- in Bundle bundle, IFingerprintDialogReceiver dialogReceiver);
+ in Bundle bundle, IBiometricDialogReceiver dialogReceiver);
// Cancel authentication for the given sessionId
void cancelAuthentication(IBinder token, String opPackageName);
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index ef58f94..ff5714b 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -17,7 +17,6 @@
package android.net;
import android.annotation.IntDef;
-import android.annotation.SystemApi;
import android.net.ConnectivityManager.NetworkCallback;
import android.os.Parcel;
import android.os.Parcelable;
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index e22c65f..8378a82 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -295,8 +295,10 @@
/**
* The current lowest supported value of app target SDK. Applications targeting
- * lower values will fail to install and run. Its possible values are defined
- * in {@link Build.VERSION_CODES}.
+ * lower values may not function on devices running this SDK version. Its possible
+ * values are defined in {@link Build.VERSION_CODES}.
+ *
+ * @hide
*/
public static final int MIN_SUPPORTED_TARGET_SDK_INT = SystemProperties.getInt(
"ro.build.version.min_supported_target_sdk", 0);
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 62bb385..e3c4870 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -2803,8 +2803,8 @@
Class<?> parcelableClass = Class.forName(name, false /* initialize */,
parcelableClassLoader);
if (!Parcelable.class.isAssignableFrom(parcelableClass)) {
- throw new BadParcelableException("Parcelable protocol requires that the "
- + "class implements Parcelable");
+ throw new BadParcelableException("Parcelable protocol requires subclassing "
+ + "from Parcelable on class " + name);
}
Field f = parcelableClass.getField("CREATOR");
if ((f.getModifiers() & Modifier.STATIC) == 0) {
diff --git a/core/java/android/se/omapi/Channel.java b/core/java/android/se/omapi/Channel.java
index 65ce67f..c8efede 100644
--- a/core/java/android/se/omapi/Channel.java
+++ b/core/java/android/se/omapi/Channel.java
@@ -47,7 +47,8 @@
private final SEService mService;
private final Object mLock = new Object();
- Channel(SEService service, Session session, ISecureElementChannel channel) {
+ Channel(@NonNull SEService service, @NonNull Session session,
+ @NonNull ISecureElementChannel channel) {
if (service == null || session == null || channel == null) {
throw new IllegalArgumentException("Parameters cannot be null");
}
@@ -158,7 +159,7 @@
* @throws SecurityException if the command is filtered by the security policy.
* @throws NullPointerException if command is NULL.
*/
- public @NonNull byte[] transmit(byte[] command) throws IOException {
+ public @NonNull byte[] transmit(@NonNull byte[] command) throws IOException {
if (!mService.isConnected()) {
throw new IllegalStateException("service not connected to system");
}
diff --git a/core/java/android/se/omapi/ISecureElementListener.aidl b/core/java/android/se/omapi/ISecureElementListener.aidl
index e0c6e04..e9dd181 100644
--- a/core/java/android/se/omapi/ISecureElementListener.aidl
+++ b/core/java/android/se/omapi/ISecureElementListener.aidl
@@ -24,8 +24,4 @@
* @hide
*/
interface ISecureElementListener {
- /**
- * Called by the framework when the service is connected.
- */
- void serviceConnected();
}
diff --git a/core/java/android/se/omapi/Reader.java b/core/java/android/se/omapi/Reader.java
index 3dec976..9be3da6 100644
--- a/core/java/android/se/omapi/Reader.java
+++ b/core/java/android/se/omapi/Reader.java
@@ -46,7 +46,7 @@
private final Object mLock = new Object();
- Reader(SEService service, String name, ISecureElementReader reader) {
+ Reader(@NonNull SEService service, @NonNull String name, @NonNull ISecureElementReader reader) {
if (reader == null || service == null || name == null) {
throw new IllegalArgumentException("Parameters cannot be null");
}
diff --git a/core/java/android/se/omapi/SEService.java b/core/java/android/se/omapi/SEService.java
index d59e86a..311dc4c 100644
--- a/core/java/android/se/omapi/SEService.java
+++ b/core/java/android/se/omapi/SEService.java
@@ -62,17 +62,32 @@
/**
* Interface to send call-backs to the application when the service is connected.
*/
- public abstract static class SecureElementListener extends ISecureElementListener.Stub {
+ public interface SecureElementListener {
+ /**
+ * Called by the framework when the service is connected.
+ */
+ void onServiceConnected();
+ }
+
+ /**
+ * Listener object that allows the notification of the caller if this
+ * SEService could be bound to the backend.
+ */
+ private class SEListener extends ISecureElementListener.Stub {
+ public SecureElementListener mListener = null;
+
@Override
public IBinder asBinder() {
return this;
}
- /**
- * Called by the framework when the service is connected.
- */
- public void serviceConnected() {};
+ public void onServiceConnected() {
+ if (mListener != null) {
+ mListener.onServiceConnected();
+ }
+ }
}
+ private SEListener mSEListener = new SEListener();
private static final String TAG = "OMAPI.SEService";
@@ -95,34 +110,28 @@
private final HashMap<String, Reader> mReaders = new HashMap<String, Reader>();
/**
- * Listener object that allows the notification of the caller if this
- * SEService could be bound to the backend.
- */
- private ISecureElementListener mSEListener;
-
- /**
* Establishes a new connection that can be used to connect to all the
* Secure Elements available in the system. The connection process can be
* quite long, so it happens in an asynchronous way. It is usable only if
* the specified listener is called or if isConnected() returns
* <code>true</code>. <br>
* The call-back object passed as a parameter will have its
- * serviceConnected() method called when the connection actually happen.
+ * onServiceConnected() method called when the connection actually happen.
*
* @param context
* the context of the calling application. Cannot be
* <code>null</code>.
* @param listener
- * a SecureElementListener object. Can be <code>null</code>.
+ * a SecureElementListener object.
*/
- public SEService(Context context, SecureElementListener listener) {
+ public SEService(@NonNull Context context, @NonNull SecureElementListener listener) {
if (context == null) {
throw new NullPointerException("context must not be null");
}
mContext = context;
- mSEListener = listener;
+ mSEListener.mListener = listener;
mConnection = new ServiceConnection() {
@@ -131,9 +140,7 @@
mSecureElementService = ISecureElementService.Stub.asInterface(service);
if (mSEListener != null) {
- try {
- mSEListener.serviceConnected();
- } catch (RemoteException ignore) { }
+ mSEListener.onServiceConnected();
}
Log.i(TAG, "Service onServiceConnected");
}
@@ -233,7 +240,7 @@
*
* @return String containing the OpenMobile API version (e.g. "3.0").
*/
- public String getVersion() {
+ public @NonNull String getVersion() {
return "3.2";
}
diff --git a/core/java/android/se/omapi/Session.java b/core/java/android/se/omapi/Session.java
index 3d8b74b..adfeddd 100644
--- a/core/java/android/se/omapi/Session.java
+++ b/core/java/android/se/omapi/Session.java
@@ -47,7 +47,8 @@
private final ISecureElementSession mSession;
private static final String TAG = "OMAPI.Session";
- Session(SEService service, ISecureElementSession session, Reader reader) {
+ Session(@NonNull SEService service, @NonNull ISecureElementSession session,
+ @NonNull Reader reader) {
if (service == null || reader == null || session == null) {
throw new IllegalArgumentException("Parameters cannot be null");
}
@@ -195,7 +196,8 @@
* supported by the device
* @return an instance of Channel if available or null.
*/
- public @Nullable Channel openBasicChannel(byte[] aid, byte p2) throws IOException {
+ public @Nullable Channel openBasicChannel(@Nullable byte[] aid, @Nullable byte p2)
+ throws IOException {
if (!mService.isConnected()) {
throw new IllegalStateException("service not connected to system");
}
@@ -223,32 +225,6 @@
}
/**
- * This method is provided to ease the development of mobile application and for compliancy
- * with existing applications.
- * This method is equivalent to openBasicChannel(aid, P2=0x00)
- *
- * @param aid the AID of the Applet to be selected on this channel, as a
- * byte array, or null if no Applet is to be selected.
- * @throws IOException if there is a communication problem to the reader or
- * the Secure Element.
- * @throws IllegalStateException if the Secure Element session is used after
- * being closed.
- * @throws IllegalArgumentException if the aid's length is not within 5 to
- * 16 (inclusive).
- * @throws SecurityException if the calling application cannot be granted
- * access to this AID or the default Applet on this
- * session.
- * @throws NoSuchElementException if the AID on the Secure Element is not available or cannot be
- * selected.
- * @throws UnsupportedOperationException if the given P2 parameter is not
- * supported by the device
- * @return an instance of Channel if available or null.
- */
- public @Nullable Channel openBasicChannel(byte[] aid) throws IOException {
- return openBasicChannel(aid, (byte) 0x00);
- }
-
- /**
* Open a logical channel with the Secure Element, selecting the Applet represented by
* the given AID. If the AID is null, which means no Applet is to be selected on this
* channel, the default Applet is used. It's up to the Secure Element to choose which
@@ -300,7 +276,8 @@
* @return an instance of Channel. Null if the Secure Element is unable to
* provide a new logical channel.
*/
- public @Nullable Channel openLogicalChannel(byte[] aid, byte p2) throws IOException {
+ public @Nullable Channel openLogicalChannel(@Nullable byte[] aid, @Nullable byte p2)
+ throws IOException {
if (!mService.isConnected()) {
throw new IllegalStateException("service not connected to system");
}
@@ -327,32 +304,4 @@
}
}
}
-
- /**
- * This method is provided to ease the development of mobile application and for compliancy
- * with existing applications.
- * This method is equivalent to openLogicalChannel(aid, P2=0x00)
- *
- * @param aid the AID of the Applet to be selected on this channel, as a
- * byte array.
- * @throws IOException if there is a communication problem to the reader or
- * the Secure Element.
- * @throws IllegalStateException if the Secure Element is used after being
- * closed.
- * @throws IllegalArgumentException if the aid's length is not within 5 to
- * 16 (inclusive).
- * @throws SecurityException if the calling application cannot be granted
- * access to this AID or the default Applet on this
- * session.
- * @throws NoSuchElementException if the AID on the Secure Element is not
- * available or cannot be selected or a logical channel is already
- * open to a non-multiselectable Applet.
- * @throws UnsupportedOperationException if the given P2 parameter is not
- * supported by the device.
- * @return an instance of Channel. Null if the Secure Element is unable to
- * provide a new logical channel.
- */
- public @Nullable Channel openLogicalChannel(byte[] aid) throws IOException {
- return openLogicalChannel(aid, (byte) 0x00);
- }
}
diff --git a/core/java/android/text/InputType.java b/core/java/android/text/InputType.java
index f38482e..7f903b6 100644
--- a/core/java/android/text/InputType.java
+++ b/core/java/android/text/InputType.java
@@ -24,7 +24,7 @@
* <h3>Examples</h3>
*
* <dl>
- * <dt>A password field with with the password visible to the user:
+ * <dt>A password field with the password visible to the user:
* <dd>inputType = TYPE_CLASS_TEXT |
* TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
*
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index d3b1e5c..df81a31 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -250,6 +250,18 @@
}
/**
+ * Destroys the HwuiContext without completely
+ * releasing the Surface.
+ * @hide
+ */
+ public void hwuiDestroy() {
+ if (mHwuiContext != null) {
+ mHwuiContext.destroy();
+ mHwuiContext = null;
+ }
+ }
+
+ /**
* Returns true if this object holds a valid surface.
*
* @return True if it holds a physical surface, so lockCanvas() will succeed.
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index abc19d0..f6181d7 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -236,6 +236,18 @@
int TRANSIT_KEYGUARD_UNOCCLUDE = 23;
/**
+ * A translucent activity is being opened.
+ * @hide
+ */
+ int TRANSIT_TRANSLUCENT_ACTIVITY_OPEN = 24;
+
+ /**
+ * A translucent activity is being closed.
+ * @hide
+ */
+ int TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE = 25;
+
+ /**
* @hide
*/
@IntDef(prefix = { "TRANSIT_" }, value = {
@@ -258,7 +270,9 @@
TRANSIT_KEYGUARD_GOING_AWAY,
TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
TRANSIT_KEYGUARD_OCCLUDE,
- TRANSIT_KEYGUARD_UNOCCLUDE
+ TRANSIT_KEYGUARD_UNOCCLUDE,
+ TRANSIT_TRANSLUCENT_ACTIVITY_OPEN,
+ TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE
})
@Retention(RetentionPolicy.SOURCE)
@interface TransitionType {}
@@ -1833,7 +1847,9 @@
public static final int SOFT_INPUT_MASK_STATE = 0x0f;
/**
- * Visibility state for {@link #softInputMode}: no state has been specified.
+ * Visibility state for {@link #softInputMode}: no state has been specified. The system may
+ * show or hide the software keyboard for better user experience when the window gains
+ * focus.
*/
public static final int SOFT_INPUT_STATE_UNSPECIFIED = 0;
@@ -2220,7 +2236,7 @@
@IntDef(
flag = true,
value = {LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT,
- LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS,
+ LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES,
LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER})
@interface LayoutInDisplayCutoutMode {}
@@ -2231,10 +2247,11 @@
* Defaults to {@link #LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT}.
*
* @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
- * @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+ * @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
* @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
* @see DisplayCutout
- * @see android.R.attr#layoutInDisplayCutoutMode
+ * @see android.R.attr#windowLayoutInDisplayCutoutMode
+ * android:windowLayoutInDisplayCutoutMode
*/
@LayoutInDisplayCutoutMode
public int layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
@@ -2245,10 +2262,10 @@
* laid out such that it does not overlap with the {@link DisplayCutout} area.
*
* <p>
- * In practice, this means that if the window did not set FLAG_FULLSCREEN or
- * SYSTEM_UI_FLAG_FULLSCREEN, it can extend into the cutout area in portrait if the cutout
- * is at the top edge. Similarly for SYSTEM_UI_FLAG_HIDE_NAVIGATION and a cutout at the
- * bottom of the screen.
+ * In practice, this means that if the window did not set {@link #FLAG_FULLSCREEN} or
+ * {@link View#SYSTEM_UI_FLAG_FULLSCREEN}, it can extend into the cutout area in portrait
+ * if the cutout is at the top edge. Similarly for
+ * {@link View#SYSTEM_UI_FLAG_HIDE_NAVIGATION} and a cutout at the bottom of the screen.
* Otherwise (i.e. fullscreen or landscape) it is laid out such that it does not overlap the
* cutout area.
*
@@ -2258,6 +2275,9 @@
*
* @see DisplayCutout
* @see WindowInsets
+ * @see #layoutInDisplayCutoutMode
+ * @see android.R.attr#windowLayoutInDisplayCutoutMode
+ * android:windowLayoutInDisplayCutoutMode
*/
public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0;
@@ -2279,8 +2299,40 @@
* The window must make sure that no important content overlaps with the
* {@link DisplayCutout}.
*
+ * <p>
+ * In this mode, the window extends under cutouts on the short edge of the display in both
+ * portrait and landscape, regardless of whether the window is hiding the system bars:<br/>
+ * <img src="{@docRoot}reference/android/images/display_cutout/short_edge/fullscreen_top_no_letterbox.png"
+ * height="720"
+ * alt="Screenshot of a fullscreen activity on a display with a cutout at the top edge in
+ * portrait, no letterbox is applied."/>
+ *
+ * <img src="{@docRoot}reference/android/images/display_cutout/short_edge/landscape_top_no_letterbox.png"
+ * width="720"
+ * alt="Screenshot of an activity on a display with a cutout at the top edge in landscape,
+ * no letterbox is applied."/>
+ *
+ * <p>
+ * A cutout in the corner is considered to be on the short edge: <br/>
+ * <img src="{@docRoot}reference/android/images/display_cutout/short_edge/fullscreen_corner_no_letterbox.png"
+ * height="720"
+ * alt="Screenshot of a fullscreen activity on a display with a cutout in the corner in
+ * portrait, no letterbox is applied."/>
+ *
+ * <p>
+ * On the other hand, should the cutout be on the long edge of the display, a letterbox will
+ * be applied such that the window does not extend into the cutout on either long edge:
+ * <br/>
+ * <img src="{@docRoot}reference/android/images/display_cutout/short_edge/portrait_side_letterbox.png"
+ * height="720"
+ * alt="Screenshot of an activity on a display with a cutout on the long edge in portrait,
+ * letterbox is applied."/>
+ *
* @see DisplayCutout
* @see WindowInsets#getDisplayCutout()
+ * @see #layoutInDisplayCutoutMode
+ * @see android.R.attr#windowLayoutInDisplayCutoutMode
+ * android:windowLayoutInDisplayCutoutMode
*/
public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES = 1;
@@ -2288,12 +2340,14 @@
* The window is never allowed to overlap with the DisplayCutout area.
*
* <p>
- * This should be used with windows that transiently set SYSTEM_UI_FLAG_FULLSCREEN to
- * avoid a relayout of the window when the flag is set or cleared.
+ * This should be used with windows that transiently set
+ * {@link View#SYSTEM_UI_FLAG_FULLSCREEN} or {@link View#SYSTEM_UI_FLAG_HIDE_NAVIGATION}
+ * to avoid a relayout of the window when the respective flag is set or cleared.
*
* @see DisplayCutout
- * @see View#SYSTEM_UI_FLAG_FULLSCREEN SYSTEM_UI_FLAG_FULLSCREEN
- * @see View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ * @see #layoutInDisplayCutoutMode
+ * @see android.R.attr#windowLayoutInDisplayCutoutMode
+ * android:windowLayoutInDisplayCutoutMode
*/
public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER = 2;
diff --git a/core/java/android/view/textclassifier/DefaultLogger.java b/core/java/android/view/textclassifier/DefaultLogger.java
index b2f4e39..46ff442 100644
--- a/core/java/android/view/textclassifier/DefaultLogger.java
+++ b/core/java/android/view/textclassifier/DefaultLogger.java
@@ -39,7 +39,7 @@
public final class DefaultLogger extends Logger {
private static final String LOG_TAG = "DefaultLogger";
- private static final String CLASSIFIER_ID = "androidtc";
+ static final String CLASSIFIER_ID = "androidtc";
private static final int START_EVENT_DELTA = MetricsEvent.FIELD_SELECTION_SINCE_START;
private static final int PREV_EVENT_DELTA = MetricsEvent.FIELD_SELECTION_SINCE_PREVIOUS;
diff --git a/core/java/android/view/textclassifier/Logger.java b/core/java/android/view/textclassifier/Logger.java
index 9c92fd4..c29d3e6 100644
--- a/core/java/android/view/textclassifier/Logger.java
+++ b/core/java/android/view/textclassifier/Logger.java
@@ -18,56 +18,25 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.StringDef;
import android.content.Context;
-import android.util.Log;
import com.android.internal.util.Preconditions;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
import java.text.BreakIterator;
import java.util.Locale;
import java.util.Objects;
-import java.util.UUID;
/**
* A helper for logging TextClassifier related events.
+ * @hide
*/
public abstract class Logger {
- /**
- * Use this to specify an indeterminate positive index.
- */
- public static final int OUT_OF_BOUNDS = Integer.MAX_VALUE;
-
- /**
- * Use this to specify an indeterminate negative index.
- */
- public static final int OUT_OF_BOUNDS_NEGATIVE = Integer.MIN_VALUE;
-
private static final String LOG_TAG = "Logger";
/* package */ static final boolean DEBUG_LOG_ENABLED = true;
private static final String NO_SIGNATURE = "";
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @StringDef({WIDGET_TEXTVIEW, WIDGET_WEBVIEW, WIDGET_EDITTEXT,
- WIDGET_EDIT_WEBVIEW, WIDGET_CUSTOM_TEXTVIEW, WIDGET_CUSTOM_EDITTEXT,
- WIDGET_CUSTOM_UNSELECTABLE_TEXTVIEW, WIDGET_UNKNOWN})
- public @interface WidgetType {}
-
- public static final String WIDGET_TEXTVIEW = "textview";
- public static final String WIDGET_EDITTEXT = "edittext";
- public static final String WIDGET_UNSELECTABLE_TEXTVIEW = "nosel-textview";
- public static final String WIDGET_WEBVIEW = "webview";
- public static final String WIDGET_EDIT_WEBVIEW = "edit-webview";
- public static final String WIDGET_CUSTOM_TEXTVIEW = "customview";
- public static final String WIDGET_CUSTOM_EDITTEXT = "customedit";
- public static final String WIDGET_CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview";
- public static final String WIDGET_UNKNOWN = "unknown";
-
private @SelectionEvent.InvocationMethod int mInvocationMethod;
private SelectionEvent mPrevEvent;
private SelectionEvent mSmartEvent;
@@ -108,7 +77,6 @@
return false;
}
-
/**
* Returns a token iterator for tokenizing text for logging purposes.
*/
@@ -299,6 +267,9 @@
// Selection did not change. Ignore event.
return;
}
+ break;
+ default:
+ // do nothing.
}
event.setEventTime(now);
@@ -325,9 +296,9 @@
}
}
- private String startNewSession() {
+ private TextClassificationSessionId startNewSession() {
endSession();
- return UUID.randomUUID().toString();
+ return new TextClassificationSessionId();
}
private void endSession() {
@@ -372,12 +343,12 @@
/**
* @param context Context of the widget the logger logs for
* @param widgetType a name for the widget being logged for. e.g.
- * {@link #WIDGET_TEXTVIEW}
+ * {@link TextClassifier#WIDGET_TYPE_TEXTVIEW}
* @param widgetVersion a string version info for the widget the logger logs for
*/
public Config(
@NonNull Context context,
- @WidgetType String widgetType,
+ @TextClassifier.WidgetType String widgetType,
@Nullable String widgetVersion) {
mPackageName = Preconditions.checkNotNull(context).getPackageName();
mWidgetType = widgetType;
@@ -392,7 +363,8 @@
}
/**
- * Returns the name for the widget being logged for. e.g. {@link #WIDGET_TEXTVIEW}.
+ * Returns the name for the widget being logged for. e.g.
+ * {@link TextClassifier#WIDGET_TYPE_TEXTVIEW}.
*/
public String getWidgetType() {
return mWidgetType;
diff --git a/core/java/android/view/textclassifier/SelectionEvent.java b/core/java/android/view/textclassifier/SelectionEvent.java
index 7ac094e..5a4d2cf 100644
--- a/core/java/android/view/textclassifier/SelectionEvent.java
+++ b/core/java/android/view/textclassifier/SelectionEvent.java
@@ -17,10 +17,12 @@
package android.view.textclassifier;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.textclassifier.TextClassifier.EntityType;
+import android.view.textclassifier.TextClassifier.WidgetType;
import com.android.internal.util.Preconditions;
@@ -103,30 +105,33 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({INVOCATION_MANUAL, INVOCATION_LINK})
+ @IntDef({INVOCATION_MANUAL, INVOCATION_LINK, INVOCATION_UNKNOWN})
public @interface InvocationMethod {}
/** Selection was invoked by the user long pressing, double tapping, or dragging to select. */
public static final int INVOCATION_MANUAL = 1;
/** Selection was invoked by the user tapping on a link. */
public static final int INVOCATION_LINK = 2;
+ /** Unknown invocation method */
+ public static final int INVOCATION_UNKNOWN = 0;
+
+ private static final String NO_SIGNATURE = "";
private final int mAbsoluteStart;
private final int mAbsoluteEnd;
- private final @EventType int mEventType;
private final @EntityType String mEntityType;
- @Nullable private final String mWidgetVersion;
- private final String mPackageName;
- private final String mWidgetType;
- private final @InvocationMethod int mInvocationMethod;
- // These fields should only be set by creator of a SelectionEvent.
- private String mSignature;
+ private @EventType int mEventType;
+ private String mPackageName = "";
+ private String mWidgetType = TextClassifier.WIDGET_TYPE_UNKNOWN;
+ private @InvocationMethod int mInvocationMethod;
+ @Nullable private String mWidgetVersion;
+ private String mSignature; // TODO: Rename to resultId.
private long mEventTime;
private long mDurationSinceSessionStart;
private long mDurationSincePreviousEvent;
private int mEventIndex;
- @Nullable private String mSessionId;
+ @Nullable private TextClassificationSessionId mSessionId;
private int mStart;
private int mEnd;
private int mSmartStart;
@@ -135,20 +140,29 @@
SelectionEvent(
int start, int end,
@EventType int eventType, @EntityType String entityType,
- @InvocationMethod int invocationMethod, String signature, Logger.Config config) {
+ @InvocationMethod int invocationMethod, String signature) {
Preconditions.checkArgument(end >= start, "end cannot be less than start");
mAbsoluteStart = start;
mAbsoluteEnd = end;
mEventType = eventType;
mEntityType = Preconditions.checkNotNull(entityType);
mSignature = Preconditions.checkNotNull(signature);
- Preconditions.checkNotNull(config);
- mWidgetVersion = config.getWidgetVersion();
- mPackageName = Preconditions.checkNotNull(config.getPackageName());
- mWidgetType = Preconditions.checkNotNull(config.getWidgetType());
mInvocationMethod = invocationMethod;
}
+ SelectionEvent(
+ int start, int end,
+ @EventType int eventType, @EntityType String entityType,
+ @InvocationMethod int invocationMethod, String signature, Logger.Config config) {
+ this(start, end, eventType, entityType, invocationMethod, signature);
+ Preconditions.checkNotNull(config);
+ setTextClassificationSessionContext(
+ new TextClassificationContext.Builder(
+ config.getPackageName(), config.getWidgetType())
+ .setWidgetVersion(config.getWidgetVersion())
+ .build());
+ }
+
private SelectionEvent(Parcel in) {
mAbsoluteStart = in.readInt();
mAbsoluteEnd = in.readInt();
@@ -163,7 +177,8 @@
mDurationSinceSessionStart = in.readLong();
mDurationSincePreviousEvent = in.readLong();
mEventIndex = in.readInt();
- mSessionId = in.readInt() > 0 ? in.readString() : null;
+ mSessionId = in.readInt() > 0
+ ? TextClassificationSessionId.CREATOR.createFromParcel(in) : null;
mStart = in.readInt();
mEnd = in.readInt();
mSmartStart = in.readInt();
@@ -190,7 +205,7 @@
dest.writeInt(mEventIndex);
dest.writeInt(mSessionId != null ? 1 : 0);
if (mSessionId != null) {
- dest.writeString(mSessionId);
+ mSessionId.writeToParcel(dest, flags);
}
dest.writeInt(mStart);
dest.writeInt(mEnd);
@@ -203,6 +218,156 @@
return 0;
}
+ /**
+ * Creates a "selection started" event.
+ *
+ * @param invocationMethod the way the selection was triggered
+ * @param start the index of the selected text
+ */
+ @NonNull
+ public static SelectionEvent createSelectionStartedEvent(
+ @SelectionEvent.InvocationMethod int invocationMethod, int start) {
+ return new SelectionEvent(
+ start, start + 1, SelectionEvent.EVENT_SELECTION_STARTED,
+ TextClassifier.TYPE_UNKNOWN, invocationMethod, NO_SIGNATURE);
+ }
+
+ /**
+ * Creates a "selection modified" event.
+ * Use when the user modifies the selection.
+ *
+ * @param start the start (inclusive) index of the selection
+ * @param end the end (exclusive) index of the selection
+ *
+ * @throws IllegalArgumentException if end is less than start
+ */
+ @NonNull
+ public static SelectionEvent createSelectionModifiedEvent(int start, int end) {
+ Preconditions.checkArgument(end >= start, "end cannot be less than start");
+ return new SelectionEvent(
+ start, end, SelectionEvent.EVENT_SELECTION_MODIFIED,
+ TextClassifier.TYPE_UNKNOWN, INVOCATION_UNKNOWN, NO_SIGNATURE);
+ }
+
+ /**
+ * Creates a "selection modified" event.
+ * Use when the user modifies the selection and the selection's entity type is known.
+ *
+ * @param start the start (inclusive) index of the selection
+ * @param end the end (exclusive) index of the selection
+ * @param classification the TextClassification object returned by the TextClassifier that
+ * classified the selected text
+ *
+ * @throws IllegalArgumentException if end is less than start
+ */
+ @NonNull
+ public static SelectionEvent createSelectionModifiedEvent(
+ int start, int end, @NonNull TextClassification classification) {
+ Preconditions.checkArgument(end >= start, "end cannot be less than start");
+ Preconditions.checkNotNull(classification);
+ final String entityType = classification.getEntityCount() > 0
+ ? classification.getEntity(0)
+ : TextClassifier.TYPE_UNKNOWN;
+ return new SelectionEvent(
+ start, end, SelectionEvent.EVENT_SELECTION_MODIFIED,
+ entityType, INVOCATION_UNKNOWN, classification.getSignature());
+ }
+
+ /**
+ * Creates a "selection modified" event.
+ * Use when a TextClassifier modifies the selection.
+ *
+ * @param start the start (inclusive) index of the selection
+ * @param end the end (exclusive) index of the selection
+ * @param selection the TextSelection object returned by the TextClassifier for the
+ * specified selection
+ *
+ * @throws IllegalArgumentException if end is less than start
+ */
+ @NonNull
+ public static SelectionEvent createSelectionModifiedEvent(
+ int start, int end, @NonNull TextSelection selection) {
+ Preconditions.checkArgument(end >= start, "end cannot be less than start");
+ Preconditions.checkNotNull(selection);
+ final String entityType = selection.getEntityCount() > 0
+ ? selection.getEntity(0)
+ : TextClassifier.TYPE_UNKNOWN;
+ return new SelectionEvent(
+ start, end, SelectionEvent.EVENT_AUTO_SELECTION,
+ entityType, INVOCATION_UNKNOWN, selection.getSignature());
+ }
+
+ /**
+ * Creates an event specifying an action taken on a selection.
+ * Use when the user clicks on an action to act on the selected text.
+ *
+ * @param start the start (inclusive) index of the selection
+ * @param end the end (exclusive) index of the selection
+ * @param actionType the action that was performed on the selection
+ *
+ * @throws IllegalArgumentException if end is less than start
+ */
+ @NonNull
+ public static SelectionEvent createSelectionActionEvent(
+ int start, int end, @SelectionEvent.ActionType int actionType) {
+ Preconditions.checkArgument(end >= start, "end cannot be less than start");
+ checkActionType(actionType);
+ return new SelectionEvent(
+ start, end, actionType, TextClassifier.TYPE_UNKNOWN, INVOCATION_UNKNOWN,
+ NO_SIGNATURE);
+ }
+
+ /**
+ * Creates an event specifying an action taken on a selection.
+ * Use when the user clicks on an action to act on the selected text and the selection's
+ * entity type is known.
+ *
+ * @param start the start (inclusive) index of the selection
+ * @param end the end (exclusive) index of the selection
+ * @param actionType the action that was performed on the selection
+ * @param classification the TextClassification object returned by the TextClassifier that
+ * classified the selected text
+ *
+ * @throws IllegalArgumentException if end is less than start
+ * @throws IllegalArgumentException If actionType is not a valid SelectionEvent actionType
+ */
+ @NonNull
+ public static SelectionEvent createSelectionActionEvent(
+ int start, int end, @SelectionEvent.ActionType int actionType,
+ @NonNull TextClassification classification) {
+ Preconditions.checkArgument(end >= start, "end cannot be less than start");
+ Preconditions.checkNotNull(classification);
+ checkActionType(actionType);
+ final String entityType = classification.getEntityCount() > 0
+ ? classification.getEntity(0)
+ : TextClassifier.TYPE_UNKNOWN;
+ return new SelectionEvent(start, end, actionType, entityType, INVOCATION_UNKNOWN,
+ classification.getSignature());
+ }
+
+ /**
+ * @throws IllegalArgumentException If eventType is not an {@link SelectionEvent.ActionType}
+ */
+ private static void checkActionType(@SelectionEvent.EventType int eventType)
+ throws IllegalArgumentException {
+ switch (eventType) {
+ case SelectionEvent.ACTION_OVERTYPE: // fall through
+ case SelectionEvent.ACTION_COPY: // fall through
+ case SelectionEvent.ACTION_PASTE: // fall through
+ case SelectionEvent.ACTION_CUT: // fall through
+ case SelectionEvent.ACTION_SHARE: // fall through
+ case SelectionEvent.ACTION_SMART_SHARE: // fall through
+ case SelectionEvent.ACTION_DRAG: // fall through
+ case SelectionEvent.ACTION_ABANDON: // fall through
+ case SelectionEvent.ACTION_SELECT_ALL: // fall through
+ case SelectionEvent.ACTION_RESET: // fall through
+ return;
+ default:
+ throw new IllegalArgumentException(
+ String.format(Locale.US, "%d is not an eventType", eventType));
+ }
+ }
+
int getAbsoluteStart() {
return mAbsoluteStart;
}
@@ -214,15 +379,24 @@
/**
* Returns the type of event that was triggered. e.g. {@link #ACTION_COPY}.
*/
+ @EventType
public int getEventType() {
return mEventType;
}
/**
+ * Sets the event type.
+ */
+ void setEventType(@EventType int eventType) {
+ mEventType = eventType;
+ }
+
+ /**
* Returns the type of entity that is associated with this event. e.g.
* {@link android.view.textclassifier.TextClassifier#TYPE_EMAIL}.
*/
@EntityType
+ @NonNull
public String getEntityType() {
return mEntityType;
}
@@ -230,6 +404,7 @@
/**
* Returns the package name of the app that this event originated in.
*/
+ @NonNull
public String getPackageName() {
return mPackageName;
}
@@ -237,6 +412,8 @@
/**
* Returns the type of widget that was involved in triggering this event.
*/
+ @WidgetType
+ @NonNull
public String getWidgetType() {
return mWidgetType;
}
@@ -244,11 +421,21 @@
/**
* Returns a string version info for the widget this event was triggered in.
*/
+ @Nullable
public String getWidgetVersion() {
return mWidgetVersion;
}
/**
+ * Sets the {@link TextClassificationContext} for this event.
+ */
+ void setTextClassificationSessionContext(TextClassificationContext context) {
+ mPackageName = context.getPackageName();
+ mWidgetType = context.getWidgetType();
+ mWidgetVersion = context.getWidgetVersion();
+ }
+
+ /**
* Returns the way the selection mode was invoked.
*/
public @InvocationMethod int getInvocationMethod() {
@@ -256,6 +443,13 @@
}
/**
+ * Sets the invocationMethod for this event.
+ */
+ void setInvocationMethod(@InvocationMethod int invocationMethod) {
+ mInvocationMethod = invocationMethod;
+ }
+
+ /**
* Returns the signature of the text classifier result associated with this event.
*/
public String getSignature() {
@@ -320,17 +514,18 @@
/**
* Returns the selection session id.
*/
- public String getSessionId() {
+ @Nullable
+ public TextClassificationSessionId getSessionId() {
return mSessionId;
}
- SelectionEvent setSessionId(String id) {
+ SelectionEvent setSessionId(TextClassificationSessionId id) {
mSessionId = id;
return this;
}
/**
- * Returns the start index of this events token relative to the index of the start selection
+ * Returns the start index of this events relative to the index of the start selection
* event in the selection session.
*/
public int getStart() {
@@ -343,7 +538,7 @@
}
/**
- * Returns the end index of this events token relative to the index of the start selection
+ * Returns the end index of this events relative to the index of the start selection
* event in the selection session.
*/
public int getEnd() {
@@ -356,7 +551,7 @@
}
/**
- * Returns the start index of this events token relative to the index of the smart selection
+ * Returns the start index of this events relative to the index of the smart selection
* event in the selection session.
*/
public int getSmartStart() {
@@ -369,7 +564,7 @@
}
/**
- * Returns the end index of this events token relative to the index of the smart selection
+ * Returns the end index of this events relative to the index of the smart selection
* event in the selection session.
*/
public int getSmartEnd() {
@@ -382,7 +577,15 @@
}
boolean isTerminal() {
- switch (mEventType) {
+ return isTerminal(mEventType);
+ }
+
+ /**
+ * Returns true if the eventType is a terminal event type. Otherwise returns false.
+ * A terminal event is an event that ends a selection interaction.
+ */
+ public static boolean isTerminal(@EventType int eventType) {
+ switch (eventType) {
case ACTION_OVERTYPE: // fall through
case ACTION_COPY: // fall through
case ACTION_PASTE: // fall through
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index b5c9de9..630007b 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -21,6 +21,8 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.app.RemoteAction;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -43,6 +45,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Calendar;
+import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -77,25 +80,16 @@
* view.startActionMode(new ActionMode.Callback() {
*
* public boolean onCreateActionMode(ActionMode mode, Menu menu) {
- * // Add the "primary" action.
- * if (thisAppHasPermissionToInvokeIntent(classification.getIntent())) {
- * menu.add(Menu.NONE, 0, 20, classification.getLabel())
- * .setIcon(classification.getIcon())
- * .setIntent(classification.getIntent());
- * }
- * // Add the "secondary" actions.
- * for (int i = 0; i < classification.getSecondaryActionsCount(); i++) {
- * if (thisAppHasPermissionToInvokeIntent(classification.getSecondaryIntent(i))) {
- * menu.add(Menu.NONE, i + 1, 20, classification.getSecondaryLabel(i))
- * .setIcon(classification.getSecondaryIcon(i))
- * .setIntent(classification.getSecondaryIntent(i));
- * }
+ * for (int i = 0; i < classification.getActions().size(); ++i) {
+ * RemoteAction action = classification.getActions().get(i);
+ * menu.add(Menu.NONE, i, 20, action.getTitle())
+ * .setIcon(action.getIcon());
* }
* return true;
* }
*
* public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
- * context.startActivity(item.getIntent());
+ * classification.getActions().get(item.getItemId()).getActionIntent().send();
* return true;
* }
*
@@ -110,9 +104,9 @@
*/
static final TextClassification EMPTY = new TextClassification.Builder().build();
+ private static final String LOG_TAG = "TextClassification";
// TODO(toki): investigate a way to derive this based on device properties.
- private static final int MAX_PRIMARY_ICON_SIZE = 192;
- private static final int MAX_SECONDARY_ICON_SIZE = 144;
+ private static final int MAX_LEGACY_ICON_SIZE = 192;
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {IntentType.UNSUPPORTED, IntentType.ACTIVITY, IntentType.SERVICE})
@@ -123,37 +117,29 @@
}
@NonNull private final String mText;
- @Nullable private final Drawable mPrimaryIcon;
- @Nullable private final String mPrimaryLabel;
- @Nullable private final Intent mPrimaryIntent;
- @Nullable private final OnClickListener mPrimaryOnClickListener;
- @NonNull private final List<Drawable> mSecondaryIcons;
- @NonNull private final List<String> mSecondaryLabels;
- @NonNull private final List<Intent> mSecondaryIntents;
+ @Nullable private final Drawable mLegacyIcon;
+ @Nullable private final String mLegacyLabel;
+ @Nullable private final Intent mLegacyIntent;
+ @Nullable private final OnClickListener mLegacyOnClickListener;
+ @NonNull private final List<RemoteAction> mActions;
@NonNull private final EntityConfidence mEntityConfidence;
@NonNull private final String mSignature;
private TextClassification(
@Nullable String text,
- @Nullable Drawable primaryIcon,
- @Nullable String primaryLabel,
- @Nullable Intent primaryIntent,
- @Nullable OnClickListener primaryOnClickListener,
- @NonNull List<Drawable> secondaryIcons,
- @NonNull List<String> secondaryLabels,
- @NonNull List<Intent> secondaryIntents,
+ @Nullable Drawable legacyIcon,
+ @Nullable String legacyLabel,
+ @Nullable Intent legacyIntent,
+ @Nullable OnClickListener legacyOnClickListener,
+ @NonNull List<RemoteAction> actions,
@NonNull Map<String, Float> entityConfidence,
@NonNull String signature) {
- Preconditions.checkArgument(secondaryLabels.size() == secondaryIntents.size());
- Preconditions.checkArgument(secondaryIcons.size() == secondaryIntents.size());
mText = text;
- mPrimaryIcon = primaryIcon;
- mPrimaryLabel = primaryLabel;
- mPrimaryIntent = primaryIntent;
- mPrimaryOnClickListener = primaryOnClickListener;
- mSecondaryIcons = secondaryIcons;
- mSecondaryLabels = secondaryLabels;
- mSecondaryIntents = secondaryIntents;
+ mLegacyIcon = legacyIcon;
+ mLegacyLabel = legacyLabel;
+ mLegacyIntent = legacyIntent;
+ mLegacyOnClickListener = legacyOnClickListener;
+ mActions = Collections.unmodifiableList(actions);
mEntityConfidence = new EntityConfidence(entityConfidence);
mSignature = signature;
}
@@ -197,108 +183,57 @@
}
/**
- * Returns the number of <i>secondary</i> actions that are available to act on the classified
- * text.
- *
- * <p><strong>Note: </strong> that there may or may not be a <i>primary</i> action.
- *
- * @see #getSecondaryIntent(int)
- * @see #getSecondaryLabel(int)
- * @see #getSecondaryIcon(int)
+ * Returns a list of actions that may be performed on the text. The list is ordered based on
+ * the likelihood that a user will use the action, with the most likely action appearing first.
*/
- @IntRange(from = 0)
- public int getSecondaryActionsCount() {
- return mSecondaryIntents.size();
+ public List<RemoteAction> getActions() {
+ return mActions;
}
/**
- * Returns one of the <i>secondary</i> icons that maybe rendered on a widget used to act on the
- * classified text.
+ * Returns an icon that may be rendered on a widget used to act on the classified text.
*
- * @param index Index of the action to get the icon for.
- * @throws IndexOutOfBoundsException if the specified index is out of range.
- * @see #getSecondaryActionsCount() for the number of actions available.
- * @see #getSecondaryIntent(int)
- * @see #getSecondaryLabel(int)
- * @see #getIcon()
+ * @deprecated Use {@link #getActions()} instead.
*/
- @Nullable
- public Drawable getSecondaryIcon(int index) {
- return mSecondaryIcons.get(index);
- }
-
- /**
- * Returns an icon for the <i>primary</i> intent that may be rendered on a widget used to act
- * on the classified text.
- *
- * @see #getSecondaryIcon(int)
- */
+ @Deprecated
@Nullable
public Drawable getIcon() {
- return mPrimaryIcon;
+ return mLegacyIcon;
}
/**
- * Returns one of the <i>secondary</i> labels that may be rendered on a widget used to act on
- * the classified text.
+ * Returns a label that may be rendered on a widget used to act on the classified text.
*
- * @param index Index of the action to get the label for.
- * @throws IndexOutOfBoundsException if the specified index is out of range.
- * @see #getSecondaryActionsCount()
- * @see #getSecondaryIntent(int)
- * @see #getSecondaryIcon(int)
- * @see #getLabel()
+ * @deprecated Use {@link #getActions()} instead.
*/
- @Nullable
- public CharSequence getSecondaryLabel(int index) {
- return mSecondaryLabels.get(index);
- }
-
- /**
- * Returns a label for the <i>primary</i> intent that may be rendered on a widget used to act
- * on the classified text.
- *
- * @see #getSecondaryLabel(int)
- */
+ @Deprecated
@Nullable
public CharSequence getLabel() {
- return mPrimaryLabel;
+ return mLegacyLabel;
}
/**
- * Returns one of the <i>secondary</i> intents that may be fired to act on the classified text.
+ * Returns an intent that may be fired to act on the classified text.
*
- * @param index Index of the action to get the intent for.
- * @throws IndexOutOfBoundsException if the specified index is out of range.
- * @see #getSecondaryActionsCount()
- * @see #getSecondaryLabel(int)
- * @see #getSecondaryIcon(int)
- * @see #getIntent()
+ * @deprecated Use {@link #getActions()} instead.
*/
- @Nullable
- public Intent getSecondaryIntent(int index) {
- return mSecondaryIntents.get(index);
- }
-
- /**
- * Returns the <i>primary</i> intent that may be fired to act on the classified text.
- *
- * @see #getSecondaryIntent(int)
- */
+ @Deprecated
@Nullable
public Intent getIntent() {
- return mPrimaryIntent;
+ return mLegacyIntent;
}
/**
- * Returns the <i>primary</i> OnClickListener that may be triggered to act on the classified
- * text. This field is not parcelable and will be null for all objects read from a parcel.
- * Instead, call Context#startActivity(Intent) with the result of #getSecondaryIntent(int).
- * Note that this may fail if the activity doesn't have permission to send the intent.
+ * Returns the OnClickListener that may be triggered to act on the classified text. This field
+ * is not parcelable and will be null for all objects read from a parcel. Instead, call
+ * Context#startActivity(Intent) with the result of #getSecondaryIntent(int). Note that this may
+ * fail if the activity doesn't have permission to send the intent.
+ *
+ * @deprecated Use {@link #getActions()} instead.
*/
@Nullable
public OnClickListener getOnClickListener() {
- return mPrimaryOnClickListener;
+ return mLegacyOnClickListener;
}
/**
@@ -313,32 +248,42 @@
@Override
public String toString() {
- return String.format(Locale.US, "TextClassification {"
- + "text=%s, entities=%s, "
- + "primaryLabel=%s, secondaryLabels=%s, "
- + "primaryIntent=%s, secondaryIntents=%s, "
- + "signature=%s}",
- mText, mEntityConfidence,
- mPrimaryLabel, mSecondaryLabels,
- mPrimaryIntent, mSecondaryIntents,
- mSignature);
+ return String.format(Locale.US,
+ "TextClassification {text=%s, entities=%s, actions=%s, signature=%s}",
+ mText, mEntityConfidence, mActions, mSignature);
}
/**
- * Creates an OnClickListener that triggers the specified intent.
+ * Creates an OnClickListener that triggers the specified PendingIntent.
+ *
+ * @hide
+ */
+ public static OnClickListener createIntentOnClickListener(@NonNull final PendingIntent intent) {
+ Preconditions.checkNotNull(intent);
+ return v -> {
+ try {
+ intent.send();
+ } catch (PendingIntent.CanceledException e) {
+ Log.e(LOG_TAG, "Error creating OnClickListener from PendingIntent", e);
+ }
+ };
+ }
+
+ /**
+ * Creates a PendingIntent for the specified intent.
* Returns null if the intent is not supported for the specified context.
*
* @throws IllegalArgumentException if context or intent is null
* @hide
*/
@Nullable
- public static OnClickListener createIntentOnClickListener(
+ public static PendingIntent createPendingIntent(
@NonNull final Context context, @NonNull final Intent intent) {
switch (getIntentType(intent, context)) {
case IntentType.ACTIVITY:
- return v -> context.startActivity(intent);
+ return PendingIntent.getActivity(context, 0, intent, 0);
case IntentType.SERVICE:
- return v -> context.startService(intent);
+ return PendingIntent.getService(context, 0, intent, 0);
default:
return null;
}
@@ -434,33 +379,6 @@
}
/**
- * Returns a list of drawables converted to Bitmaps
- *
- * @param drawables The drawables to convert.
- * @param maxDims The maximum edge length of the resulting bitmaps (in pixels).
- */
- private static List<Bitmap> drawablesToBitmaps(List<Drawable> drawables, int maxDims) {
- final List<Bitmap> bitmaps = new ArrayList<>(drawables.size());
- for (Drawable drawable : drawables) {
- bitmaps.add(drawableToBitmap(drawable, maxDims));
- }
- return bitmaps;
- }
-
- /** Returns a list of drawable wrappers for a list of bitmaps. */
- private static List<Drawable> bitmapsToDrawables(List<Bitmap> bitmaps) {
- final List<Drawable> drawables = new ArrayList<>(bitmaps.size());
- for (Bitmap bitmap : bitmaps) {
- if (bitmap != null) {
- drawables.add(new BitmapDrawable(Resources.getSystem(), bitmap));
- } else {
- drawables.add(null);
- }
- }
- return drawables;
- }
-
- /**
* Builder for building {@link TextClassification} objects.
*
* <p>e.g.
@@ -470,23 +388,20 @@
* .setText(classifiedText)
* .setEntityType(TextClassifier.TYPE_EMAIL, 0.9)
* .setEntityType(TextClassifier.TYPE_OTHER, 0.1)
- * .setPrimaryAction(intent, label, icon)
- * .addSecondaryAction(intent1, label1, icon1)
- * .addSecondaryAction(intent2, label2, icon2)
+ * .addAction(remoteAction1)
+ * .addAction(remoteAction2)
* .build();
* }</pre>
*/
public static final class Builder {
@NonNull private String mText;
- @NonNull private final List<Drawable> mSecondaryIcons = new ArrayList<>();
- @NonNull private final List<String> mSecondaryLabels = new ArrayList<>();
- @NonNull private final List<Intent> mSecondaryIntents = new ArrayList<>();
+ @NonNull private List<RemoteAction> mActions = new ArrayList<>();
@NonNull private final Map<String, Float> mEntityConfidence = new ArrayMap<>();
- @Nullable Drawable mPrimaryIcon;
- @Nullable String mPrimaryLabel;
- @Nullable Intent mPrimaryIntent;
- @Nullable OnClickListener mPrimaryOnClickListener;
+ @Nullable Drawable mLegacyIcon;
+ @Nullable String mLegacyLabel;
+ @Nullable Intent mLegacyIntent;
+ @Nullable OnClickListener mLegacyOnClickListener;
@NonNull private String mSignature = "";
/**
@@ -514,60 +429,25 @@
}
/**
- * Adds an <i>secondary</i> action that may be performed on the classified text.
- * Secondary actions are in addition to the <i>primary</i> action which may or may not
- * exist.
- *
- * <p>The label and icon are used for rendering of widgets that offer the intent.
- * Actions should be added in order of priority.
- *
- * <p><stong>Note: </stong> If all input parameters are set to null, this method will be a
- * no-op.
- *
- * @see #setPrimaryAction(Intent, String, Drawable)
+ * Adds an action that may be performed on the classified text. Actions should be added in
+ * order of likelihood that the user will use them, with the most likely action being added
+ * first.
*/
- public Builder addSecondaryAction(
- @Nullable Intent intent, @Nullable String label, @Nullable Drawable icon) {
- if (intent != null || label != null || icon != null) {
- mSecondaryIntents.add(intent);
- mSecondaryLabels.add(label);
- mSecondaryIcons.add(icon);
- }
+ public Builder addAction(@NonNull RemoteAction action) {
+ Preconditions.checkArgument(action != null);
+ mActions.add(action);
return this;
}
/**
- * Removes all the <i>secondary</i> actions.
- */
- public Builder clearSecondaryActions() {
- mSecondaryIntents.clear();
- mSecondaryLabels.clear();
- mSecondaryIcons.clear();
- return this;
- }
-
- /**
- * Sets the <i>primary</i> action that may be performed on the classified text. This is
- * equivalent to calling {@code setIntent(intent).setLabel(label).setIcon(icon)}.
- *
- * <p><strong>Note: </strong>If all input parameters are null, there will be no
- * <i>primary</i> action but there may still be <i>secondary</i> actions.
- *
- * @see #addSecondaryAction(Intent, String, Drawable)
- */
- public Builder setPrimaryAction(
- @Nullable Intent intent, @Nullable String label, @Nullable Drawable icon) {
- return setIntent(intent).setLabel(label).setIcon(icon);
- }
-
- /**
* Sets the icon for the <i>primary</i> action that may be rendered on a widget used to act
* on the classified text.
*
- * @see #setPrimaryAction(Intent, String, Drawable)
+ * @deprecated Use {@link #addAction(RemoteAction)} instead.
*/
+ @Deprecated
public Builder setIcon(@Nullable Drawable icon) {
- mPrimaryIcon = icon;
+ mLegacyIcon = icon;
return this;
}
@@ -575,10 +455,11 @@
* Sets the label for the <i>primary</i> action that may be rendered on a widget used to
* act on the classified text.
*
- * @see #setPrimaryAction(Intent, String, Drawable)
+ * @deprecated Use {@link #addAction(RemoteAction)} instead.
*/
+ @Deprecated
public Builder setLabel(@Nullable String label) {
- mPrimaryLabel = label;
+ mLegacyLabel = label;
return this;
}
@@ -586,10 +467,11 @@
* Sets the intent for the <i>primary</i> action that may be fired to act on the classified
* text.
*
- * @see #setPrimaryAction(Intent, String, Drawable)
+ * @deprecated Use {@link #addAction(RemoteAction)} instead.
*/
+ @Deprecated
public Builder setIntent(@Nullable Intent intent) {
- mPrimaryIntent = intent;
+ mLegacyIntent = intent;
return this;
}
@@ -597,9 +479,11 @@
* Sets the OnClickListener for the <i>primary</i> action that may be triggered to act on
* the classified text. This field is not parcelable and will always be null when the
* object is read from a parcel.
+ *
+ * @deprecated Use {@link #addAction(RemoteAction)} instead.
*/
public Builder setOnClickListener(@Nullable OnClickListener onClickListener) {
- mPrimaryOnClickListener = onClickListener;
+ mLegacyOnClickListener = onClickListener;
return this;
}
@@ -617,11 +501,8 @@
* Builds and returns a {@link TextClassification} object.
*/
public TextClassification build() {
- return new TextClassification(
- mText,
- mPrimaryIcon, mPrimaryLabel, mPrimaryIntent, mPrimaryOnClickListener,
- mSecondaryIcons, mSecondaryLabels, mSecondaryIntents,
- mEntityConfidence, mSignature);
+ return new TextClassification(mText, mLegacyIcon, mLegacyLabel, mLegacyIntent,
+ mLegacyOnClickListener, mActions, mEntityConfidence, mSignature);
}
}
@@ -721,20 +602,18 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mText);
- final Bitmap primaryIconBitmap = drawableToBitmap(mPrimaryIcon, MAX_PRIMARY_ICON_SIZE);
- dest.writeInt(primaryIconBitmap != null ? 1 : 0);
- if (primaryIconBitmap != null) {
- primaryIconBitmap.writeToParcel(dest, flags);
+ final Bitmap legacyIconBitmap = drawableToBitmap(mLegacyIcon, MAX_LEGACY_ICON_SIZE);
+ dest.writeInt(legacyIconBitmap != null ? 1 : 0);
+ if (legacyIconBitmap != null) {
+ legacyIconBitmap.writeToParcel(dest, flags);
}
- dest.writeString(mPrimaryLabel);
- dest.writeInt(mPrimaryIntent != null ? 1 : 0);
- if (mPrimaryIntent != null) {
- mPrimaryIntent.writeToParcel(dest, flags);
+ dest.writeString(mLegacyLabel);
+ dest.writeInt(mLegacyIntent != null ? 1 : 0);
+ if (mLegacyIntent != null) {
+ mLegacyIntent.writeToParcel(dest, flags);
}
- // mPrimaryOnClickListener is not parcelable.
- dest.writeTypedList(drawablesToBitmaps(mSecondaryIcons, MAX_SECONDARY_ICON_SIZE));
- dest.writeStringList(mSecondaryLabels);
- dest.writeTypedList(mSecondaryIntents);
+ // mOnClickListener is not parcelable.
+ dest.writeTypedList(mActions);
mEntityConfidence.writeToParcel(dest, flags);
dest.writeString(mSignature);
}
@@ -754,15 +633,19 @@
private TextClassification(Parcel in) {
mText = in.readString();
- mPrimaryIcon = in.readInt() == 0
+ mLegacyIcon = in.readInt() == 0
? null
: new BitmapDrawable(Resources.getSystem(), Bitmap.CREATOR.createFromParcel(in));
- mPrimaryLabel = in.readString();
- mPrimaryIntent = in.readInt() == 0 ? null : Intent.CREATOR.createFromParcel(in);
- mPrimaryOnClickListener = null; // not parcelable
- mSecondaryIcons = bitmapsToDrawables(in.createTypedArrayList(Bitmap.CREATOR));
- mSecondaryLabels = in.createStringArrayList();
- mSecondaryIntents = in.createTypedArrayList(Intent.CREATOR);
+ mLegacyLabel = in.readString();
+ if (in.readInt() == 0) {
+ mLegacyIntent = null;
+ } else {
+ mLegacyIntent = Intent.CREATOR.createFromParcel(in);
+ mLegacyIntent.removeFlags(
+ Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ }
+ mLegacyOnClickListener = null; // not parcelable
+ mActions = in.createTypedArrayList(RemoteAction.CREATOR);
mEntityConfidence = EntityConfidence.CREATOR.createFromParcel(in);
mSignature = in.readString();
}
diff --git a/core/java/android/view/textclassifier/TextClassificationContext.java b/core/java/android/view/textclassifier/TextClassificationContext.java
new file mode 100644
index 0000000..a88f2f6
--- /dev/null
+++ b/core/java/android/view/textclassifier/TextClassificationContext.java
@@ -0,0 +1,123 @@
+/*
+ * 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.view.textclassifier;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.view.textclassifier.TextClassifier.WidgetType;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Locale;
+
+/**
+ * A representation of the context in which text classification would be performed.
+ * @see TextClassificationManager#createTextClassificationSession(TextClassificationContext)
+ */
+public final class TextClassificationContext {
+
+ private final String mPackageName;
+ private final String mWidgetType;
+ @Nullable private final String mWidgetVersion;
+
+ private TextClassificationContext(
+ String packageName,
+ String widgetType,
+ String widgetVersion) {
+ mPackageName = Preconditions.checkNotNull(packageName);
+ mWidgetType = Preconditions.checkNotNull(widgetType);
+ mWidgetVersion = widgetVersion;
+ }
+
+ /**
+ * Returns the package name for the calling package.
+ */
+ @NonNull
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ /**
+ * Returns the widget type for this classification context.
+ */
+ @NonNull
+ @WidgetType
+ public String getWidgetType() {
+ return mWidgetType;
+ }
+
+ /**
+ * Returns a custom version string for the widget type.
+ *
+ * @see #getWidgetType()
+ */
+ @Nullable
+ public String getWidgetVersion() {
+ return mWidgetVersion;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(Locale.US, "TextClassificationContext{"
+ + "packageName=%s, widgetType=%s, widgetVersion=%s}",
+ mPackageName, mWidgetType, mWidgetVersion);
+ }
+
+ /**
+ * A builder for building a TextClassification context.
+ */
+ public static final class Builder {
+
+ private final String mPackageName;
+ private final String mWidgetType;
+
+ @Nullable private String mWidgetVersion;
+
+ /**
+ * Initializes a new builder for text classification context objects.
+ *
+ * @param packageName the name of the calling package
+ * @param widgetType the type of widget e.g. {@link TextClassifier#WIDGET_TYPE_TEXTVIEW}
+ *
+ * @return this builder
+ */
+ public Builder(@NonNull String packageName, @NonNull @WidgetType String widgetType) {
+ mPackageName = Preconditions.checkNotNull(packageName);
+ mWidgetType = Preconditions.checkNotNull(widgetType);
+ }
+
+ /**
+ * Sets an optional custom version string for the widget type.
+ *
+ * @return this builder
+ */
+ public Builder setWidgetVersion(@Nullable String widgetVersion) {
+ mWidgetVersion = widgetVersion;
+ return this;
+ }
+
+ /**
+ * Builds the text classification context object.
+ *
+ * @return the built TextClassificationContext object
+ */
+ @NonNull
+ public TextClassificationContext build() {
+ return new TextClassificationContext(mPackageName, mWidgetType, mWidgetVersion);
+ }
+ }
+}
diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java
index a7f1ca1..262d9b8 100644
--- a/core/java/android/view/textclassifier/TextClassificationManager.java
+++ b/core/java/android/view/textclassifier/TextClassificationManager.java
@@ -16,6 +16,7 @@
package android.view.textclassifier;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemService;
import android.content.Context;
@@ -36,6 +37,9 @@
private static final String LOG_TAG = "TextClassificationManager";
private final Object mLock = new Object();
+ private final TextClassificationSessionFactory mDefaultSessionFactory =
+ classificationContext -> new TextClassificationSession(
+ classificationContext, getTextClassifier());
private final Context mContext;
private final TextClassificationConstants mSettings;
@@ -46,12 +50,15 @@
private TextClassifier mLocalTextClassifier;
@GuardedBy("mLock")
private TextClassifier mSystemTextClassifier;
+ @GuardedBy("mLock")
+ private TextClassificationSessionFactory mSessionFactory;
/** @hide */
public TextClassificationManager(Context context) {
mContext = Preconditions.checkNotNull(context);
mSettings = TextClassificationConstants.loadFromString(Settings.Global.getString(
context.getContentResolver(), Settings.Global.TEXT_CLASSIFIER_CONSTANTS));
+ mSessionFactory = mDefaultSessionFactory;
}
/**
@@ -61,6 +68,7 @@
*
* @see #setTextClassifier(TextClassifier)
*/
+ @NonNull
public TextClassifier getTextClassifier() {
synchronized (mLock) {
if (mTextClassifier == null) {
@@ -93,7 +101,6 @@
* @see TextClassifier#SYSTEM
* @hide
*/
- // TODO: Expose as system API.
public TextClassifier getTextClassifier(@TextClassifierType int type) {
switch (type) {
case TextClassifier.LOCAL:
@@ -108,6 +115,61 @@
return mSettings;
}
+ /**
+ * Call this method to start a text classification session with the given context.
+ * A session is created with a context helping the classifier better understand
+ * what the user needs and consists of queries and feedback events. The queries
+ * are directly related to providing useful functionality to the user and the events
+ * are a feedback loop back to the classifier helping it learn and better serve
+ * future queries.
+ *
+ * <p> All interactions with the returned classifier are considered part of a single
+ * session and are logically grouped. For example, when a text widget is focused
+ * all user interactions around text editing (selection, editing, etc) can be
+ * grouped together to allow the classifier get better.
+ *
+ * @param classificationContext The context in which classification would occur
+ *
+ * @return An instance to perform classification in the given context
+ */
+ @NonNull
+ public TextClassifier createTextClassificationSession(
+ @NonNull TextClassificationContext classificationContext) {
+ Preconditions.checkNotNull(classificationContext);
+ final TextClassifier textClassifier =
+ mSessionFactory.createTextClassificationSession(classificationContext);
+ Preconditions.checkNotNull(textClassifier, "Session Factory should never return null");
+ return textClassifier;
+ }
+
+ /**
+ * @see #createTextClassificationSession(TextClassificationContext, TextClassifier)
+ * @hide
+ */
+ public TextClassifier createTextClassificationSession(
+ TextClassificationContext classificationContext, TextClassifier textClassifier) {
+ Preconditions.checkNotNull(classificationContext);
+ Preconditions.checkNotNull(textClassifier);
+ return new TextClassificationSession(classificationContext, textClassifier);
+ }
+
+ /**
+ * Sets a TextClassificationSessionFactory to be used to create session-aware TextClassifiers.
+ *
+ * @param factory the textClassification session factory. If this is null, the default factory
+ * will be used.
+ */
+ public void setTextClassificationSessionFactory(
+ @Nullable TextClassificationSessionFactory factory) {
+ synchronized (mLock) {
+ if (factory != null) {
+ mSessionFactory = factory;
+ } else {
+ mSessionFactory = mDefaultSessionFactory;
+ }
+ }
+ }
+
private TextClassifier getSystemTextClassifier() {
synchronized (mLock) {
if (mSystemTextClassifier == null && isSystemTextClassifierEnabled()) {
diff --git a/core/java/android/view/textclassifier/TextClassificationSession.java b/core/java/android/view/textclassifier/TextClassificationSession.java
new file mode 100644
index 0000000..6938e1a
--- /dev/null
+++ b/core/java/android/view/textclassifier/TextClassificationSession.java
@@ -0,0 +1,217 @@
+/*
+ * 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.view.textclassifier;
+
+import android.annotation.WorkerThread;
+import android.view.textclassifier.DefaultLogger.SignatureParser;
+import android.view.textclassifier.SelectionEvent.InvocationMethod;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Session-aware TextClassifier.
+ */
+@WorkerThread
+final class TextClassificationSession implements TextClassifier {
+
+ /* package */ static final boolean DEBUG_LOG_ENABLED = true;
+ private static final String LOG_TAG = "TextClassificationSession";
+
+ private final TextClassifier mDelegate;
+ private final SelectionEventHelper mEventHelper;
+
+ private boolean mDestroyed;
+
+ TextClassificationSession(TextClassificationContext context, TextClassifier delegate) {
+ mDelegate = Preconditions.checkNotNull(delegate);
+ mEventHelper = new SelectionEventHelper(new TextClassificationSessionId(), context);
+ }
+
+ @Override
+ public TextSelection suggestSelection(CharSequence text, int selectionStartIndex,
+ int selectionEndIndex, TextSelection.Options options) {
+ checkDestroyed();
+ return mDelegate.suggestSelection(text, selectionStartIndex, selectionEndIndex, options);
+ }
+
+ @Override
+ public TextClassification classifyText(CharSequence text, int startIndex, int endIndex,
+ TextClassification.Options options) {
+ checkDestroyed();
+ return mDelegate.classifyText(text, startIndex, endIndex, options);
+ }
+
+ @Override
+ public TextLinks generateLinks(CharSequence text, TextLinks.Options options) {
+ checkDestroyed();
+ return mDelegate.generateLinks(text, options);
+ }
+
+ @Override
+ public void onSelectionEvent(SelectionEvent event) {
+ checkDestroyed();
+ Preconditions.checkNotNull(event);
+ if (mEventHelper.sanitizeEvent(event)) {
+ mDelegate.onSelectionEvent(event);
+ }
+ }
+
+ @Override
+ public void destroy() {
+ mEventHelper.endSession();
+ mDestroyed = true;
+ }
+
+ @Override
+ public boolean isDestroyed() {
+ return mDestroyed;
+ }
+
+ /**
+ * @throws IllegalStateException if this TextClassification session has been destroyed.
+ * @see #isDestroyed()
+ * @see #destroy()
+ */
+ private void checkDestroyed() {
+ if (mDestroyed) {
+ throw new IllegalStateException("This TextClassification session has been destroyed");
+ }
+ }
+
+ /**
+ * Helper class for updating SelectionEvent fields.
+ */
+ private static final class SelectionEventHelper {
+
+ private final TextClassificationSessionId mSessionId;
+ private final TextClassificationContext mContext;
+
+ @InvocationMethod
+ private int mInvocationMethod = SelectionEvent.INVOCATION_UNKNOWN;
+ private SelectionEvent mPrevEvent;
+ private SelectionEvent mSmartEvent;
+ private SelectionEvent mStartEvent;
+
+ SelectionEventHelper(
+ TextClassificationSessionId sessionId, TextClassificationContext context) {
+ mSessionId = Preconditions.checkNotNull(sessionId);
+ mContext = Preconditions.checkNotNull(context);
+ }
+
+ /**
+ * Updates the necessary fields in the event for the current session.
+ *
+ * @return true if the event should be reported. false if the event should be ignored
+ */
+ boolean sanitizeEvent(SelectionEvent event) {
+ updateInvocationMethod(event);
+ modifyAutoSelectionEventType(event);
+
+ if (event.getEventType() != SelectionEvent.EVENT_SELECTION_STARTED
+ && mStartEvent == null) {
+ if (DEBUG_LOG_ENABLED) {
+ Log.d(LOG_TAG, "Selection session not yet started. Ignoring event");
+ }
+ return false;
+ }
+
+ final long now = System.currentTimeMillis();
+ switch (event.getEventType()) {
+ case SelectionEvent.EVENT_SELECTION_STARTED:
+ Preconditions.checkArgument(
+ event.getAbsoluteEnd() == event.getAbsoluteStart() + 1);
+ event.setSessionId(mSessionId);
+ mStartEvent = event;
+ break;
+ case SelectionEvent.EVENT_SMART_SELECTION_SINGLE: // fall through
+ case SelectionEvent.EVENT_SMART_SELECTION_MULTI:
+ mSmartEvent = event;
+ break;
+ case SelectionEvent.EVENT_SELECTION_MODIFIED: // fall through
+ case SelectionEvent.EVENT_AUTO_SELECTION:
+ if (mPrevEvent != null
+ && mPrevEvent.getAbsoluteStart() == event.getAbsoluteStart()
+ && mPrevEvent.getAbsoluteEnd() == event.getAbsoluteEnd()) {
+ // Selection did not change. Ignore event.
+ return false;
+ }
+ break;
+ default:
+ // do nothing.
+ }
+
+ event.setEventTime(now);
+ if (mStartEvent != null) {
+ event.setSessionId(mStartEvent.getSessionId())
+ .setDurationSinceSessionStart(now - mStartEvent.getEventTime())
+ .setStart(event.getAbsoluteStart() - mStartEvent.getAbsoluteStart())
+ .setEnd(event.getAbsoluteEnd() - mStartEvent.getAbsoluteStart());
+ }
+ if (mSmartEvent != null) {
+ event.setSignature(mSmartEvent.getSignature())
+ .setSmartStart(
+ mSmartEvent.getAbsoluteStart() - mStartEvent.getAbsoluteStart())
+ .setSmartEnd(mSmartEvent.getAbsoluteEnd() - mStartEvent.getAbsoluteStart());
+ }
+ if (mPrevEvent != null) {
+ event.setDurationSincePreviousEvent(now - mPrevEvent.getEventTime())
+ .setEventIndex(mPrevEvent.getEventIndex() + 1);
+ }
+ mPrevEvent = event;
+ return true;
+ }
+
+ void endSession() {
+ mPrevEvent = null;
+ mSmartEvent = null;
+ mStartEvent = null;
+ }
+
+ private void updateInvocationMethod(SelectionEvent event) {
+ event.setTextClassificationSessionContext(mContext);
+ if (event.getInvocationMethod() == SelectionEvent.INVOCATION_UNKNOWN) {
+ event.setInvocationMethod(mInvocationMethod);
+ } else {
+ mInvocationMethod = event.getInvocationMethod();
+ }
+ }
+
+ private void modifyAutoSelectionEventType(SelectionEvent event) {
+ switch (event.getEventType()) {
+ case SelectionEvent.EVENT_SMART_SELECTION_SINGLE: // fall through
+ case SelectionEvent.EVENT_SMART_SELECTION_MULTI: // fall through
+ case SelectionEvent.EVENT_AUTO_SELECTION:
+ if (isPlatformLocalTextClassifierSmartSelection(event.getSignature())) {
+ if (event.getAbsoluteEnd() - event.getAbsoluteStart() > 1) {
+ event.setEventType(SelectionEvent.EVENT_SMART_SELECTION_MULTI);
+ } else {
+ event.setEventType(SelectionEvent.EVENT_SMART_SELECTION_SINGLE);
+ }
+ } else {
+ event.setEventType(SelectionEvent.EVENT_AUTO_SELECTION);
+ }
+ return;
+ default:
+ return;
+ }
+ }
+
+ private static boolean isPlatformLocalTextClassifierSmartSelection(String signature) {
+ return DefaultLogger.CLASSIFIER_ID.equals(SignatureParser.getClassifierId(signature));
+ }
+ }
+}
diff --git a/core/java/android/view/textclassifier/TextClassificationSessionFactory.java b/core/java/android/view/textclassifier/TextClassificationSessionFactory.java
new file mode 100644
index 0000000..c0914b6
--- /dev/null
+++ b/core/java/android/view/textclassifier/TextClassificationSessionFactory.java
@@ -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.view.textclassifier;
+
+import android.annotation.NonNull;
+
+/**
+ * An interface for creating a session-aware TextClassifier.
+ *
+ * @see TextClassificationManager#createTextClassificationSession(TextClassificationContext)
+ */
+public interface TextClassificationSessionFactory {
+
+ /**
+ * Creates and returns a session-aware TextClassifier.
+ *
+ * @param classificationContext the classification context
+ */
+ @NonNull
+ TextClassifier createTextClassificationSession(
+ @NonNull TextClassificationContext classificationContext);
+}
diff --git a/core/java/android/view/textclassifier/TextClassificationSessionId.java b/core/java/android/view/textclassifier/TextClassificationSessionId.java
new file mode 100644
index 0000000..3e4dc1c
--- /dev/null
+++ b/core/java/android/view/textclassifier/TextClassificationSessionId.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.textclassifier;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.UUID;
+
+/**
+ * This class represents the id of a text classification session.
+ */
+public final class TextClassificationSessionId implements Parcelable {
+ private final @NonNull String mValue;
+
+ /**
+ * Creates a new instance.
+ *
+ * @hide
+ */
+ public TextClassificationSessionId() {
+ this(UUID.randomUUID().toString());
+ }
+
+ /**
+ * Creates a new instance.
+ *
+ * @param value The internal value.
+ *
+ * @hide
+ */
+ public TextClassificationSessionId(@NonNull String value) {
+ mValue = value;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + mValue.hashCode();
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ TextClassificationSessionId other = (TextClassificationSessionId) obj;
+ if (!mValue.equals(other.mValue)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(mValue);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Flattens this id to a string.
+ *
+ * @return The flattened id.
+ *
+ * @hide
+ */
+ public @NonNull String flattenToString() {
+ return mValue;
+ }
+
+ /**
+ * Unflattens a print job id from a string.
+ *
+ * @param string The string.
+ * @return The unflattened id, or null if the string is malformed.
+ *
+ * @hide
+ */
+ public static @NonNull TextClassificationSessionId unflattenFromString(@NonNull String string) {
+ return new TextClassificationSessionId(string);
+ }
+
+ public static final Parcelable.Creator<TextClassificationSessionId> CREATOR =
+ new Parcelable.Creator<TextClassificationSessionId>() {
+ @Override
+ public TextClassificationSessionId createFromParcel(Parcel parcel) {
+ return new TextClassificationSessionId(
+ Preconditions.checkNotNull(parcel.readString()));
+ }
+
+ @Override
+ public TextClassificationSessionId[] newArray(int size) {
+ return new TextClassificationSessionId[size];
+ }
+ };
+}
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index 98fa574..2048f2b 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -112,6 +112,38 @@
@StringDef(prefix = { "HINT_" }, value = {HINT_TEXT_IS_EDITABLE, HINT_TEXT_IS_NOT_EDITABLE})
@interface Hints {}
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @StringDef({WIDGET_TYPE_TEXTVIEW, WIDGET_TYPE_WEBVIEW, WIDGET_TYPE_EDITTEXT,
+ WIDGET_TYPE_EDIT_WEBVIEW, WIDGET_TYPE_CUSTOM_TEXTVIEW, WIDGET_TYPE_CUSTOM_EDITTEXT,
+ WIDGET_TYPE_CUSTOM_UNSELECTABLE_TEXTVIEW, WIDGET_TYPE_UNKNOWN})
+ @interface WidgetType {}
+
+ /** The widget involved in the text classification session is a standard
+ * {@link android.widget.TextView}. */
+ String WIDGET_TYPE_TEXTVIEW = "textview";
+ /** The widget involved in the text classification session is a standard
+ * {@link android.widget.EditText}. */
+ String WIDGET_TYPE_EDITTEXT = "edittext";
+ /** The widget involved in the text classification session is a standard non-selectable
+ * {@link android.widget.TextView}. */
+ String WIDGET_TYPE_UNSELECTABLE_TEXTVIEW = "nosel-textview";
+ /** The widget involved in the text classification session is a standard
+ * {@link android.webkit.WebView}. */
+ String WIDGET_TYPE_WEBVIEW = "webview";
+ /** The widget involved in the text classification session is a standard editable
+ * {@link android.webkit.WebView}. */
+ String WIDGET_TYPE_EDIT_WEBVIEW = "edit-webview";
+ /** The widget involved in the text classification session is a custom text widget. */
+ String WIDGET_TYPE_CUSTOM_TEXTVIEW = "customview";
+ /** The widget involved in the text classification session is a custom editable text widget. */
+ String WIDGET_TYPE_CUSTOM_EDITTEXT = "customedit";
+ /** The widget involved in the text classification session is a custom non-selectable text
+ * widget. */
+ String WIDGET_TYPE_CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview";
+ /** The widget involved in the text classification session is of an unknown/unspecified type. */
+ String WIDGET_TYPE_UNKNOWN = "unknown";
+
/**
* No-op TextClassifier.
* This may be used to turn off TextClassifier features.
@@ -124,6 +156,9 @@
*
* <p><strong>NOTE: </strong>Call on a worker thread.
*
+ * <strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to this method should
+ * throw an {@link IllegalStateException}. See {@link #isDestroyed()}.
+ *
* @param text text providing context for the selected text (which is specified
* by the sub sequence starting at selectionStartIndex and ending at selectionEndIndex)
* @param selectionStartIndex start index of the selected part of text
@@ -156,6 +191,9 @@
*
* <p><strong>NOTE: </strong>Call on a worker thread.
*
+ * <strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to this method should
+ * throw an {@link IllegalStateException}. See {@link #isDestroyed()}.
+ *
* @param text text providing context for the selected text (which is specified
* by the sub sequence starting at selectionStartIndex and ending at selectionEndIndex)
* @param selectionStartIndex start index of the selected part of text
@@ -185,6 +223,9 @@
* <p><b>NOTE:</b> Do not implement. The default implementation of this method calls
* {@link #suggestSelection(CharSequence, int, int, TextSelection.Options)}. If that method
* calls this method, a stack overflow error will happen.
+ *
+ * <strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to this method should
+ * throw an {@link IllegalStateException}. See {@link #isDestroyed()}.
*/
@WorkerThread
@NonNull
@@ -205,6 +246,9 @@
*
* <p><strong>NOTE: </strong>Call on a worker thread.
*
+ * <strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to this method should
+ * throw an {@link IllegalStateException}. See {@link #isDestroyed()}.
+ *
* @param text text providing context for the text to classify (which is specified
* by the sub sequence starting at startIndex and ending at endIndex)
* @param startIndex start index of the text to classify
@@ -237,6 +281,9 @@
* {@link #classifyText(CharSequence, int, int, TextClassification.Options)}. If that method
* calls this method, a stack overflow error will happen.
*
+ * <strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to this method should
+ * throw an {@link IllegalStateException}. See {@link #isDestroyed()}.
+ *
* @param text text providing context for the text to classify (which is specified
* by the sub sequence starting at startIndex and ending at endIndex)
* @param startIndex start index of the text to classify
@@ -265,6 +312,9 @@
* <p><b>NOTE:</b> Do not implement. The default implementation of this method calls
* {@link #classifyText(CharSequence, int, int, TextClassification.Options)}. If that method
* calls this method, a stack overflow error will happen.
+ *
+ * <strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to this method should
+ * throw an {@link IllegalStateException}. See {@link #isDestroyed()}.
*/
@WorkerThread
@NonNull
@@ -285,6 +335,9 @@
*
* <p><strong>NOTE: </strong>Call on a worker thread.
*
+ * <strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to this method should
+ * throw an {@link IllegalStateException}. See {@link #isDestroyed()}.
+ *
* @param text the text to generate annotations for
* @param options configuration for link generation
*
@@ -295,6 +348,7 @@
* @see #getMaxGenerateLinksTextLength()
*/
@WorkerThread
+ @NonNull
default TextLinks generateLinks(
@NonNull CharSequence text, @Nullable TextLinks.Options options) {
Utils.validate(text, false);
@@ -311,6 +365,9 @@
* {@link #generateLinks(CharSequence, TextLinks.Options)}. If that method calls this method,
* a stack overflow error will happen.
*
+ * <strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to this method should
+ * throw an {@link IllegalStateException}. See {@link #isDestroyed()}.
+ *
* @param text the text to generate annotations for
*
* @throws IllegalArgumentException if text is null or the text is too long for the
@@ -320,6 +377,7 @@
* @see #getMaxGenerateLinksTextLength()
*/
@WorkerThread
+ @NonNull
default TextLinks generateLinks(@NonNull CharSequence text) {
return generateLinks(text, null);
}
@@ -327,6 +385,9 @@
/**
* Returns the maximal length of text that can be processed by generateLinks.
*
+ * <strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to this method should
+ * throw an {@link IllegalStateException}. See {@link #isDestroyed()}.
+ *
* @see #generateLinks(CharSequence)
* @see #generateLinks(CharSequence, TextLinks.Options)
*/
@@ -339,6 +400,7 @@
* Returns a helper for logging TextClassifier related events.
*
* @param config logger configuration
+ * @hide
*/
@WorkerThread
default Logger getLogger(@NonNull Logger.Config config) {
@@ -347,6 +409,37 @@
}
/**
+ * Reports a selection event.
+ *
+ * <strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to this method should
+ * throw an {@link IllegalStateException}. See {@link #isDestroyed()}.
+ */
+ default void onSelectionEvent(@NonNull SelectionEvent event) {}
+
+ /**
+ * Destroys this TextClassifier.
+ *
+ * <strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to its methods should
+ * throw an {@link IllegalStateException}. See {@link #isDestroyed()}.
+ *
+ * <p>Subsequent calls to this method are no-ops.
+ */
+ default void destroy() {}
+
+ /**
+ * Returns whether or not this TextClassifier has been destroyed.
+ *
+ * <strong>NOTE: </strong>If a TextClassifier has been destroyed, caller should not interact
+ * with the classifier and an attempt to do so would throw an {@link IllegalStateException}.
+ * However, this method should never throw an {@link IllegalStateException}.
+ *
+ * @see #destroy()
+ */
+ default boolean isDestroyed() {
+ return false;
+ }
+
+ /**
* Configuration object for specifying what entities to identify.
*
* Configs are initially based on a predefined preset, and can be modified from there.
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index c2fb032..5ba470a 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.WorkerThread;
+import android.app.RemoteAction;
import android.app.SearchManager;
import android.content.ComponentName;
import android.content.ContentUris;
@@ -26,7 +27,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Bundle;
import android.os.LocaleList;
@@ -93,6 +94,8 @@
private Logger.Config mLoggerConfig;
@GuardedBy("mLoggerLock") // Do not access outside this lock.
private Logger mLogger;
+ @GuardedBy("mLoggerLock") // Do not access outside this lock.
+ private Logger mLogger2; // This is the new logger. Will replace mLogger.
private final TextClassificationConstants mSettings;
@@ -299,6 +302,18 @@
return mLogger;
}
+ @Override
+ public void onSelectionEvent(SelectionEvent event) {
+ Preconditions.checkNotNull(event);
+ synchronized (mLoggerLock) {
+ if (mLogger2 == null) {
+ mLogger2 = new DefaultLogger(
+ new Logger.Config(mContext, WIDGET_TYPE_UNKNOWN, null));
+ }
+ mLogger2.writeEvent(event);
+ }
+ }
+
private TextClassifierImplNative getNative(LocaleList localeList)
throws FileNotFoundException {
synchronized (mLock) {
@@ -418,50 +433,27 @@
}
}
- addActions(builder, IntentFactory.create(
- mContext, referenceTime, highestScoringResult, classifiedText));
+ boolean isPrimaryAction = true;
+ for (LabeledIntent labeledIntent : IntentFactory.create(
+ mContext, referenceTime, highestScoringResult, classifiedText)) {
+ RemoteAction action = labeledIntent.asRemoteAction(mContext);
+ if (isPrimaryAction) {
+ // For O backwards compatibility, the first RemoteAction is also written to the
+ // legacy API fields.
+ builder.setIcon(action.getIcon().loadDrawable(mContext));
+ builder.setLabel(action.getTitle().toString());
+ builder.setIntent(labeledIntent.getIntent());
+ builder.setOnClickListener(TextClassification.createIntentOnClickListener(
+ TextClassification.createPendingIntent(mContext,
+ labeledIntent.getIntent())));
+ isPrimaryAction = false;
+ }
+ builder.addAction(action);
+ }
return builder.setSignature(getSignature(text, start, end)).build();
}
- /** Extends the classification with the intents that can be resolved. */
- private void addActions(
- TextClassification.Builder builder, List<Intent> intents) {
- final PackageManager pm = mContext.getPackageManager();
- final int size = intents.size();
- for (int i = 0; i < size; i++) {
- final Intent intent = intents.get(i);
- final ResolveInfo resolveInfo;
- if (intent != null) {
- resolveInfo = pm.resolveActivity(intent, 0);
- } else {
- resolveInfo = null;
- }
- if (resolveInfo != null && resolveInfo.activityInfo != null) {
- final String packageName = resolveInfo.activityInfo.packageName;
- final String label = IntentFactory.getLabel(mContext, intent);
- Drawable icon;
- if ("android".equals(packageName)) {
- // Requires the chooser to find an activity to handle the intent.
- icon = null;
- } else {
- // A default activity will handle the intent.
- intent.setComponent(
- new ComponentName(packageName, resolveInfo.activityInfo.name));
- icon = resolveInfo.activityInfo.loadIcon(pm);
- if (icon == null) {
- icon = resolveInfo.loadIcon(pm);
- }
- }
- if (i == 0) {
- builder.setPrimaryAction(intent, label, icon);
- } else {
- builder.addSecondaryAction(intent, label, icon);
- }
- }
- }
- }
-
/**
* Closes the ParcelFileDescriptor and logs any errors that occur.
*/
@@ -588,6 +580,60 @@
}
/**
+ * Helper class to store the information from which RemoteActions are built.
+ */
+ private static final class LabeledIntent {
+ private String mTitle;
+ private String mDescription;
+ private Intent mIntent;
+
+ LabeledIntent(String title, String description, Intent intent) {
+ mTitle = title;
+ mDescription = description;
+ mIntent = intent;
+ }
+
+ String getTitle() {
+ return mTitle;
+ }
+
+ String getDescription() {
+ return mDescription;
+ }
+
+ Intent getIntent() {
+ return mIntent;
+ }
+
+ RemoteAction asRemoteAction(Context context) {
+ final PackageManager pm = context.getPackageManager();
+ final ResolveInfo resolveInfo = pm.resolveActivity(mIntent, 0);
+ final String packageName = resolveInfo != null && resolveInfo.activityInfo != null
+ ? resolveInfo.activityInfo.packageName : null;
+ Icon icon = null;
+ boolean shouldShowIcon = false;
+ if (packageName != null && !"android".equals(packageName)) {
+ // There is a default activity handling the intent.
+ mIntent.setComponent(new ComponentName(packageName, resolveInfo.activityInfo.name));
+ if (resolveInfo.activityInfo.getIconResource() != 0) {
+ icon = Icon.createWithResource(
+ packageName, resolveInfo.activityInfo.getIconResource());
+ shouldShowIcon = true;
+ }
+ }
+ if (icon == null) {
+ // RemoteAction requires that there be an icon.
+ icon = Icon.createWithResource("android",
+ com.android.internal.R.drawable.ic_more_items);
+ }
+ RemoteAction action = new RemoteAction(icon, mTitle, mDescription,
+ TextClassification.createPendingIntent(context, mIntent));
+ action.setShouldShowIcon(shouldShowIcon);
+ return action;
+ }
+ }
+
+ /**
* Creates intents based on the classification type.
*/
static final class IntentFactory {
@@ -598,7 +644,7 @@
private IntentFactory() {}
@NonNull
- public static List<Intent> create(
+ public static List<LabeledIntent> create(
Context context,
@Nullable Calendar referenceTime,
TextClassifierImplNative.ClassificationResult classification,
@@ -607,11 +653,11 @@
text = text.trim();
switch (type) {
case TextClassifier.TYPE_EMAIL:
- return createForEmail(text);
+ return createForEmail(context, text);
case TextClassifier.TYPE_PHONE:
return createForPhone(context, text);
case TextClassifier.TYPE_ADDRESS:
- return createForAddress(text);
+ return createForAddress(context, text);
case TextClassifier.TYPE_URL:
return createForUrl(context, text);
case TextClassifier.TYPE_DATE:
@@ -620,62 +666,80 @@
Calendar eventTime = Calendar.getInstance();
eventTime.setTimeInMillis(
classification.getDatetimeResult().getTimeMsUtc());
- return createForDatetime(type, referenceTime, eventTime);
+ return createForDatetime(context, type, referenceTime, eventTime);
} else {
return new ArrayList<>();
}
case TextClassifier.TYPE_FLIGHT_NUMBER:
- return createForFlight(text);
+ return createForFlight(context, text);
default:
return new ArrayList<>();
}
}
@NonNull
- private static List<Intent> createForEmail(String text) {
+ private static List<LabeledIntent> createForEmail(Context context, String text) {
return Arrays.asList(
- new Intent(Intent.ACTION_SENDTO)
- .setData(Uri.parse(String.format("mailto:%s", text))),
- new Intent(Intent.ACTION_INSERT_OR_EDIT)
- .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
- .putExtra(ContactsContract.Intents.Insert.EMAIL, text));
+ new LabeledIntent(
+ context.getString(com.android.internal.R.string.email),
+ context.getString(com.android.internal.R.string.email_desc),
+ new Intent(Intent.ACTION_SENDTO)
+ .setData(Uri.parse(String.format("mailto:%s", text)))),
+ new LabeledIntent(
+ context.getString(com.android.internal.R.string.add_contact),
+ context.getString(com.android.internal.R.string.add_contact_desc),
+ new Intent(Intent.ACTION_INSERT_OR_EDIT)
+ .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
+ .putExtra(ContactsContract.Intents.Insert.EMAIL, text)));
}
@NonNull
- private static List<Intent> createForPhone(Context context, String text) {
- final List<Intent> intents = new ArrayList<>();
+ private static List<LabeledIntent> createForPhone(Context context, String text) {
+ final List<LabeledIntent> actions = new ArrayList<>();
final UserManager userManager = context.getSystemService(UserManager.class);
final Bundle userRestrictions = userManager != null
? userManager.getUserRestrictions() : new Bundle();
if (!userRestrictions.getBoolean(UserManager.DISALLOW_OUTGOING_CALLS, false)) {
- intents.add(new Intent(Intent.ACTION_DIAL)
- .setData(Uri.parse(String.format("tel:%s", text))));
+ actions.add(new LabeledIntent(
+ context.getString(com.android.internal.R.string.dial),
+ context.getString(com.android.internal.R.string.dial_desc),
+ new Intent(Intent.ACTION_DIAL).setData(
+ Uri.parse(String.format("tel:%s", text)))));
}
- intents.add(new Intent(Intent.ACTION_INSERT_OR_EDIT)
- .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
- .putExtra(ContactsContract.Intents.Insert.PHONE, text));
+ actions.add(new LabeledIntent(
+ context.getString(com.android.internal.R.string.add_contact),
+ context.getString(com.android.internal.R.string.add_contact_desc),
+ new Intent(Intent.ACTION_INSERT_OR_EDIT)
+ .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
+ .putExtra(ContactsContract.Intents.Insert.PHONE, text)));
if (!userRestrictions.getBoolean(UserManager.DISALLOW_SMS, false)) {
- intents.add(new Intent(Intent.ACTION_SENDTO)
- .setData(Uri.parse(String.format("smsto:%s", text))));
+ actions.add(new LabeledIntent(
+ context.getString(com.android.internal.R.string.sms),
+ context.getString(com.android.internal.R.string.sms_desc),
+ new Intent(Intent.ACTION_SENDTO)
+ .setData(Uri.parse(String.format("smsto:%s", text)))));
}
- return intents;
+ return actions;
}
@NonNull
- private static List<Intent> createForAddress(String text) {
- final List<Intent> intents = new ArrayList<>();
+ private static List<LabeledIntent> createForAddress(Context context, String text) {
+ final List<LabeledIntent> actions = new ArrayList<>();
try {
final String encText = URLEncoder.encode(text, "UTF-8");
- intents.add(new Intent(Intent.ACTION_VIEW)
- .setData(Uri.parse(String.format("geo:0,0?q=%s", encText))));
+ actions.add(new LabeledIntent(
+ context.getString(com.android.internal.R.string.map),
+ context.getString(com.android.internal.R.string.map_desc),
+ new Intent(Intent.ACTION_VIEW)
+ .setData(Uri.parse(String.format("geo:0,0?q=%s", encText)))));
} catch (UnsupportedEncodingException e) {
Log.e(LOG_TAG, "Could not encode address", e);
}
- return intents;
+ return actions;
}
@NonNull
- private static List<Intent> createForUrl(Context context, String text) {
+ private static List<LabeledIntent> createForUrl(Context context, String text) {
final String httpPrefix = "http://";
final String httpsPrefix = "https://";
if (text.toLowerCase().startsWith(httpPrefix)) {
@@ -685,99 +749,65 @@
} else {
text = httpPrefix + text;
}
- return Arrays.asList(new Intent(Intent.ACTION_VIEW, Uri.parse(text))
- .putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()));
+ return Arrays.asList(new LabeledIntent(
+ context.getString(com.android.internal.R.string.browse),
+ context.getString(com.android.internal.R.string.browse_desc),
+ new Intent(Intent.ACTION_VIEW, Uri.parse(text))
+ .putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName())));
}
@NonNull
- private static List<Intent> createForDatetime(
- String type, @Nullable Calendar referenceTime, Calendar eventTime) {
+ private static List<LabeledIntent> createForDatetime(
+ Context context, String type, @Nullable Calendar referenceTime,
+ Calendar eventTime) {
if (referenceTime == null) {
// If no reference time was given, use now.
referenceTime = Calendar.getInstance();
}
- List<Intent> intents = new ArrayList<>();
- intents.add(createCalendarViewIntent(eventTime));
+ List<LabeledIntent> actions = new ArrayList<>();
+ actions.add(createCalendarViewIntent(context, eventTime));
final long millisSinceReference =
eventTime.getTimeInMillis() - referenceTime.getTimeInMillis();
if (millisSinceReference > MIN_EVENT_FUTURE_MILLIS) {
- intents.add(createCalendarCreateEventIntent(eventTime, type));
+ actions.add(createCalendarCreateEventIntent(context, eventTime, type));
}
- return intents;
+ return actions;
}
@NonNull
- private static List<Intent> createForFlight(String text) {
- return Arrays.asList(new Intent(Intent.ACTION_WEB_SEARCH)
- .putExtra(SearchManager.QUERY, text));
+ private static List<LabeledIntent> createForFlight(Context context, String text) {
+ return Arrays.asList(new LabeledIntent(
+ context.getString(com.android.internal.R.string.view_flight),
+ context.getString(com.android.internal.R.string.view_flight_desc),
+ new Intent(Intent.ACTION_WEB_SEARCH)
+ .putExtra(SearchManager.QUERY, text)));
}
@NonNull
- private static Intent createCalendarViewIntent(Calendar eventTime) {
+ private static LabeledIntent createCalendarViewIntent(Context context, Calendar eventTime) {
Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon();
builder.appendPath("time");
ContentUris.appendId(builder, eventTime.getTimeInMillis());
- return new Intent(Intent.ACTION_VIEW).setData(builder.build());
+ return new LabeledIntent(
+ context.getString(com.android.internal.R.string.view_calendar),
+ context.getString(com.android.internal.R.string.view_calendar_desc),
+ new Intent(Intent.ACTION_VIEW).setData(builder.build()));
}
@NonNull
- private static Intent createCalendarCreateEventIntent(
- Calendar eventTime, @EntityType String type) {
+ private static LabeledIntent createCalendarCreateEventIntent(
+ Context context, Calendar eventTime, @EntityType String type) {
final boolean isAllDay = TextClassifier.TYPE_DATE.equals(type);
- return new Intent(Intent.ACTION_INSERT)
- .setData(CalendarContract.Events.CONTENT_URI)
- .putExtra(CalendarContract.EXTRA_EVENT_ALL_DAY, isAllDay)
- .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, eventTime.getTimeInMillis())
- .putExtra(CalendarContract.EXTRA_EVENT_END_TIME,
- eventTime.getTimeInMillis() + DEFAULT_EVENT_DURATION);
- }
-
- @Nullable
- public static String getLabel(Context context, @Nullable Intent intent) {
- if (intent == null || intent.getAction() == null) {
- return null;
- }
- final String authority =
- intent.getData() == null ? null : intent.getData().getAuthority();
- switch (intent.getAction()) {
- case Intent.ACTION_DIAL:
- return context.getString(com.android.internal.R.string.dial);
- case Intent.ACTION_SENDTO:
- if ("mailto".equals(intent.getScheme())) {
- return context.getString(com.android.internal.R.string.email);
- } else if ("smsto".equals(intent.getScheme())) {
- return context.getString(com.android.internal.R.string.sms);
- } else {
- return null;
- }
- case Intent.ACTION_INSERT:
- if (CalendarContract.AUTHORITY.equals(authority)) {
- return context.getString(com.android.internal.R.string.add_calendar_event);
- }
- return null;
- case Intent.ACTION_INSERT_OR_EDIT:
- if (ContactsContract.Contacts.CONTENT_ITEM_TYPE.equals(
- intent.getType())) {
- return context.getString(com.android.internal.R.string.add_contact);
- } else {
- return null;
- }
- case Intent.ACTION_VIEW:
- if (CalendarContract.AUTHORITY.equals(authority)) {
- return context.getString(com.android.internal.R.string.view_calendar);
- } else if ("geo".equals(intent.getScheme())) {
- return context.getString(com.android.internal.R.string.map);
- } else if ("http".equals(intent.getScheme())
- || "https".equals(intent.getScheme())) {
- return context.getString(com.android.internal.R.string.browse);
- } else {
- return null;
- }
- case Intent.ACTION_WEB_SEARCH:
- return context.getString(com.android.internal.R.string.view_flight);
- default:
- return null;
- }
+ return new LabeledIntent(
+ context.getString(com.android.internal.R.string.add_calendar_event),
+ context.getString(com.android.internal.R.string.add_calendar_event_desc),
+ new Intent(Intent.ACTION_INSERT)
+ .setData(CalendarContract.Events.CONTENT_URI)
+ .putExtra(CalendarContract.EXTRA_EVENT_ALL_DAY, isAllDay)
+ .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME,
+ eventTime.getTimeInMillis())
+ .putExtra(CalendarContract.EXTRA_EVENT_END_TIME,
+ eventTime.getTimeInMillis() + DEFAULT_EVENT_DURATION));
}
}
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 57d64b9..92f496a8 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -23,6 +23,7 @@
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException;
+import android.app.RemoteAction;
import android.content.ClipData;
import android.content.ClipData.Item;
import android.content.Context;
@@ -4045,43 +4046,46 @@
if (textClassification == null) {
return;
}
- final OnClickListener onClick = getSupportedOnClickListener(
- textClassification.getIcon(),
- textClassification.getLabel(),
- textClassification.getIntent());
- if (onClick != null) {
+ if (!textClassification.getActions().isEmpty()) {
+ // Primary assist action (Always shown).
+ final MenuItem item = addAssistMenuItem(menu,
+ textClassification.getActions().get(0), TextView.ID_ASSIST,
+ MENU_ITEM_ORDER_ASSIST, MenuItem.SHOW_AS_ACTION_ALWAYS);
+ item.setIntent(textClassification.getIntent());
+ } else if (hasLegacyAssistItem(textClassification)) {
+ // Legacy primary assist action (Always shown).
final MenuItem item = menu.add(
TextView.ID_ASSIST, TextView.ID_ASSIST, MENU_ITEM_ORDER_ASSIST,
textClassification.getLabel())
.setIcon(textClassification.getIcon())
.setIntent(textClassification.getIntent());
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
- mAssistClickHandlers.put(
- item, TextClassification.createIntentOnClickListener(
- mTextView.getContext(), textClassification.getIntent()));
+ mAssistClickHandlers.put(item, TextClassification.createIntentOnClickListener(
+ TextClassification.createPendingIntent(mTextView.getContext(),
+ textClassification.getIntent())));
}
- final int count = textClassification.getSecondaryActionsCount();
- for (int i = 0; i < count; i++) {
- final OnClickListener onClick1 = getSupportedOnClickListener(
- textClassification.getSecondaryIcon(i),
- textClassification.getSecondaryLabel(i),
- textClassification.getSecondaryIntent(i));
- if (onClick1 == null) {
- continue;
- }
- final int order = MENU_ITEM_ORDER_SECONDARY_ASSIST_ACTIONS_START + i;
- final MenuItem item = menu.add(
- TextView.ID_ASSIST, Menu.NONE, order,
- textClassification.getSecondaryLabel(i))
- .setIcon(textClassification.getSecondaryIcon(i))
- .setIntent(textClassification.getSecondaryIntent(i));
- item.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
- mAssistClickHandlers.put(item,
- TextClassification.createIntentOnClickListener(
- mTextView.getContext(), textClassification.getSecondaryIntent(i)));
+ final int count = textClassification.getActions().size();
+ for (int i = 1; i < count; i++) {
+ // Secondary assist action (Never shown).
+ addAssistMenuItem(menu, textClassification.getActions().get(i), Menu.NONE,
+ MENU_ITEM_ORDER_SECONDARY_ASSIST_ACTIONS_START + i - 1,
+ MenuItem.SHOW_AS_ACTION_NEVER);
}
}
+ private MenuItem addAssistMenuItem(Menu menu, RemoteAction action, int intemId, int order,
+ int showAsAction) {
+ final MenuItem item = menu.add(TextView.ID_ASSIST, intemId, order, action.getTitle())
+ .setContentDescription(action.getContentDescription());
+ if (action.shouldShowIcon()) {
+ item.setIcon(action.getIcon().loadDrawable(mTextView.getContext()));
+ }
+ item.setShowAsAction(showAsAction);
+ mAssistClickHandlers.put(item,
+ TextClassification.createIntentOnClickListener(action.getActionIntent()));
+ return item;
+ }
+
private void clearAssistMenuItems(Menu menu) {
int i = 0;
while (i < menu.size()) {
@@ -4094,15 +4098,11 @@
}
}
- @Nullable
- private OnClickListener getSupportedOnClickListener(
- Drawable icon, CharSequence label, Intent intent) {
- final boolean hasUi = icon != null || !TextUtils.isEmpty(label);
- if (hasUi) {
- return TextClassification.createIntentOnClickListener(
- mTextView.getContext(), intent);
- }
- return null;
+ private boolean hasLegacyAssistItem(TextClassification classification) {
+ // Check whether we have the UI data and and action.
+ return (classification.getIcon() != null || !TextUtils.isEmpty(
+ classification.getLabel())) && (classification.getIntent() != null
+ || classification.getOnClickListener() != null);
}
private boolean onAssistMenuItemClicked(MenuItem assistMenuItem) {
@@ -4120,7 +4120,7 @@
final Intent intent = assistMenuItem.getIntent();
if (intent != null) {
onClickListener = TextClassification.createIntentOnClickListener(
- mTextView.getContext(), intent);
+ TextClassification.createPendingIntent(mTextView.getContext(), intent));
}
}
if (onClickListener != null) {
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 05204d0..8b49ccb 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -35,6 +35,7 @@
import android.view.ActionMode;
import android.view.textclassifier.Logger;
import android.view.textclassifier.SelectionEvent;
+import android.view.textclassifier.SelectionEvent.InvocationMethod;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationConstants;
import android.view.textclassifier.TextClassificationManager;
@@ -86,7 +87,7 @@
mTextClassificationSettings = TextClassificationManager.getSettings(mTextView.getContext());
mTextClassificationHelper = new TextClassificationHelper(
mTextView.getContext(),
- mTextView.getTextClassifier(),
+ mTextView::getTextClassifier,
getText(mTextView),
0, 1, mTextView.getTextLocales());
mSelectionTracker = new SelectionTracker(mTextView);
@@ -221,7 +222,7 @@
private boolean skipTextClassification() {
// No need to make an async call for a no-op TextClassifier.
- final boolean noOpTextClassifier = mTextView.getTextClassifier() == TextClassifier.NO_OP;
+ final boolean noOpTextClassifier = mTextView.usesNoOpTextClassifier();
// Do not call the TextClassifier if there is no selection.
final boolean noSelection = mTextView.getSelectionEnd() == mTextView.getSelectionStart();
// Do not call the TextClassifier if this is a password field.
@@ -447,7 +448,7 @@
selectionEnd = mTextView.getSelectionEnd();
}
mTextClassificationHelper.init(
- mTextView.getTextClassifier(),
+ mTextView::getTextClassifier,
getText(mTextView),
selectionStart, selectionEnd,
mTextView.getTextLocales());
@@ -660,6 +661,7 @@
private static final String LOG_TAG = "SelectionMetricsLogger";
private static final Pattern PATTERN_WHITESPACE = Pattern.compile("\\s+");
+ private final Supplier<TextClassifier> mTextClassificationSession;
private final Logger mLogger;
private final boolean mEditTextLogger;
private final BreakIterator mTokenIterator;
@@ -668,26 +670,27 @@
SelectionMetricsLogger(TextView textView) {
Preconditions.checkNotNull(textView);
+ mTextClassificationSession = textView::getTextClassificationSession;
mLogger = textView.getTextClassifier().getLogger(
new Logger.Config(textView.getContext(), getWidetType(textView), null));
mEditTextLogger = textView.isTextEditable();
mTokenIterator = mLogger.getTokenIterator(textView.getTextLocale());
}
- @Logger.WidgetType
+ @TextClassifier.WidgetType
private static String getWidetType(TextView textView) {
if (textView.isTextEditable()) {
- return Logger.WIDGET_EDITTEXT;
+ return TextClassifier.WIDGET_TYPE_EDITTEXT;
}
if (textView.isTextSelectable()) {
- return Logger.WIDGET_TEXTVIEW;
+ return TextClassifier.WIDGET_TYPE_TEXTVIEW;
}
- return Logger.WIDGET_UNSELECTABLE_TEXTVIEW;
+ return TextClassifier.WIDGET_TYPE_UNSELECTABLE_TEXTVIEW;
}
public void logSelectionStarted(
CharSequence text, int index,
- @SelectionEvent.InvocationMethod int invocationMethod) {
+ @InvocationMethod int invocationMethod) {
try {
Preconditions.checkNotNull(text);
Preconditions.checkArgumentInRange(index, 0, text.length(), "index");
@@ -697,9 +700,12 @@
mTokenIterator.setText(mText);
mStartIndex = index;
mLogger.logSelectionStartedEvent(invocationMethod, 0);
+ // TODO: Remove the above legacy logging.
+ mTextClassificationSession.get().onSelectionEvent(
+ SelectionEvent.createSelectionStartedEvent(invocationMethod, 0));
} catch (Exception e) {
// Avoid crashes due to logging.
- Log.d(LOG_TAG, e.getMessage());
+ Log.e(LOG_TAG, "" + e.getMessage(), e);
}
}
@@ -712,16 +718,28 @@
if (selection != null) {
mLogger.logSelectionModifiedEvent(
wordIndices[0], wordIndices[1], selection);
+ // TODO: Remove the above legacy logging.
+ mTextClassificationSession.get().onSelectionEvent(
+ SelectionEvent.createSelectionModifiedEvent(
+ wordIndices[0], wordIndices[1], selection));
} else if (classification != null) {
mLogger.logSelectionModifiedEvent(
wordIndices[0], wordIndices[1], classification);
+ // TODO: Remove the above legacy logging.
+ mTextClassificationSession.get().onSelectionEvent(
+ SelectionEvent.createSelectionModifiedEvent(
+ wordIndices[0], wordIndices[1], classification));
} else {
mLogger.logSelectionModifiedEvent(
wordIndices[0], wordIndices[1]);
+ // TODO: Remove the above legacy logging.
+ mTextClassificationSession.get().onSelectionEvent(
+ SelectionEvent.createSelectionModifiedEvent(
+ wordIndices[0], wordIndices[1]));
}
} catch (Exception e) {
// Avoid crashes due to logging.
- Log.d(LOG_TAG, e.getMessage());
+ Log.e(LOG_TAG, "" + e.getMessage(), e);
}
}
@@ -736,13 +754,25 @@
if (classification != null) {
mLogger.logSelectionActionEvent(
wordIndices[0], wordIndices[1], action, classification);
+ // TODO: Remove the above legacy logging.
+ mTextClassificationSession.get().onSelectionEvent(
+ SelectionEvent.createSelectionActionEvent(
+ wordIndices[0], wordIndices[1], action, classification));
} else {
mLogger.logSelectionActionEvent(
wordIndices[0], wordIndices[1], action);
+ // TODO: Remove the above legacy logging.
+ mTextClassificationSession.get().onSelectionEvent(
+ SelectionEvent.createSelectionActionEvent(
+ wordIndices[0], wordIndices[1], action));
}
} catch (Exception e) {
// Avoid crashes due to logging.
- Log.d(LOG_TAG, e.getMessage());
+ Log.e(LOG_TAG, "" + e.getMessage(), e);
+ } finally {
+ if (SelectionEvent.isTerminal(action)) {
+ mTextClassificationSession.get().destroy();
+ }
}
}
@@ -887,7 +917,7 @@
private final Context mContext;
private final boolean mDarkLaunchEnabled;
- private TextClassifier mTextClassifier;
+ private Supplier<TextClassifier> mTextClassifier;
/** The original TextView text. **/
private String mText;
@@ -919,7 +949,7 @@
/** Whether the TextClassifier has been initialized. */
private boolean mHot;
- TextClassificationHelper(Context context, TextClassifier textClassifier,
+ TextClassificationHelper(Context context, Supplier<TextClassifier> textClassifier,
CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
init(textClassifier, text, selectionStart, selectionEnd, locales);
mContext = Preconditions.checkNotNull(context);
@@ -928,7 +958,7 @@
}
@UiThread
- public void init(TextClassifier textClassifier, CharSequence text,
+ public void init(Supplier<TextClassifier> textClassifier, CharSequence text,
int selectionStart, int selectionEnd, LocaleList locales) {
mTextClassifier = Preconditions.checkNotNull(textClassifier);
mText = Preconditions.checkNotNull(text).toString();
@@ -953,11 +983,11 @@
trimText();
final TextSelection selection;
if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.O_MR1) {
- selection = mTextClassifier.suggestSelection(
+ selection = mTextClassifier.get().suggestSelection(
mTrimmedText, mRelativeStart, mRelativeEnd, mSelectionOptions);
} else {
// Use old APIs.
- selection = mTextClassifier.suggestSelection(
+ selection = mTextClassifier.get().suggestSelection(
mTrimmedText, mRelativeStart, mRelativeEnd,
mSelectionOptions.getDefaultLocales());
}
@@ -1006,11 +1036,11 @@
trimText();
final TextClassification classification;
if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.O_MR1) {
- classification = mTextClassifier.classifyText(
+ classification = mTextClassifier.get().classifyText(
mTrimmedText, mRelativeStart, mRelativeEnd, mClassificationOptions);
} else {
// Use old APIs.
- classification = mTextClassifier.classifyText(
+ classification = mTextClassifier.get().classifyText(
mTrimmedText, mRelativeStart, mRelativeEnd,
mClassificationOptions.getDefaultLocales());
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 7b1acb1..8bf497e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -163,6 +163,7 @@
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.view.textclassifier.TextClassification;
+import android.view.textclassifier.TextClassificationContext;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassifier;
import android.view.textclassifier.TextLinks;
@@ -427,6 +428,7 @@
private boolean mPreDrawListenerDetached;
private TextClassifier mTextClassifier;
+ private TextClassifier mTextClassificationSession;
// A flag to prevent repeated movements from escaping the enclosing text view. The idea here is
// that if a user is holding down a movement key to traverse text, we shouldn't also traverse
@@ -11527,18 +11529,63 @@
@NonNull
public TextClassifier getTextClassifier() {
if (mTextClassifier == null) {
- TextClassificationManager tcm =
+ final TextClassificationManager tcm =
mContext.getSystemService(TextClassificationManager.class);
if (tcm != null) {
- mTextClassifier = tcm.getTextClassifier();
- } else {
- mTextClassifier = TextClassifier.NO_OP;
+ return tcm.getTextClassifier();
}
+ return TextClassifier.NO_OP;
}
return mTextClassifier;
}
/**
+ * Returns a session-aware text classifier.
+ */
+ @NonNull
+ TextClassifier getTextClassificationSession() {
+ if (mTextClassificationSession == null || mTextClassificationSession.isDestroyed()) {
+ final TextClassificationManager tcm =
+ mContext.getSystemService(TextClassificationManager.class);
+ if (tcm != null) {
+ final String widgetType;
+ if (isTextEditable()) {
+ widgetType = TextClassifier.WIDGET_TYPE_EDITTEXT;
+ } else if (isTextSelectable()) {
+ widgetType = TextClassifier.WIDGET_TYPE_TEXTVIEW;
+ } else {
+ widgetType = TextClassifier.WIDGET_TYPE_UNSELECTABLE_TEXTVIEW;
+ }
+ // TODO: Tagged this widgetType with a * so it we can monitor if it reports
+ // SelectionEvents exactly as the older Logger does. Remove once investigations
+ // are complete.
+ final TextClassificationContext textClassificationContext =
+ new TextClassificationContext.Builder(
+ mContext.getPackageName(), "*" + widgetType)
+ .build();
+ if (mTextClassifier != null) {
+ mTextClassificationSession = tcm.createTextClassificationSession(
+ textClassificationContext, mTextClassifier);
+ } else {
+ mTextClassificationSession = tcm.createTextClassificationSession(
+ textClassificationContext);
+ }
+ } else {
+ mTextClassificationSession = TextClassifier.NO_OP;
+ }
+ }
+ return mTextClassificationSession;
+ }
+
+ /**
+ * Returns true if this TextView uses a no-op TextClassifier.
+ */
+ boolean usesNoOpTextClassifier() {
+ return getTextClassifier() == TextClassifier.NO_OP;
+ }
+
+
+ /**
* Starts an ActionMode for the specified TextLinkSpan.
*
* @return Whether or not we're attempting to start the action mode.
@@ -12474,9 +12521,8 @@
+ " before=" + before + " after=" + after + ": " + buffer);
}
- if (AccessibilityManager.getInstance(mContext).isEnabled()
- && !isPasswordInputType(getInputType()) && !hasPasswordTransformationMethod()) {
- mBeforeText = buffer.toString();
+ if (AccessibilityManager.getInstance(mContext).isEnabled() && (mTransformed != null)) {
+ mBeforeText = mTransformed.toString();
}
TextView.this.sendBeforeTextChanged(buffer, start, before, after);
diff --git a/core/java/com/android/internal/os/RoSystemProperties.java b/core/java/com/android/internal/os/RoSystemProperties.java
index 89a4e17..dc660a4 100644
--- a/core/java/com/android/internal/os/RoSystemProperties.java
+++ b/core/java/com/android/internal/os/RoSystemProperties.java
@@ -31,6 +31,8 @@
SystemProperties.get("ro.control_privapp_permissions");
// ------ ro.config.* -------- //
+ public static final boolean CONFIG_AVOID_GFX_ACCEL =
+ SystemProperties.getBoolean("ro.config.avoid_gfx_accel", false);
public static final boolean CONFIG_LOW_RAM =
SystemProperties.getBoolean("ro.config.low_ram", false);
public static final boolean CONFIG_SMALL_BATTERY =
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 221bf88..ad5743d 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -18,7 +18,7 @@
import android.content.ComponentName;
import android.graphics.Rect;
-import android.hardware.fingerprint.IFingerprintDialogReceiver;
+import android.hardware.biometrics.IBiometricDialogReceiver;
import android.os.Bundle;
import android.service.notification.StatusBarNotification;
@@ -141,7 +141,7 @@
void showShutdownUi(boolean isReboot, String reason);
// Used to show the dialog when FingerprintService starts authentication
- void showFingerprintDialog(in Bundle bundle, IFingerprintDialogReceiver receiver);
+ void showFingerprintDialog(in Bundle bundle, IBiometricDialogReceiver receiver);
// Used to hide the dialog when a finger is authenticated
void onFingerprintAuthenticated();
// Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index adf4287..0c5efe2 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -20,7 +20,7 @@
import android.graphics.Rect;
import android.os.Bundle;
import android.service.notification.StatusBarNotification;
-import android.hardware.fingerprint.IFingerprintDialogReceiver;
+import android.hardware.biometrics.IBiometricDialogReceiver;
import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.StatusBarIcon;
@@ -88,7 +88,7 @@
void showPinningEscapeToast();
// Used to show the dialog when FingerprintService starts authentication
- void showFingerprintDialog(in Bundle bundle, IFingerprintDialogReceiver receiver);
+ void showFingerprintDialog(in Bundle bundle, IBiometricDialogReceiver receiver);
// Used to hide the dialog when a finger is authenticated
void onFingerprintAuthenticated();
// Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index c71e505..c5be8e4 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -142,12 +142,24 @@
// Package names that are exempted from private API blacklisting
final ArraySet<String> mHiddenApiPackageWhitelist = new ArraySet<>();
+ // The list of carrier applications which should be disabled until used.
+ // This function suppresses update notifications for these pre-installed apps.
+ // In SubscriptionInfoUpdater, the listed applications are disabled until used when all of the
+ // following conditions are met.
+ // 1. Not currently carrier-privileged according to the inserted SIM
+ // 2. Pre-installed
+ // 3. In the default state (enabled but not explicitly)
+ // And SubscriptionInfoUpdater undoes this and marks the app enabled when a SIM is inserted
+ // that marks the app as carrier privileged. It also grants the app default permissions
+ // for Phone and Location. As such, apps MUST only ever be added to this list if they
+ // obtain user consent to access their location through other means.
+ final ArraySet<String> mDisabledUntilUsedPreinstalledCarrierApps = new ArraySet<>();
+
// These are the packages of carrier-associated apps which should be disabled until used until
// a SIM is inserted which grants carrier privileges to that carrier app.
final ArrayMap<String, List<String>> mDisabledUntilUsedPreinstalledCarrierAssociatedApps =
new ArrayMap<>();
-
final ArrayMap<String, ArraySet<String>> mPrivAppPermissions = new ArrayMap<>();
final ArrayMap<String, ArraySet<String>> mPrivAppDenyPermissions = new ArrayMap<>();
@@ -232,6 +244,10 @@
return mBackupTransportWhitelist;
}
+ public ArraySet<String> getDisabledUntilUsedPreinstalledCarrierApps() {
+ return mDisabledUntilUsedPreinstalledCarrierApps;
+ }
+
public ArrayMap<String, List<String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps() {
return mDisabledUntilUsedPreinstalledCarrierAssociatedApps;
}
@@ -630,6 +646,18 @@
associatedPkgs.add(pkgname);
}
XmlUtils.skipCurrentTag(parser);
+ } else if ("disabled-until-used-preinstalled-carrier-app".equals(name)
+ && allowAppConfigs) {
+ String pkgname = parser.getAttributeValue(null, "package");
+ if (pkgname == null) {
+ Slog.w(TAG,
+ "<disabled-until-used-preinstalled-carrier-app> without "
+ + "package in " + permFile + " at "
+ + parser.getPositionDescription());
+ } else {
+ mDisabledUntilUsedPreinstalledCarrierApps.add(pkgname);
+ }
+ XmlUtils.skipCurrentTag(parser);
} else if ("privapp-permissions".equals(name) && allowPrivappPermissions) {
// privapp permissions from system, vendor and product partitions are stored
// separately. This is to prevent xml files in the vendor partition from
diff --git a/core/proto/android/content/clipdata.proto b/core/proto/android/content/clipdata.proto
index aeeef97..cbc00a7 100644
--- a/core/proto/android/content/clipdata.proto
+++ b/core/proto/android/content/clipdata.proto
@@ -25,7 +25,7 @@
// An android.content.ClipData object.
message ClipDataProto {
- option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+ option (.android.msg_privacy).dest = DEST_LOCAL;
optional android.content.ClipDescriptionProto description = 1;
@@ -40,7 +40,7 @@
// An android.content.ClipData.Item object.
message Item {
- option (.android.msg_privacy).dest = DEST_EXPLICIT;
+ option (.android.msg_privacy).dest = DEST_LOCAL;
oneof data {
string html_text = 1;
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 476d5fe..0fea0dc 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -134,8 +134,14 @@
// Linux services
optional ProcrankProto procrank = 2000 [
- (section).type = SECTION_NONE, // disable procrank until figure out permission
- (section).args = "/system/xbin/procrank"
+ // Disable procrank for reasons below:
+ // 1. incidentd can't execute `procrank` because it don't have DAC perms
+ // since it is running as its own uid, no root access.
+ // 2. the same information is able to be accessed by meminfo dumpsys.
+ // 3. leave this one here to show case of how to disable a section
+ // (no removal allowed if you are familiar with PROTOBUF).
+ (section).type = SECTION_NONE,
+ (section).args = "procrank"
];
optional PageTypeInfoProto page_type_info = 2001 [
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index f40d669..76a3b5d 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -20,9 +20,9 @@
option java_multiple_files = true;
option java_outer_classname = "SettingsServiceProto";
-import "frameworks/base/core/proto/android/providers/settings/common.proto";
import "frameworks/base/core/proto/android/providers/settings/global.proto";
import "frameworks/base/core/proto/android/providers/settings/secure.proto";
+import "frameworks/base/core/proto/android/providers/settings/system.proto";
import "frameworks/base/libs/incident/proto/android/privacy.proto";
message SettingsServiceDumpProto {
@@ -48,111 +48,6 @@
optional SystemSettingsProto system_settings = 3;
}
-// Note: it's a conscious decision to add each setting as a separate field. This
-// allows annotating each setting with its own privacy tag.
-message SystemSettingsProto {
- option (android.msg_privacy).dest = DEST_EXPLICIT;
-
- repeated SettingsOperationProto historical_operations = 1;
-
- optional SettingProto end_button_behavior = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto advanced_settings = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto bluetooth_discoverability = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto bluetooth_discoverability_timeout = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto font_scale = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto system_locales = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto display_color_mode = 8 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto screen_off_timeout = 9 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto screen_brightness = 10 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto screen_brightness_for_vr = 11 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto screen_brightness_mode = 12 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto screen_auto_brightness_adj = 13 [ (android.privacy).dest = DEST_AUTOMATIC ];
- // Determines which streams are affected by ringer mode changes. The stream
- // type's bit will be set to 1 if it should be muted when going into an
- // inaudible ringer mode.
- optional SettingProto mode_ringer_streams_affected = 14 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto mute_streams_affected = 15 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto vibrate_on = 16 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto vibrate_input_devices = 17 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto notification_vibration_intensity = 18 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto haptic_feedback_intensity = 19 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto volume_ring = 20 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto volume_system = 21 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto volume_voice = 22 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto volume_music = 23 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto volume_alarm = 24 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto volume_notification = 25 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto volume_bluetooth_sco = 26 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto volume_accessibility = 27 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto volume_master = 28 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto master_mono = 29 [ (android.privacy).dest = DEST_AUTOMATIC ];
- // Whether silent mode should allow vibration feedback. This is used
- // internally in AudioService and the Sound settings activity to coordinate
- // decoupling of vibrate and silent modes. This setting will likely be
- // removed in a future release with support for audio/vibe feedback
- // profiles.
- // Not used anymore. On devices with vibrator, the user explicitly selects
- // silent or vibrate mode. Kept for use by legacy database upgrade code in
- // DatabaseHelper.
- optional SettingProto vibrate_in_silent = 30 [ (android.privacy).dest = DEST_AUTOMATIC ];
- // Appended to various volume related settings to record the previous values
- // before the settings were affected by a silent/vibrate ringer mode change.
- optional SettingProto append_for_last_audible = 31 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto ringtone = 32;
- optional SettingProto ringtone_cache = 33;
- optional SettingProto notification_sound = 34;
- optional SettingProto notification_sound_cache = 35;
- optional SettingProto alarm_alert = 36;
- optional SettingProto alarm_alert_cache = 37;
- optional SettingProto media_button_receiver = 38;
- optional SettingProto text_auto_replace = 39 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto text_auto_caps = 40 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto text_auto_punctuate = 41 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto text_show_password = 42 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto show_gtalk_service_status = 43 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto time_12_24 = 44 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto date_format = 45 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto setup_wizard_has_run = 46 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto accelerometer_rotation = 47 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto user_rotation = 48 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto hide_rotation_lock_toggle_for_accessibility = 49 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto vibrate_when_ringing = 50 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto dtmf_tone_when_dialing = 51 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto dtmf_tone_type_when_dialing = 52 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto hearing_aid = 53 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto tty_mode = 54 [ (android.privacy).dest = DEST_AUTOMATIC ];
- // User-selected RTT mode. When on, outgoing and incoming calls will be
- // answered as RTT calls when supported by the device and carrier. Boolean
- // value.
- optional SettingProto rtt_calling_mode = 55 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto sound_effects_enabled = 56 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto haptic_feedback_enabled = 57 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto notification_light_pulse = 58 [ (android.privacy).dest = DEST_AUTOMATIC ];
- // Show pointer location on screen? 0 = no, 1 = yes.
- optional SettingProto pointer_location = 59 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto show_touches = 60 [ (android.privacy).dest = DEST_AUTOMATIC ];
- // Log raw orientation data from {@link
- // com.android.server.policy.WindowOrientationListener} for use with the
- // orientationplot.py tool.
- // 0 = no, 1 = yes
- optional SettingProto window_orientation_listener_log = 61 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto lockscreen_sounds_enabled = 62 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto lockscreen_disabled = 63 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto sip_receive_calls = 64 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto sip_call_options = 65 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto sip_always = 66 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto sip_address_only = 67 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto pointer_speed = 68 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto lock_to_app_enabled = 69 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto egg_mode = 70 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto show_battery_percent = 71 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto when_to_make_wifi_calls = 72 [ (android.privacy).dest = DEST_AUTOMATIC ];
-
- // Please insert fields in the same order as in
- // frameworks/base/core/java/android/provider/Settings.java.
- // Next tag = 73;
-}
-
message SettingsProto {
// Enum values gotten from Settings.java
enum ScreenBrightnessMode {
diff --git a/core/proto/android/providers/settings/system.proto b/core/proto/android/providers/settings/system.proto
new file mode 100644
index 0000000..6b6edd2
--- /dev/null
+++ b/core/proto/android/providers/settings/system.proto
@@ -0,0 +1,246 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.providers.settings;
+
+option java_multiple_files = true;
+
+import "frameworks/base/core/proto/android/providers/settings/common.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
+// Note: it's a conscious decision to add each setting as a separate field. This
+// allows annotating each setting with its own privacy tag.
+message SystemSettingsProto {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ repeated SettingsOperationProto historical_operations = 1;
+
+ optional SettingProto advanced_settings = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+ message Alarm {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ // "alarm_alert" in code.
+ optional SettingProto default_uri = 1;
+ optional SettingProto alert_cache = 2;
+ }
+ optional Alarm alarm = 3;
+
+ message Bluetooth {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ // Whether remote devices may discover and/or connect to this device:
+ // 2 -- discoverable and connectable
+ // 1 -- connectable but not discoverable
+ // 0 -- neither connectable nor discoverable
+ optional SettingProto discoverability = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto discoverability_timeout_secs = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ }
+ optional Bluetooth bluetooth = 4;
+
+ optional SettingProto date_format = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto display_color_mode = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+ message DevOptions {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ // Show pointer location on screen? 0 = no, 1 = yes. "pointer_location
+ // in code.
+ optional SettingProto pointer_location = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto show_touches = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ // Log raw orientation data from {@link
+ // com.android.server.policy.WindowOrientationListener} for use with the
+ // orientationplot.py tool.
+ // 0 = no, 1 = yes
+ optional SettingProto window_orientation_listener_log = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ }
+ optional DevOptions developer_options = 7;
+
+ message DtmfTone {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ // "dtmf_tone_when_dialing" in code.
+ optional SettingProto play_when_dialing = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ // "dtmf_tone_type_when_dialing" in code.
+ optional SettingProto type_played_when_dialing = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ }
+ optional DtmfTone dtmf_tone = 8;
+
+ optional SettingProto egg_mode = 9 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto end_button_behavior = 10 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto font_scale = 11 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+ message HapticFeedback {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ optional SettingProto enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto intensity = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ }
+ optional HapticFeedback haptic_feedback = 12;
+
+ // Whether the hearing aid is enabled. The value is boolean (1 or 0).
+ optional SettingProto hearing_aid = 13 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto lock_to_app_enabled = 14 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+ message Lockscreen {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ optional SettingProto sounds_enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto disabled = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ }
+ optional Lockscreen lockscreen = 15;
+
+ // The system default media button event receiver.
+ optional SettingProto media_button_receiver = 16;
+
+ message Notification {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ optional SettingProto sound = 1;
+ optional SettingProto sound_cache = 2;
+ optional SettingProto light_pulse = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto vibration_intensity = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ }
+ optional Notification notification = 17;
+
+ optional SettingProto pointer_speed = 18 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+ message Ringtone {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ // "ringtone" in code. The system-wide default ringtone URI.
+ optional SettingProto default_uri = 1;
+ optional SettingProto cache = 2;
+ }
+ optional Ringtone ringtone = 19;
+
+ message Rotation {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ // Control whether the accelerometer will be used to change screen
+ // orientation. If 0, it will not be used unless explicitly requested
+ // by the application; if 1, it will be used by default unless
+ // explicitly disabled by the application.
+ optional SettingProto accelerometer_rotation = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ // Default screen rotation when no other policy applies.
+ // When accelerometer_rotation is zero and no on-screen Activity expresses a
+ // preference, this rotation value will be used. Must be one of the
+ // {@link android.view.Surface#ROTATION_0 Surface rotation constants}.
+ optional SettingProto user_rotation = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ // Control whether the rotation lock toggle in the System UI should be hidden.
+ // Typically this is done for accessibility purposes to make it harder for
+ // the user to accidentally toggle the rotation lock while the display rotation
+ // has been locked for accessibility.
+ // If 0, then rotation lock toggle is not hidden for accessibility (although it may be
+ // unavailable for other reasons). If 1, then the rotation lock toggle is hidden.
+ optional SettingProto hide_rotation_lock_toggle_for_accessibility = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ }
+ optional Rotation rotation = 20;
+
+ // User-selected RTT mode. When on, outgoing and incoming calls will be
+ // answered as RTT calls when supported by the device and carrier. Boolean
+ // value.
+ optional SettingProto rtt_calling_mode = 21 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+ message Screen {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ optional SettingProto off_timeout = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto brightness = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto brightness_for_vr = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto brightness_mode = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto auto_brightness_adj = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ }
+ optional Screen screen = 22;
+
+ optional SettingProto setup_wizard_has_run = 23 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto show_battery_percent = 24 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto show_gtalk_service_status = 25 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+ message Sip {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ optional SettingProto receive_calls = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto call_options = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto always = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto address_only = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ }
+ optional Sip sip = 26;
+
+ optional SettingProto sound_effects_enabled = 27 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto system_locales = 28 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+ message Text {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ optional SettingProto auto_replace = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto auto_caps = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto auto_punctuate = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto show_password = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ }
+ optional Text text = 29;
+
+ optional SettingProto time_12_24 = 30 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto tty_mode = 31 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+ message Vibrate {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ optional SettingProto on = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto input_devices = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ // Whether silent mode should allow vibration feedback. This is used
+ // internally in AudioService and the Sound settings activity to coordinate
+ // decoupling of vibrate and silent modes. This setting will likely be
+ // removed in a future release with support for audio/vibe feedback
+ // profiles.
+ // Not used anymore. On devices with vibrator, the user explicitly selects
+ // silent or vibrate mode. Kept for use by legacy database upgrade code in
+ // DatabaseHelper.
+ optional SettingProto in_silent = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto when_ringing = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ }
+ optional Vibrate vibrate = 32;
+
+ message Volume {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ optional SettingProto ring = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto system = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto voice = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto music = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto alarm = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto notification = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto bluetooth_sco = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto accessibility = 8 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto master = 9 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto master_mono = 10 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ // Determines which streams are affected by ringer mode changes. The stream
+ // type's bit will be set to 1 if it should be muted when going into an
+ // inaudible ringer mode.
+ optional SettingProto mode_ringer_streams_affected = 11 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ // Which streams are affected by mute. The stream type's bit should be set
+ // to 1 if it should be muted when a mute request is received.
+ optional SettingProto mute_streams_affected = 12 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ }
+ optional Volume volume = 33;
+
+ optional SettingProto when_to_make_wifi_calls = 34 [ (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 = 35;
+}
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 8d4b56c..bb8ce81 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -578,6 +578,12 @@
optional .android.os.PersistableBundleProto extras = 14;
optional .android.os.BundleProto transient_extras = 15;
+ // ClipData of information that is returned to the application at
+ // execution time, but not persisted by the system. This is provided by
+ // the app and the main purpose of providing a ClipData is to allow
+ // granting of URI permissions for data associated with the clip. The
+ // exact kind of permission grant to perform is specified in the flags
+ // field.
optional .android.content.ClipDataProto clip_data = 16;
optional GrantedUriPermissionsDumpProto granted_uri_permissions = 17;
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 063135d..a8d0825 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -156,6 +156,8 @@
TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER = 21;
TRANSIT_KEYGUARD_OCCLUDE = 22;
TRANSIT_KEYGUARD_UNOCCLUDE = 23;
+ TRANSIT_TRANSLUCENT_ACTIVITY_OPEN = 24;
+ TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE = 25;
}
optional TransitionType last_used_app_transition = 2;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3fb52dc..48d394a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -89,6 +89,8 @@
<protected-broadcast android:name="android.intent.action.OVERLAY_REMOVED" />
<protected-broadcast android:name="android.intent.action.OVERLAY_PRIORITY_CHANGED" />
<protected-broadcast android:name="android.intent.action.USER_ACTIVITY_NOTIFICATION" />
+ <protected-broadcast android:name="android.intent.action.MY_PACKAGE_SUSPENDED" />
+ <protected-broadcast android:name="android.intent.action.MY_PACKAGE_UNSUSPENDED" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGING" />
@@ -1102,6 +1104,8 @@
<!-- Allows an app to use fingerprint hardware.
<p>Protection level: normal
+ @deprecated Applications should request {@link
+ android.Manifest.permission#USE_BIOMETRIC} instead
-->
<permission android:name="android.permission.USE_FINGERPRINT"
android:permissionGroup="android.permission-group.SENSORS"
@@ -1109,6 +1113,15 @@
android:description="@string/permdesc_useFingerprint"
android:protectionLevel="normal" />
+ <!-- Allows an app to use device supported biometric modalities.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.USE_BIOMETRIC"
+ android:permissionGroup="android.permission-group.SENSORS"
+ android:label="@string/permlab_useBiometric"
+ android:description="@string/permdesc_useBiometric"
+ android:protectionLevel="normal" />
+
<!-- ====================================================================== -->
<!-- REMOVED PERMISSIONS -->
<!-- ====================================================================== -->
@@ -4224,7 +4237,7 @@
android:exported="false">
</receiver>
- <receiver android:name="com.android.server.stats.StatsCompanionService$PollingAlarmReceiver"
+ <receiver android:name="com.android.server.stats.StatsCompanionService$PullingAlarmReceiver"
android:permission="android.permission.STATSCOMPANION"
android:exported="false">
</receiver>
diff --git a/core/res/res/anim/activity_translucent_close_exit.xml b/core/res/res/anim/activity_translucent_close_exit.xml
new file mode 100644
index 0000000..04c5dea
--- /dev/null
+++ b/core/res/res/anim/activity_translucent_close_exit.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false"
+ android:zAdjustment="top">
+ <translate
+ android:fromYDelta="0%"
+ android:toYDelta="100%"
+ android:interpolator="@interpolator/fast_out_linear_in"
+ android:duration="300"/>
+</set>
diff --git a/core/res/res/anim/activity_translucent_open_enter.xml b/core/res/res/anim/activity_translucent_open_enter.xml
new file mode 100644
index 0000000..da3dded
--- /dev/null
+++ b/core/res/res/anim/activity_translucent_open_enter.xml
@@ -0,0 +1,24 @@
+<?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
+ -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false">
+ <translate
+ android:fromYDelta="100%"
+ android:toYDelta="0"
+ android:interpolator="@interpolator/linear_out_slow_in"
+ android:duration="300"/>
+</set>
diff --git a/core/res/res/layout/autofill_dataset_picker_header_footer.xml b/core/res/res/layout/autofill_dataset_picker_header_footer.xml
new file mode 100644
index 0000000..048494a
--- /dev/null
+++ b/core/res/res/layout/autofill_dataset_picker_header_footer.xml
@@ -0,0 +1,57 @@
+<?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.
+-->
+
+<view xmlns:android="http://schemas.android.com/apk/res/android"
+ class="com.android.server.autofill.ui.FillUi$AutofillFrameLayout"
+ android:id="@+id/autofill_dataset_picker"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ style="@style/AutofillDatasetPicker">
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:id="@+id/autofill_dataset_header"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"/>
+
+ <ListView
+ android:id="@+id/autofill_dataset_list"
+ android:layout_weight="1"
+ android:layout_width="fill_parent"
+ android:layout_height="0dp"
+ android:drawSelectorOnTop="true"
+ android:clickable="true"
+ android:divider="@null"
+ android:visibility="gone">
+ </ListView>
+
+ <LinearLayout
+ android:id="@+id/autofill_dataset_footer"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"/>
+
+ </LinearLayout>
+
+</view>
diff --git a/core/res/res/layout/autofill_dataset_picker_header_footer_fullscreen.xml b/core/res/res/layout/autofill_dataset_picker_header_footer_fullscreen.xml
new file mode 100644
index 0000000..24b14a0
--- /dev/null
+++ b/core/res/res/layout/autofill_dataset_picker_header_footer_fullscreen.xml
@@ -0,0 +1,73 @@
+<?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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/autofill_dataset_picker"
+ style="@style/AutofillDatasetPicker"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/autofill_window_title"
+ android:layout_above="@+id/autofill_dataset_container"
+ android:layout_alignStart="@+id/autofill_dataset_container"
+ android:textSize="16sp"/>
+
+ <!-- autofill_container is the common parent for inserting authentication item or
+ autofill_dataset_list-->
+ <FrameLayout
+ android:id="@+id/autofill_dataset_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true">
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:id="@+id/autofill_dataset_header"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"/>
+
+ <ListView
+ android:id="@+id/autofill_dataset_list"
+ android:layout_weight="1"
+ android:layout_width="fill_parent"
+ android:layout_height="0dp"
+ android:clickable="true"
+ android:divider="@null"
+ android:drawSelectorOnTop="true"
+ android:visibility="gone"/>
+
+ <LinearLayout
+ android:id="@+id/autofill_dataset_footer"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"/>
+
+ </LinearLayout>
+
+ </FrameLayout>
+
+</RelativeLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 3135455..aceba08 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2123,44 +2123,48 @@
<!-- Controls how the window is laid out if there is a {@code DisplayCutout}.
<p>
Defaults to {@code default}.
-
- @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
- @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
- @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
- @see android.view.DisplayCutout
- @see android.R.attr#layoutInDisplayCutoutMode -->
+ <p>
+ See also
+ {@link android.view.WindowManager.LayoutParams#layoutInDisplayCutoutMode
+ WindowManager.LayoutParams.layoutInDisplayCutoutMode},
+ {@link android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT},
+ {@link android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES},
+ {@link android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER},
+ and {@link android.view.DisplayCutout DisplayCutout}
+ -->
<attr name="windowLayoutInDisplayCutoutMode">
- <!-- The window is allowed to extend into the {@code DisplayCutout} area, only if the
- {@code DisplayCutout} is fully contained within a system bar. Otherwise, the window is
- laid out such that it does not overlap with the {@code DisplayCutout} area.
-
- @see android.view.DisplayCutout
- @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
+ <!-- <p>
+ The window is allowed to extend into the <code>DisplayCutout</code> area, only if
+ the <code>DisplayCutout</code> is fully contained within a system bar. Otherwise, the
+ window is laid out such that it does not overlap with the <code>DisplayCutout</code>
+ area.
+ <p>
+ Corresponds to <code>LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT</code>.
-->
<enum name="default" value="0" />
- <!--
- The window is always allowed to extend into the {@code DisplayCutout} areas on the short
- edges of the screen even if fullscreen or in landscape.
- The window will never extend into a {@link DisplayCutout} area on the long edges of the
- screen.
+ <!-- <p>
+ The window is always allowed to extend into the <code>DisplayCutout</code> areas on the
+ short edges of the screen even if fullscreen or in landscape.
+ The window will never extend into a <code>DisplayCutout</code> area on the long edges of
+ the screen.
<p>
The window must make sure that no important content overlaps with the
- {@link DisplayCutout}.
-
- @see android.view.DisplayCutout
- @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
+ <code>DisplayCutout</code>.
+ <p>
+ Corresponds to <code>LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES</code>.
-->
<enum name="shortEdges" value="1" />
- <!-- Use {@code shortEdges} instead. This is temporarily here to unblock pushing the SDK
- until all usages have been migrated to {@code shortEdges} -->
+ <!-- Use <code>shortEdges</code> instead. This is temporarily here to unblock pushing
+ the SDK until all usages have been migrated to <code>shortEdges</code> -->
<enum name="always" value="1" />
- <!-- The window is never allowed to overlap with the DisplayCutout area.
+ <!-- <p>
+ The window is never allowed to overlap with the <code>DisplayCutout</code> area.
<p>
- This should be used with windows that transiently set {@code SYSTEM_UI_FLAG_FULLSCREEN}
- to avoid a relayout of the window when the flag is set or cleared.
-
- @see android.view.DisplayCutout
- @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
+ This should be used with windows that transiently set
+ <code>SYSTEM_UI_FLAG_FULLSCREEN</code> to avoid a relayout of the window when the
+ flag is set or cleared.
+ <p>
+ Corresponds to <code>LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER</code>.
-->
<enum name="never" value="2" />
</attr>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 29fd9e9..66d25df 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1343,30 +1343,6 @@
<integer-array name="config_autoBrightnessKeyboardBacklightValues">
</integer-array>
- <!-- Array of light sensor lux values to define the minimum brightness curve, which guarantees
- that any curve that dips below it is rejected by the system.
- This prevents auto-brightness from setting the screen so dark as to prevent the user from
- disabling auto-brightness or reseting the brightness curve via ADB.
-
- The control points must be strictly increasing. Each control point corresponds to an entry
- in the minimum brightness nits array. -->
- <integer-array name="config_autoBrightnessMinimumBrightnessCurveLux">
- <item>2000</item>
- <item>4000</item>
- </integer-array>
-
- <!-- Array of desired screen brightness in nits corresponding to the lux values
- in the config_autoBrightnessMinimumBrightnessCurveLux array.
-
- This array should have size one greater than the size of the
- config_autoBrightnessMinimumBrightnessCurveLux array. The values must be non-negative and
- non-decreasing. -->
- <array name="config_autoBrightnessMinimumBrightnessCurveNits">
- <item>1.0</item>
- <item>50.0</item>
- <item>90.0</item>
- </array>
-
<!-- Array of hysteresis constraint values for brightening, represented as tenths of a
percent. The length of this array is assumed to be one greater than
config_dynamicHysteresisLuxLevels. The brightening threshold is calculated as
@@ -2392,19 +2368,6 @@
<item>com.android.inputmethod.latin</item>
</string-array>
- <!-- The list of carrier applications which should be disabled until used.
- This function suppresses update notifications for these pre-installed apps.
- In SubscriptionInfoUpdater, the listed applications are disabled until used when all of the
- following conditions are met.
- 1. Not currently carrier-privileged according to the inserted SIM
- 2. Pre-installed
- 3. In the default state (enabled but not explicitly)
- And SubscriptionInfoUpdater undoes this and marks the app enabled when a SIM is inserted
- that marks the app as carrier privileged. It also grants the app default permissions
- for Phone and Location. As such, apps MUST only ever be added to this list if they
- obtain user consent to access their location through other means. -->
- <string-array name="config_disabledUntilUsedPreinstalledCarrierApps" translatable="false" />
-
<!-- The list of classes that should be added to the notification ranking pipeline.
See {@link com.android.server.notification.NotificationSignalExtractor}
If you add a new extractor to this list make sure to update
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2e8f663..49cd272 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1325,6 +1325,11 @@
disables the keylock when receiving an incoming phone call, then
re-enables the keylock when the call is finished.</string>
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=NONE] -->
+ <string name="permlab_useBiometric">use biometric hardware</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this.[CHAR_LIMIT=NONE] -->
+ <string name="permdesc_useBiometric">Allows the app to use biometric hardware for authentication</string>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_manageFingerprint">manage fingerprint hardware</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -2752,30 +2757,57 @@
<!-- Label for item in the text selection menu to trigger an Email app [CHAR LIMIT=20] -->
<string name="email">Email</string>
+ <!-- Accessibility description for an item in the text selection menu to trigger an Email app [CHAR LIMIT=NONE] -->
+ <string name="email_desc">Email selected address</string>
+
<!-- Label for item in the text selection menu to trigger a Dialer app [CHAR LIMIT=20] -->
<string name="dial">Call</string>
+ <!-- Accessibility description for an item in the text selection menu to call a phone number [CHAR LIMIT=NONE] -->
+ <string name="dial_desc">Call selected phone number</string>
+
<!-- Label for item in the text selection menu to trigger a Map app [CHAR LIMIT=20] -->
<string name="map">Locate</string>
+ <!-- Accessibility description for an item in the text selection menu to open maps for an address [CHAR LIMIT=NONE] -->
+ <string name="map_desc">Locale selected address</string>
+
<!-- Label for item in the text selection menu to trigger a Browser app [CHAR LIMIT=20] -->
<string name="browse">Open</string>
+ <!-- Accessibility description for an item in the text selection menu to open a URL in a browser [CHAR LIMIT=NONE] -->
+ <string name="browse_desc">Open selected URL</string>
+
<!-- Label for item in the text selection menu to trigger an SMS app [CHAR LIMIT=20] -->
<string name="sms">Message</string>
+ <!-- Accessibility description for an item in the text selection menu to send an SMS to a phone number [CHAR LIMIT=NONE] -->
+ <string name="sms_desc">Message selected phone number</string>
+
<!-- Label for item in the text selection menu to trigger adding a contact [CHAR LIMIT=20] -->
<string name="add_contact">Add</string>
+ <!-- Accessibility description for an item in the text selection menu to add the selected detail to contacts [CHAR LIMIT=NONE] -->
+ <string name="add_contact_desc">Add to contacts</string>
+
<!-- Label for item in the text selection menu to view the calendar for the selected time/date [CHAR LIMIT=20] -->
<string name="view_calendar">View</string>
+ <!-- Accessibility description for an item in the text selection menu to view the calendar for a date [CHAR LIMIT=NONE]-->
+ <string name="view_calendar_desc">View selected time in calendar</string>
+
<!-- Label for item in the text selection menu to create a calendar event at the selected time/date [CHAR LIMIT=20] -->
<string name="add_calendar_event">Schedule</string>
+ <!-- Accessibility description for an item in the text selection menu to schedule an event for a date [CHAR LIMIT=NONE] -->
+ <string name="add_calendar_event_desc">Schedule event for selected time</string>
+
<!-- Label for item in the text selection menu to track a selected flight number [CHAR LIMIT=20] -->
<string name="view_flight">Track</string>
+ <!-- Accessibility description for an item in the text selection menu to track a flight [CHAR LIMIT=NONE] -->
+ <string name="view_flight_desc">Track selected flight</string>
+
<!-- If the device is getting low on internal storage, a notification is shown to the user. This is the title of that notification. -->
<string name="low_internal_storage_view_title">Storage space running out</string>
<!-- If the device is getting low on internal storage, a notification is shown to the user. This is the message of that notification. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a4d184d..c73a7cb 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -545,14 +545,23 @@
<java-symbol type="string" name="undo" />
<java-symbol type="string" name="redo" />
<java-symbol type="string" name="email" />
+ <java-symbol type="string" name="email_desc" />
<java-symbol type="string" name="dial" />
+ <java-symbol type="string" name="dial_desc" />
<java-symbol type="string" name="map" />
+ <java-symbol type="string" name="map_desc" />
<java-symbol type="string" name="browse" />
+ <java-symbol type="string" name="browse_desc" />
<java-symbol type="string" name="sms" />
+ <java-symbol type="string" name="sms_desc" />
<java-symbol type="string" name="add_contact" />
+ <java-symbol type="string" name="add_contact_desc" />
<java-symbol type="string" name="view_calendar" />
+ <java-symbol type="string" name="view_calendar_desc" />
<java-symbol type="string" name="add_calendar_event" />
+ <java-symbol type="string" name="add_calendar_event_desc" />
<java-symbol type="string" name="view_flight" />
+ <java-symbol type="string" name="view_flight_desc" />
<java-symbol type="string" name="textSelectionCABTitle" />
<java-symbol type="string" name="BaMmi" />
<java-symbol type="string" name="CLIRDefaultOffNextCallOff" />
@@ -1233,7 +1242,6 @@
<java-symbol type="array" name="supported_locales" />
<java-symbol type="array" name="config_cdma_dun_supported_types" />
<java-symbol type="array" name="config_disabledUntilUsedPreinstalledImes" />
- <java-symbol type="array" name="config_disabledUntilUsedPreinstalledCarrierApps" />
<java-symbol type="array" name="config_callBarringMMI" />
<java-symbol type="array" name="config_globalActionsList" />
<java-symbol type="array" name="config_telephonyEuiccDeviceCapabilities" />
@@ -1611,6 +1619,8 @@
<java-symbol type="anim" name="task_open_enter" />
<java-symbol type="anim" name="cross_profile_apps_thumbnail_enter" />
<java-symbol type="anim" name="task_open_enter_cross_profile_apps" />
+ <java-symbol type="anim" name="activity_translucent_open_enter" />
+ <java-symbol type="anim" name="activity_translucent_close_exit" />
<java-symbol type="array" name="config_autoRotationTiltTolerance" />
<java-symbol type="array" name="config_keyboardTapVibePattern" />
@@ -1795,8 +1805,6 @@
<java-symbol type="array" name="config_autoBrightnessKeyboardBacklightValues" />
<java-symbol type="array" name="config_autoBrightnessLcdBacklightValues" />
<java-symbol type="array" name="config_autoBrightnessLevels" />
- <java-symbol type="array" name="config_autoBrightnessMinimumBrightnessCurveLux" />
- <java-symbol type="array" name="config_autoBrightnessMinimumBrightnessCurveNits" />
<java-symbol type="array" name="config_dynamicHysteresisBrightLevels" />
<java-symbol type="array" name="config_dynamicHysteresisDarkLevels" />
<java-symbol type="array" name="config_dynamicHysteresisLuxLevels" />
@@ -3022,7 +3030,11 @@
<java-symbol type="layout" name="autofill_save"/>
<java-symbol type="layout" name="autofill_dataset_picker"/>
<java-symbol type="layout" name="autofill_dataset_picker_fullscreen"/>
+ <java-symbol type="layout" name="autofill_dataset_picker_header_footer"/>
+ <java-symbol type="layout" name="autofill_dataset_picker_header_footer_fullscreen"/>
<java-symbol type="id" name="autofill_dataset_container"/>
+ <java-symbol type="id" name="autofill_dataset_footer"/>
+ <java-symbol type="id" name="autofill_dataset_header"/>
<java-symbol type="id" name="autofill_dataset_list"/>
<java-symbol type="id" name="autofill_dataset_picker"/>
<java-symbol type="id" name="autofill" />
diff --git a/core/tests/coretests/src/android/app/backup/FullBackupTest.java b/core/tests/coretests/src/android/app/backup/FullBackupTest.java
index 58ee7a7..5db416b 100644
--- a/core/tests/coretests/src/android/app/backup/FullBackupTest.java
+++ b/core/tests/coretests/src/android/app/backup/FullBackupTest.java
@@ -16,9 +16,6 @@
package android.app.backup;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
import android.app.backup.FullBackup.BackupScheme.PathWithRequiredFlags;
import android.content.Context;
import android.support.test.filters.LargeTest;
@@ -102,6 +99,28 @@
include.getRequiredFlags());
}
+ public void testParseBackupSchemeFromXml_onlyIncludeRequireFakeEncryptionFlag()
+ throws Exception {
+ mXpp.setInput(new StringReader(
+ "<full-backup-content>"
+ + "<include path=\"onlyInclude.txt\" domain=\"file\""
+ + " requireFlags=\"fakeClientSideEncryption\"/>"
+ + "</full-backup-content>"));
+
+ FullBackup.BackupScheme bs = FullBackup.getBackupSchemeForTest(mContext);
+ bs.parseBackupSchemeFromXmlLocked(mXpp, excludesSet, includeMap);
+
+ Set<PathWithRequiredFlags> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
+ assertEquals("Didn't find expected file domain include.", 1, fileDomainIncludes.size());
+ PathWithRequiredFlags include = fileDomainIncludes.iterator().next();
+ assertEquals("Invalid path parsed for <include/>",
+ new File(mContext.getFilesDir(), "onlyInclude.txt").getCanonicalPath(),
+ include.getPath());
+ assertEquals("Invalid requireFlags parsed for <include/>",
+ BackupAgent.FLAG_FAKE_CLIENT_SIDE_ENCRYPTION_ENABLED,
+ include.getRequiredFlags());
+ }
+
public void testparseBackupSchemeFromXml_onlyIncludeRequireD2DFlag() throws Exception {
mXpp.setInput(new StringReader(
"<full-backup-content>" +
diff --git a/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java b/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java
index b77982b..861a43a 100644
--- a/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java
@@ -33,8 +33,11 @@
@Test
public void testParcel() {
final SelectionEvent[] captured = new SelectionEvent[1];
- final Logger logger = new Logger(new Logger.Config(
- InstrumentationRegistry.getTargetContext(), Logger.WIDGET_TEXTVIEW, null)) {
+ final Logger logger = new Logger(
+ new Logger.Config(
+ InstrumentationRegistry.getTargetContext(),
+ TextClassifier.WIDGET_TYPE_TEXTVIEW,
+ null)) {
@Override
public void writeEvent(SelectionEvent event) {
captured[0] = event;
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index 57db153..f96027d 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -126,11 +126,7 @@
TextClassification classification = mClassifier.classifyText(
text, startIndex, endIndex, mClassificationOptions);
- assertThat(classification,
- isTextClassification(
- classifiedText,
- TextClassifier.TYPE_EMAIL,
- "mailto:" + classifiedText));
+ assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_EMAIL));
}
@Test
@@ -144,11 +140,7 @@
TextClassification classification = mClassifier.classifyText(
text, startIndex, endIndex, mClassificationOptions);
- assertThat(classification,
- isTextClassification(
- classifiedText,
- TextClassifier.TYPE_URL,
- "http://" + classifiedText));
+ assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_URL));
}
@Test
@@ -158,11 +150,7 @@
String text = "Brandschenkestrasse 110, Zürich, Switzerland";
TextClassification classification = mClassifier.classifyText(
text, 0, text.length(), mClassificationOptions);
- assertThat(classification,
- isTextClassification(
- text,
- TextClassifier.TYPE_ADDRESS,
- "geo:0,0?q=Brandschenkestrasse+110%2C+Z%C3%BCrich%2C+Switzerland"));
+ assertThat(classification, isTextClassification(text, TextClassifier.TYPE_ADDRESS));
}
@Test
@@ -176,11 +164,7 @@
TextClassification classification = mClassifier.classifyText(
text, startIndex, endIndex, mClassificationOptions);
- assertThat(classification,
- isTextClassification(
- classifiedText,
- TextClassifier.TYPE_URL,
- "http://ANDROID.COM"));
+ assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_URL));
}
@Test
@@ -194,11 +178,7 @@
TextClassification classification = mClassifier.classifyText(
text, startIndex, endIndex, mClassificationOptions);
- assertThat(classification,
- isTextClassification(
- classifiedText,
- TextClassifier.TYPE_DATE,
- null));
+ assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_DATE));
}
@Test
@@ -213,10 +193,7 @@
TextClassification classification = mClassifier.classifyText(
text, startIndex, endIndex, mClassificationOptions);
assertThat(classification,
- isTextClassification(
- classifiedText,
- TextClassifier.TYPE_DATE_TIME,
- null));
+ isTextClassification(classifiedText, TextClassifier.TYPE_DATE_TIME));
}
@Test
@@ -355,39 +332,15 @@
}
private static Matcher<TextClassification> isTextClassification(
- final String text, final String type, final String intentUri) {
+ final String text, final String type) {
return new BaseMatcher<TextClassification>() {
@Override
public boolean matches(Object o) {
if (o instanceof TextClassification) {
TextClassification result = (TextClassification) o;
- final boolean typeRequirementSatisfied;
- String scheme;
- switch (type) {
- case TextClassifier.TYPE_EMAIL:
- scheme = result.getIntent().getData().getScheme();
- typeRequirementSatisfied = "mailto".equals(scheme);
- break;
- case TextClassifier.TYPE_URL:
- scheme = result.getIntent().getData().getScheme();
- typeRequirementSatisfied = "http".equals(scheme)
- || "https".equals(scheme);
- break;
- case TextClassifier.TYPE_ADDRESS:
- scheme = result.getIntent().getData().getScheme();
- typeRequirementSatisfied = "geo".equals(scheme);
- break;
- default:
- typeRequirementSatisfied = true;
- }
-
- return typeRequirementSatisfied
- && text.equals(result.getText())
+ return text.equals(result.getText())
&& result.getEntityCount() > 0
- && type.equals(result.getEntity(0))
- && (intentUri == null
- || intentUri.equals(result.getIntent().getDataString()));
- // TODO: Include other properties.
+ && type.equals(result.getEntity(0));
}
return false;
}
@@ -395,8 +348,7 @@
@Override
public void describeTo(Description description) {
description.appendText("text=").appendValue(text)
- .appendText(", type=").appendValue(type)
- .appendText(", intent.data=").appendValue(intentUri);
+ .appendText(", type=").appendValue(type);
}
};
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
index ada19fc..afc4bd5 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
@@ -17,15 +17,19 @@
package android.view.textclassifier;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import android.app.PendingIntent;
+import android.app.RemoteAction;
+import android.content.Context;
import android.content.Intent;
-import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Icon;
import android.os.LocaleList;
import android.os.Parcel;
+import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.View;
@@ -41,47 +45,44 @@
@RunWith(AndroidJUnit4.class)
public class TextClassificationTest {
- public BitmapDrawable generateTestDrawable(int width, int height, int colorValue) {
+ public Icon generateTestIcon(int width, int height, int colorValue) {
final int numPixels = width * height;
final int[] colors = new int[numPixels];
for (int i = 0; i < numPixels; ++i) {
colors[i] = colorValue;
}
final Bitmap bitmap = Bitmap.createBitmap(colors, width, height, Bitmap.Config.ARGB_8888);
- final BitmapDrawable drawable = new BitmapDrawable(Resources.getSystem(), bitmap);
- drawable.setTargetDensity(bitmap.getDensity());
- return drawable;
+ return Icon.createWithBitmap(bitmap);
}
@Test
public void testParcel() {
+ final Context context = InstrumentationRegistry.getTargetContext();
final String text = "text";
- final BitmapDrawable primaryIcon = generateTestDrawable(16, 16, Color.RED);
- final String primaryLabel = "primarylabel";
- final Intent primaryIntent = new Intent("primaryintentaction");
- final View.OnClickListener primaryOnClick = v -> { };
- final BitmapDrawable secondaryIcon0 = generateTestDrawable(32, 288, Color.GREEN);
- final String secondaryLabel0 = "secondarylabel0";
- final Intent secondaryIntent0 = new Intent("secondaryintentaction0");
- final BitmapDrawable secondaryIcon1 = generateTestDrawable(576, 288, Color.BLUE);
- final String secondaryLabel1 = "secondaryLabel1";
- final Intent secondaryIntent1 = null;
- final BitmapDrawable secondaryIcon2 = null;
- final String secondaryLabel2 = null;
- final Intent secondaryIntent2 = new Intent("secondaryintentaction2");
- final ColorDrawable secondaryIcon3 = new ColorDrawable(Color.CYAN);
- final String secondaryLabel3 = null;
- final Intent secondaryIntent3 = null;
+
+ final Icon primaryIcon = generateTestIcon(576, 288, Color.BLUE);
+ final String primaryLabel = "primaryLabel";
+ final String primaryDescription = "primaryDescription";
+ final Intent primaryIntent = new Intent("primaryIntentAction");
+ final PendingIntent primaryPendingIntent = PendingIntent.getActivity(context, 0,
+ primaryIntent, 0);
+ final RemoteAction remoteAction0 = new RemoteAction(primaryIcon, primaryLabel,
+ primaryDescription, primaryPendingIntent);
+
+ final Icon secondaryIcon = generateTestIcon(32, 288, Color.GREEN);
+ final String secondaryLabel = "secondaryLabel";
+ final String secondaryDescription = "secondaryDescription";
+ final Intent secondaryIntent = new Intent("secondaryIntentAction");
+ final PendingIntent secondaryPendingIntent = PendingIntent.getActivity(context, 0,
+ secondaryIntent, 0);
+ final RemoteAction remoteAction1 = new RemoteAction(secondaryIcon, secondaryLabel,
+ secondaryDescription, secondaryPendingIntent);
+
final String signature = "signature";
final TextClassification reference = new TextClassification.Builder()
.setText(text)
- .setPrimaryAction(primaryIntent, primaryLabel, primaryIcon)
- .setOnClickListener(primaryOnClick)
- .addSecondaryAction(null, null, null) // ignored
- .addSecondaryAction(secondaryIntent0, secondaryLabel0, secondaryIcon0)
- .addSecondaryAction(secondaryIntent1, secondaryLabel1, secondaryIcon1)
- .addSecondaryAction(secondaryIntent2, secondaryLabel2, secondaryIcon2)
- .addSecondaryAction(secondaryIntent3, secondaryLabel3, secondaryIcon3)
+ .addAction(remoteAction0)
+ .addAction(remoteAction1)
.setEntityType(TextClassifier.TYPE_ADDRESS, 0.3f)
.setEntityType(TextClassifier.TYPE_PHONE, 0.7f)
.setSignature(signature)
@@ -95,45 +96,25 @@
assertEquals(text, result.getText());
assertEquals(signature, result.getSignature());
- assertEquals(4, result.getSecondaryActionsCount());
+ assertEquals(2, result.getActions().size());
- // Primary action (re-use existing icon).
- final Bitmap resPrimaryIcon = ((BitmapDrawable) result.getIcon()).getBitmap();
- assertEquals(primaryIcon.getBitmap().getPixel(0, 0), resPrimaryIcon.getPixel(0, 0));
- assertEquals(16, resPrimaryIcon.getWidth());
- assertEquals(16, resPrimaryIcon.getHeight());
- assertEquals(primaryLabel, result.getLabel());
- assertEquals(primaryIntent.getAction(), result.getIntent().getAction());
- assertEquals(null, result.getOnClickListener()); // Non-parcelable.
+ // Legacy API.
+ assertNull(result.getIcon());
+ assertNull(result.getLabel());
+ assertNull(result.getIntent());
+ assertNull(result.getOnClickListener());
- // Secondary action 0 (scale with height limit).
- final Bitmap resSecondaryIcon0 = ((BitmapDrawable) result.getSecondaryIcon(0)).getBitmap();
- assertEquals(secondaryIcon0.getBitmap().getPixel(0, 0), resSecondaryIcon0.getPixel(0, 0));
- assertEquals(16, resSecondaryIcon0.getWidth());
- assertEquals(144, resSecondaryIcon0.getHeight());
- assertEquals(secondaryLabel0, result.getSecondaryLabel(0));
- assertEquals(secondaryIntent0.getAction(), result.getSecondaryIntent(0).getAction());
+ // Primary action.
+ final RemoteAction primaryAction = result.getActions().get(0);
+ assertEquals(primaryLabel, primaryAction.getTitle());
+ assertEquals(primaryDescription, primaryAction.getContentDescription());
+ assertEquals(primaryPendingIntent, primaryAction.getActionIntent());
- // Secondary action 1 (scale with width limit).
- final Bitmap resSecondaryIcon1 = ((BitmapDrawable) result.getSecondaryIcon(1)).getBitmap();
- assertEquals(secondaryIcon1.getBitmap().getPixel(0, 0), resSecondaryIcon1.getPixel(0, 0));
- assertEquals(144, resSecondaryIcon1.getWidth());
- assertEquals(72, resSecondaryIcon1.getHeight());
- assertEquals(secondaryLabel1, result.getSecondaryLabel(1));
- assertEquals(null, result.getSecondaryIntent(1));
-
- // Secondary action 2 (no icon).
- assertEquals(null, result.getSecondaryIcon(2));
- assertEquals(null, result.getSecondaryLabel(2));
- assertEquals(secondaryIntent2.getAction(), result.getSecondaryIntent(2).getAction());
-
- // Secondary action 3 (convert non-bitmap drawable with negative size).
- final Bitmap resSecondaryIcon3 = ((BitmapDrawable) result.getSecondaryIcon(3)).getBitmap();
- assertEquals(secondaryIcon3.getColor(), resSecondaryIcon3.getPixel(0, 0));
- assertEquals(1, resSecondaryIcon3.getWidth());
- assertEquals(1, resSecondaryIcon3.getHeight());
- assertEquals(null, result.getSecondaryLabel(3));
- assertEquals(null, result.getSecondaryIntent(3));
+ // Secondary action.
+ final RemoteAction secondaryAction = result.getActions().get(1);
+ assertEquals(secondaryLabel, secondaryAction.getTitle());
+ assertEquals(secondaryDescription, secondaryAction.getContentDescription());
+ assertEquals(secondaryPendingIntent, secondaryAction.getActionIntent());
// Entities.
assertEquals(2, result.getEntityCount());
@@ -144,6 +125,43 @@
}
@Test
+ public void testParcelLegacy() {
+ final Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ final String text = "text";
+
+ final Icon icon = generateTestIcon(384, 192, Color.BLUE);
+ final String label = "label";
+ final Intent intent = new Intent("intent");
+ final View.OnClickListener onClickListener = v -> { };
+
+ final String signature = "signature";
+ final TextClassification reference = new TextClassification.Builder()
+ .setText(text)
+ .setIcon(icon.loadDrawable(context))
+ .setLabel(label)
+ .setIntent(intent)
+ .setOnClickListener(onClickListener)
+ .setEntityType(TextClassifier.TYPE_ADDRESS, 0.3f)
+ .setEntityType(TextClassifier.TYPE_PHONE, 0.7f)
+ .setSignature(signature)
+ .build();
+
+ // Parcel and unparcel
+ final Parcel parcel = Parcel.obtain();
+ reference.writeToParcel(parcel, reference.describeContents());
+ parcel.setDataPosition(0);
+ final TextClassification result = TextClassification.CREATOR.createFromParcel(parcel);
+
+ final Bitmap resultIcon = ((BitmapDrawable) result.getIcon()).getBitmap();
+ assertEquals(icon.getBitmap().getPixel(0, 0), resultIcon.getPixel(0, 0));
+ assertEquals(192, resultIcon.getWidth());
+ assertEquals(96, resultIcon.getHeight());
+ assertEquals(label, result.getLabel());
+ assertEquals(intent.getAction(), result.getIntent().getAction());
+ assertNull(result.getOnClickListener());
+ }
+
+ @Test
public void testParcelOptions() {
Calendar referenceTime = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.US);
referenceTime.setTimeInMillis(946771200000L); // 2000-01-02
diff --git a/docs/html/reference/images/display_cutout/default_mode/fullscreen_letterbox.png b/docs/html/reference/images/display_cutout/default_mode/fullscreen_letterbox.png
new file mode 100644
index 0000000..8602290
--- /dev/null
+++ b/docs/html/reference/images/display_cutout/default_mode/fullscreen_letterbox.png
Binary files differ
diff --git a/docs/html/reference/images/display_cutout/default_mode/landscape.png b/docs/html/reference/images/display_cutout/default_mode/landscape.png
new file mode 100644
index 0000000..be112f4
--- /dev/null
+++ b/docs/html/reference/images/display_cutout/default_mode/landscape.png
Binary files differ
diff --git a/docs/html/reference/images/display_cutout/default_mode/landscape_corner.png b/docs/html/reference/images/display_cutout/default_mode/landscape_corner.png
new file mode 100644
index 0000000..7aa92b4
--- /dev/null
+++ b/docs/html/reference/images/display_cutout/default_mode/landscape_corner.png
Binary files differ
diff --git a/docs/html/reference/images/display_cutout/default_mode/portrait.png b/docs/html/reference/images/display_cutout/default_mode/portrait.png
new file mode 100644
index 0000000..6392ad5
--- /dev/null
+++ b/docs/html/reference/images/display_cutout/default_mode/portrait.png
Binary files differ
diff --git a/docs/html/reference/images/display_cutout/default_mode/portrait_corner.png b/docs/html/reference/images/display_cutout/default_mode/portrait_corner.png
new file mode 100644
index 0000000..dc8e6d0
--- /dev/null
+++ b/docs/html/reference/images/display_cutout/default_mode/portrait_corner.png
Binary files differ
diff --git a/docs/html/reference/images/display_cutout/never_mode/landscape.png b/docs/html/reference/images/display_cutout/never_mode/landscape.png
new file mode 100644
index 0000000..be112f4
--- /dev/null
+++ b/docs/html/reference/images/display_cutout/never_mode/landscape.png
Binary files differ
diff --git a/docs/html/reference/images/display_cutout/never_mode/portrait_top_letterbox.png b/docs/html/reference/images/display_cutout/never_mode/portrait_top_letterbox.png
new file mode 100644
index 0000000..fc7dfcf
--- /dev/null
+++ b/docs/html/reference/images/display_cutout/never_mode/portrait_top_letterbox.png
Binary files differ
diff --git a/docs/html/reference/images/display_cutout/short_edge/fullscreen_corner_no_letterbox.png b/docs/html/reference/images/display_cutout/short_edge/fullscreen_corner_no_letterbox.png
new file mode 100644
index 0000000..09f942d
--- /dev/null
+++ b/docs/html/reference/images/display_cutout/short_edge/fullscreen_corner_no_letterbox.png
Binary files differ
diff --git a/docs/html/reference/images/display_cutout/short_edge/fullscreen_side_letterbox.png b/docs/html/reference/images/display_cutout/short_edge/fullscreen_side_letterbox.png
new file mode 100644
index 0000000..9aafc58
--- /dev/null
+++ b/docs/html/reference/images/display_cutout/short_edge/fullscreen_side_letterbox.png
Binary files differ
diff --git a/docs/html/reference/images/display_cutout/short_edge/fullscreen_top_no_letterbox.png b/docs/html/reference/images/display_cutout/short_edge/fullscreen_top_no_letterbox.png
new file mode 100644
index 0000000..75e913b
--- /dev/null
+++ b/docs/html/reference/images/display_cutout/short_edge/fullscreen_top_no_letterbox.png
Binary files differ
diff --git a/docs/html/reference/images/display_cutout/short_edge/landscape_corner.png b/docs/html/reference/images/display_cutout/short_edge/landscape_corner.png
new file mode 100644
index 0000000..d9e0f99
--- /dev/null
+++ b/docs/html/reference/images/display_cutout/short_edge/landscape_corner.png
Binary files differ
diff --git a/docs/html/reference/images/display_cutout/short_edge/landscape_sideboxed.png b/docs/html/reference/images/display_cutout/short_edge/landscape_sideboxed.png
new file mode 100644
index 0000000..9d44493
--- /dev/null
+++ b/docs/html/reference/images/display_cutout/short_edge/landscape_sideboxed.png
Binary files differ
diff --git a/docs/html/reference/images/display_cutout/short_edge/landscape_top_no_letterbox.png b/docs/html/reference/images/display_cutout/short_edge/landscape_top_no_letterbox.png
new file mode 100644
index 0000000..ac023c5
--- /dev/null
+++ b/docs/html/reference/images/display_cutout/short_edge/landscape_top_no_letterbox.png
Binary files differ
diff --git a/docs/html/reference/images/display_cutout/short_edge/portrait_side_letterbox.png b/docs/html/reference/images/display_cutout/short_edge/portrait_side_letterbox.png
new file mode 100644
index 0000000..50228db
--- /dev/null
+++ b/docs/html/reference/images/display_cutout/short_edge/portrait_side_letterbox.png
Binary files differ
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index 09b3b9b..419eb24 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -243,13 +243,7 @@
// Check that user authentication related parameters are acceptable. This method
// will throw an IllegalStateException if there are issues (e.g., secure lock screen
// not set up).
- KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
- spec.isUserAuthenticationRequired(),
- spec.getUserAuthenticationValidityDurationSeconds(),
- spec.isUserAuthenticationValidWhileOnBody(),
- spec.isInvalidatedByBiometricEnrollment(),
- GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
- spec.isUserConfirmationRequired());
+ KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), spec);
} catch (IllegalStateException | IllegalArgumentException e) {
throw new InvalidAlgorithmParameterException(e);
}
@@ -285,16 +279,7 @@
args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes);
args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterPaddings);
args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
- KeymasterUtils.addUserAuthArgs(args,
- spec.isUserAuthenticationRequired(),
- spec.getUserAuthenticationValidityDurationSeconds(),
- spec.isUserAuthenticationValidWhileOnBody(),
- spec.isInvalidatedByBiometricEnrollment(),
- GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
- spec.isUserConfirmationRequired());
- if (spec.isTrustedUserPresenceRequired()) {
- args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
- }
+ KeymasterUtils.addUserAuthArgs(args, spec);
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
args,
mKeymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index e33e3cd..d68a33d 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -344,13 +344,7 @@
// Check that user authentication related parameters are acceptable. This method
// will throw an IllegalStateException if there are issues (e.g., secure lock screen
// not set up).
- KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
- mSpec.isUserAuthenticationRequired(),
- mSpec.getUserAuthenticationValidityDurationSeconds(),
- mSpec.isUserAuthenticationValidWhileOnBody(),
- mSpec.isInvalidatedByBiometricEnrollment(),
- GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
- mSpec.isUserConfirmationRequired());
+ KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), mSpec);
} catch (IllegalArgumentException | IllegalStateException e) {
throw new InvalidAlgorithmParameterException(e);
}
@@ -541,13 +535,7 @@
args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterSignaturePaddings);
args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
- KeymasterUtils.addUserAuthArgs(args,
- mSpec.isUserAuthenticationRequired(),
- mSpec.getUserAuthenticationValidityDurationSeconds(),
- mSpec.isUserAuthenticationValidWhileOnBody(),
- mSpec.isInvalidatedByBiometricEnrollment(),
- GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
- mSpec.isUserConfirmationRequired());
+ KeymasterUtils.addUserAuthArgs(args, mSpec);
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
mSpec.getKeyValidityForOriginationEnd());
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index 05cc74a..fc86ca0 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -497,13 +497,7 @@
importArgs.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterEncryptionPaddings);
importArgs.addEnums(KeymasterDefs.KM_TAG_PADDING,
KeyProperties.SignaturePadding.allToKeymaster(spec.getSignaturePaddings()));
- KeymasterUtils.addUserAuthArgs(importArgs,
- spec.isUserAuthenticationRequired(),
- spec.getUserAuthenticationValidityDurationSeconds(),
- spec.isUserAuthenticationValidWhileOnBody(),
- spec.isInvalidatedByBiometricEnrollment(),
- spec.getBoundToSpecificSecureUserId(),
- spec.isUserConfirmationRequired());
+ KeymasterUtils.addUserAuthArgs(importArgs, spec);
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
spec.getKeyValidityStart());
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
@@ -700,13 +694,7 @@
int[] keymasterPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
params.getEncryptionPaddings());
args.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
- KeymasterUtils.addUserAuthArgs(args,
- params.isUserAuthenticationRequired(),
- params.getUserAuthenticationValidityDurationSeconds(),
- params.isUserAuthenticationValidWhileOnBody(),
- params.isInvalidatedByBiometricEnrollment(),
- params.getBoundToSpecificSecureUserId(),
- params.isUserConfirmationRequired());
+ KeymasterUtils.addUserAuthArgs(args, params);
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
args,
keymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index da23c70..4b9f3c80 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -21,6 +21,7 @@
import android.annotation.Nullable;
import android.app.KeyguardManager;
import android.hardware.fingerprint.FingerprintManager;
+import android.security.GateKeeper;
import android.security.KeyStore;
import android.text.TextUtils;
@@ -232,7 +233,7 @@
* key = (SecretKey) keyStore.getKey("key2", null);
* }</pre>
*/
-public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
+public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAuthArgs {
private static final X500Principal DEFAULT_CERT_SUBJECT = new X500Principal("CN=fake");
private static final BigInteger DEFAULT_CERT_SERIAL_NUMBER = new BigInteger("1");
@@ -669,6 +670,13 @@
}
/**
+ * @hide
+ */
+ public long getBoundToSpecificSecureUserId() {
+ return GateKeeper.INVALID_SECURE_USER_ID;
+ }
+
+ /**
* Builder of {@link KeyGenParameterSpec} instances.
*/
public final static class Builder {
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index b5b3281..95eeec7 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -212,7 +212,7 @@
* ...
* }</pre>
*/
-public final class KeyProtection implements ProtectionParameter {
+public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
private final Date mKeyValidityStart;
private final Date mKeyValidityForOriginationEnd;
private final Date mKeyValidityForConsumptionEnd;
@@ -224,6 +224,7 @@
private final boolean mRandomizedEncryptionRequired;
private final boolean mUserAuthenticationRequired;
private final int mUserAuthenticationValidityDurationSeconds;
+ private final boolean mTrustedUserPresenceRequred;
private final boolean mUserAuthenticationValidWhileOnBody;
private final boolean mInvalidatedByBiometricEnrollment;
private final long mBoundToSecureUserId;
@@ -242,6 +243,7 @@
boolean randomizedEncryptionRequired,
boolean userAuthenticationRequired,
int userAuthenticationValidityDurationSeconds,
+ boolean trustedUserPresenceRequred,
boolean userAuthenticationValidWhileOnBody,
boolean invalidatedByBiometricEnrollment,
long boundToSecureUserId,
@@ -260,6 +262,7 @@
mRandomizedEncryptionRequired = randomizedEncryptionRequired;
mUserAuthenticationRequired = userAuthenticationRequired;
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
+ mTrustedUserPresenceRequred = trustedUserPresenceRequred;
mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
mBoundToSecureUserId = boundToSecureUserId;
@@ -437,6 +440,14 @@
}
/**
+ * Returns {@code true} if the key is authorized to be used only if a test of user presence has
+ * been performed between the {@code Signature.initSign()} and {@code Signature.sign()} calls.
+ */
+ public boolean isTrustedUserPresenceRequired() {
+ return mTrustedUserPresenceRequred;
+ }
+
+ /**
* Returns {@code true} if the key will be de-authorized when the device is removed from the
* user's body. This option has no effect on keys that don't have an authentication validity
* duration, and has no effect if the device lacks an on-body sensor.
@@ -509,6 +520,7 @@
private boolean mRandomizedEncryptionRequired = true;
private boolean mUserAuthenticationRequired;
private int mUserAuthenticationValidityDurationSeconds = -1;
+ private boolean mTrustedUserPresenceRequired = false;
private boolean mUserAuthenticationValidWhileOnBody;
private boolean mInvalidatedByBiometricEnrollment = true;
private boolean mUserConfirmationRequired;
@@ -811,6 +823,16 @@
}
/**
+ * Sets whether a test of user presence is required to be performed between the
+ * {@code Signature.initSign()} and {@code Signature.sign()} method calls.
+ */
+ @NonNull
+ public Builder setTrustedUserPresenceRequired(boolean required) {
+ mTrustedUserPresenceRequired = required;
+ return this;
+ }
+
+ /**
* Sets whether the key will remain authorized only until the device is removed from the
* user's body up to the limit of the authentication validity period (see
* {@link #setUserAuthenticationValidityDurationSeconds} and
@@ -910,6 +932,7 @@
mRandomizedEncryptionRequired,
mUserAuthenticationRequired,
mUserAuthenticationValidityDurationSeconds,
+ mTrustedUserPresenceRequired,
mUserAuthenticationValidWhileOnBody,
mInvalidatedByBiometricEnrollment,
mBoundToSecureUserId,
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
index 4e28601..0ef08f2 100644
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore/KeymasterUtils.java
@@ -18,6 +18,7 @@
import android.util.Log;
import android.hardware.fingerprint.FingerprintManager;
+import android.os.UserHandle;
import android.security.GateKeeper;
import android.security.KeyStore;
import android.security.keymaster.KeymasterArguments;
@@ -101,22 +102,21 @@
* require user authentication.
*/
public static void addUserAuthArgs(KeymasterArguments args,
- boolean userAuthenticationRequired,
- int userAuthenticationValidityDurationSeconds,
- boolean userAuthenticationValidWhileOnBody,
- boolean invalidatedByBiometricEnrollment,
- long boundToSpecificSecureUserId,
- boolean userConfirmationRequired) {
- if (userConfirmationRequired) {
+ UserAuthArgs spec) {
+ if (spec.isUserConfirmationRequired()) {
args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED);
}
- if (!userAuthenticationRequired) {
+ if (spec.isTrustedUserPresenceRequired()) {
+ args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
+ }
+
+ if (!spec.isUserAuthenticationRequired()) {
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
return;
}
- if (userAuthenticationValidityDurationSeconds == -1) {
+ if (spec.getUserAuthenticationValidityDurationSeconds() == -1) {
// Every use of this key needs to be authorized by the user. This currently means
// fingerprint-only auth.
FingerprintManager fingerprintManager =
@@ -132,9 +132,9 @@
}
long sid;
- if (boundToSpecificSecureUserId != GateKeeper.INVALID_SECURE_USER_ID) {
- sid = boundToSpecificSecureUserId;
- } else if (invalidatedByBiometricEnrollment) {
+ if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
+ sid = spec.getBoundToSpecificSecureUserId();
+ } else if (spec.isInvalidatedByBiometricEnrollment()) {
// The fingerprint-only SID will change on fingerprint enrollment or removal of all,
// enrolled fingerprints, invalidating the key.
sid = fingerprintOnlySid;
@@ -147,14 +147,14 @@
args.addUnsignedLong(
KeymasterDefs.KM_TAG_USER_SECURE_ID, KeymasterArguments.toUint64(sid));
args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, KeymasterDefs.HW_AUTH_FINGERPRINT);
- if (userAuthenticationValidWhileOnBody) {
+ if (spec.isUserAuthenticationValidWhileOnBody()) {
throw new ProviderException("Key validity extension while device is on-body is not "
+ "supported for keys requiring fingerprint authentication");
}
} else {
long sid;
- if (boundToSpecificSecureUserId != GateKeeper.INVALID_SECURE_USER_ID) {
- sid = boundToSpecificSecureUserId;
+ if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
+ sid = spec.getBoundToSpecificSecureUserId();
} else {
// The key is authorized for use for the specified amount of time after the user has
// authenticated. Whatever unlocks the secure lock screen should authorize this key.
@@ -165,8 +165,8 @@
args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
KeymasterDefs.HW_AUTH_PASSWORD | KeymasterDefs.HW_AUTH_FINGERPRINT);
args.addUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
- userAuthenticationValidityDurationSeconds);
- if (userAuthenticationValidWhileOnBody) {
+ spec.getUserAuthenticationValidityDurationSeconds());
+ if (spec.isUserAuthenticationValidWhileOnBody()) {
args.addBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
}
}
diff --git a/keystore/java/android/security/keystore/UserAuthArgs.java b/keystore/java/android/security/keystore/UserAuthArgs.java
new file mode 100644
index 0000000..1949592
--- /dev/null
+++ b/keystore/java/android/security/keystore/UserAuthArgs.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+/**
+ * @hide
+ *
+ * This is an interface to encapsulate the user authentication arguments that
+ * are passed to KeymasterUtils.addUserAuthArgs. Classes that represent
+ * authorization characteristics for new or imported keys can implement this
+ * interface to be passed to that method.
+ */
+public interface UserAuthArgs {
+
+ boolean isUserAuthenticationRequired();
+ int getUserAuthenticationValidityDurationSeconds();
+ boolean isUserAuthenticationValidWhileOnBody();
+ boolean isInvalidatedByBiometricEnrollment();
+ boolean isUserConfirmationRequired();
+ long getBoundToSpecificSecureUserId();
+ boolean isTrustedUserPresenceRequired();
+
+}
diff --git a/libs/hwui/PathParser.cpp b/libs/hwui/PathParser.cpp
index a48fdfc..47fcca9 100644
--- a/libs/hwui/PathParser.cpp
+++ b/libs/hwui/PathParser.cpp
@@ -156,10 +156,63 @@
return;
}
-bool PathParser::isVerbValid(char verb) {
- verb = tolower(verb);
- return verb == 'a' || verb == 'c' || verb == 'h' || verb == 'l' || verb == 'm' || verb == 'q' ||
- verb == 's' || verb == 't' || verb == 'v' || verb == 'z';
+void PathParser::validateVerbAndPoints(char verb, size_t points, PathParser::ParseResult* result) {
+ size_t numberOfPointsExpected = -1;
+ switch (verb) {
+ case 'z':
+ case 'Z':
+ numberOfPointsExpected = 0;
+ break;
+ case 'm':
+ case 'l':
+ case 't':
+ case 'M':
+ case 'L':
+ case 'T':
+ numberOfPointsExpected = 2;
+ break;
+ case 'h':
+ case 'v':
+ case 'H':
+ case 'V':
+ numberOfPointsExpected = 1;
+ break;
+ case 'c':
+ case 'C':
+ numberOfPointsExpected = 6;
+ break;
+ case 's':
+ case 'q':
+ case 'S':
+ case 'Q':
+ numberOfPointsExpected = 4;
+ break;
+ case 'a':
+ case 'A':
+ numberOfPointsExpected = 7;
+ break;
+ default:
+ result->failureOccurred = true;
+ result->failureMessage += verb;
+ result->failureMessage += " is not a valid verb. ";
+ return;
+ }
+ if (numberOfPointsExpected == 0 && points == 0) {
+ return;
+ }
+ if (numberOfPointsExpected > 0 && points % numberOfPointsExpected == 0) {
+ return;
+ }
+
+ result->failureOccurred = true;
+ result->failureMessage += verb;
+ result->failureMessage += " needs to be followed by ";
+ if (numberOfPointsExpected > 0) {
+ result->failureMessage += "a multiple of ";
+ }
+ result->failureMessage += std::to_string(numberOfPointsExpected)
+ + " floats. However, " + std::to_string(points)
+ + " float(s) are found. ";
}
void PathParser::getPathDataFromAsciiString(PathData* data, ParseResult* result,
@@ -186,13 +239,11 @@
end = nextStart(pathStr, strLen, end);
std::vector<float> points;
getFloats(&points, result, pathStr, start, end);
- if (!isVerbValid(pathStr[start])) {
- result->failureOccurred = true;
- result->failureMessage = "Invalid pathData. Failure occurred at position " +
- std::to_string(start) + " of path: " + pathStr;
- }
- // If either verb or points is not valid, return immediately.
+ validateVerbAndPoints(pathStr[start], points.size(), result);
if (result->failureOccurred) {
+ // If either verb or points is not valid, return immediately.
+ result->failureMessage += "Failure occurred at position " +
+ std::to_string(start) + " of path: " + pathStr;
return;
}
data->verbs.push_back(pathStr[start]);
@@ -203,9 +254,10 @@
}
if ((end - start) == 1 && start < strLen) {
- if (!isVerbValid(pathStr[start])) {
- result->failureOccurred = true;
- result->failureMessage = "Invalid pathData. Failure occurred at position " +
+ validateVerbAndPoints(pathStr[start], 0, result);
+ if (result->failureOccurred) {
+ // If either verb or points is not valid, return immediately.
+ result->failureMessage += "Failure occurred at position " +
std::to_string(start) + " of path: " + pathStr;
return;
}
diff --git a/libs/hwui/PathParser.h b/libs/hwui/PathParser.h
index e4ec7be..474eb97 100644
--- a/libs/hwui/PathParser.h
+++ b/libs/hwui/PathParser.h
@@ -43,7 +43,7 @@
ANDROID_API static void getPathDataFromAsciiString(PathData* outData, ParseResult* result,
const char* pathStr, size_t strLength);
static void dump(const PathData& data);
- static bool isVerbValid(char verb);
+ static void validateVerbAndPoints(char verb, size_t points, ParseResult* result);
};
}; // namespace uirenderer
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index fedcc10..d93a757 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -243,24 +243,11 @@
return;
}
- if (info.canvasContext.createOrUpdateLayer(this, *info.damageAccumulator)) {
+ if (info.canvasContext.createOrUpdateLayer(this, *info.damageAccumulator, info.errorHandler)) {
damageSelf(info);
}
if (!hasLayer()) {
- Caches::getInstance().dumpMemoryUsage();
- if (info.errorHandler) {
- std::ostringstream err;
- err << "Unable to create layer for " << getName();
- const int maxTextureSize = Caches::getInstance().maxTextureSize;
- if (getWidth() > maxTextureSize || getHeight() > maxTextureSize) {
- err << ", size " << getWidth() << "x" << getHeight() << " exceeds max size "
- << maxTextureSize;
- } else {
- err << ", see logcat for more info";
- }
- info.errorHandler->onError(err.str());
- }
return;
}
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 0cd1c15..07052cd 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -22,6 +22,7 @@
#include <SkOverdrawColorFilter.h>
#include <SkPicture.h>
#include <SkPictureRecorder.h>
+#include "TreeInfo.h"
#include "VectorDrawable.h"
#include "utils/TraceUtils.h"
@@ -158,7 +159,7 @@
}
bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
- bool wideColorGamut) {
+ bool wideColorGamut, ErrorHandler* errorHandler) {
// compute the size of the surface (i.e. texture) to be allocated for this layer
const int surfaceWidth = ceilf(node->getWidth() / float(LAYER_SIZE)) * LAYER_SIZE;
const int surfaceHeight = ceilf(node->getHeight() / float(LAYER_SIZE)) * LAYER_SIZE;
@@ -182,6 +183,20 @@
Matrix4 windowTransform;
damageAccumulator.computeCurrentTransform(&windowTransform);
node->getSkiaLayer()->inverseTransformInWindow = windowTransform;
+ } else {
+ String8 cachesOutput;
+ mRenderThread.cacheManager().dumpMemoryUsage(cachesOutput,
+ &mRenderThread.renderState());
+ ALOGE("%s", cachesOutput.string());
+ if (errorHandler) {
+ std::ostringstream err;
+ err << "Unable to create layer for " << node->getName();
+ const int maxTextureSize = DeviceInfo::get()->maxTextureSize();
+ err << ", size " << info.width() << "x" << info.height() << " max size "
+ << maxTextureSize << " color type " << (int)info.colorType()
+ << " has context " << (int)(mRenderThread.getGrContext() != nullptr);
+ errorHandler->onError(err.str());
+ }
}
return true;
}
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 3800194..38ad9c0 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -47,7 +47,7 @@
const BakedOpRenderer::LightInfo& lightInfo) override;
bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
- bool wideColorGamut) override;
+ bool wideColorGamut, ErrorHandler* errorHandler) override;
void renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
const std::vector<sp<RenderNode>>& nodes, bool opaque, bool wideColorGamut,
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index d80a247..c2cc72a 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -49,6 +49,7 @@
class AnimationContext;
class DeferredLayerUpdater;
+class ErrorHandler;
class Layer;
class Rect;
class RenderState;
@@ -74,8 +75,10 @@
*
* @return true if the layer has been created or updated
*/
- bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& dmgAccumulator) {
- return mRenderPipeline->createOrUpdateLayer(node, dmgAccumulator, mWideColorGamut);
+ bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& dmgAccumulator,
+ ErrorHandler* errorHandler) {
+ return mRenderPipeline->createOrUpdateLayer(node, dmgAccumulator, mWideColorGamut,
+ errorHandler);
}
/**
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index 246ab26..b1de497 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -31,6 +31,7 @@
namespace uirenderer {
class DeferredLayerUpdater;
+class ErrorHandler;
namespace renderthread {
@@ -68,7 +69,7 @@
const BakedOpRenderer::LightInfo& lightInfo) = 0;
virtual TaskManager* getTaskManager() = 0;
virtual bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
- bool wideColorGamut) = 0;
+ bool wideColorGamut, ErrorHandler* errorHandler) = 0;
virtual bool pinImages(std::vector<SkImage*>& mutableImages) = 0;
virtual bool pinImages(LsaVector<sk_sp<Bitmap>>& images) = 0;
virtual void unpinImages() = 0;
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
index f3103fd..876af47 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -23,6 +23,7 @@
#include "OpenGLReadback.h"
#include "ProfileRenderer.h"
#include "renderstate/RenderState.h"
+#include "TreeInfo.h"
#include <cutils/properties.h>
#include <strings.h>
@@ -202,7 +203,8 @@
bool OpenGLPipeline::createOrUpdateLayer(RenderNode* node,
const DamageAccumulator& damageAccumulator,
- bool wideColorGamut) {
+ bool wideColorGamut,
+ ErrorHandler* errorHandler) {
RenderState& renderState = mRenderThread.renderState();
OffscreenBufferPool& layerPool = renderState.layerPool();
bool transformUpdateNeeded = false;
@@ -228,6 +230,22 @@
node->getLayer()->setWindowTransform(windowTransform);
}
+ if (!node->hasLayer()) {
+ Caches::getInstance().dumpMemoryUsage();
+ if (errorHandler) {
+ std::ostringstream err;
+ err << "Unable to create layer for " << node->getName();
+ const int maxTextureSize = Caches::getInstance().maxTextureSize;
+ if (node->getWidth() > maxTextureSize || node->getHeight() > maxTextureSize) {
+ err << ", size " << node->getWidth() << "x" << node->getHeight()
+ << " exceeds max size " << maxTextureSize;
+ } else {
+ err << ", see logcat for more info";
+ }
+ errorHandler->onError(err.str());
+ }
+ }
+
return transformUpdateNeeded;
}
diff --git a/libs/hwui/renderthread/OpenGLPipeline.h b/libs/hwui/renderthread/OpenGLPipeline.h
index 118007c..9859e93 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.h
+++ b/libs/hwui/renderthread/OpenGLPipeline.h
@@ -53,7 +53,7 @@
const BakedOpRenderer::LightInfo& lightInfo) override;
TaskManager* getTaskManager() override;
bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
- bool wideColorGamut) override;
+ bool wideColorGamut, ErrorHandler* errorHandler) override;
bool pinImages(std::vector<SkImage*>& mutableImages) override { return false; }
bool pinImages(LsaVector<sk_sp<Bitmap>>& images) override;
void unpinImages() override;
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index e7496f7..02f740c 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -242,7 +242,8 @@
{"\n \t z", true}, // Valid path data with leading spaces
{"1-2e34567", false}, // Not starting with a verb and ill-formatted float
{"f 4 5", false}, // Invalid verb
- {"\r ", false} // Empty string
+ {"\r ", false}, // Empty string
+ {"L1,0 L1,1 L0,1 z M1000", false} // Not enough floats following verb M.
};
static bool hasSameVerbs(const PathData& from, const PathData& to) {
diff --git a/media/java/android/media/ClosedCaptionRenderer.java b/media/java/android/media/ClosedCaptionRenderer.java
index cc7722a..66759e5 100644
--- a/media/java/android/media/ClosedCaptionRenderer.java
+++ b/media/java/android/media/ClosedCaptionRenderer.java
@@ -59,7 +59,7 @@
public boolean supports(MediaFormat format) {
if (format.containsKey(MediaFormat.KEY_MIME)) {
String mimeType = format.getString(MediaFormat.KEY_MIME);
- return MediaPlayer.MEDIA_MIMETYPE_TEXT_CEA_608.equals(mimeType);
+ return MediaFormat.MIMETYPE_TEXT_CEA_608.equals(mimeType);
}
return false;
}
@@ -67,7 +67,7 @@
@Override
public SubtitleTrack createTrack(MediaFormat format) {
String mimeType = format.getString(MediaFormat.KEY_MIME);
- if (MediaPlayer.MEDIA_MIMETYPE_TEXT_CEA_608.equals(mimeType)) {
+ if (MediaFormat.MIMETYPE_TEXT_CEA_608.equals(mimeType)) {
if (mCCWidget == null) {
mCCWidget = new Cea608CCWidget(mContext);
}
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 56edace..72d52d3 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -727,18 +727,7 @@
return false;
}
- if (format == ImageFormat.PRIVATE) {
- // Usage need to be either USAGE0_GPU_SAMPLED_IMAGE or USAGE0_VIDEO_ENCODE or combined.
- boolean isAllowed = (usage == HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
- isAllowed = isAllowed || (usage == HardwareBuffer.USAGE_VIDEO_ENCODE);
- isAllowed = isAllowed || (usage ==
- (HardwareBuffer.USAGE_VIDEO_ENCODE | HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE));
- return isAllowed;
- } else {
- // Usage need to make the buffer CPU readable for explicit format.
- return ((usage == HardwareBuffer.USAGE_CPU_READ_RARELY) ||
- (usage == HardwareBuffer.USAGE_CPU_READ_OFTEN));
- }
+ return true;
}
/**
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 3bfbcc2..384326f 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -174,10 +174,20 @@
public static final String MIMETYPE_TEXT_VTT = "text/vtt";
/**
+ * MIME type for SubRip (SRT) container.
+ */
+ public static final String MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
+
+ /**
* MIME type for CEA-608 closed caption data.
*/
public static final String MIMETYPE_TEXT_CEA_608 = "text/cea-608";
+ /**
+ * MIME type for CEA-708 closed caption data.
+ */
+ public static final String MIMETYPE_TEXT_CEA_708 = "text/cea-708";
+
private Map<String, Object> mMap;
/**
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index fe5e822..befbade 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -2416,7 +2416,7 @@
* Gets the track type.
* @return TrackType which indicates if the track is video, audio, timed text.
*/
- public int getTrackType() {
+ public @TrackType int getTrackType() {
return mTrackType;
}
@@ -2450,6 +2450,19 @@
public static final int MEDIA_TRACK_TYPE_SUBTITLE = 4;
public static final int MEDIA_TRACK_TYPE_METADATA = 5;
+ /** @hide */
+ @IntDef(flag = false, prefix = "MEDIA_TRACK_TYPE", value = {
+ MEDIA_TRACK_TYPE_UNKNOWN,
+ MEDIA_TRACK_TYPE_VIDEO,
+ MEDIA_TRACK_TYPE_AUDIO,
+ MEDIA_TRACK_TYPE_TIMEDTEXT,
+ MEDIA_TRACK_TYPE_SUBTITLE,
+ MEDIA_TRACK_TYPE_METADATA }
+ )
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TrackType {}
+
+
final int mTrackType;
final MediaFormat mFormat;
@@ -2600,26 +2613,30 @@
*/
/**
* MIME type for SubRip (SRT) container. Used in addTimedTextSource APIs.
+ * @deprecated use {@link MediaFormat#MIMETYPE_TEXT_SUBRIP}
*/
- public static final String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
+ public static final String MEDIA_MIMETYPE_TEXT_SUBRIP = MediaFormat.MIMETYPE_TEXT_SUBRIP;
/**
* MIME type for WebVTT subtitle data.
* @hide
+ * @deprecated
*/
- public static final String MEDIA_MIMETYPE_TEXT_VTT = "text/vtt";
+ public static final String MEDIA_MIMETYPE_TEXT_VTT = MediaFormat.MIMETYPE_TEXT_VTT;
/**
* MIME type for CEA-608 closed caption data.
* @hide
+ * @deprecated
*/
- public static final String MEDIA_MIMETYPE_TEXT_CEA_608 = "text/cea-608";
+ public static final String MEDIA_MIMETYPE_TEXT_CEA_608 = MediaFormat.MIMETYPE_TEXT_CEA_608;
/**
* MIME type for CEA-708 closed caption data.
* @hide
+ * @deprecated
*/
- public static final String MEDIA_MIMETYPE_TEXT_CEA_708 = "text/cea-708";
+ public static final String MEDIA_MIMETYPE_TEXT_CEA_708 = MediaFormat.MIMETYPE_TEXT_CEA_708;
/*
* A helper function to check if the mime type is supported by media framework.
@@ -3108,7 +3125,7 @@
* this function is called.
* </p>
* <p>
- * Currently, only timed text tracks or audio tracks can be selected via this method.
+ * Currently, only timed text, subtitle or audio tracks can be selected via this method.
* In addition, the support for selecting an audio track at runtime is pretty limited
* in that an audio track can only be selected in the <em>Prepared</em> state.
* </p>
@@ -3795,29 +3812,158 @@
private OnTimedTextListener mOnTimedTextListener;
/**
- * Interface definition of a callback to be invoked when a
- * track has data available.
- *
- * @hide
+ * Interface definition of a callback to be invoked when a player subtitle track has new
+ * subtitle data available.
+ * See the {@link MediaPlayer#setOnSubtitleDataListener(OnSubtitleDataListener, Handler)}
+ * method for the description of which track will report data through this listener.
*/
- public interface OnSubtitleDataListener
- {
- public void onSubtitleData(MediaPlayer mp, SubtitleData data);
+ public interface OnSubtitleDataListener {
+ /**
+ * Method called when new subtitle data is available
+ * @param mp the player that reports the new subtitle data
+ * @param data the subtitle data
+ */
+ public void onSubtitleData(@NonNull MediaPlayer mp, @NonNull SubtitleData data);
}
/**
- * Register a callback to be invoked when a track has data available.
- *
- * @param listener the callback that will be run
- *
- * @hide
+ * Sets the listener to be invoked when a subtitle track has new data available.
+ * The subtitle data comes from a subtitle track previously selected with
+ * {@link #selectTrack(int)}. Use {@link #getTrackInfo()} to determine which tracks are
+ * subtitles (of type {@link TrackInfo#MEDIA_TRACK_TYPE_SUBTITLE}), Subtitle track encodings
+ * can be determined by {@link TrackInfo#getFormat()}).<br>
+ * See {@link SubtitleData} for an example of querying subtitle encoding.
+ * @param listener the listener called when new data is available
+ * @param handler the {@link Handler} that receives the listener events
*/
- public void setOnSubtitleDataListener(OnSubtitleDataListener listener)
+ public void setOnSubtitleDataListener(@NonNull OnSubtitleDataListener listener,
+ @NonNull Handler handler) {
+ if (listener == null) {
+ throw new IllegalArgumentException("Illegal null listener");
+ }
+ if (handler == null) {
+ throw new IllegalArgumentException("Illegal null handler");
+ }
+ setOnSubtitleDataListenerInt(listener, handler);
+ }
+ /**
+ * Sets the listener to be invoked when a subtitle track has new data available.
+ * The subtitle data comes from a subtitle track previously selected with
+ * {@link #selectTrack(int)}. Use {@link #getTrackInfo()} to determine which tracks are
+ * subtitles (of type {@link TrackInfo#MEDIA_TRACK_TYPE_SUBTITLE}), Subtitle track encodings
+ * can be determined by {@link TrackInfo#getFormat()}).<br>
+ * See {@link SubtitleData} for an example of querying subtitle encoding.<br>
+ * The listener will be called on the same thread as the one in which the MediaPlayer was
+ * created.
+ * @param listener the listener called when new data is available
+ */
+ public void setOnSubtitleDataListener(@NonNull OnSubtitleDataListener listener)
{
- mOnSubtitleDataListener = listener;
+ if (listener == null) {
+ throw new IllegalArgumentException("Illegal null listener");
+ }
+ setOnSubtitleDataListenerInt(listener, null);
+ }
+
+ /**
+ * Clears the listener previously set with
+ * {@link #setOnSubtitleDataListener(OnSubtitleDataListener)} or
+ * {@link #setOnSubtitleDataListener(OnSubtitleDataListener, Handler)}.
+ */
+ public void clearOnSubtitleDataListener() {
+ setOnSubtitleDataListenerInt(null, null);
+ }
+
+ private void setOnSubtitleDataListenerInt(
+ @Nullable OnSubtitleDataListener listener, @Nullable Handler handler) {
+ synchronized (this) {
+ mOnSubtitleDataListener = listener;
+ mOnSubtitleDataHandler = handler;
+ }
}
private OnSubtitleDataListener mOnSubtitleDataListener;
+ private Handler mOnSubtitleDataHandler;
+
+ /**
+ * Interface definition of a callback to be invoked when discontinuity in the normal progression
+ * of the media time is detected.
+ * The "normal progression" of media time is defined as the expected increase of the playback
+ * position when playing media, relative to the playback speed (for instance every second, media
+ * time increases by two seconds when playing at 2x).<br>
+ * Discontinuities are encountered in the following cases:
+ * <ul>
+ * <li>when the player is starved for data and cannot play anymore</li>
+ * <li>when the player encounters a playback error</li>
+ * <li>when the a seek operation starts, and when it's completed</li>
+ * <li>when the playback speed changes</li>
+ * <li>when the playback state changes</li>
+ * <li>when the player is reset</li>
+ * </ul>
+ * See the
+ * {@link MediaPlayer#setOnMediaTimeDiscontinuityListener(OnMediaTimeDiscontinuityListener, Handler)}
+ * method to set a listener for these events.
+ */
+ public interface OnMediaTimeDiscontinuityListener {
+ /**
+ * Called to indicate a time discontinuity has occured.
+ * @param mp the MediaPlayer for which the discontinuity has occured.
+ * @param mts the timestamp that correlates media time, system time and clock rate,
+ * or {@link MediaTimestamp#TIMESTAMP_UNKNOWN} in an error case.
+ */
+ public void onMediaTimeDiscontinuity(@NonNull MediaPlayer mp, @NonNull MediaTimestamp mts);
+ }
+
+ /**
+ * Sets the listener to be invoked when a media time discontinuity is encountered.
+ * @param listener the listener called after a discontinuity
+ * @param handler the {@link Handler} that receives the listener events
+ */
+ public void setOnMediaTimeDiscontinuityListener(
+ @NonNull OnMediaTimeDiscontinuityListener listener, @NonNull Handler handler) {
+ if (listener == null) {
+ throw new IllegalArgumentException("Illegal null listener");
+ }
+ if (handler == null) {
+ throw new IllegalArgumentException("Illegal null handler");
+ }
+ setOnMediaTimeDiscontinuityListenerInt(listener, handler);
+ }
+
+ /**
+ * Sets the listener to be invoked when a media time discontinuity is encountered.
+ * The listener will be called on the same thread as the one in which the MediaPlayer was
+ * created.
+ * @param listener the listener called after a discontinuity
+ */
+ public void setOnMediaTimeDiscontinuityListener(
+ @NonNull OnMediaTimeDiscontinuityListener listener)
+ {
+ if (listener == null) {
+ throw new IllegalArgumentException("Illegal null listener");
+ }
+ setOnMediaTimeDiscontinuityListenerInt(listener, null);
+ }
+
+ /**
+ * Clears the listener previously set with
+ * {@link #setOnMediaTimeDiscontinuityListener(OnMediaTimeDiscontinuityListener)}
+ * or {@link #setOnMediaTimeDiscontinuityListener(OnMediaTimeDiscontinuityListener, Handler)}
+ */
+ public void clearOnMediaTimeDiscontinuityListener() {
+ setOnMediaTimeDiscontinuityListenerInt(null, null);
+ }
+
+ private void setOnMediaTimeDiscontinuityListenerInt(
+ @Nullable OnMediaTimeDiscontinuityListener listener, @Nullable Handler handler) {
+ synchronized (this) {
+ mOnMediaTimeDiscontinuityListener = listener;
+ mOnMediaTimeDiscontinuityHandler = handler;
+ }
+ }
+
+ private OnMediaTimeDiscontinuityListener mOnMediaTimeDiscontinuityListener;
+ private Handler mOnMediaTimeDiscontinuityHandler;
/**
* Interface definition of a callback to be invoked when a
diff --git a/media/java/android/media/MediaTimestamp.java b/media/java/android/media/MediaTimestamp.java
index 5ea6bbe..938dd14 100644
--- a/media/java/android/media/MediaTimestamp.java
+++ b/media/java/android/media/MediaTimestamp.java
@@ -37,6 +37,11 @@
public final class MediaTimestamp
{
/**
+ * An unknown media timestamp value
+ */
+ public static final MediaTimestamp TIMESTAMP_UNKNOWN = new MediaTimestamp(-1, -1, 0.0f);
+
+ /**
* Get the media time of the anchor in microseconds.
*/
public long getAnchorMediaTimeUs() {
@@ -82,4 +87,15 @@
nanoTime = 0;
clockRate = 1.0f;
}
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null || getClass() != obj.getClass()) return false;
+
+ final MediaTimestamp that = (MediaTimestamp) obj;
+ return (this.mediaTimeUs == that.mediaTimeUs)
+ && (this.nanoTime == that.nanoTime)
+ && (this.clockRate == that.clockRate);
+ }
}
diff --git a/media/java/android/media/SubtitleData.java b/media/java/android/media/SubtitleData.java
index 3e6f6f9..9797828 100644
--- a/media/java/android/media/SubtitleData.java
+++ b/media/java/android/media/SubtitleData.java
@@ -16,26 +16,50 @@
package android.media;
+import android.annotation.NonNull;
import android.os.Parcel;
/**
- * @hide
- *
- * Class to hold the subtitle track's data, including:
+ * Class encapsulating subtitle data, as received through the
+ * {@link MediaPlayer.OnSubtitleDataListener} interface.
+ * The subtitle data includes:
* <ul>
- * <li> Track index</li>
- * <li> Start time (in microseconds) of the data</li>
- * <li> Duration (in microseconds) of the data</li>
- * <li> A byte-array of the data</li>
+ * <li> the track index</li>
+ * <li> the start time (in microseconds) of the data</li>
+ * <li> the duration (in microseconds) of the data</li>
+ * <li> the actual data.</li>
* </ul>
- *
- * <p> To receive the subtitle data, applications need to do the following:
- *
- * <ul>
- * <li> Select a track of type MEDIA_TRACK_TYPE_SUBTITLE with {@link MediaPlayer.selectTrack(int)</li>
- * <li> Implement the {@link MediaPlayer.OnSubtitleDataListener} interface</li>
- * <li> Register the {@link MediaPlayer.OnSubtitleDataListener} callback on a MediaPlayer object</li>
- * </ul>
+ * The data is stored in a byte-array, and is encoded in one of the supported in-band
+ * subtitle formats. The subtitle encoding is determined by the MIME type of the
+ * {@link MediaPlayer.TrackInfo} of the subtitle track, one of
+ * {@link MediaFormat#MIMETYPE_TEXT_CEA_608}, {@link MediaFormat#MIMETYPE_TEXT_CEA_708},
+ * {@link MediaFormat#MIMETYPE_TEXT_VTT}.
+ * <p>
+ * Here is an example of iterating over the tracks of a {@link MediaPlayer}, and checking which
+ * encoding is used for the subtitle tracks:
+ * <p>
+ * <pre class="prettyprint">
+ * MediaPlayer mp = new MediaPlayer();
+ * mp.setDataSource(myContentLocation);
+ * mp.prepare(); // synchronous prepare, ready to use when method returns
+ * final TrackInfo[] trackInfos = mp.getTrackInfo();
+ * for (TrackInfo info : trackInfo) {
+ * if (info.getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
+ * final String mime = info.getFormat().getString(MediaFormat.KEY_MIME);
+ * if (MediaFormat.MIMETYPE_TEXT_CEA_608.equals(mime) {
+ * // subtitle encoding is CEA 608
+ * } else if (MediaFormat.MIMETYPE_TEXT_CEA_708.equals(mime) {
+ * // subtitle encoding is CEA 708
+ * } else if (MediaFormat.MIMETYPE_TEXT_VTT.equals(mime) {
+ * // subtitle encoding is WebVTT
+ * }
+ * }
+ * }
+ * </pre>
+ * <p>
+ * See
+ * {@link MediaPlayer#setOnSubtitleDataListener(android.media.MediaPlayer.OnSubtitleDataListener, android.os.Handler)}
+ * to receive subtitle data from a MediaPlayer object.
*
* @see android.media.MediaPlayer
*/
@@ -48,25 +72,47 @@
private long mDurationUs;
private byte[] mData;
+ /** @hide */
public SubtitleData(Parcel parcel) {
if (!parseParcel(parcel)) {
throw new IllegalArgumentException("parseParcel() fails");
}
}
+ /**
+ * Returns the index of the MediaPlayer track which contains this subtitle data.
+ * @return an index in the array returned by {@link MediaPlayer#getTrackInfo()}.
+ */
public int getTrackIndex() {
return mTrackIndex;
}
+ /**
+ * Returns the media time at which the subtitle should be displayed, expressed in microseconds.
+ * @return the display start time for the subtitle
+ */
public long getStartTimeUs() {
return mStartTimeUs;
}
+ /**
+ * Returns the duration in microsecond during which the subtitle should be displayed.
+ * @return the display duration for the subtitle
+ */
public long getDurationUs() {
return mDurationUs;
}
- public byte[] getData() {
+ /**
+ * Returns the encoded data for the subtitle content.
+ * Encoding format depends on the subtitle type, refer to
+ * <a href="https://en.wikipedia.org/wiki/CEA-708">CEA 708</a>,
+ * <a href="https://en.wikipedia.org/wiki/EIA-608">CEA/EIA 608</a> and
+ * <a href="https://www.w3.org/TR/webvtt1/">WebVTT</a>, defined by the MIME type
+ * of the subtitle track.
+ * @return the encoded subtitle data
+ */
+ public @NonNull byte[] getData() {
return mData;
}
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 12d7440..4d8c96f 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "MtpDatabaseJNI"
#include "utils/Log.h"
+#include "utils/String8.h"
#include "android_media_Utils.h"
#include "mtp.h"
@@ -161,7 +162,7 @@
virtual void* getThumbnail(MtpObjectHandle handle, size_t& outThumbSize);
virtual MtpResponseCode getObjectFilePath(MtpObjectHandle handle,
- MtpString& outFilePath,
+ MtpStringBuffer& outFilePath,
int64_t& outFileLength,
MtpObjectFormat& outFormat);
virtual MtpResponseCode beginDeleteObject(MtpObjectHandle handle);
@@ -287,7 +288,7 @@
jint* handles = env->GetIntArrayElements(array, 0);
jsize length = env->GetArrayLength(array);
for (int i = 0; i < length; i++)
- list->push(handles[i]);
+ list->push_back(handles[i]);
env->ReleaseIntArrayElements(array, handles, 0);
env->DeleteLocalRef(array);
@@ -316,7 +317,7 @@
jint* formats = env->GetIntArrayElements(array, 0);
jsize length = env->GetArrayLength(array);
for (int i = 0; i < length; i++)
- list->push(formats[i]);
+ list->push_back(formats[i]);
env->ReleaseIntArrayElements(array, formats, 0);
env->DeleteLocalRef(array);
@@ -334,7 +335,7 @@
jint* formats = env->GetIntArrayElements(array, 0);
jsize length = env->GetArrayLength(array);
for (int i = 0; i < length; i++)
- list->push(formats[i]);
+ list->push_back(formats[i]);
env->ReleaseIntArrayElements(array, formats, 0);
env->DeleteLocalRef(array);
@@ -352,7 +353,7 @@
jint* properties = env->GetIntArrayElements(array, 0);
jsize length = env->GetArrayLength(array);
for (int i = 0; i < length; i++)
- list->push(properties[i]);
+ list->push_back(properties[i]);
env->ReleaseIntArrayElements(array, properties, 0);
env->DeleteLocalRef(array);
@@ -370,7 +371,7 @@
jint* properties = env->GetIntArrayElements(array, 0);
jsize length = env->GetArrayLength(array);
for (int i = 0; i < length; i++)
- list->push(properties[i]);
+ list->push_back(properties[i]);
env->ReleaseIntArrayElements(array, properties, 0);
env->DeleteLocalRef(array);
@@ -826,7 +827,7 @@
MtpResponseCode MtpDatabase::getObjectInfo(MtpObjectHandle handle,
MtpObjectInfo& info) {
- MtpString path;
+ MtpStringBuffer path;
int64_t length;
MtpObjectFormat format;
@@ -861,8 +862,8 @@
info.mAssociationType = MTP_ASSOCIATION_TYPE_UNDEFINED;
jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
- MtpString temp(reinterpret_cast<char16_t*>(str));
- info.mName = strdup((const char *)temp);
+ MtpStringBuffer temp(str);
+ info.mName = strdup(temp);
env->ReleaseCharArrayElements(mStringBuffer, str, 0);
// read EXIF data for thumbnail information
@@ -901,9 +902,10 @@
case MTP_FORMAT_TIFF:
case MTP_FORMAT_TIFF_EP:
case MTP_FORMAT_DEFINED: {
- std::unique_ptr<FileStream> stream(new FileStream(path));
+ String8 temp(path);
+ std::unique_ptr<FileStream> stream(new FileStream(temp));
piex::PreviewImageData image_data;
- if (!GetExifFromRawImage(stream.get(), path, image_data)) {
+ if (!GetExifFromRawImage(stream.get(), temp, image_data)) {
// Couldn't parse EXIF data from a image file via piex.
break;
}
@@ -922,7 +924,7 @@
}
void* MtpDatabase::getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) {
- MtpString path;
+ MtpStringBuffer path;
int64_t length;
MtpObjectFormat format;
void* result = NULL;
@@ -957,9 +959,10 @@
case MTP_FORMAT_TIFF:
case MTP_FORMAT_TIFF_EP:
case MTP_FORMAT_DEFINED: {
- std::unique_ptr<FileStream> stream(new FileStream(path));
+ String8 temp(path);
+ std::unique_ptr<FileStream> stream(new FileStream(temp));
piex::PreviewImageData image_data;
- if (!GetExifFromRawImage(stream.get(), path, image_data)) {
+ if (!GetExifFromRawImage(stream.get(), temp, image_data)) {
// Couldn't parse EXIF data from a image file via piex.
break;
}
@@ -992,7 +995,7 @@
}
MtpResponseCode MtpDatabase::getObjectFilePath(MtpObjectHandle handle,
- MtpString& outFilePath,
+ MtpStringBuffer& outFilePath,
int64_t& outFileLength,
MtpObjectFormat& outFormat) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
@@ -1004,8 +1007,7 @@
}
jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
- outFilePath.setTo(reinterpret_cast<char16_t*>(str),
- strlen16(reinterpret_cast<char16_t*>(str)));
+ outFilePath.set(str);
env->ReleaseCharArrayElements(mStringBuffer, str, 0);
jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
@@ -1146,7 +1148,7 @@
jint* handles = env->GetIntArrayElements(array, 0);
jsize length = env->GetArrayLength(array);
for (int i = 0; i < length; i++)
- list->push(handles[i]);
+ list->push_back(handles[i]);
env->ReleaseIntArrayElements(array, handles, 0);
env->DeleteLocalRef(array);
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index d42c39e..060eaf9 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -258,7 +258,7 @@
return NULL;
}
for (size_t i = 0; i < size; ++i) {
- elements[i] = deviceInfo->mOperations->itemAt(i);
+ elements[i] = static_cast<int>(deviceInfo->mOperations->at(i));
}
env->SetObjectField(info, field_deviceInfo_operationsSupported, operations.get());
}
@@ -274,7 +274,7 @@
return NULL;
}
for (size_t i = 0; i < size; ++i) {
- elements[i] = deviceInfo->mEvents->itemAt(i);
+ elements[i] = static_cast<int>(deviceInfo->mEvents->at(i));
}
env->SetObjectField(info, field_deviceInfo_eventsSupported, events.get());
}
@@ -296,7 +296,7 @@
int length = storageIDs->size();
jintArray array = env->NewIntArray(length);
// FIXME is this cast safe?
- env->SetIntArrayRegion(array, 0, length, (const jint *)storageIDs->array());
+ env->SetIntArrayRegion(array, 0, length, (const jint *)storageIDs->data());
delete storageIDs;
return array;
@@ -350,7 +350,7 @@
int length = handles->size();
jintArray array = env->NewIntArray(length);
// FIXME is this cast safe?
- env->SetIntArrayRegion(array, 0, length, (const jint *)handles->array());
+ env->SetIntArrayRegion(array, 0, length, (const jint *)handles->data());
delete handles;
return array;
diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp
index 8730e06..c60590a 100644
--- a/media/jni/android_mtp_MtpServer.cpp
+++ b/media/jni/android_mtp_MtpServer.cpp
@@ -67,10 +67,10 @@
int controlFd = dup(jniGetFDFromFileDescriptor(env, jControlFd));
MtpServer* server = new MtpServer(getMtpDatabase(env, javaDatabase), controlFd,
usePtp,
- MtpString((deviceInfoManufacturerStr != NULL) ? deviceInfoManufacturerStr : ""),
- MtpString((deviceInfoModelStr != NULL) ? deviceInfoModelStr : ""),
- MtpString((deviceInfoDeviceVersionStr != NULL) ? deviceInfoDeviceVersionStr : ""),
- MtpString((deviceInfoSerialNumberStr != NULL) ? deviceInfoSerialNumberStr : ""));
+ (deviceInfoManufacturerStr != NULL) ? deviceInfoManufacturerStr : "",
+ (deviceInfoModelStr != NULL) ? deviceInfoModelStr : "",
+ (deviceInfoDeviceVersionStr != NULL) ? deviceInfoDeviceVersionStr : "",
+ (deviceInfoSerialNumberStr != NULL) ? deviceInfoSerialNumberStr : "");
if (deviceInfoManufacturerStr != NULL) {
env->ReleaseStringUTFChars(deviceInfoManufacturer, deviceInfoManufacturerStr);
}
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index 7828c4c..dbdf5e16 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -35,6 +35,7 @@
import android.os.Bundle;
import android.provider.Settings;
import android.support.v4.widget.SwipeRefreshLayout;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.TypedValue;
@@ -531,7 +532,7 @@
private String getHeaderTitle() {
NetworkInfo info = mCm.getNetworkInfo(mNetwork);
- if (info == null) {
+ if (info == null || TextUtils.isEmpty(info.getExtraInfo())) {
return getString(R.string.action_bar_label);
}
NetworkCapabilities nc = mCm.getNetworkCapabilities(mNetwork);
diff --git a/packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java b/packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java
index 4ad4b24..de2659f 100644
--- a/packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java
+++ b/packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java
@@ -30,7 +30,7 @@
private static final String TAG = "ExtAssistant.CI";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- static final double DISMISS_TO_VIEW_RATIO_LIMIT = .8;
+ static final double DISMISS_TO_VIEW_RATIO_LIMIT = .4;
static final int STREAK_LIMIT = 2;
static final String ATT_DISMISSALS = "dismisses";
static final String ATT_VIEWS = "views";
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 584fc34..82bc6af8 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -500,10 +500,10 @@
<string name="keep_screen_on">Stay awake</string>
<!-- setting Checkbox summary whether to keep the screen on when plugged in -->
<string name="keep_screen_on_summary">Screen will never sleep while charging</string>
- <!-- Setting Checkbox title whether to enable bluetooth HCI snoop log -->
+ <!-- Setting Checkbox title whether to enable Bluetooth HCI snoop log -->
<string name="bt_hci_snoop_log">Enable Bluetooth HCI snoop log</string>
- <!-- setting Checkbox summary whether to capture all bluetooth HCI packets in a file -->
- <string name="bt_hci_snoop_log_summary">Capture all bluetooth HCI packets in a file</string>
+ <!-- setting Checkbox summary whether to capture all Bluetooth HCI packets in a file -->
+ <string name="bt_hci_snoop_log_summary">Capture all Bluetooth HCI packets in a file (Toggle Bluetooth after changing this setting)</string>
<!-- setting Checkbox title whether to enable OEM unlock [CHAR_LIMIT=35] -->
<string name="oem_unlock_enable">OEM unlocking</string>
<!-- setting Checkbox summary whether to enable OEM unlock [CHAR_LIMIT=50] -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java b/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java
index 81a2d43..3e3c039 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java
@@ -41,10 +41,11 @@
public static final int SECONDS_PER_DAY = 24 * 60 * 60;
/**
- * Returns elapsed time for the given millis, in the following format:
- * 2d 5h 40m 29s
- * @param context the application context
- * @param millis the elapsed time in milli seconds
+ * Returns elapsed time for the given millis, in the following format:
+ * 2 days, 5 hr, 40 min, 29 sec
+ *
+ * @param context the application context
+ * @param millis the elapsed time in milli seconds
* @param withSeconds include seconds?
* @return the formatted elapsed time
*/
@@ -92,7 +93,7 @@
final Locale locale = context.getResources().getConfiguration().locale;
final MeasureFormat measureFormat = MeasureFormat.getInstance(
- locale, FormatWidth.NARROW);
+ locale, FormatWidth.SHORT);
sb.append(measureFormat.formatMeasures(measureArray));
if (measureArray.length == 1 && MeasureUnit.MINUTE.equals(measureArray[0].getUnit())) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 78045f9..50dfc26 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -43,8 +43,6 @@
import android.net.wifi.WifiNetworkScoreCache;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -896,6 +894,13 @@
summary.append(WifiUtils.buildLoggingSummary(this, config));
}
+ if (config != null && (WifiUtils.isMeteredOverridden(config) || config.meteredHint)) {
+ return mContext.getResources().getString(
+ R.string.preference_summary_default_combination,
+ WifiUtils.getMeteredLabel(mContext, config),
+ summary.toString());
+ }
+
// If Speed label and summary are both present, use the preference combination to combine
// the two, else return the non-null one.
if (getSpeedLabel() != null && summary.length() != 0) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
index 61efabc..bee2fa1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
@@ -16,12 +16,15 @@
package com.android.settingslib.wifi;
+import android.content.Context;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.os.SystemClock;
import android.support.annotation.VisibleForTesting;
+import com.android.settingslib.R;
+
import java.util.Map;
public class WifiUtils {
@@ -198,4 +201,18 @@
// speed wil be determined by mRssi
return timedScore.getScore().calculateBadge(result.level);
}
+
+ public static String getMeteredLabel(Context context, WifiConfiguration config) {
+ // meteredOverride is whether the user manually set the metered setting or not.
+ // meteredHint is whether the network itself is telling us that it is metered
+ if (config.meteredOverride == WifiConfiguration.METERED_OVERRIDE_METERED
+ || (config.meteredHint && !isMeteredOverridden(config))) {
+ return context.getString(R.string.wifi_metered_label);
+ }
+ return context.getString(R.string.wifi_unmetered_label);
+ }
+
+ public static boolean isMeteredOverridden(WifiConfiguration config) {
+ return config.meteredOverride != WifiConfiguration.METERED_OVERRIDE_NONE;
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
index c11687b..05247ba 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
@@ -137,9 +137,9 @@
true /* basedOnUsage */);
// shortened string should not have percentage
- assertThat(info).isEqualTo("Less than 15m remaining");
+ assertThat(info).isEqualTo("Less than 15 min remaining");
// Add percentage to string when provided
- assertThat(info2).isEqualTo("Less than 15m remaining (10%)");
+ assertThat(info2).isEqualTo("Less than 15 min remaining (10%)");
}
@Test
@@ -154,9 +154,9 @@
false /* basedOnUsage */);
// We only add special mention for the long string
- assertThat(info).isEqualTo("About 1d 6h left based on your usage");
+ assertThat(info).isEqualTo("About 1 day, 6 hr left based on your usage");
// shortened string should not have extra text
- assertThat(info2).isEqualTo("About 1d 6h left (10%)");
+ assertThat(info2).isEqualTo("About 1 day, 6 hr left (10%)");
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java
index 532c755..743951a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java
@@ -43,7 +43,7 @@
@Test
public void testFormatElapsedTime_WithSeconds_ShowSeconds() {
final double testMillis = 5 * DateUtils.MINUTE_IN_MILLIS + 30 * DateUtils.SECOND_IN_MILLIS;
- final String expectedTime = "5m 30s";
+ final String expectedTime = "5 min, 30 sec";
assertThat(StringUtil.formatElapsedTime(mContext, testMillis, true).toString())
.isEqualTo(expectedTime);
@@ -52,7 +52,7 @@
@Test
public void testFormatElapsedTime_NoSeconds_DoNotShowSeconds() {
final double testMillis = 5 * DateUtils.MINUTE_IN_MILLIS + 30 * DateUtils.SECOND_IN_MILLIS;
- final String expectedTime = "6m";
+ final String expectedTime = "6 min";
assertThat(StringUtil.formatElapsedTime(mContext, testMillis, false).toString())
.isEqualTo(expectedTime);
@@ -62,7 +62,7 @@
public void testFormatElapsedTime_TimeMoreThanOneDay_ShowCorrectly() {
final double testMillis = 2 * DateUtils.DAY_IN_MILLIS
+ 4 * DateUtils.HOUR_IN_MILLIS + 15 * DateUtils.MINUTE_IN_MILLIS;
- final String expectedTime = "2d 4h 15m";
+ final String expectedTime = "2 days, 4 hr, 15 min";
assertThat(StringUtil.formatElapsedTime(mContext, testMillis, false).toString())
.isEqualTo(expectedTime);
@@ -71,7 +71,7 @@
@Test
public void testFormatElapsedTime_ZeroFieldsInTheMiddleDontShow() {
final double testMillis = 2 * DateUtils.DAY_IN_MILLIS + 15 * DateUtils.MINUTE_IN_MILLIS;
- final String expectedTime = "2d 15m";
+ final String expectedTime = "2 days, 15 min";
assertThat(StringUtil.formatElapsedTime(mContext, testMillis, false).toString())
.isEqualTo(expectedTime);
@@ -80,7 +80,7 @@
@Test
public void testFormatElapsedTime_FormatZero_WithSeconds() {
final double testMillis = 0;
- final String expectedTime = "0s";
+ final String expectedTime = "0 sec";
assertThat(StringUtil.formatElapsedTime(mContext, testMillis, true).toString())
.isEqualTo(expectedTime);
@@ -89,7 +89,7 @@
@Test
public void testFormatElapsedTime_FormatZero_NoSeconds() {
final double testMillis = 0;
- final String expectedTime = "0m";
+ final String expectedTime = "0 min";
assertThat(StringUtil.formatElapsedTime(mContext, testMillis, false).toString())
.isEqualTo(expectedTime);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java
index 91d9f91..d25adde 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java
@@ -27,6 +27,7 @@
import android.net.ScoredNetwork;
import android.net.WifiKey;
import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiNetworkScoreCache;
import android.os.Bundle;
import android.os.Parcelable;
@@ -61,6 +62,8 @@
private WifiNetworkScoreCache mockWifiNetworkScoreCache;
@Mock
private AccessPoint mAccessPoint;
+ @Mock
+ WifiConfiguration mWifiConfig;
@Before
public void setUp() {
@@ -98,6 +101,52 @@
WifiUtils.getVisibilityStatus(mAccessPoint);
}
+ @Test
+ public void testGetMeteredLabel_returnsCorrectValues() {
+ mWifiConfig.meteredHint = true;
+ mWifiConfig.meteredOverride = WifiConfiguration.METERED_OVERRIDE_NONE;
+ assertThat(WifiUtils.getMeteredLabel(mContext, mWifiConfig)).isEqualTo("Metered");
+
+ mWifiConfig.meteredHint = false;
+ mWifiConfig.meteredOverride = WifiConfiguration.METERED_OVERRIDE_METERED;
+ assertThat(WifiUtils.getMeteredLabel(mContext, mWifiConfig)).isEqualTo("Metered");
+
+ mWifiConfig.meteredHint = true;
+ mWifiConfig.meteredOverride = WifiConfiguration.METERED_OVERRIDE_METERED;
+ assertThat(WifiUtils.getMeteredLabel(mContext, mWifiConfig)).isEqualTo("Metered");
+
+ mWifiConfig.meteredHint = false;
+ mWifiConfig.meteredOverride = WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
+ assertThat(WifiUtils.getMeteredLabel(mContext, mWifiConfig)).isEqualTo("Unmetered");
+
+ mWifiConfig.meteredHint = true;
+ mWifiConfig.meteredOverride = WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
+ assertThat(WifiUtils.getMeteredLabel(mContext, mWifiConfig)).isEqualTo("Unmetered");
+ }
+
+ @Test
+ public void testIsMeteredOverridden_returnsCorrectValues() {
+ mWifiConfig.meteredHint = true;
+ mWifiConfig.meteredOverride = WifiConfiguration.METERED_OVERRIDE_NONE;
+ assertThat(WifiUtils.isMeteredOverridden(mWifiConfig)).isFalse();
+
+ mWifiConfig.meteredHint = false;
+ mWifiConfig.meteredOverride = WifiConfiguration.METERED_OVERRIDE_METERED;
+ assertThat(WifiUtils.isMeteredOverridden(mWifiConfig)).isTrue();
+
+ mWifiConfig.meteredHint = true;
+ mWifiConfig.meteredOverride = WifiConfiguration.METERED_OVERRIDE_METERED;
+ assertThat(WifiUtils.isMeteredOverridden(mWifiConfig)).isTrue();
+
+ mWifiConfig.meteredHint = false;
+ mWifiConfig.meteredOverride = WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
+ assertThat(WifiUtils.isMeteredOverridden(mWifiConfig)).isTrue();
+
+ mWifiConfig.meteredHint = true;
+ mWifiConfig.meteredOverride = WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
+ assertThat(WifiUtils.isMeteredOverridden(mWifiConfig)).isTrue();
+ }
+
private static ArrayList<ScanResult> buildScanResultCache() {
ArrayList<ScanResult> scanResults = new ArrayList<>();
for (int i = 0; i < 5; i++) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 6daed35..a444ac8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -2258,7 +2258,6 @@
// Please insert new settings using the same order as in SecureSettingsProto.
-
}
private static void dumpProtoSystemSettingsLocked(
@@ -2267,15 +2266,293 @@
s.dumpHistoricalOperations(p, SystemSettingsProto.HISTORICAL_OPERATIONS);
- // This uses the same order as in Settings.System.
+ // This uses the same order as in SystemSettingsProto.
- // Settings.System.STAY_ON_WHILE_PLUGGED_IN intentionally excluded since it's deprecated.
+ dumpSetting(s, p,
+ Settings.System.ADVANCED_SETTINGS,
+ SystemSettingsProto.ADVANCED_SETTINGS);
+
+ final long alarmToken = p.start(SystemSettingsProto.ALARM);
+ dumpSetting(s, p,
+ Settings.System.ALARM_ALERT,
+ SystemSettingsProto.Alarm.DEFAULT_URI);
+ dumpSetting(s, p,
+ Settings.System.ALARM_ALERT_CACHE,
+ SystemSettingsProto.Alarm.ALERT_CACHE);
+ // Settings.System.NEXT_ALARM_FORMATTED intentionally excluded since it's deprecated.
+ p.end(alarmToken);
+
+ final long bluetoothToken = p.start(SystemSettingsProto.BLUETOOTH);
+ dumpSetting(s, p,
+ Settings.System.BLUETOOTH_DISCOVERABILITY,
+ SystemSettingsProto.Bluetooth.DISCOVERABILITY);
+ dumpSetting(s, p,
+ Settings.System.BLUETOOTH_DISCOVERABILITY_TIMEOUT,
+ SystemSettingsProto.Bluetooth.DISCOVERABILITY_TIMEOUT_SECS);
+ p.end(bluetoothToken);
+
+ dumpSetting(s, p,
+ Settings.System.DATE_FORMAT,
+ SystemSettingsProto.DATE_FORMAT);
+ dumpSetting(s, p,
+ Settings.System.DISPLAY_COLOR_MODE,
+ SystemSettingsProto.DISPLAY_COLOR_MODE);
+
+ final long devOptionsToken = p.start(SystemSettingsProto.DEVELOPER_OPTIONS);
+ dumpSetting(s, p,
+ Settings.System.SHOW_TOUCHES,
+ SystemSettingsProto.DevOptions.SHOW_TOUCHES);
+ dumpSetting(s, p,
+ Settings.System.POINTER_LOCATION,
+ SystemSettingsProto.DevOptions.POINTER_LOCATION);
+ dumpSetting(s, p,
+ Settings.System.WINDOW_ORIENTATION_LISTENER_LOG,
+ SystemSettingsProto.DevOptions.WINDOW_ORIENTATION_LISTENER_LOG);
+ p.end(devOptionsToken);
+
+ final long dtmfToneToken = p.start(SystemSettingsProto.DTMF_TONE);
+ dumpSetting(s, p,
+ Settings.System.DTMF_TONE_WHEN_DIALING,
+ SystemSettingsProto.DtmfTone.PLAY_WHEN_DIALING);
+ dumpSetting(s, p,
+ Settings.System.DTMF_TONE_TYPE_WHEN_DIALING,
+ SystemSettingsProto.DtmfTone.TYPE_PLAYED_WHEN_DIALING);
+ p.end(dtmfToneToken);
+
+ dumpSetting(s, p,
+ Settings.System.EGG_MODE,
+ SystemSettingsProto.EGG_MODE);
dumpSetting(s, p,
Settings.System.END_BUTTON_BEHAVIOR,
SystemSettingsProto.END_BUTTON_BEHAVIOR);
dumpSetting(s, p,
- Settings.System.ADVANCED_SETTINGS,
- SystemSettingsProto.ADVANCED_SETTINGS);
+ Settings.System.FONT_SCALE,
+ SystemSettingsProto.FONT_SCALE);
+
+ final long hapticFeedbackToken = p.start(SystemSettingsProto.HAPTIC_FEEDBACK);
+ dumpSetting(s, p,
+ Settings.System.HAPTIC_FEEDBACK_ENABLED,
+ SystemSettingsProto.HapticFeedback.ENABLED);
+ dumpSetting(s, p,
+ Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+ SystemSettingsProto.HapticFeedback.INTENSITY);
+ p.end(hapticFeedbackToken);
+
+ dumpSetting(s, p,
+ Settings.System.HEARING_AID,
+ SystemSettingsProto.HEARING_AID);
+ dumpSetting(s, p,
+ Settings.System.LOCK_TO_APP_ENABLED,
+ SystemSettingsProto.LOCK_TO_APP_ENABLED);
+
+ final long lockscreenToken = p.start(SystemSettingsProto.LOCKSCREEN);
+ dumpSetting(s, p,
+ Settings.System.LOCKSCREEN_SOUNDS_ENABLED,
+ SystemSettingsProto.Lockscreen.SOUNDS_ENABLED);
+ dumpSetting(s, p,
+ Settings.System.LOCKSCREEN_DISABLED,
+ SystemSettingsProto.Lockscreen.DISABLED);
+ p.end(lockscreenToken);
+
+ dumpSetting(s, p,
+ Settings.System.MEDIA_BUTTON_RECEIVER,
+ SystemSettingsProto.MEDIA_BUTTON_RECEIVER);
+
+ final long notificationToken = p.start(SystemSettingsProto.NOTIFICATION);
+ dumpSetting(s, p,
+ Settings.System.NOTIFICATION_SOUND,
+ SystemSettingsProto.Notification.SOUND);
+ dumpSetting(s, p,
+ Settings.System.NOTIFICATION_SOUND_CACHE,
+ SystemSettingsProto.Notification.SOUND_CACHE);
+ dumpSetting(s, p,
+ Settings.System.NOTIFICATION_LIGHT_PULSE,
+ SystemSettingsProto.Notification.LIGHT_PULSE);
+ dumpSetting(s, p,
+ Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+ SystemSettingsProto.Notification.VIBRATION_INTENSITY);
+ // Settings.System.NOTIFICATIONS_USE_RING_VOLUME intentionally excluded since it's deprecated.
+ p.end(notificationToken);
+
+ dumpSetting(s, p,
+ Settings.System.POINTER_SPEED,
+ SystemSettingsProto.POINTER_SPEED);
+
+ final long ringtoneToken = p.start(SystemSettingsProto.RINGTONE);
+ dumpSetting(s, p,
+ Settings.System.RINGTONE,
+ SystemSettingsProto.Ringtone.DEFAULT_URI);
+ dumpSetting(s, p,
+ Settings.System.RINGTONE_CACHE,
+ SystemSettingsProto.Ringtone.CACHE);
+ p.end(ringtoneToken);
+
+ final long rotationToken = p.start(SystemSettingsProto.ROTATION);
+ dumpSetting(s, p,
+ Settings.System.ACCELEROMETER_ROTATION,
+ SystemSettingsProto.Rotation.ACCELEROMETER_ROTATION);
+ dumpSetting(s, p,
+ Settings.System.USER_ROTATION,
+ SystemSettingsProto.Rotation.USER_ROTATION);
+ dumpSetting(s, p,
+ Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY,
+ SystemSettingsProto.Rotation.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY);
+ p.end(rotationToken);
+
+ dumpSetting(s, p,
+ Settings.System.RTT_CALLING_MODE,
+ SystemSettingsProto.RTT_CALLING_MODE);
+
+ final long screenToken = p.start(SystemSettingsProto.SCREEN);
+ dumpSetting(s, p,
+ Settings.System.SCREEN_OFF_TIMEOUT,
+ SystemSettingsProto.Screen.OFF_TIMEOUT);
+ dumpSetting(s, p,
+ Settings.System.SCREEN_BRIGHTNESS,
+ SystemSettingsProto.Screen.BRIGHTNESS);
+ dumpSetting(s, p,
+ Settings.System.SCREEN_BRIGHTNESS_FOR_VR,
+ SystemSettingsProto.Screen.BRIGHTNESS_FOR_VR);
+ dumpSetting(s, p,
+ Settings.System.SCREEN_BRIGHTNESS_MODE,
+ SystemSettingsProto.Screen.BRIGHTNESS_MODE);
+ dumpSetting(s, p,
+ Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ,
+ SystemSettingsProto.Screen.AUTO_BRIGHTNESS_ADJ);
+ p.end(screenToken);
+
+ dumpSetting(s, p,
+ Settings.System.SETUP_WIZARD_HAS_RUN,
+ SystemSettingsProto.SETUP_WIZARD_HAS_RUN);
+ dumpSetting(s, p,
+ Settings.System.SHOW_BATTERY_PERCENT,
+ SystemSettingsProto.SHOW_BATTERY_PERCENT);
+ dumpSetting(s, p,
+ Settings.System.SHOW_GTALK_SERVICE_STATUS,
+ SystemSettingsProto.SHOW_GTALK_SERVICE_STATUS);
+ // Settings.System.SHOW_PROCESSES intentionally excluded since it's deprecated.
+ // Settings.System.SHOW_WEB_SUGGESTIONS intentionally excluded since it's deprecated.
+
+ final long sipToken = p.start(SystemSettingsProto.SIP);
+ dumpSetting(s, p,
+ Settings.System.SIP_RECEIVE_CALLS,
+ SystemSettingsProto.Sip.RECEIVE_CALLS);
+ dumpSetting(s, p,
+ Settings.System.SIP_CALL_OPTIONS,
+ SystemSettingsProto.Sip.CALL_OPTIONS);
+ dumpSetting(s, p,
+ Settings.System.SIP_ALWAYS,
+ SystemSettingsProto.Sip.ALWAYS);
+ dumpSetting(s, p,
+ Settings.System.SIP_ADDRESS_ONLY,
+ SystemSettingsProto.Sip.ADDRESS_ONLY);
+ // Settings.System.SIP_ASK_ME_EACH_TIME intentionally excluded since it's deprecated.
+ p.end(sipToken);
+
+ dumpSetting(s, p,
+ Settings.System.SOUND_EFFECTS_ENABLED,
+ SystemSettingsProto.SOUND_EFFECTS_ENABLED);
+ // Settings.System.POWER_SOUNDS_ENABLED intentionally excluded since it's deprecated.
+ // Settings.System.DOCK_SOUNDS_ENABLED intentionally excluded since it's deprecated.
+ // Settings.System.LOW_BATTERY_SOUND intentionally excluded since it's deprecated.
+ // Settings.System.DESK_DOCK_SOUND intentionally excluded since it's deprecated.
+ // Settings.System.DESK_UNDOCK_SOUND intentionally excluded since it's deprecated.
+ // Settings.System.CAR_DOCK_SOUND intentionally excluded since it's deprecated.
+ // Settings.System.CAR_UNDOCK_SOUND intentionally excluded since it's deprecated.
+ // Settings.System.LOCK_SOUND intentionally excluded since it's deprecated.
+ // Settings.System.UNLOCK_SOUND intentionally excluded since it's deprecated.
+ dumpSetting(s, p,
+ Settings.System.SYSTEM_LOCALES,
+ SystemSettingsProto.SYSTEM_LOCALES);
+
+ final long textToken = p.start(SystemSettingsProto.TEXT);
+ dumpSetting(s, p,
+ Settings.System.TEXT_AUTO_REPLACE,
+ SystemSettingsProto.Text.AUTO_REPLACE);
+ dumpSetting(s, p,
+ Settings.System.TEXT_AUTO_CAPS,
+ SystemSettingsProto.Text.AUTO_CAPS);
+ dumpSetting(s, p,
+ Settings.System.TEXT_AUTO_PUNCTUATE,
+ SystemSettingsProto.Text.AUTO_PUNCTUATE);
+ dumpSetting(s, p,
+ Settings.System.TEXT_SHOW_PASSWORD,
+ SystemSettingsProto.Text.SHOW_PASSWORD);
+ p.end(textToken);
+
+ // Settings.System.AUTO_TIME intentionally excluded since it's deprecated.
+ // Settings.System.AUTO_TIME_ZONE intentionally excluded since it's deprecated.
+ dumpSetting(s, p,
+ Settings.System.TIME_12_24,
+ SystemSettingsProto.TIME_12_24);
+ dumpSetting(s, p,
+ Settings.System.TTY_MODE,
+ SystemSettingsProto.TTY_MODE);
+
+ final long vibrateToken = p.start(SystemSettingsProto.VIBRATE);
+ dumpSetting(s, p,
+ Settings.System.VIBRATE_ON,
+ SystemSettingsProto.Vibrate.ON);
+ dumpSetting(s, p,
+ Settings.System.VIBRATE_INPUT_DEVICES,
+ SystemSettingsProto.Vibrate.INPUT_DEVICES);
+ dumpSetting(s, p,
+ Settings.System.VIBRATE_IN_SILENT,
+ SystemSettingsProto.Vibrate.IN_SILENT);
+ dumpSetting(s, p,
+ Settings.System.VIBRATE_WHEN_RINGING,
+ SystemSettingsProto.Vibrate.WHEN_RINGING);
+ p.end(vibrateToken);
+
+ final long volumeToken = p.start(SystemSettingsProto.VOLUME);
+ dumpSetting(s, p,
+ Settings.System.VOLUME_RING,
+ SystemSettingsProto.Volume.RING);
+ dumpSetting(s, p,
+ Settings.System.VOLUME_SYSTEM,
+ SystemSettingsProto.Volume.SYSTEM);
+ dumpSetting(s, p,
+ Settings.System.VOLUME_VOICE,
+ SystemSettingsProto.Volume.VOICE);
+ dumpSetting(s, p,
+ Settings.System.VOLUME_MUSIC,
+ SystemSettingsProto.Volume.MUSIC);
+ dumpSetting(s, p,
+ Settings.System.VOLUME_ALARM,
+ SystemSettingsProto.Volume.ALARM);
+ dumpSetting(s, p,
+ Settings.System.VOLUME_NOTIFICATION,
+ SystemSettingsProto.Volume.NOTIFICATION);
+ dumpSetting(s, p,
+ Settings.System.VOLUME_BLUETOOTH_SCO,
+ SystemSettingsProto.Volume.BLUETOOTH_SCO);
+ dumpSetting(s, p,
+ Settings.System.VOLUME_ACCESSIBILITY,
+ SystemSettingsProto.Volume.ACCESSIBILITY);
+ dumpSetting(s, p,
+ Settings.System.VOLUME_MASTER,
+ SystemSettingsProto.Volume.MASTER);
+ dumpSetting(s, p,
+ Settings.System.MASTER_MONO,
+ SystemSettingsProto.Volume.MASTER_MONO);
+ dumpSetting(s, p,
+ Settings.System.MODE_RINGER_STREAMS_AFFECTED,
+ SystemSettingsProto.Volume.MODE_RINGER_STREAMS_AFFECTED);
+ dumpSetting(s, p,
+ Settings.System.MUTE_STREAMS_AFFECTED,
+ SystemSettingsProto.Volume.MUTE_STREAMS_AFFECTED);
+ p.end(volumeToken);
+
+ dumpSetting(s, p,
+ Settings.System.WHEN_TO_MAKE_WIFI_CALLS,
+ SystemSettingsProto.WHEN_TO_MAKE_WIFI_CALLS);
+
+ // Please insert new settings using the same order as in SecureSettingsProto.
+
+ // The rest of the settings were moved to Settings.Secure, and are thus excluded here since
+ // they're deprecated from Settings.System.
+
+ // Settings.System.STAY_ON_WHILE_PLUGGED_IN intentionally excluded since it's deprecated.
// Settings.System.AIRPLANE_MODE_ON intentionally excluded since it's deprecated.
// Settings.System.RADIO_BLUETOOTH intentionally excluded since it's just a constant.
// Settings.System.RADIO_WIFI intentionally excluded since it's just a constant.
@@ -2292,245 +2569,24 @@
// Settings.System.WIFI_STATIC_NETMASK intentionally excluded since it's deprecated.
// Settings.System.WIFI_STATIC_DNS1 intentionally excluded since it's deprecated.
// Settings.System.WIFI_STATIC_DNS2 intentionally excluded since it's deprecated.
- dumpSetting(s, p,
- Settings.System.BLUETOOTH_DISCOVERABILITY,
- SystemSettingsProto.BLUETOOTH_DISCOVERABILITY);
- dumpSetting(s, p,
- Settings.System.BLUETOOTH_DISCOVERABILITY_TIMEOUT,
- SystemSettingsProto.BLUETOOTH_DISCOVERABILITY_TIMEOUT);
// Settings.System.LOCK_PATTERN_ENABLED intentionally excluded since it's deprecated.
// Settings.System.LOCK_PATTERN_VISIBLE intentionally excluded since it's deprecated.
// Settings.System.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED intentionally excluded since it's deprecated.
- // Settings.System.NEXT_ALARM_FORMATTED intentionally excluded since it's deprecated.
- dumpSetting(s, p,
- Settings.System.FONT_SCALE,
- SystemSettingsProto.FONT_SCALE);
- dumpSetting(s, p,
- Settings.System.SYSTEM_LOCALES,
- SystemSettingsProto.SYSTEM_LOCALES);
// Settings.System.DEBUG_APP intentionally excluded since it's deprecated.
// Settings.System.WAIT_FOR_DEBUGGER intentionally excluded since it's deprecated.
// Settings.System.DIM_SCREEN intentionally excluded since it's deprecated.
- dumpSetting(s, p,
- Settings.System.DISPLAY_COLOR_MODE,
- SystemSettingsProto.DISPLAY_COLOR_MODE);
- dumpSetting(s, p,
- Settings.System.SCREEN_OFF_TIMEOUT,
- SystemSettingsProto.SCREEN_OFF_TIMEOUT);
- dumpSetting(s, p,
- Settings.System.SCREEN_BRIGHTNESS,
- SystemSettingsProto.SCREEN_BRIGHTNESS);
- dumpSetting(s, p,
- Settings.System.SCREEN_BRIGHTNESS_FOR_VR,
- SystemSettingsProto.SCREEN_BRIGHTNESS_FOR_VR);
- dumpSetting(s, p,
- Settings.System.SCREEN_BRIGHTNESS_MODE,
- SystemSettingsProto.SCREEN_BRIGHTNESS_MODE);
- dumpSetting(s, p,
- Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ,
- SystemSettingsProto.SCREEN_AUTO_BRIGHTNESS_ADJ);
- // Settings.System.SHOW_PROCESSES intentionally excluded since it's deprecated.
// Settings.System.ALWAYS_FINISH_ACTIVITIES intentionally excluded since it's deprecated.
- dumpSetting(s, p,
- Settings.System.MODE_RINGER_STREAMS_AFFECTED,
- SystemSettingsProto.MODE_RINGER_STREAMS_AFFECTED);
- dumpSetting(s, p,
- Settings.System.MUTE_STREAMS_AFFECTED,
- SystemSettingsProto.MUTE_STREAMS_AFFECTED);
- dumpSetting(s, p,
- Settings.System.VIBRATE_ON,
- SystemSettingsProto.VIBRATE_ON);
- dumpSetting(s, p,
- Settings.System.VIBRATE_INPUT_DEVICES,
- SystemSettingsProto.VIBRATE_INPUT_DEVICES);
- dumpSetting(s, p,
- Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
- SystemSettingsProto.NOTIFICATION_VIBRATION_INTENSITY);
- dumpSetting(s, p,
- Settings.System.HAPTIC_FEEDBACK_INTENSITY,
- SystemSettingsProto.HAPTIC_FEEDBACK_INTENSITY);
- dumpSetting(s, p,
- Settings.System.VOLUME_RING,
- SystemSettingsProto.VOLUME_RING);
- dumpSetting(s, p,
- Settings.System.VOLUME_SYSTEM,
- SystemSettingsProto.VOLUME_SYSTEM);
- dumpSetting(s, p,
- Settings.System.VOLUME_VOICE,
- SystemSettingsProto.VOLUME_VOICE);
- dumpSetting(s, p,
- Settings.System.VOLUME_MUSIC,
- SystemSettingsProto.VOLUME_MUSIC);
- dumpSetting(s, p,
- Settings.System.VOLUME_ALARM,
- SystemSettingsProto.VOLUME_ALARM);
- dumpSetting(s, p,
- Settings.System.VOLUME_NOTIFICATION,
- SystemSettingsProto.VOLUME_NOTIFICATION);
- dumpSetting(s, p,
- Settings.System.VOLUME_BLUETOOTH_SCO,
- SystemSettingsProto.VOLUME_BLUETOOTH_SCO);
- dumpSetting(s, p,
- Settings.System.VOLUME_ACCESSIBILITY,
- SystemSettingsProto.VOLUME_ACCESSIBILITY);
- dumpSetting(s, p,
- Settings.System.VOLUME_MASTER,
- SystemSettingsProto.VOLUME_MASTER);
- dumpSetting(s, p,
- Settings.System.MASTER_MONO,
- SystemSettingsProto.MASTER_MONO);
- // Settings.System.NOTIFICATIONS_USE_RING_VOLUME intentionally excluded since it's deprecated.
- dumpSetting(s, p,
- Settings.System.VIBRATE_IN_SILENT,
- SystemSettingsProto.VIBRATE_IN_SILENT);
- dumpSetting(s, p,
- Settings.System.APPEND_FOR_LAST_AUDIBLE,
- SystemSettingsProto.APPEND_FOR_LAST_AUDIBLE);
- dumpSetting(s, p,
- Settings.System.RINGTONE,
- SystemSettingsProto.RINGTONE);
- dumpSetting(s, p,
- Settings.System.RINGTONE_CACHE,
- SystemSettingsProto.RINGTONE_CACHE);
- dumpSetting(s, p,
- Settings.System.NOTIFICATION_SOUND,
- SystemSettingsProto.NOTIFICATION_SOUND);
- dumpSetting(s, p,
- Settings.System.NOTIFICATION_SOUND_CACHE,
- SystemSettingsProto.NOTIFICATION_SOUND_CACHE);
- dumpSetting(s, p,
- Settings.System.ALARM_ALERT,
- SystemSettingsProto.ALARM_ALERT);
- dumpSetting(s, p,
- Settings.System.ALARM_ALERT_CACHE,
- SystemSettingsProto.ALARM_ALERT_CACHE);
- dumpSetting(s, p,
- Settings.System.MEDIA_BUTTON_RECEIVER,
- SystemSettingsProto.MEDIA_BUTTON_RECEIVER);
- dumpSetting(s, p,
- Settings.System.TEXT_AUTO_REPLACE,
- SystemSettingsProto.TEXT_AUTO_REPLACE);
- dumpSetting(s, p,
- Settings.System.TEXT_AUTO_CAPS,
- SystemSettingsProto.TEXT_AUTO_CAPS);
- dumpSetting(s, p,
- Settings.System.TEXT_AUTO_PUNCTUATE,
- SystemSettingsProto.TEXT_AUTO_PUNCTUATE);
- dumpSetting(s, p,
- Settings.System.TEXT_SHOW_PASSWORD,
- SystemSettingsProto.TEXT_SHOW_PASSWORD);
- dumpSetting(s, p,
- Settings.System.SHOW_GTALK_SERVICE_STATUS,
- SystemSettingsProto.SHOW_GTALK_SERVICE_STATUS);
+ // Settings.System.APPEND_FOR_LAST_AUDIBLE intentionally excluded since it hasn't been used since API 2.
// Settings.System.WALLPAPER_ACTIVITY intentionally excluded since it's deprecated.
- // Settings.System.AUTO_TIME intentionally excluded since it's deprecated.
- // Settings.System.AUTO_TIME_ZONE intentionally excluded since it's deprecated.
- dumpSetting(s, p,
- Settings.System.TIME_12_24,
- SystemSettingsProto.TIME_12_24);
- dumpSetting(s, p,
- Settings.System.DATE_FORMAT,
- SystemSettingsProto.DATE_FORMAT);
- dumpSetting(s, p,
- Settings.System.SETUP_WIZARD_HAS_RUN,
- SystemSettingsProto.SETUP_WIZARD_HAS_RUN);
// Settings.System.WINDOW_ANIMATION_SCALE intentionally excluded since it's deprecated.
// Settings.System.TRANSITION_ANIMATION_SCALE intentionally excluded since it's deprecated.
// Settings.System.ANIMATOR_ANIMATION_SCALE intentionally excluded since it's deprecated.
- dumpSetting(s, p,
- Settings.System.ACCELEROMETER_ROTATION,
- SystemSettingsProto.ACCELEROMETER_ROTATION);
- dumpSetting(s, p,
- Settings.System.USER_ROTATION,
- SystemSettingsProto.USER_ROTATION);
- dumpSetting(s, p,
- Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY,
- SystemSettingsProto.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY);
- dumpSetting(s, p,
- Settings.System.VIBRATE_WHEN_RINGING,
- SystemSettingsProto.VIBRATE_WHEN_RINGING);
- dumpSetting(s, p,
- Settings.System.DTMF_TONE_WHEN_DIALING,
- SystemSettingsProto.DTMF_TONE_WHEN_DIALING);
- dumpSetting(s, p,
- Settings.System.DTMF_TONE_TYPE_WHEN_DIALING,
- SystemSettingsProto.DTMF_TONE_TYPE_WHEN_DIALING);
- dumpSetting(s, p,
- Settings.System.HEARING_AID,
- SystemSettingsProto.HEARING_AID);
- dumpSetting(s, p,
- Settings.System.TTY_MODE,
- SystemSettingsProto.TTY_MODE);
- dumpSetting(s, p,
- Settings.System.RTT_CALLING_MODE,
- SystemSettingsProto.RTT_CALLING_MODE);
- dumpSetting(s, p,
- Settings.System.SOUND_EFFECTS_ENABLED,
- SystemSettingsProto.SOUND_EFFECTS_ENABLED);
- dumpSetting(s, p,
- Settings.System.HAPTIC_FEEDBACK_ENABLED,
- SystemSettingsProto.HAPTIC_FEEDBACK_ENABLED);
- // Settings.System.SHOW_WEB_SUGGESTIONS intentionally excluded since it's deprecated.
- dumpSetting(s, p,
- Settings.System.NOTIFICATION_LIGHT_PULSE,
- SystemSettingsProto.NOTIFICATION_LIGHT_PULSE);
- dumpSetting(s, p,
- Settings.System.POINTER_LOCATION,
- SystemSettingsProto.POINTER_LOCATION);
- dumpSetting(s, p,
- Settings.System.SHOW_TOUCHES,
- SystemSettingsProto.SHOW_TOUCHES);
- dumpSetting(s, p,
- Settings.System.WINDOW_ORIENTATION_LISTENER_LOG,
- SystemSettingsProto.WINDOW_ORIENTATION_LISTENER_LOG);
- // Settings.System.POWER_SOUNDS_ENABLED intentionally excluded since it's deprecated.
- // Settings.System.DOCK_SOUNDS_ENABLED intentionally excluded since it's deprecated.
- dumpSetting(s, p,
- Settings.System.LOCKSCREEN_SOUNDS_ENABLED,
- SystemSettingsProto.LOCKSCREEN_SOUNDS_ENABLED);
- dumpSetting(s, p,
- Settings.System.LOCKSCREEN_DISABLED,
- SystemSettingsProto.LOCKSCREEN_DISABLED);
- // Settings.System.LOW_BATTERY_SOUND intentionally excluded since it's deprecated.
- // Settings.System.DESK_DOCK_SOUND intentionally excluded since it's deprecated.
- // Settings.System.DESK_UNDOCK_SOUND intentionally excluded since it's deprecated.
- // Settings.System.CAR_DOCK_SOUND intentionally excluded since it's deprecated.
- // Settings.System.CAR_UNDOCK_SOUND intentionally excluded since it's deprecated.
- // Settings.System.LOCK_SOUND intentionally excluded since it's deprecated.
- // Settings.System.UNLOCK_SOUND intentionally excluded since it's deprecated.
- dumpSetting(s, p,
- Settings.System.SIP_RECEIVE_CALLS,
- SystemSettingsProto.SIP_RECEIVE_CALLS);
- dumpSetting(s, p,
- Settings.System.SIP_CALL_OPTIONS,
- SystemSettingsProto.SIP_CALL_OPTIONS);
- dumpSetting(s, p,
- Settings.System.SIP_ALWAYS,
- SystemSettingsProto.SIP_ALWAYS);
- dumpSetting(s, p,
- Settings.System.SIP_ADDRESS_ONLY,
- SystemSettingsProto.SIP_ADDRESS_ONLY);
- // Settings.System.SIP_ASK_ME_EACH_TIME intentionally excluded since it's deprecated.
- dumpSetting(s, p,
- Settings.System.POINTER_SPEED,
- SystemSettingsProto.POINTER_SPEED);
- dumpSetting(s, p,
- Settings.System.LOCK_TO_APP_ENABLED,
- SystemSettingsProto.LOCK_TO_APP_ENABLED);
- dumpSetting(s, p,
- Settings.System.EGG_MODE,
- SystemSettingsProto.EGG_MODE);
- dumpSetting(s, p,
- Settings.System.SHOW_BATTERY_PERCENT,
- SystemSettingsProto.SHOW_BATTERY_PERCENT);
- dumpSetting(s, p,
- Settings.System.WHEN_TO_MAKE_WIFI_CALLS,
- SystemSettingsProto.WHEN_TO_MAKE_WIFI_CALLS);
+
// The rest of the settings were moved to Settings.Secure, and are thus excluded here since
// they're deprecated from Settings.System.
- // Please insert new settings using the same order as in Settings.System.
-
+ // Please insert new settings using the same order as in SecureSettingsProto.
p.end(token);
+ // Please insert new settings using the same order as in SecureSettingsProto.
}
}
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 0076927..ed105ee 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -33,17 +33,18 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"চলিত"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"জাননীসমূহ"</string>
<string name="battery_low_title" msgid="6456385927409742437">"বেটাৰি কম আছে"</string>
- <!-- no translation found for battery_low_title_hybrid (6268991275887381595) -->
- <skip />
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> বাকী আছে"</string>
<!-- no translation found for battery_low_percent_format_hybrid (6838677459286775617) -->
<skip />
<!-- no translation found for battery_low_percent_format_hybrid_short (9025795469949145586) -->
<skip />
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> বাকী আছে। বেটাৰি সঞ্চয়কাৰী অন হৈ আছে।"</string>
- <string name="invalid_charger" msgid="4549105996740522523">"ইউএছবি চ্চার্জিং কৰিব পৰা নাযাব।\nআপোনাৰ ফ\'নৰ লগত দিয়া চ্চার্জাৰ ব্যৱহাৰ কৰক।"</string>
- <string name="invalid_charger_title" msgid="3515740382572798460">"ইউএছবি চ্চার্জিং সমৰ্থিত নহয়।"</string>
- <string name="invalid_charger_text" msgid="5474997287953892710">"কেৱল যোগান ধৰা চ্চার্জাৰ ব্যৱহাৰ কৰক।"</string>
+ <!-- no translation found for invalid_charger (2741987096648693172) -->
+ <skip />
+ <!-- no translation found for invalid_charger_title (2836102177577255404) -->
+ <skip />
+ <!-- no translation found for invalid_charger_text (6480624964117840005) -->
+ <skip />
<string name="battery_low_why" msgid="4553600287639198111">"ছেটিংসমূহ"</string>
<string name="battery_saver_confirmation_title" msgid="2052100465684817154">"বেটাৰি সঞ্চয়কাৰী অন কৰেনে?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"অন কৰক"</string>
@@ -69,8 +70,7 @@
<string name="usb_debugging_title" msgid="4513918393387141949">"ইউএছবি ডিবাগিংৰ অনুমতি দিবনে?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"এয়া হৈছে কম্পিউটাৰটোৰ RSA কী ফিংগাৰপ্ৰিণ্ট:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"এই কম্পিউটাৰটোৰ পৰা সদায় অনুমতি দিয়ক"</string>
- <!-- no translation found for usb_debugging_secondary_user_title (6353808721761220421) -->
- <skip />
+ <string name="usb_debugging_secondary_user_title" msgid="6353808721761220421">"ইউএছবি ডিবাগিঙৰ অনুমতি নাই"</string>
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"এই ডিভাইচটোত বর্তমান ছাইন ইন হৈ থকা ব্যৱহাৰকাৰীজনে ইউএছবি ডিবাগিং অন কৰিব নোৱাৰে। এই সুবিধাটো ব্যৱহাৰ কৰিবলৈ হ\'লে মুখ্য ব্যৱহাৰকাৰী হিচাপে ছাইন ইন কৰক।"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"স্ক্ৰীণ পূর্ণ কৰিবলৈ জুম কৰক"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"স্ক্ৰীণ পূর্ণ কৰিবলৈ প্ৰসাৰিত কৰক"</string>
@@ -78,15 +78,13 @@
<skip />
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"স্ক্ৰীণশ্বট ছেভ কৰি থকা হৈছে…"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"স্ক্ৰীণশ্বট ছেভ কৰি থকা হৈছে…"</string>
- <!-- no translation found for screenshot_saving_text (2545047868936087248) -->
- <skip />
<!-- no translation found for screenshot_saved_title (5637073968117370753) -->
<skip />
<!-- no translation found for screenshot_saved_text (7574667448002050363) -->
<skip />
- <!-- no translation found for screenshot_failed_title (9096484883063264803) -->
+ <!-- no translation found for screenshot_failed_title (7612509838919089748) -->
<skip />
- <!-- no translation found for screenshot_failed_to_save_unknown_text (8844781948876286488) -->
+ <!-- no translation found for screenshot_failed_to_save_unknown_text (3637758096565605541) -->
<skip />
<!-- no translation found for screenshot_failed_to_save_text (3041612585107107310) -->
<skip />
@@ -105,18 +103,15 @@
<string name="accessibility_search_light" msgid="1103867596330271848">"সন্ধান কৰক"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"কেমেৰা"</string>
<string name="accessibility_phone_button" msgid="6738112589538563574">"ফ\'ন"</string>
- <!-- no translation found for accessibility_voice_assist_button (487611083884852965) -->
- <skip />
+ <string name="accessibility_voice_assist_button" msgid="487611083884852965">"কণ্ঠধ্বনিৰে সহায়"</string>
<string name="accessibility_unlock_button" msgid="128158454631118828">"আনলক কৰক"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="4808860050517462885">"ফিংগাৰপ্ৰিণ্টৰ বাবে ৰৈ থকা হৈছে"</string>
<string name="accessibility_unlock_without_fingerprint" msgid="7541705575183694446">"ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ নকৰাকৈ আনলক কৰক"</string>
<string name="unlock_label" msgid="8779712358041029439">"আনলক কৰক"</string>
<string name="phone_label" msgid="2320074140205331708">"ফ\'ন খোলক"</string>
- <!-- no translation found for voice_assist_label (3956854378310019854) -->
- <skip />
+ <string name="voice_assist_label" msgid="3956854378310019854">"কণ্ঠধ্বনিৰে সহায় খোলক"</string>
<string name="camera_label" msgid="7261107956054836961">"কেমেৰা খোলক"</string>
- <!-- no translation found for recents_caption_resize (3517056471774958200) -->
- <skip />
+ <string name="recents_caption_resize" msgid="3517056471774958200">"নতুন কাৰ্যৰ চানেকি বাছনি কৰক"</string>
<string name="cancel" msgid="6442560571259935130">"বাতিল কৰক"</string>
<!-- no translation found for fingerprint_dialog_touch_sensor (8511557690663181761) -->
<skip />
@@ -153,10 +148,8 @@
<string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"WiMAXৰ দুডাল দণ্ড আছে।"</string>
<string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"WiMAXৰ তিনিডাল দণ্ড আছে।"</string>
<string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"WiMAXৰ ছিগনেল পূৰা আছে৷"</string>
- <!-- no translation found for accessibility_ethernet_disconnected (5896059303377589469) -->
- <skip />
- <!-- no translation found for accessibility_ethernet_connected (2692130313069182636) -->
- <skip />
+ <string name="accessibility_ethernet_disconnected" msgid="5896059303377589469">"ইথাৰনেট সংযোগ বিচ্ছিন্ন হৈছে।"</string>
+ <string name="accessibility_ethernet_connected" msgid="2692130313069182636">"ইথাৰনেট সংযোগ হৈছে।"</string>
<string name="accessibility_no_signal" msgid="7064645320782585167">"কোনো ছিগনেল নাই।"</string>
<string name="accessibility_not_connected" msgid="6395326276213402883">"সংযোগ হৈ থকা নাই।"</string>
<string name="accessibility_zero_bars" msgid="3806060224467027887">"এডালো দণ্ড নাই।"</string>
@@ -168,28 +161,41 @@
<string name="accessibility_desc_off" msgid="6475508157786853157">"অফ।"</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"সংযোগ কৰা হ’ল।"</string>
<string name="accessibility_desc_connecting" msgid="3812924520316280149">"সংযোগ কৰি থকা হৈছে।"</string>
- <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"জিপিআৰএছ"</string>
- <string name="accessibility_data_connection_1x" msgid="994133468120244018">"১ X"</string>
- <string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
- <string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string>
- <string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3.5G"</string>
- <string name="accessibility_data_connection_4g" msgid="7741000750630089612">"4G"</string>
- <string name="accessibility_data_connection_4g_plus" msgid="3032226872470658661">"4G+"</string>
- <string name="accessibility_data_connection_lte" msgid="5413468808637540658">"এলটিই"</string>
- <string name="accessibility_data_connection_lte_plus" msgid="361876866906946007">"LTE+"</string>
- <string name="accessibility_data_connection_cdma" msgid="6132648193978823023">"CDMA"</string>
- <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"ৰ\'মিং"</string>
- <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string>
+ <!-- no translation found for data_connection_gprs (7652872568358508452) -->
+ <skip />
+ <!-- no translation found for data_connection_hspa (1499615426569473562) -->
+ <skip />
+ <!-- no translation found for data_connection_3g (503045449315378373) -->
+ <skip />
+ <!-- no translation found for data_connection_3_5g (5218328297191657602) -->
+ <skip />
+ <!-- no translation found for data_connection_3_5g_plus (7570783890290275297) -->
+ <skip />
+ <!-- no translation found for data_connection_4g (9139963475267449144) -->
+ <skip />
+ <!-- no translation found for data_connection_4g_plus (1148687201877800700) -->
+ <skip />
+ <!-- no translation found for data_connection_lte (2694876797724028614) -->
+ <skip />
+ <!-- no translation found for data_connection_lte_plus (3423013208570937424) -->
+ <skip />
+ <!-- no translation found for data_connection_cdma (4677985502159869585) -->
+ <skip />
+ <!-- no translation found for data_connection_roaming (6037232010953697354) -->
+ <skip />
+ <!-- no translation found for data_connection_edge (871835227939216682) -->
+ <skip />
<string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"ৱাই-ফাই"</string>
<string name="accessibility_no_sim" msgid="8274017118472455155">"ছিম নাই।"</string>
<string name="accessibility_cell_data" msgid="5326139158682385073">"ম\'বাইল ডেটা"</string>
<string name="accessibility_cell_data_on" msgid="5927098403452994422">"ম\'বাইল ডেটা অন অৱস্থাত আছে"</string>
- <string name="accessibility_cell_data_off" msgid="443267573897409704">"ম\'বাইল ডেটা অফ অৱস্থাত আছে"</string>
+ <!-- no translation found for cell_data_off (5287705247512911922) -->
+ <skip />
<string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"ব্লুটুথ টেডাৰিং।"</string>
<string name="accessibility_airplane_mode" msgid="834748999790763092">"এয়াৰপ্লেইন ম\'ড।"</string>
<string name="accessibility_vpn_on" msgid="5993385083262856059">"ভিপিএন অন অৱস্থাত আছে।"</string>
<string name="accessibility_no_sims" msgid="3957997018324995781">"কোনো ছিম কাৰ্ড নাই"</string>
- <!-- no translation found for accessibility_carrier_network_change_mode (4017301580441304305) -->
+ <!-- no translation found for carrier_network_change_mode (8149202439957837762) -->
<skip />
<string name="accessibility_battery_details" msgid="7645516654955025422">"বেটাৰিৰ বিৱৰণসমূহ খোলক"</string>
<string name="accessibility_battery_level" msgid="7451474187113371965">"<xliff:g id="NUMBER">%d</xliff:g> শতাংশ বেটাৰি।"</string>
@@ -209,8 +215,7 @@
<skip />
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>ক আঁতৰাব।"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> আঁতৰোৱা হৈছে৷"</string>
- <!-- no translation found for accessibility_recents_all_items_dismissed (4464697366179168836) -->
- <skip />
+ <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"শেহতীয়া সকলো এপ্লিকেশ্বন অগ্ৰাহ্য কৰা হৈছে।"</string>
<string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> এপ্লিকেশ্বনৰ তথ্য় খোলক।"</string>
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> আৰম্ভ কৰা হৈছে।"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"জাননী অগ্ৰাহ্য কৰা হৈছে।"</string>
@@ -220,8 +225,7 @@
<string name="accessibility_desc_settings" msgid="3417884241751434521">"ছেটিংসমূহ"</string>
<string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"অৱলোকন।"</string>
<string name="accessibility_desc_work_lock" msgid="4288774420752813383">"কৰ্মস্থানৰ প্ৰ\'ফাইলৰ লক স্ক্ৰীণ"</string>
- <!-- no translation found for accessibility_desc_close (7479755364962766729) -->
- <skip />
+ <string name="accessibility_desc_close" msgid="7479755364962766729">"বন্ধ কৰক"</string>
<string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
<string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"ৱাই-ফাই অফ কৰা হ\'ল।"</string>
<string name="accessibility_quick_settings_wifi_changed_on" msgid="6440117170789528622">"ৱাই-ফাই অন কৰা হ\'ল।"</string>
@@ -231,19 +235,14 @@
<string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"এয়াৰপ্লেইন ম\'ড অন হৈ আছে৷"</string>
<string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"এয়াৰপ্লেইন ম\'ড অফ কৰা হ\'ল।"</string>
<string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"এয়াৰপ্লেইন ম\'ড অন কৰা হ\'ল।"</string>
- <!-- no translation found for accessibility_quick_settings_dnd_priority_on (1448402297221249355) -->
+ <!-- no translation found for accessibility_quick_settings_dnd_priority_on (5836205286254617194) -->
<skip />
- <!-- no translation found for accessibility_quick_settings_dnd_none_on (6882582132662613537) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_dnd_alarms_on (9152834845587554157) -->
- <skip />
+ <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"অসুবিধা নিদিব অন হৈ আছে, সম্পূর্ণ নিৰৱতা।"</string>
+ <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"অসুবিধা নিদিব অন হৈ আছে, মাত্ৰ এলাৰ্মসমূহ বাজিব।"</string>
<string name="accessibility_quick_settings_dnd" msgid="6607873236717185815">"অসুবিধা নিদিব।"</string>
- <!-- no translation found for accessibility_quick_settings_dnd_off (2371832603753738581) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_dnd_changed_off (898107593453022935) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_dnd_changed_on (4483780856613561039) -->
- <skip />
+ <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"অসুবিধা নিদিব বন্ধ হৈ আছে।"</string>
+ <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"অসুবিধা নিদিব বন্ধ কৰা হ\'ল।"</string>
+ <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"অসুবিধা নিদিব অন কৰা হৈছে।"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="6341675755803320038">"ব্লুটুথ।"</string>
<string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"ব্লুটুথ অফ হৈ আছে।"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"ব্লুটুথ অন হৈ আছে।"</string>
@@ -277,16 +276,12 @@
<string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"ডেটা সঞ্চয়কাৰী সুবিধা অন কৰা হ\'ল।"</string>
<string name="accessibility_brightness" msgid="8003681285547803095">"ডিছপ্লেৰ উজ্জ্বলতা"</string>
<string name="accessibility_ambient_display_charging" msgid="9084521679384069087">"চ্চার্জ কৰি থকা হৈছে"</string>
- <!-- no translation found for data_usage_disabled_dialog_3g_title (5281770593459841889) -->
- <skip />
- <!-- no translation found for data_usage_disabled_dialog_4g_title (1601769736881078016) -->
- <skip />
+ <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ডেটা পজ কৰা হৈছে"</string>
+ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ডেটা পজ কৰা হৈছে"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="6801382439018099779">"ম\'বাইল ডেটা পজ কৰা হৈছে"</string>
- <!-- no translation found for data_usage_disabled_dialog_title (3932437232199671967) -->
- <skip />
+ <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ডেটা পজ কৰা হৈছে"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"আপুনি নির্ধাৰণ কৰা ডেটাৰ সীমা শেষ হৈছে। আপুনি এতিয়া ম\'বাইল ডেটা ব্যৱহাৰ কৰিব নোৱাৰে। \n\nযদিহে আপুনি আকৌ ম\'বাইল ডেটা ব্যৱহাৰ কৰে তেন্তে ডেটাৰ ব্যৱহাৰৰ বাবে মাচুল ভৰিবলগীয়া হ\'ব পাৰে।"</string>
- <!-- no translation found for data_usage_disabled_dialog_enable (1412395410306390593) -->
- <skip />
+ <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"পুনৰ আৰম্ভ কৰক"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"জিপিএছ সন্ধান কৰি থকা হৈছে"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"জিপিএছএ অৱস্থান ছেট কৰিছে"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"অৱস্থানৰ অনুৰোধ সক্ৰিয় হৈ আছে"</string>
@@ -307,16 +302,12 @@
<string name="dessert_case" msgid="1295161776223959221">"মিষ্টান্ন ভাণ্ডাৰ"</string>
<string name="start_dreams" msgid="5640361424498338327">"স্ক্ৰীণ ছেভাৰ"</string>
<string name="ethernet_label" msgid="7967563676324087464">"ইথাৰনেট"</string>
- <!-- no translation found for quick_settings_header_onboarding_text (7872508260264044734) -->
+ <!-- no translation found for quick_settings_header_onboarding_text (8030309023792936283) -->
<skip />
- <!-- no translation found for quick_settings_dnd_label (8735855737575028208) -->
- <skip />
- <!-- no translation found for quick_settings_dnd_priority_label (483232950670692036) -->
- <skip />
- <!-- no translation found for quick_settings_dnd_alarms_label (2559229444312445858) -->
- <skip />
- <!-- no translation found for quick_settings_dnd_none_label (5025477807123029478) -->
- <skip />
+ <string name="quick_settings_dnd_label" msgid="8735855737575028208">"অসুবিধা নিদিব"</string>
+ <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"কেৱল গুৰুত্বপূৰ্ণ"</string>
+ <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"কেৱল এলাৰ্মসমূহ"</string>
+ <string name="quick_settings_dnd_none_label" msgid="5025477807123029478">"সম্পূর্ণ নিৰৱতা"</string>
<string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ব্লুটুথ"</string>
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ব্লুটুথ (<xliff:g id="NUMBER">%d</xliff:g>টা ডিভাইচ)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ব্লুটুথ বন্ধ অৱস্থাত আছে"</string>
@@ -354,12 +345,10 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"নেটৱৰ্ক নাই"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"ৱাই-ফাই অফ"</string>
<string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"ৱাই-ফাই অন হৈ আছে"</string>
- <!-- no translation found for quick_settings_wifi_detail_empty_text (269990350383909226) -->
- <skip />
+ <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"কোনো ৱাই-ফাই নেটৱৰ্ক নাই"</string>
<!-- no translation found for quick_settings_wifi_secondary_label_transient (7748206246119760554) -->
<skip />
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"কাষ্ট"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"কাষ্টিং"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"নাম নথকা ডিভাইচ"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"কাষ্টৰ বাবে সাজু"</string>
@@ -377,6 +366,8 @@
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"হটস্পট"</string>
<!-- no translation found for quick_settings_hotspot_secondary_label_transient (8010579363691405477) -->
<skip />
+ <!-- no translation found for quick_settings_hotspot_secondary_label_data_saver_enabled (5672131949987422420) -->
+ <skip />
<!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"জাননীসমূহ"</string>
<string name="quick_settings_flashlight_label" msgid="2133093497691661546">"ফ্লাশ্বলাইট"</string>
@@ -396,7 +387,7 @@
<skip />
<!-- no translation found for quick_settings_night_secondary_label_on_at (6256314040368487637) -->
<skip />
- <!-- no translation found for quick_settings_night_secondary_label_until (8664820079774824618) -->
+ <!-- no translation found for quick_settings_secondary_label_until (2749196569462600150) -->
<skip />
<string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC নিষ্ক্ৰিয় হৈ আছে"</string>
@@ -410,12 +401,9 @@
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g>টো সুৰক্ষিত ম\'ডত অক্ষম কৰা হ\'ল।"</string>
<string name="recents_stack_action_button_label" msgid="6593727103310426253">"সকলো মচক"</string>
<string name="recents_drag_hint_message" msgid="2649739267073203985">"বিভাজিত স্ক্ৰীণ ব্য়ৱহাৰ কৰিবলৈ ইয়ালৈ টানি আনি এৰক"</string>
- <!-- no translation found for recents_multistack_add_stack_dialog_split_horizontal (8848514474543427332) -->
- <skip />
- <!-- no translation found for recents_multistack_add_stack_dialog_split_vertical (9075292233696180813) -->
- <skip />
- <!-- no translation found for recents_multistack_add_stack_dialog_split_custom (4177837597513701943) -->
- <skip />
+ <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"আনুভূমিকভাৱে বিভাজিত কৰক"</string>
+ <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"উলম্বভাৱে বিভাজিত কৰক"</string>
+ <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"উপযোগিতা অনুসৰি বিভাজিত কৰক"</string>
<string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"স্ক্ৰীণখনক ওপৰফাললৈ ভাগ কৰক"</string>
<string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"স্ক্ৰীণখনক বাওঁফাললৈ ভাগ কৰক"</string>
<string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"স্ক্ৰীণখনক সোঁফাললৈ ভাগ কৰক"</string>
@@ -429,8 +417,7 @@
<string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>ৰ বাবে বাওঁফাললৈ শ্লাইড কৰক।"</string>
<string name="zen_priority_introduction" msgid="1149025108714420281">"আপুনি নিৰ্দিষ্ট কৰা এলাৰ্ম, ৰিমাইণ্ডাৰ, ইভেন্ট আৰু কল কৰোঁতাৰ বাহিৰে আন কোনো শব্দৰ পৰা আপুনি অসুবিধা নাপাব। কিন্তু, সংগীত, ভিডিঅ\' আৰু খেলসমূহকে ধৰি আপুনি প্লে কৰিব খোজা যিকোনো বস্তু তথাপি শুনিব পাৰিব।"</string>
<string name="zen_alarms_introduction" msgid="4934328096749380201">"আপুনি নিৰ্দিষ্ট কৰা এলাৰ্মৰ বাহিৰে আন কোনো ধ্বনি আৰু কম্পনৰ পৰা আপুনি অসুবিধা নাপাব। কিন্তু, সংগীত, ভিডিঅ\' আৰু খেলসমূহকে ধৰি আপুনি প্লে কৰিব খোজা যিকোনো বস্তু তথাপি শুনিব পাৰিব।"</string>
- <!-- no translation found for zen_priority_customize_button (7948043278226955063) -->
- <skip />
+ <string name="zen_priority_customize_button" msgid="7948043278226955063">"নিজৰ উপযোগিতা অনুসৰি"</string>
<string name="zen_silence_introduction_voice" msgid="3948778066295728085">"এই কার্যই এলার্ম, সংগীত, ভিডিঅ\' আৰু খেলসমূহকে ধৰি সকলোৰে বাবে ধ্বনি আৰু কম্পন অৱৰোধ কৰিব। আপুনি ফ\'ন কল তথাপি কৰিবলৈ সক্ষম হ\'ব।"</string>
<string name="zen_silence_introduction" msgid="3137882381093271568">"এই কার্যই এলার্ম, মিউজিক, ভিডিঅ\' আৰু গেইমকে ধৰি সকলোৰে ধ্বনি আৰু কম্পন অৱৰোধ কৰে।"</string>
<string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
@@ -439,25 +426,16 @@
<string name="keyguard_unlock" msgid="8043466894212841998">"আনলক কৰিবলৈ ওপৰলৈ ছোৱাইপ কৰক"</string>
<string name="do_disclosure_generic" msgid="5615898451805157556">"আপোনাৰ প্ৰতিষ্ঠানে এই ডিভাইচটো পৰিচালনা কৰে"</string>
<string name="do_disclosure_with_name" msgid="5640615509915445501">"এই ডিভাইচটো <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>ৰ দ্বাৰা পৰিচালিত।"</string>
- <!-- no translation found for phone_hint (4872890986869209950) -->
- <skip />
- <!-- no translation found for voice_hint (8939888732119726665) -->
- <skip />
- <!-- no translation found for camera_hint (7939688436797157483) -->
- <skip />
+ <string name="phone_hint" msgid="4872890986869209950">"ফ\'নৰ বাবে আইকনৰপৰা ছোৱাইপ কৰক"</string>
+ <string name="voice_hint" msgid="8939888732119726665">"কণ্ঠধ্বনিৰে সহায়ৰ বাবে আইকনৰ পৰা ছোৱাইপ কৰক"</string>
+ <string name="camera_hint" msgid="7939688436797157483">"কেমেৰা খুলিবলৈ আইকনৰপৰা ছোৱাইপ কৰক"</string>
<string name="interruption_level_none_with_warning" msgid="5114872171614161084">"সম্পূর্ণ নিৰৱতা। এই কার্যই স্ক্ৰীণ ৰীডাৰসমূহকো নিৰৱ কৰিব।"</string>
- <!-- no translation found for interruption_level_none (6000083681244492992) -->
- <skip />
- <!-- no translation found for interruption_level_priority (6426766465363855505) -->
- <skip />
- <!-- no translation found for interruption_level_alarms (5226306993448328896) -->
- <skip />
- <!-- no translation found for interruption_level_none_twoline (3957581548190765889) -->
- <skip />
- <!-- no translation found for interruption_level_priority_twoline (1564715335217164124) -->
- <skip />
- <!-- no translation found for interruption_level_alarms_twoline (3266909566410106146) -->
- <skip />
+ <string name="interruption_level_none" msgid="6000083681244492992">"সম্পূর্ণ নিৰৱতা"</string>
+ <string name="interruption_level_priority" msgid="6426766465363855505">"কেৱল গুৰুত্বপূৰ্ণ"</string>
+ <string name="interruption_level_alarms" msgid="5226306993448328896">"কেৱল এলাৰ্মসমূহ"</string>
+ <string name="interruption_level_none_twoline" msgid="3957581548190765889">"সম্পূর্ণ \n নিৰৱতা"</string>
+ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"কেৱল\nগুৰুত্বপূৰ্ণ"</string>
+ <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"কেৱল\nএলাৰ্মসমূহ"</string>
<!-- no translation found for keyguard_indication_charging_time (2056340799276374421) -->
<skip />
<!-- no translation found for keyguard_indication_charging_time_fast (7767562163577492332) -->
@@ -480,11 +458,9 @@
<string name="guest_wipe_session_message" msgid="8476238178270112811">"আপুনি আপোনাৰ ছেশ্বন অব্যাহত ৰাখিব বিচাৰেনে?"</string>
<string name="guest_wipe_session_wipe" msgid="5065558566939858884">"আকৌ আৰম্ভ কৰক"</string>
<string name="guest_wipe_session_dontwipe" msgid="1401113462524894716">"হয়, অব্যাহত ৰাখক"</string>
- <!-- no translation found for guest_notification_title (1585278533840603063) -->
- <skip />
+ <string name="guest_notification_title" msgid="1585278533840603063">"অতিথি ব্য়ৱহাৰকাৰী"</string>
<string name="guest_notification_text" msgid="335747957734796689">"এপসমূহ আৰু ডেটা মচিবলৈ অতিথি ব্যৱহাৰকাৰীক আঁতৰাওক"</string>
- <!-- no translation found for guest_notification_remove_action (8820670703892101990) -->
- <skip />
+ <string name="guest_notification_remove_action" msgid="8820670703892101990">"অতিথি আঁতৰাওক"</string>
<string name="user_logout_notification_title" msgid="1453960926437240727">"ব্যৱহাৰকাৰীক লগ আউট কৰক"</string>
<string name="user_logout_notification_text" msgid="3350262809611876284">"বর্তমানৰ ব্যৱহাৰকাৰীক লগ আউট কৰক"</string>
<string name="user_logout_notification_action" msgid="1195428991423425062">"ব্যৱহাৰকাৰীক লগ আউট কৰক"</string>
@@ -499,6 +475,10 @@
<string name="media_projection_dialog_text" msgid="3071431025448218928">"আপোনাৰ স্ক্ৰীণত প্ৰদৰ্শন হোৱা সকলো <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> কেপশ্বাৰ কৰা আৰম্ভ কৰিব।"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"পুনৰাই নেদেখুৱাব"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"সকলো মচক"</string>
+ <!-- no translation found for manage_notifications_text (8035284146227267681) -->
+ <skip />
+ <!-- no translation found for dnd_suppressing_shade_text (7986451830430707907) -->
+ <skip />
<string name="media_projection_action_text" msgid="8470872969457985954">"এতিয়াই আৰম্ভ কৰক"</string>
<string name="empty_shade_text" msgid="708135716272867002">"কোনো জাননী নাই"</string>
<string name="profile_owned_footer" msgid="8021888108553696069">"প্ৰ\'ফাইল নিৰীক্ষণ কৰা হ\'ব পাৰে"</string>
@@ -549,11 +529,9 @@
<string name="monitoring_description_ca_cert_settings_separator" msgid="4987350385906393626">" "</string>
<string name="monitoring_description_ca_cert_settings" msgid="5489969458872997092">"বিশ্বাসী পৰিচয়-পত্ৰসমূহ খোলক"</string>
<string name="monitoring_description_network_logging" msgid="7223505523384076027">"আপোনাৰ প্ৰশাসকে নেটৱৰ্ক লগিং অন কৰিছে, যিয়ে আপোনাৰ ডিভাইচটোত নেটৱৰ্ক ট্ৰেফিক পৰ্যবেক্ষণ কৰে।\n\nএই সম্পৰ্কে অধিক জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক।"</string>
- <!-- no translation found for monitoring_description_vpn (4445150119515393526) -->
- <skip />
+ <string name="monitoring_description_vpn" msgid="4445150119515393526">"আপুনি এটা এপক ভিপিএন সংযোগ ছেট আপ কৰিবলৈ অনুমতি দিছে। \n\n এই এপটোৱে ইমেইল, এপ্ আৰু ৱেবছাইটকে ধৰি আপোনাৰ নেটৱর্কৰ কাৰ্যকলাপ পৰ্যবেক্ষণ কৰিব পাৰে।"</string>
<string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"<xliff:g id="ORGANIZATION">%1$s</xliff:g>য়ে আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইল পৰিচালনা কৰে।\n\nআপোনাৰ প্ৰশাসকে ইমেইল, এপসমূহ আৰু আপুনি চোৱা ৱেবছাইটকে ধৰি আপোনাৰ নেটৱৰ্কৰ সকলো কাৰ্যকলাপ পৰ্যবেক্ষণ কৰিব পাৰে। \n\nঅধিক তথ্যৰ বাবে আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক।\n\nইয়াৰ উপৰি, আপুনি এটা ভিপিএনৰ সৈতে সংযুক্ত হৈ আছে, যিয়ে আপোনাৰ নেটৱৰ্কৰ কাৰ্যকলাপ পৰ্যবেক্ষণ কৰিব পাৰে।"</string>
- <!-- no translation found for legacy_vpn_name (6604123105765737830) -->
- <skip />
+ <string name="legacy_vpn_name" msgid="6604123105765737830">"ভিপিএন"</string>
<string name="monitoring_description_app" msgid="1828472472674709532">"আপুনি <xliff:g id="APPLICATION">%1$s</xliff:g>ৰে সংযুক্ত হৈ আছে যিয়ে আপোনাৰ ইমেইল, এপ্ আৰু ৱেবছাইটকে ধৰি নেটৱর্কৰ কাৰ্যকলাপ পৰ্যবেক্ষণ কৰিব পাৰে।"</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"আপুনি <xliff:g id="APPLICATION">%1$s</xliff:g>ৰে সংযুক্ত হৈ আছে, যি ইমেইল, এপ্ আৰু ৱেবছাইটসমূহকে ধৰি আপোনাৰ ব্যক্তিগত নেটৱর্কৰ কাৰ্যকলাপ নিৰীক্ষণ কৰিব পাৰে।"</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"আপুনি <xliff:g id="APPLICATION">%1$s</xliff:g>ৰ সৈতে সংযুক্ত হৈ আছে, যিয়ে ইমেইল, এপ্ আৰু ৱেবছাইটসমূহকে সামৰি আপোনাৰ ব্যক্তিগত নেটৱর্কৰ কার্যকলাপ নিৰীক্ষণ কৰিব পাৰে।"</string>
@@ -568,10 +546,10 @@
<string name="hidden_notifications_setup" msgid="41079514801976810">"ছেট আপ কৰক"</string>
<string name="zen_mode_and_condition" msgid="4462471036429759903">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="volume_zen_end_now" msgid="6930243045593601084">"এতিয়া অফ কৰক"</string>
- <!-- no translation found for accessibility_volume_expand (5946812790999244205) -->
+ <!-- no translation found for accessibility_volume_settings (4915364006817819212) -->
<skip />
- <!-- no translation found for accessibility_volume_collapse (3609549593031810875) -->
- <skip />
+ <string name="accessibility_volume_expand" msgid="5946812790999244205">"সম্প্ৰসাৰণ কৰক"</string>
+ <string name="accessibility_volume_collapse" msgid="3609549593031810875">"সংকুচিত কৰক"</string>
<!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
<skip />
<string name="screen_pinning_title" msgid="3273740381976175811">"স্ক্ৰীণ পিন কৰা হ\'ল"</string>
@@ -615,10 +593,6 @@
<string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s। মিউট কৰিবলৈ টিপক।"</string>
<!-- no translation found for volume_dialog_title (7272969888820035876) -->
<skip />
- <!-- no translation found for volume_dialog_ringer_guidance_vibrate (8902050240801159042) -->
- <skip />
- <!-- no translation found for volume_dialog_ringer_guidance_silent (2128975224280276122) -->
- <skip />
<!-- no translation found for volume_dialog_ringer_guidance_ring (6144469689490528338) -->
<skip />
<string name="output_title" msgid="5355078100792942802">"মিডিয়া আউটপুট"</string>
@@ -629,44 +603,26 @@
<string name="output_service_wifi" msgid="3749735218931825054">"ৱাই-ফাই"</string>
<string name="output_service_bt_wifi" msgid="4486837869988770896">"ব্লুটুথ আৰু ৱাই-ফাই"</string>
<string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
- <!-- no translation found for show_battery_percentage (5444136600512968798) -->
- <skip />
- <!-- no translation found for show_battery_percentage_summary (3215025775576786037) -->
- <skip />
- <!-- no translation found for quick_settings (10042998191725428) -->
- <skip />
- <!-- no translation found for status_bar (4877645476959324760) -->
- <skip />
+ <string name="show_battery_percentage" msgid="5444136600512968798">"সংযুক্ত বেটাৰিৰ কিমান শতাংশ বাকী আছে দেখুওৱাক"</string>
+ <string name="show_battery_percentage_summary" msgid="3215025775576786037">"চাৰ্জ হৈ নথকা অৱস্থাত বেটাৰি কিমান শতাংশ বাকী স্থিতি দণ্ডৰ ভিতৰত দেখুৱাওক"</string>
+ <string name="quick_settings" msgid="10042998191725428">"ক্ষিপ্ৰ ছেটিংসমূহ"</string>
+ <string name="status_bar" msgid="4877645476959324760">"স্থিতি দণ্ড"</string>
<string name="overview" msgid="4018602013895926956">"অৱলোকন"</string>
<string name="demo_mode" msgid="2532177350215638026">"ছিষ্টেমৰ UI প্ৰদৰ্শন ম\'ড"</string>
- <!-- no translation found for enable_demo_mode (4844205668718636518) -->
- <skip />
- <!-- no translation found for show_demo_mode (2018336697782464029) -->
- <skip />
- <!-- no translation found for status_bar_ethernet (5044290963549500128) -->
- <skip />
- <!-- no translation found for status_bar_alarm (8536256753575881818) -->
- <skip />
- <!-- no translation found for status_bar_work (6022553324802866373) -->
- <skip />
- <!-- no translation found for status_bar_airplane (7057575501472249002) -->
- <skip />
- <!-- no translation found for add_tile (2995389510240786221) -->
- <skip />
- <!-- no translation found for broadcast_tile (3894036511763289383) -->
- <skip />
- <!-- no translation found for zen_alarm_warning_indef (3482966345578319605) -->
- <skip />
- <!-- no translation found for zen_alarm_warning (444533119582244293) -->
- <skip />
- <!-- no translation found for alarm_template (3980063409350522735) -->
- <skip />
- <!-- no translation found for alarm_template_far (4242179982586714810) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_detail (2579369091672902101) -->
- <skip />
- <!-- no translation found for accessibility_status_bar_hotspot (4099381329956402865) -->
- <skip />
+ <string name="enable_demo_mode" msgid="4844205668718636518">"ডেম\' ম\'ড সক্ষম কৰক"</string>
+ <string name="show_demo_mode" msgid="2018336697782464029">"ডেম\' ম\'ড দেখুৱাওক"</string>
+ <string name="status_bar_ethernet" msgid="5044290963549500128">"ইথাৰনেট"</string>
+ <string name="status_bar_alarm" msgid="8536256753575881818">"এলাৰ্ম"</string>
+ <string name="status_bar_work" msgid="6022553324802866373">"কৰ্মস্থানৰ প্ৰ\'ফাইল"</string>
+ <string name="status_bar_airplane" msgid="7057575501472249002">"এয়াৰপ্লেইন ম\'ড"</string>
+ <string name="add_tile" msgid="2995389510240786221">"টাইল যোগ দিয়ক"</string>
+ <string name="broadcast_tile" msgid="3894036511763289383">"সম্প্ৰচাৰ টাইল"</string>
+ <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"আপুনি আপোনাৰ পিছৰটো এলাৰ্ম <xliff:g id="WHEN">%1$s</xliff:g> বজাত শুনা নাপাব যদিহে তাৰ আগতে আপুনি এইটো অফ নকৰে"</string>
+ <string name="zen_alarm_warning" msgid="444533119582244293">"আপুনি আপোনাৰ পিছৰটো এলাৰ্ম <xliff:g id="WHEN">%1$s</xliff:g> বজাত শুনা নাপাব"</string>
+ <string name="alarm_template" msgid="3980063409350522735">"<xliff:g id="WHEN">%1$s</xliff:g> বজাত"</string>
+ <string name="alarm_template_far" msgid="4242179982586714810">"<xliff:g id="WHEN">%1$s</xliff:g> বজাত"</string>
+ <string name="accessibility_quick_settings_detail" msgid="2579369091672902101">"ক্ষিপ্ৰ ছেটিংসমূহ, <xliff:g id="TITLE">%s</xliff:g>।"</string>
+ <string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"হটস্পট"</string>
<string name="accessibility_managed_profile" msgid="6613641363112584120">"কৰ্মস্থানৰ প্ৰ\'ফাইল"</string>
<string name="tuner_warning_title" msgid="7094689930793031682">"কিছুমানৰ বাবে আমোদজনক হয় কিন্তু সকলোৰে বাবে নহয়"</string>
<string name="tuner_warning" msgid="8730648121973575701">"System UI Tunerএ আপোনাক Android ব্যৱহাৰকাৰী ইণ্টাৰফেইচ সলনি কৰিবলৈ আৰু নিজৰ উপযোগিতা অনুসৰি ব্যৱহাৰ কৰিবলৈ অতিৰিক্ত সুবিধা প্ৰদান কৰে। এই পৰীক্ষামূলক সুবিধাসমূহ সলনি হ\'ব পাৰে, সেইবোৰে কাম নকৰিব পাৰে বা আগন্তুক সংস্কৰণসমূহত সেইবোৰ অন্তৰ্ভুক্ত কৰা নহ\'ব পাৰে। সাৱধানেৰে আগবাঢ়ক।"</string>
@@ -695,6 +651,8 @@
<string name="notification_header_default_channel" msgid="7506845022070889909">"জাননীসমূহ"</string>
<!-- no translation found for notification_channel_disabled (344536703863700565) -->
<skip />
+ <!-- no translation found for notification_channel_minimized (1664411570378910931) -->
+ <skip />
<!-- no translation found for inline_blocking_helper (3055064577771478591) -->
<skip />
<!-- no translation found for inline_keep_showing (8945102997083836858) -->
@@ -703,10 +661,24 @@
<skip />
<!-- no translation found for inline_keep_button (6665940297019018232) -->
<skip />
+ <!-- no translation found for inline_minimize_button (966233327974702195) -->
+ <skip />
<!-- no translation found for inline_keep_showing_app (1723113469580031041) -->
<skip />
<!-- no translation found for notification_unblockable_desc (1037434112919403708) -->
<skip />
+ <!-- no translation found for notification_appops_camera_active (730959943016785931) -->
+ <skip />
+ <!-- no translation found for notification_appops_microphone_active (1546319728924580686) -->
+ <skip />
+ <!-- no translation found for notification_appops_overlay_active (633813008357934729) -->
+ <skip />
+ <!-- no translation found for notification_appops (1258122060887196817) -->
+ <!-- no translation found for notification_using (2211008461429037973) -->
+ <!-- no translation found for notification_appops_settings (1028328314935908050) -->
+ <skip />
+ <!-- no translation found for notification_appops_ok (602562195588819631) -->
+ <skip />
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ জাননী নিয়ন্ত্ৰণসমূহ খোলা অৱস্থাত আছে"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ জাননী নিয়ন্ত্ৰণসমূহ বন্ধ অৱস্থাত আছে"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"এই চ্চেনেলৰ পৰা জাননী দিবলৈ অনুমতি দিয়ক"</string>
@@ -719,6 +691,8 @@
<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">"জাননীৰ নিয়ন্ত্ৰণসমূহ"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"জাননীক স্নুজ কৰাৰ বিকল্পসমূহ"</string>
+ <!-- no translation found for notification_menu_snooze_action (1112254519029621372) -->
+ <skip />
<string name="snooze_undo" msgid="6074877317002985129">"আনডু কৰক"</string>
<string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g>ৰ বাবে স্নুজ কৰক"</string>
<plurals name="snoozeHourOptions" formatted="false" msgid="2124335842674413030">
@@ -811,8 +785,11 @@
<string name="right_keycode" msgid="708447961000848163">"সোঁ কীক\'ড"</string>
<string name="left_icon" msgid="3096287125959387541">"বাওঁ আইকন"</string>
<string name="right_icon" msgid="3952104823293824311">"সোঁ আইকন"</string>
- <string name="drag_to_add_tiles" msgid="7058945779098711293">"টাইল যোগ কৰিবৰ বাবে টানি আনি এৰক"</string>
+ <!-- no translation found for drag_to_add_tiles (230586591689084925) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"আঁতৰাবৰ বাবে টানি আনি ইয়াত এৰি দিয়ক"</string>
+ <!-- no translation found for drag_to_remove_disabled (2390968976638993382) -->
+ <skip />
<string name="qs_edit" msgid="2232596095725105230">"সম্পাদনা কৰক"</string>
<string name="tuner_time" msgid="6572217313285536011">"সময়"</string>
<string-array name="clock_options">
@@ -856,7 +833,8 @@
<string name="accessibility_quick_settings_collapse" msgid="1792625797142648105">"ক্ষিপ্ৰ ছেটিংসমূহ বন্ধ কৰক।"</string>
<string name="accessibility_quick_settings_alarm_set" msgid="1863000242431528676">"এলার্ম ছেট কৰা হ\'ল।"</string>
<string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> হিচাপে ছাইন ইন হ\'ল"</string>
- <string name="accessibility_quick_settings_no_internet" msgid="31890692343084075">"ইণ্টাৰনেট সংযোগ নাই।"</string>
+ <!-- no translation found for data_connection_no_internet (4503302451650972989) -->
+ <skip />
<string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"বিৱৰণসমূহ খোলক।"</string>
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g>ৰ ছেটিংসমূহ খোলক।"</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ছেটিংসমূহৰ ক্ৰম সম্পাদনা কৰক।"</string>
@@ -899,11 +877,15 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"স্ক্ৰীণশ্বটসমূহ"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"সাধাৰণ বার্তাসমূহ"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"সঞ্চয়াগাৰ"</string>
+ <!-- no translation found for notification_channel_hints (7323870212489152689) -->
+ <skip />
<string name="instant_apps" msgid="6647570248119804907">"তাৎক্ষণিক এপসমূহ"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"তাৎক্ষণিক এপসমূহক ইনষ্টল কৰাৰ প্ৰয়োজন নাই।"</string>
<string name="app_info" msgid="6856026610594615344">"এপ্ সম্পৰ্কীয় তথ্য"</string>
<string name="go_to_web" msgid="2650669128861626071">"ব্ৰাউজাৰলৈ যাওক"</string>
<string name="mobile_data" msgid="7094582042819250762">"ম\'বাইল ডেটা"</string>
+ <!-- no translation found for mobile_data_text_format (3526214522670876454) -->
+ <skip />
<string name="wifi_is_off" msgid="1838559392210456893">"ৱাই-ফাই অফ অৱস্থাত আছে"</string>
<string name="bt_is_off" msgid="2640685272289706392">"ব্লুটুথ অফ অৱস্থাত আছে"</string>
<string name="dnd_is_off" msgid="6167780215212497572">"অসুবিধা নিদিব অফ অৱস্থাত আছে"</string>
@@ -915,7 +897,12 @@
<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="data_usage_disable_mobile" msgid="5116269981510015864">"ম’বাইল ডেটা অফ কৰিবনে?"</string>
+ <!-- no translation found for mobile_data_disable_title (1068272097382942231) -->
+ <skip />
+ <!-- no translation found for mobile_data_disable_message (4756541658791493506) -->
+ <skip />
+ <!-- no translation found for mobile_data_disable_message_default_carrier (6078110473451946831) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8671693809204767551">"এটা এপে অনুমতি বিচাৰি কৰা অনুৰোধ এটা ঢাকি ধৰা বাবে ছেটিংসমূহে আপোনাৰ উত্তৰ সত্যাপন কৰিব পৰা নাই।"</string>
<!-- no translation found for slice_permission_title (7465009437851044444) -->
<skip />
@@ -929,4 +916,18 @@
<skip />
<!-- no translation found for slice_permission_deny (7683681514008048807) -->
<skip />
+ <!-- no translation found for auto_saver_title (1217959994732964228) -->
+ <skip />
+ <!-- no translation found for auto_saver_text (6324376061044218113) -->
+ <skip />
+ <!-- no translation found for no_auto_saver_action (8086002101711328500) -->
+ <skip />
+ <!-- no translation found for auto_saver_enabled_title (6726474226058316862) -->
+ <skip />
+ <!-- no translation found for auto_saver_enabled_text (874711029884777579) -->
+ <skip />
+ <!-- no translation found for open_saver_setting_action (8314624730997322529) -->
+ <skip />
+ <!-- no translation found for auto_saver_okay_action (2701221740227683650) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 5649557..36aa511 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -33,7 +33,6 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Ongoing"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Battery is low"</string>
- <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Battery is low. Turn on Battery Saver"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining"</string>
<string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining, about <xliff:g id="TIME">%s</xliff:g> left based on your usage"</string>
<string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining, about <xliff:g id="TIME">%s</xliff:g> left"</string>
@@ -73,11 +72,12 @@
<string name="global_action_screenshot" msgid="8329831278085426283">"Screenshot"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Saving screenshot…"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Saving screenshot…"</string>
- <string name="screenshot_saving_text" msgid="2545047868936087248">"Screenshot is being saved"</string>
<string name="screenshot_saved_title" msgid="5637073968117370753">"Screenshot saved"</string>
<string name="screenshot_saved_text" msgid="7574667448002050363">"Tap to view your screenshot"</string>
- <string name="screenshot_failed_title" msgid="9096484883063264803">"Couldn\'t capture screenshot"</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Problem encountered while saving screenshot"</string>
+ <!-- no translation found for screenshot_failed_title (7612509838919089748) -->
+ <skip />
+ <!-- no translation found for screenshot_failed_to_save_unknown_text (3637758096565605541) -->
+ <skip />
<string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Can\'t save screenshot due to limited storage space"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Taking screenshots isn\'t allowed by the app or your organisation"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB file transfer options"</string>
@@ -348,7 +348,8 @@
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"On at sunset"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Until sunrise"</string>
<string name="quick_settings_night_secondary_label_on_at" msgid="6256314040368487637">"On at <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_night_secondary_label_until" msgid="8664820079774824618">"Until <xliff:g id="TIME">%s</xliff:g>"</string>
+ <!-- no translation found for quick_settings_secondary_label_until (2749196569462600150) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC is disabled"</string>
<string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC is enabled"</string>
@@ -432,6 +433,8 @@
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will start capturing everything that\'s displayed on your screen."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Clear all"</string>
+ <!-- no translation found for manage_notifications_text (8035284146227267681) -->
+ <skip />
<string name="dnd_suppressing_shade_text" msgid="7986451830430707907">"Do not disturb is hiding notifications"</string>
<string name="media_projection_action_text" msgid="8470872969457985954">"Start now"</string>
<string name="empty_shade_text" msgid="708135716272867002">"No notifications"</string>
@@ -625,6 +628,8 @@
<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">"notification controls"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"notification snooze options"</string>
+ <!-- no translation found for notification_menu_snooze_action (1112254519029621372) -->
+ <skip />
<string name="snooze_undo" msgid="6074877317002985129">"UNDO"</string>
<string name="snoozed_for_time" msgid="2390718332980204462">"Snoozed for <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<plurals name="snoozeHourOptions" formatted="false" msgid="2124335842674413030">
@@ -811,6 +816,8 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"General Messages"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>
+ <!-- no translation found for notification_channel_hints (7323870212489152689) -->
+ <skip />
<string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Instant apps don\'t require installation."</string>
<string name="app_info" msgid="6856026610594615344">"App info"</string>
@@ -838,4 +845,18 @@
<string name="slice_permission_checkbox" msgid="7986504458640562900">"Allow <xliff:g id="APP">%1$s</xliff:g> to show slices from any app"</string>
<string name="slice_permission_allow" msgid="2340244901366722709">"Allow"</string>
<string name="slice_permission_deny" msgid="7683681514008048807">"Deny"</string>
+ <!-- no translation found for auto_saver_title (1217959994732964228) -->
+ <skip />
+ <!-- no translation found for auto_saver_text (6324376061044218113) -->
+ <skip />
+ <!-- no translation found for no_auto_saver_action (8086002101711328500) -->
+ <skip />
+ <!-- no translation found for auto_saver_enabled_title (6726474226058316862) -->
+ <skip />
+ <!-- no translation found for auto_saver_enabled_text (874711029884777579) -->
+ <skip />
+ <!-- no translation found for open_saver_setting_action (8314624730997322529) -->
+ <skip />
+ <!-- no translation found for auto_saver_okay_action (2701221740227683650) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 783160c..cfb9033 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -33,7 +33,6 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Ongoing"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Battery is low"</string>
- <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Battery is low. Turn on Battery Saver"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining"</string>
<string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining, about <xliff:g id="TIME">%s</xliff:g> left based on your usage"</string>
<string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining, about <xliff:g id="TIME">%s</xliff:g> left"</string>
@@ -73,11 +72,10 @@
<string name="global_action_screenshot" msgid="8329831278085426283">"Screenshot"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Saving screenshot…"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Saving screenshot…"</string>
- <string name="screenshot_saving_text" msgid="2545047868936087248">"Screenshot is being saved"</string>
<string name="screenshot_saved_title" msgid="5637073968117370753">"Screenshot saved"</string>
<string name="screenshot_saved_text" msgid="7574667448002050363">"Tap to view your screenshot"</string>
- <string name="screenshot_failed_title" msgid="9096484883063264803">"Couldn\'t capture screenshot"</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Problem encountered while saving screenshot"</string>
+ <string name="screenshot_failed_title" msgid="7612509838919089748">"Couldn\'t save screenshot"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="3637758096565605541">"Try taking screenshot again"</string>
<string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Can\'t save screenshot due to limited storage space"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Taking screenshots isn\'t allowed by the app or your organization"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB file transfer options"</string>
@@ -348,7 +346,7 @@
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"On at sunset"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Until sunrise"</string>
<string name="quick_settings_night_secondary_label_on_at" msgid="6256314040368487637">"On at <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_night_secondary_label_until" msgid="8664820079774824618">"Until <xliff:g id="TIME">%s</xliff:g>"</string>
+ <string name="quick_settings_secondary_label_until" msgid="2749196569462600150">"Until <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC is disabled"</string>
<string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC is enabled"</string>
@@ -432,6 +430,7 @@
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will start capturing everything that\'s displayed on your screen."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Clear all"</string>
+ <string name="manage_notifications_text" msgid="8035284146227267681">"Manage notifications"</string>
<string name="dnd_suppressing_shade_text" msgid="7986451830430707907">"Do Not disturb is hiding notifications"</string>
<string name="media_projection_action_text" msgid="8470872969457985954">"Start now"</string>
<string name="empty_shade_text" msgid="708135716272867002">"No notifications"</string>
@@ -625,6 +624,7 @@
<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">"notification controls"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"notification snooze options"</string>
+ <string name="notification_menu_snooze_action" msgid="1112254519029621372">"Snooze"</string>
<string name="snooze_undo" msgid="6074877317002985129">"UNDO"</string>
<string name="snoozed_for_time" msgid="2390718332980204462">"Snoozed for <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<plurals name="snoozeHourOptions" formatted="false" msgid="2124335842674413030">
@@ -811,6 +811,8 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"General Messages"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>
+ <!-- no translation found for notification_channel_hints (7323870212489152689) -->
+ <skip />
<string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Instant apps don\'t require installation."</string>
<string name="app_info" msgid="6856026610594615344">"App info"</string>
@@ -838,4 +840,18 @@
<string name="slice_permission_checkbox" msgid="7986504458640562900">"Allow <xliff:g id="APP">%1$s</xliff:g> to show slices from any app"</string>
<string name="slice_permission_allow" msgid="2340244901366722709">"Allow"</string>
<string name="slice_permission_deny" msgid="7683681514008048807">"Deny"</string>
+ <!-- no translation found for auto_saver_title (1217959994732964228) -->
+ <skip />
+ <!-- no translation found for auto_saver_text (6324376061044218113) -->
+ <skip />
+ <!-- no translation found for no_auto_saver_action (8086002101711328500) -->
+ <skip />
+ <!-- no translation found for auto_saver_enabled_title (6726474226058316862) -->
+ <skip />
+ <!-- no translation found for auto_saver_enabled_text (874711029884777579) -->
+ <skip />
+ <!-- no translation found for open_saver_setting_action (8314624730997322529) -->
+ <skip />
+ <!-- no translation found for auto_saver_okay_action (2701221740227683650) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 1a10610..287e0b4 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -33,7 +33,6 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"En cours"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Batterie faible"</string>
- <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Batterie faible : activez l\'économiseur de batterie"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> restants"</string>
<string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> – Temps restant en fonction de votre utilisation : environ <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> – Temps restant : environ <xliff:g id="TIME">%s</xliff:g>"</string>
@@ -73,11 +72,12 @@
<string name="global_action_screenshot" msgid="8329831278085426283">"Capture d\'écran"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Enregistrement capture écran…"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Enregistrement de la capture d\'écran…"</string>
- <string name="screenshot_saving_text" msgid="2545047868936087248">"Enregistrement de la capture d\'écran…"</string>
<string name="screenshot_saved_title" msgid="5637073968117370753">"Capture d\'écran enregistrée"</string>
<string name="screenshot_saved_text" msgid="7574667448002050363">"Appuyez pour afficher votre capture d\'écran"</string>
- <string name="screenshot_failed_title" msgid="9096484883063264803">"Impossible d\'effectuer une capture d\'écran"</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Erreur lors de l\'enregistrement de la capture d\'écran"</string>
+ <!-- no translation found for screenshot_failed_title (7612509838919089748) -->
+ <skip />
+ <!-- no translation found for screenshot_failed_to_save_unknown_text (3637758096565605541) -->
+ <skip />
<string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Impossible d\'enregistrer la capture d\'écran, car l\'espace de stockage est limité"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Les captures d\'écran ne sont pas autorisées par l\'application ni par votre organisation"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Options transfert fichiers USB"</string>
@@ -275,8 +275,7 @@
<string name="dessert_case" msgid="1295161776223959221">"Vitrine des desserts"</string>
<string name="start_dreams" msgid="5640361424498338327">"Économiseur d\'écran"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
- <!-- no translation found for quick_settings_header_onboarding_text (8030309023792936283) -->
- <skip />
+ <string name="quick_settings_header_onboarding_text" msgid="8030309023792936283">"Appuyez de manière prolongée sur les icônes pour accéder à d\'autres options"</string>
<string name="quick_settings_dnd_label" msgid="8735855737575028208">"Ne pas déranger"</string>
<string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Prioritaires uniquement"</string>
<string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Alarmes uniquement"</string>
@@ -351,7 +350,8 @@
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"Activé au crépuscule"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Jusqu\'à l\'aube"</string>
<string name="quick_settings_night_secondary_label_on_at" msgid="6256314040368487637">"Activé à <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_night_secondary_label_until" msgid="8664820079774824618">"Jusqu\'à <xliff:g id="TIME">%s</xliff:g>"</string>
+ <!-- no translation found for quick_settings_secondary_label_until (2749196569462600150) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="6883274004315134333">"La technologie NFC est désactivée"</string>
<string name="quick_settings_nfc_on" msgid="6680317193676884311">"La technologie NFC est activée"</string>
@@ -435,6 +435,8 @@
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> va commencer à capturer tous les contenus affichés à l\'écran."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Ne plus afficher"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Tout effacer"</string>
+ <!-- no translation found for manage_notifications_text (8035284146227267681) -->
+ <skip />
<string name="dnd_suppressing_shade_text" msgid="7986451830430707907">"Le mode Ne pas déranger masque les notifications"</string>
<string name="media_projection_action_text" msgid="8470872969457985954">"Commencer"</string>
<string name="empty_shade_text" msgid="708135716272867002">"Aucune notification"</string>
@@ -628,6 +630,8 @@
<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">"paramètres des notifications"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"options de répétition des notifications"</string>
+ <!-- no translation found for notification_menu_snooze_action (1112254519029621372) -->
+ <skip />
<string name="snooze_undo" msgid="6074877317002985129">"ANNULER"</string>
<string name="snoozed_for_time" msgid="2390718332980204462">"Répétée après <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<plurals name="snoozeHourOptions" formatted="false" msgid="2124335842674413030">
@@ -725,11 +729,9 @@
<string name="right_keycode" msgid="708447961000848163">"Code de touche droit"</string>
<string name="left_icon" msgid="3096287125959387541">"Icône gauche"</string>
<string name="right_icon" msgid="3952104823293824311">"Icône droite"</string>
- <!-- no translation found for drag_to_add_tiles (230586591689084925) -->
- <skip />
+ <string name="drag_to_add_tiles" msgid="230586591689084925">"Sélectionnez et faites glisser les tuiles pour les ajouter"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Faites glisser les tuiles ici pour les supprimer."</string>
- <!-- no translation found for drag_to_remove_disabled (2390968976638993382) -->
- <skip />
+ <string name="drag_to_remove_disabled" msgid="2390968976638993382">"Au minimum six tuiles sont nécessaires"</string>
<string name="qs_edit" msgid="2232596095725105230">"Modifier"</string>
<string name="tuner_time" msgid="6572217313285536011">"Heure"</string>
<string-array name="clock_options">
@@ -816,6 +818,8 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Captures d\'écran"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Nouveaux messages"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Espace de stockage"</string>
+ <!-- no translation found for notification_channel_hints (7323870212489152689) -->
+ <skip />
<string name="instant_apps" msgid="6647570248119804907">"Applis instantanées"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Les applis instantanées ne nécessitent pas d\'installation."</string>
<string name="app_info" msgid="6856026610594615344">"Infos sur l\'appli"</string>
@@ -833,12 +837,9 @@
<string name="qs_dnd_replace" msgid="8019520786644276623">"Remplacer"</string>
<string name="running_foreground_services_title" msgid="381024150898615683">"Applications en cours d\'exécution en arrière-plan"</string>
<string name="running_foreground_services_msg" msgid="6326247670075574355">"Appuyer pour obtenir des informations sur l\'utilisation de la batterie et des données"</string>
- <!-- no translation found for mobile_data_disable_title (1068272097382942231) -->
- <skip />
- <!-- no translation found for mobile_data_disable_message (4756541658791493506) -->
- <skip />
- <!-- no translation found for mobile_data_disable_message_default_carrier (6078110473451946831) -->
- <skip />
+ <string name="mobile_data_disable_title" msgid="1068272097382942231">"Désactiver les données mobiles ?"</string>
+ <string name="mobile_data_disable_message" msgid="4756541658791493506">"Vous n\'accéderez pas aux données mobiles ni à Internet via <xliff:g id="CARRIER">%s</xliff:g>. Internet ne sera disponible qu\'avec une connexion Wi-Fi."</string>
+ <string name="mobile_data_disable_message_default_carrier" msgid="6078110473451946831">"votre opérateur"</string>
<string name="touch_filtered_warning" msgid="8671693809204767551">"L\'application Paramètres ne peut pas valider votre réponse, car une application masque la demande d\'autorisation."</string>
<string name="slice_permission_title" msgid="7465009437851044444">"Autoriser <xliff:g id="APP_0">%1$s</xliff:g> à afficher des éléments de <xliff:g id="APP_2">%2$s</xliff:g> ?"</string>
<string name="slice_permission_text_1" msgid="3514586565609596523">"- Accès aux informations de <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -846,4 +847,18 @@
<string name="slice_permission_checkbox" msgid="7986504458640562900">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à afficher des éléments de n\'importe quelle application"</string>
<string name="slice_permission_allow" msgid="2340244901366722709">"Autoriser"</string>
<string name="slice_permission_deny" msgid="7683681514008048807">"Refuser"</string>
+ <!-- no translation found for auto_saver_title (1217959994732964228) -->
+ <skip />
+ <!-- no translation found for auto_saver_text (6324376061044218113) -->
+ <skip />
+ <!-- no translation found for no_auto_saver_action (8086002101711328500) -->
+ <skip />
+ <!-- no translation found for auto_saver_enabled_title (6726474226058316862) -->
+ <skip />
+ <!-- no translation found for auto_saver_enabled_text (874711029884777579) -->
+ <skip />
+ <!-- no translation found for open_saver_setting_action (8314624730997322529) -->
+ <skip />
+ <!-- no translation found for auto_saver_okay_action (2701221740227683650) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 30ec2d5..a1e41f3 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -33,24 +33,22 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"ଚାଲୁଅଛି"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"ବିଜ୍ଞପ୍ତି"</string>
<string name="battery_low_title" msgid="6456385927409742437">"ବ୍ୟାଟେରୀ କମ୍ ଅଛି"</string>
- <!-- no translation found for battery_low_title_hybrid (6268991275887381595) -->
- <skip />
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> ବାକି ଅଛି"</string>
<!-- no translation found for battery_low_percent_format_hybrid (6838677459286775617) -->
<skip />
<!-- no translation found for battery_low_percent_format_hybrid_short (9025795469949145586) -->
<skip />
- <!-- no translation found for battery_low_percent_format_saver_started (7879389868952879166) -->
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> ବାକି ଅଛି। ବ୍ୟାଟେରୀ ସେଭର୍ ଅନ୍ ଅଛି।"</string>
+ <!-- no translation found for invalid_charger (2741987096648693172) -->
<skip />
- <string name="invalid_charger" msgid="4549105996740522523">"USB ଚାର୍ଜିଙ୍ଗ ସପୋର୍ଟ କରୁନାହିଁ।\nକେବଳ ଦିଆଯାଇଥିବା ଚାର୍ଜର୍ ହିଁ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
- <string name="invalid_charger_title" msgid="3515740382572798460">"USB ଚାର୍ଜିଙ୍ଗ ସପୋର୍ଟ କରୁନାହିଁ।"</string>
- <string name="invalid_charger_text" msgid="5474997287953892710">"କେବଳ ଦିଆଯାଇଥିବା ଚାର୍ଜର୍ ହିଁ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
+ <!-- no translation found for invalid_charger_title (2836102177577255404) -->
+ <skip />
+ <!-- no translation found for invalid_charger_text (6480624964117840005) -->
+ <skip />
<string name="battery_low_why" msgid="4553600287639198111">"ସେଟିଙ୍ଗ"</string>
- <!-- no translation found for battery_saver_confirmation_title (2052100465684817154) -->
- <skip />
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"ବ୍ୟାଟେରୀ ସେଭର୍ ଅନ୍ କରିବେ?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"ଅନ୍ କରନ୍ତୁ"</string>
- <!-- no translation found for battery_saver_start_action (8187820911065797519) -->
- <skip />
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"ବ୍ୟାଟେରୀ ସେଭର୍ ଅନ୍ କରନ୍ତୁ"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ସେଟିଙ୍ଗ"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"ୱାଇ-ଫାଇ"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"ଅଟୋ-ରୋଟେଟ୍ ସ୍କ୍ରୀନ୍"</string>
@@ -60,47 +58,37 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"ବ୍ଲୁ-ଟୁଥ୍ ଟିଥରିଙ୍ଗ୍"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"ଇନପୁଟ୍ ପଦ୍ଧତି ସେଟ୍ କରନ୍ତୁ"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"ଫିଜିକଲ୍ କୀ’ବୋର୍ଡ୍"</string>
- <!-- no translation found for usb_device_permission_prompt (1825685909587559679) -->
- <skip />
- <!-- no translation found for usb_accessory_permission_prompt (2465531696941369047) -->
- <skip />
- <!-- no translation found for usb_device_confirm_prompt (7440562274256843905) -->
- <skip />
- <!-- no translation found for usb_accessory_confirm_prompt (4333670517539993561) -->
- <skip />
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ଆକ୍ସେସ୍ କରିବାକୁ <xliff:g id="APPLICATION">%1$s</xliff:g>କୁ ଅନୁମତି ଦେବେ?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ଆକ୍ସେସ୍ କରିବାକୁ <xliff:g id="APPLICATION">%1$s</xliff:g>କୁ ଅନୁମତି ଦେବେ?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ନିୟନ୍ତ୍ରଣ କରିବାକୁ <xliff:g id="APPLICATION">%1$s</xliff:g> ଖୋଲିବେ?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ନିୟନ୍ତ୍ରଣ କରିବାକୁ <xliff:g id="APPLICATION">%1$s</xliff:g> ଖୋଲିବେ?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"ଇନଷ୍ଟଲ୍ ହୋଇଥିବା କୌଣସି ଆପ୍ ଏହି USB ଆକ୍ସେସୋରୀରେ କାମ କରେନାହିଁ। ଏହି ଆକ୍ସେସୋରୀ ବିଷୟରେ <xliff:g id="URL">%1$s</xliff:g>ରେ ଅଧିକ ଜାଣନ୍ତୁ"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB ଆକ୍ସେସରୀ"</string>
<string name="label_view" msgid="6304565553218192990">"ଦେଖନ୍ତୁ"</string>
- <!-- no translation found for always_use_device (4015357883336738417) -->
- <skip />
- <!-- no translation found for always_use_accessory (3257892669444535154) -->
- <skip />
+ <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> କନେକ୍ଟ ଥିବାବେଳେ <xliff:g id="APPLICATION">%1$s</xliff:g> ସର୍ବଦା ଖୋଲନ୍ତୁ"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> କନେକ୍ଟ ଥିବାବେଳେ <xliff:g id="APPLICATION">%1$s</xliff:g> ସର୍ବଦା ଖୋଲନ୍ତୁ"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"USB ଡିବଗିଙ୍ଗ କରିବେ?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"କମ୍ପ୍ୟୁଟର୍ର RSA କୀ\' ଆଙ୍ଗୁଠି ଚିହ୍ନ ହେଉଛି:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"ସବୁବେଳେ ଏହି କମ୍ପ୍ୟୁଟର୍ରୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="usb_debugging_secondary_user_title" msgid="6353808721761220421">"USBରେ ଡିବଗ୍ କରାଯାଇପାରିବ ନାହିଁ"</string>
- <!-- no translation found for usb_debugging_secondary_user_message (6067122453571699801) -->
- <skip />
+ <string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"ସମ୍ପ୍ରତି ସାଇନ୍-ଇନ୍ କରିଥିବା ୟୁଜର୍ ଜଣକ ଏହି ଡିଭାଇସରେ USB ଡିବଗିଙ୍ଗ ଅନ୍ କରିପାରିବେ ନାହିଁ। ଏହି ବୈଶିଷ୍ଟ୍ୟ ବ୍ୟବହାର କରିବାକୁ, ପ୍ରାଥମିକ ୟୁଜର୍ରେ ସାଇନ୍-ଇନ୍ କରନ୍ତୁ।"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"ସ୍କ୍ରୀନ ଭରିବା ପାଇଁ ଜୁମ୍ କରନ୍ତୁ"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"ସ୍କ୍ରୀନ୍କୁ ଭରିବା ପାଇଁ ଟାଣନ୍ତୁ"</string>
<!-- no translation found for global_action_screenshot (8329831278085426283) -->
<skip />
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"ସ୍କ୍ରୀନଶଟ୍ ସେଭ୍ କରାଯାଉଛି…"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"ସ୍କ୍ରୀନଶଟ୍ ସେଭ୍ କରାଯାଉଛି…"</string>
- <!-- no translation found for screenshot_saving_text (2545047868936087248) -->
- <skip />
<!-- no translation found for screenshot_saved_title (5637073968117370753) -->
<skip />
<!-- no translation found for screenshot_saved_text (7574667448002050363) -->
<skip />
- <!-- no translation found for screenshot_failed_title (9096484883063264803) -->
+ <!-- no translation found for screenshot_failed_title (7612509838919089748) -->
<skip />
- <!-- no translation found for screenshot_failed_to_save_unknown_text (8844781948876286488) -->
+ <!-- no translation found for screenshot_failed_to_save_unknown_text (3637758096565605541) -->
<skip />
<!-- no translation found for screenshot_failed_to_save_text (3041612585107107310) -->
<skip />
- <!-- no translation found for screenshot_failed_to_capture_text (173674476457581486) -->
- <skip />
+ <string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"ଆପ୍ କିମ୍ବା ସଂସ୍ଥା ଦ୍ୱାରା ସ୍କ୍ରୀନଶଟ୍ ନେବାକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB ଫାଇଲ୍ ଟ୍ରାନ୍ସଫର୍ର ବିକଳ୍ପ"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"ଏକ ମିଡିଆ ପ୍ଲେୟାର୍ (MTP) ଭାବରେ ଭର୍ତ୍ତି କରନ୍ତୁ"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"ଏକ କ୍ୟାମେରା (PTP) ଭାବରେ ଭର୍ତ୍ତି କରନ୍ତୁ"</string>
@@ -108,8 +96,7 @@
<string name="accessibility_back" msgid="567011538994429120">"ଫେରନ୍ତୁ"</string>
<string name="accessibility_home" msgid="8217216074895377641">"ହୋମ୍"</string>
<string name="accessibility_menu" msgid="316839303324695949">"ମେନୁ"</string>
- <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
- <skip />
+ <string name="accessibility_accessibility_button" msgid="7601252764577607915">"ଆକ୍ସେସିବିଲିଟୀ"</string>
<!-- no translation found for accessibility_rotate_button (7402949513740253006) -->
<skip />
<string name="accessibility_recent" msgid="5208608566793607626">"ସଂକ୍ଷିପ୍ତ ବିବରଣୀ"</string>
@@ -118,8 +105,7 @@
<string name="accessibility_phone_button" msgid="6738112589538563574">"ଫୋନ୍"</string>
<string name="accessibility_voice_assist_button" msgid="487611083884852965">"ଭଏସ୍ ସହାୟକ"</string>
<string name="accessibility_unlock_button" msgid="128158454631118828">"ଅନଲକ୍ କରନ୍ତୁ"</string>
- <!-- no translation found for accessibility_waiting_for_fingerprint (4808860050517462885) -->
- <skip />
+ <string name="accessibility_waiting_for_fingerprint" msgid="4808860050517462885">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ପାଇଁ ଅପେକ୍ଷା କରିଛି"</string>
<string name="accessibility_unlock_without_fingerprint" msgid="7541705575183694446">"ଆଙ୍ଗୁଠିଚିହ୍ନ ବ୍ୟବହାର ନକରି ଅନଲକ୍ କରନ୍ତୁ"</string>
<string name="unlock_label" msgid="8779712358041029439">"ଅନଲକ୍"</string>
<string name="phone_label" msgid="2320074140205331708">"ଫୋନ୍ ଖୋଲନ୍ତୁ"</string>
@@ -175,40 +161,48 @@
<string name="accessibility_desc_off" msgid="6475508157786853157">"ଅଫ୍।"</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"ସଂଯୁକ୍ତ।"</string>
<string name="accessibility_desc_connecting" msgid="3812924520316280149">"ସଂଯୋଗ କରୁଛି।"</string>
- <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
- <string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
- <string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
- <string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string>
- <string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3.5G"</string>
- <string name="accessibility_data_connection_4g" msgid="7741000750630089612">"4G"</string>
- <string name="accessibility_data_connection_4g_plus" msgid="3032226872470658661">"4G+"</string>
- <string name="accessibility_data_connection_lte" msgid="5413468808637540658">"LTE"</string>
- <string name="accessibility_data_connection_lte_plus" msgid="361876866906946007">"LTE+"</string>
- <string name="accessibility_data_connection_cdma" msgid="6132648193978823023">"CDMA"</string>
- <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"ରୋମିଙ୍ଗ"</string>
- <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"ଏଜ୍"</string>
+ <!-- no translation found for data_connection_gprs (7652872568358508452) -->
+ <skip />
+ <!-- no translation found for data_connection_hspa (1499615426569473562) -->
+ <skip />
+ <!-- no translation found for data_connection_3g (503045449315378373) -->
+ <skip />
+ <!-- no translation found for data_connection_3_5g (5218328297191657602) -->
+ <skip />
+ <!-- no translation found for data_connection_3_5g_plus (7570783890290275297) -->
+ <skip />
+ <!-- no translation found for data_connection_4g (9139963475267449144) -->
+ <skip />
+ <!-- no translation found for data_connection_4g_plus (1148687201877800700) -->
+ <skip />
+ <!-- no translation found for data_connection_lte (2694876797724028614) -->
+ <skip />
+ <!-- no translation found for data_connection_lte_plus (3423013208570937424) -->
+ <skip />
+ <!-- no translation found for data_connection_cdma (4677985502159869585) -->
+ <skip />
+ <!-- no translation found for data_connection_roaming (6037232010953697354) -->
+ <skip />
+ <!-- no translation found for data_connection_edge (871835227939216682) -->
+ <skip />
<string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"ୱାଇ-ଫାଇ"</string>
<string name="accessibility_no_sim" msgid="8274017118472455155">"କୌଣସି SIM ନାହିଁ।"</string>
- <!-- no translation found for accessibility_cell_data (5326139158682385073) -->
- <skip />
- <!-- no translation found for accessibility_cell_data_on (5927098403452994422) -->
- <skip />
- <!-- no translation found for accessibility_cell_data_off (443267573897409704) -->
+ <string name="accessibility_cell_data" msgid="5326139158682385073">"ମୋବାଇଲ୍ ଡାଟା"</string>
+ <string name="accessibility_cell_data_on" msgid="5927098403452994422">"ମୋବାଇଲ୍ ଡାଟା ଅନ୍"</string>
+ <!-- no translation found for cell_data_off (5287705247512911922) -->
<skip />
<string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"ବ୍ଲୁ-ଟୁଥ୍ ଟିଥରିଙ୍ଗ"</string>
<string name="accessibility_airplane_mode" msgid="834748999790763092">"ଏରୋପ୍ଲେନ୍ ମୋଡ୍।"</string>
- <!-- no translation found for accessibility_vpn_on (5993385083262856059) -->
- <skip />
+ <string name="accessibility_vpn_on" msgid="5993385083262856059">"VPN ଅନ୍।"</string>
<string name="accessibility_no_sims" msgid="3957997018324995781">"କୌଣସି SIM କାର୍ଡ ନାହିଁ।"</string>
- <string name="accessibility_carrier_network_change_mode" msgid="4017301580441304305">"କେରିଅର୍ ନେଟ୍ୱର୍କ ବଦଳାଯାଉଛି।"</string>
+ <!-- no translation found for carrier_network_change_mode (8149202439957837762) -->
+ <skip />
<string name="accessibility_battery_details" msgid="7645516654955025422">"ବ୍ୟାଟେରୀ ବିବରଣୀ ଖୋଲନ୍ତୁ"</string>
<string name="accessibility_battery_level" msgid="7451474187113371965">"ବ୍ୟାଟେରୀ <xliff:g id="NUMBER">%d</xliff:g> ଶତକଡ଼ା ଅଛି।"</string>
- <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
- <skip />
+ <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"ବ୍ୟାଟେରୀ ଚାର୍ଜ ହେଉଛି, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> ଶତକଡ଼ା।"</string>
<string name="accessibility_settings_button" msgid="799583911231893380">"ସିଷ୍ଟମ୍ ସେଟିଙ୍ଗ।"</string>
<string name="accessibility_notifications_button" msgid="4498000369779421892">"ବିଜ୍ଞପ୍ତି"</string>
- <!-- no translation found for accessibility_overflow_action (5681882033274783311) -->
- <skip />
+ <string name="accessibility_overflow_action" msgid="5681882033274783311">"ସମସ୍ତ ବିଜ୍ଞପ୍ତି ଦେଖନ୍ତୁ"</string>
<string name="accessibility_remove_notification" msgid="3603099514902182350">"ବିଜ୍ଞପ୍ତି ଖାଲି କରନ୍ତୁ।"</string>
<string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS ସକ୍ଷମ।"</string>
<string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS ପ୍ରାପ୍ତ କରୁଛି।"</string>
@@ -222,8 +216,7 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> ଖାରଜ।"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ଖାରଜ କରିଦିଆଗଲା।"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ସମସ୍ତ ସମ୍ପ୍ରତି ଆପ୍ଲିକେଶନଗୁଡ଼ିକ ଖାରଜ କରାଯାଇଛି।"</string>
- <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
- <skip />
+ <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> ଆପ୍ଲିକେଶନ୍ ସୂଚନା ଖୋଲନ୍ତୁ।"</string>
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ଆରମ୍ଭ ହେଉଛି।"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"ବିଜ୍ଞପ୍ତି ଖାରଜ କରାଗଲା।"</string>
<string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"ବିଜ୍ଞପ୍ତି ଶେଡ୍।"</string>
@@ -231,8 +224,7 @@
<string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"ଲକ୍ ସ୍କ୍ରୀନ୍।"</string>
<string name="accessibility_desc_settings" msgid="3417884241751434521">"ସେଟିଙ୍ଗ"</string>
<string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"ସଂକ୍ଷିପ୍ତ ବିବରଣୀ"</string>
- <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
- <skip />
+ <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"ୱର୍କ ଲକ୍ ସ୍କ୍ରୀନ୍"</string>
<string name="accessibility_desc_close" msgid="7479755364962766729">"ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>।"</string>
<string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"ୱାଇ-ଫାଇ ବନ୍ଦ ଅଛି।"</string>
@@ -243,7 +235,8 @@
<string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"ଏୟାର୍ପ୍ଲେନ୍ ମୋଡ୍ ଅନ୍ ଅଛି।"</string>
<string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"ଏୟାର୍ପ୍ଲେନ୍ ମୋଡ୍କୁ ବନ୍ଦ କରାଯାଇଛି।"</string>
<string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"ଏୟାର୍ପ୍ଲେନ୍ ମୋଡ୍କୁ ଚାଲୁ କରାଯାଇଛି।"</string>
- <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଅନ୍ ଅଛି, କେବଳ ଗୁରୁତ୍ୱର୍ଣ୍ଣ।"</string>
+ <!-- no translation found for accessibility_quick_settings_dnd_priority_on (5836205286254617194) -->
+ <skip />
<string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଅନ୍ ଅଛି, ସମ୍ପୂର୍ଣ୍ଣ ନୀରବ।"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଅନ୍ ଅଛି, କେବଳ ଆଲାର୍ମ।"</string>
<string name="accessibility_quick_settings_dnd" msgid="6607873236717185815">"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ।"</string>
@@ -266,8 +259,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"ଅଧିକ ସମୟ।"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"କମ୍ ସମୟ।"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ଫ୍ଲାଶ୍ଲାଇଟ୍ ଅଫ୍ ଅଛି।"</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ଟର୍ଚ୍ଚ ଲାଇଟ୍ ଅନୁପଲବ୍ଧ।"</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ଫ୍ଲାଶ୍ଲାଇଟ୍ ଅନ୍ ଅଛି।"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ଟର୍ଚ୍ଚ ଲାଇଟ୍ ବନ୍ଦ ଅଛି।"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ଟର୍ଚ୍ଚ ଲାଇଟ୍ ଅନ୍ ଅଛି।"</string>
@@ -280,27 +272,21 @@
<string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"ୱର୍କ ମୋଡ୍ ଅନ୍।"</string>
<string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"ୱର୍କ ମୋଡ୍କୁ ଅଫ୍ କରାଯାଇଛି।"</string>
<string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"ୱର୍କ ମୋଡ୍କୁ ଅନ୍ କରାଯାଇଛି।"</string>
- <!-- no translation found for accessibility_quick_settings_data_saver_changed_off (650231949881093289) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_data_saver_changed_on (4218725402373934151) -->
- <skip />
+ <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"ଡାଟା ସେଭର୍ ଅଫ୍ କରାଗଲା।"</string>
+ <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"ଡାଟା ସେଭର୍ ଅନ୍ କରାଗଲା।"</string>
<string name="accessibility_brightness" msgid="8003681285547803095">"ଡିସ୍ପ୍ଲେ ଉଜ୍ଜ୍ୱଳତା"</string>
- <!-- no translation found for accessibility_ambient_display_charging (9084521679384069087) -->
- <skip />
+ <string name="accessibility_ambient_display_charging" msgid="9084521679384069087">"ଚାର୍ଜ କରାଯାଉଛି"</string>
<string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ଡାଟା ପଜ୍ କରାଯାଇଛି"</string>
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ଡାଟା ପଜ୍ କରାଯାଇଛି"</string>
- <!-- no translation found for data_usage_disabled_dialog_mobile_title (6801382439018099779) -->
- <skip />
+ <string name="data_usage_disabled_dialog_mobile_title" msgid="6801382439018099779">"ମୋବାଇଲ୍ ଡାଟା ପଜ୍ କରାଯାଇଛି"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ଡାଟା ପଜ୍ କରାଯାଇଛି"</string>
- <!-- no translation found for data_usage_disabled_dialog (4919541636934603816) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="4919541636934603816">"ଆପଣ ସେଟ୍ କରିଥିବା ଡାଟାର ସୀମାରେ ପହଞ୍ଚିଲେ। ଆପଣ ଆଉ ମୋବାଇଲ୍ ଡାଟା ବ୍ୟବହାର କରୁନାହାଁନ୍ତି।\n\nଯଦି ଆପଣ ପୁଣି ଆରମ୍ଭ କରନ୍ତି, ଡାଟା ବ୍ୟବହାର ପାଇଁ ଆପଣଙ୍କୁ ଦେୟ ଲାଗୁ କରାଯାଇ ପାରେ।"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ପୁଣି ଚାଲୁ କରନ୍ତୁ"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS ଖୋଜାଯାଉଛି"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS ଦ୍ୱାରା ଲୋକେଶନ୍ ସେଟ୍ କରାଯାଇଛି"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"ଲୋକେଶନ୍ ଅନୁରୋଧ ସକ୍ରିୟ ଅଛି"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"ସମସ୍ତ ବିଜ୍ଞପ୍ତି ଖାଲି କରନ୍ତୁ।"</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<plurals name="notification_group_overflow_description" formatted="false" msgid="4579313201268495404">
<item quantity="other">ଭିତରେ ଆଉ <xliff:g id="NUMBER_1">%s</xliff:g>ଟି ଅଧିକ ବିଜ୍ଞପ୍ତି ରହିଛି।</item>
<item quantity="one">ଭିତରେ ଆଉ <xliff:g id="NUMBER_0">%s</xliff:g>ଟି ଅଧିକ ବିଜ୍ଞପ୍ତି ରହିଛି।</item>
@@ -316,7 +302,7 @@
<string name="dessert_case" msgid="1295161776223959221">"ଡେଜର୍ଟ କେସ୍"</string>
<string name="start_dreams" msgid="5640361424498338327">"ସ୍କ୍ରୀନ୍ ସେଭର୍"</string>
<string name="ethernet_label" msgid="7967563676324087464">"ଇଥରନେଟ୍"</string>
- <!-- no translation found for quick_settings_header_onboarding_text (7872508260264044734) -->
+ <!-- no translation found for quick_settings_header_onboarding_text (8030309023792936283) -->
<skip />
<string name="quick_settings_dnd_label" msgid="8735855737575028208">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\""</string>
<string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"କେବଳ ପ୍ରାଥମିକତା"</string>
@@ -339,8 +325,7 @@
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"ଉଜ୍ଜ୍ୱଳତା"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"ସ୍ୱତଃ-ଘୂର୍ଣ୍ଣନ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4231661040698488779">"ସ୍କ୍ରୀନ୍କୁ ଅଟୋ-ରୋଟେଟ୍ କରନ୍ତୁ"</string>
- <!-- no translation found for accessibility_quick_settings_rotation_value (8187398200140760213) -->
- <skip />
+ <string name="accessibility_quick_settings_rotation_value" msgid="8187398200140760213">"<xliff:g id="ID_1">%s</xliff:g> ମୋଡ୍"</string>
<string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"ଘୂର୍ଣ୍ଣନ ଲକ୍ ହୋଇଛି"</string>
<string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"ପୋର୍ଟ୍ରେଟ୍"</string>
<string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"ଲ୍ୟାଣ୍ଡସ୍କେପ୍"</string>
@@ -375,18 +360,18 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"ଅଧିକ ସେଟିଙ୍ଗ"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"ହୋଇଗଲା"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"ସଂଯୁକ୍ତ"</string>
- <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
- <skip />
+ <string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"କନେକ୍ଟ ରହିଛି, ବ୍ୟାଟେରୀ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="quick_settings_connecting" msgid="47623027419264404">"ସଂଯୋଗ କରୁଛି..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"ଟିଥରିଙ୍ଗ"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ହଟସ୍ପଟ୍"</string>
<!-- no translation found for quick_settings_hotspot_secondary_label_transient (8010579363691405477) -->
<skip />
+ <!-- no translation found for quick_settings_hotspot_secondary_label_data_saver_enabled (5672131949987422420) -->
+ <skip />
<!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"ବିଜ୍ଞପ୍ତି"</string>
<string name="quick_settings_flashlight_label" msgid="2133093497691661546">"ଫ୍ଲାଶ୍ଲାଇଟ"</string>
- <!-- no translation found for quick_settings_cellular_detail_title (3661194685666477347) -->
- <skip />
+ <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"ମୋବାଇଲ୍ ଡାଟା"</string>
<string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"ଡାଟାର ବ୍ୟବହାର"</string>
<string name="quick_settings_cellular_detail_remaining_data" msgid="722715415543541249">"ଅବଶିଷ୍ଟ ଡାଟା"</string>
<string name="quick_settings_cellular_detail_over_limit" msgid="967669665390990427">"ସୀମାଠାରୁ ଅଧିକ"</string>
@@ -402,37 +387,26 @@
<skip />
<!-- no translation found for quick_settings_night_secondary_label_on_at (6256314040368487637) -->
<skip />
- <!-- no translation found for quick_settings_night_secondary_label_until (8664820079774824618) -->
+ <!-- no translation found for quick_settings_secondary_label_until (2749196569462600150) -->
<skip />
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
- <!-- no translation found for recents_empty_message (808480104164008572) -->
- <skip />
- <!-- no translation found for recents_empty_message_dismissed_all (2791312568666558651) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC ଅକ୍ଷମ କରାଯାଇଛି"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC ସକ୍ଷମ କରାଯାଇଛି"</string>
+ <string name="recents_empty_message" msgid="808480104164008572">"କୌଣସି ସାମ୍ପ୍ରତିକ ଆଇଟମ୍ ନାହିଁ"</string>
+ <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ଆପଣ ସୁବୁକିଛି ଖାଲି କରିଦେଇଛନ୍ତି"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ଆପ୍ଲିକେଶନ୍ ସୂଚନା"</string>
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ସ୍କ୍ରୀନ୍ ଲକ୍"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> କୁ ଆରମ୍ଭ କରାଯାଇପାରିଲା ନାହିଁ।"</string>
- <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
- <skip />
- <!-- no translation found for recents_stack_action_button_label (6593727103310426253) -->
- <skip />
- <!-- no translation found for recents_drag_hint_message (2649739267073203985) -->
- <skip />
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ସୁରକ୍ଷିତ-ମୋଡ୍ରେ ଅକ୍ଷମ ଅଟେ।"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"ସବୁ ଖାଲି କରନ୍ତୁ"</string>
+ <string name="recents_drag_hint_message" msgid="2649739267073203985">"ସ୍ପ୍ଲିଟ୍ ସ୍କ୍ରୀନ୍ ବ୍ୟବହାର କରିବା ପାଇଁ ଏଠାକୁ ଡ୍ରାଗ୍ କରନ୍ତୁ"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ଭୂସମାନ୍ତର ଭାବରେ ଭାଗ କରନ୍ତୁ"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ଭୂଲମ୍ବ ଭାବରେ ଭାଗ କରନ୍ତୁ"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"କଷ୍ଟମ୍ କରି ଭାଗ କରନ୍ତୁ"</string>
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"ସ୍କ୍ରୀନ୍କୁ ଉପର ଆଡ଼କୁ ଭାଗ କରନ୍ତୁ"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"ସ୍କ୍ରୀନ୍କୁ ବାମ ଆଡ଼କୁ ଭାଗ କରନ୍ତୁ"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"ସ୍କ୍ରୀନ୍କୁ ଡାହାଣ ଆଡ଼କୁ ଭାଗ କରନ୍ତୁ"</string>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"ଚାର୍ଜ ହୋଇଗଲା"</string>
<string name="expanded_header_battery_charging" msgid="205623198487189724">"ଚାର୍ଜ କରାଯାଉଛି"</string>
<string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"ପୂର୍ଣ୍ଣ ଚାର୍ଜ ହେବାକୁ ଆଉ <xliff:g id="CHARGING_TIME">%s</xliff:g> ଅଛି"</string>
@@ -441,20 +415,16 @@
<string name="description_target_search" msgid="3091587249776033139">"ସର୍ଚ୍ଚ"</string>
<string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ପାଇଁ ଉପରକୁ ସ୍ଲାଇଡ୍ କରନ୍ତୁ।"</string>
<string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ପାଇଁ ବାମକୁ ସ୍ଲାଇଡ୍ କରନ୍ତୁ"</string>
- <!-- no translation found for zen_priority_introduction (1149025108714420281) -->
- <skip />
- <!-- no translation found for zen_alarms_introduction (4934328096749380201) -->
- <skip />
+ <string name="zen_priority_introduction" msgid="1149025108714420281">"ଆଲାର୍ମ, ରିମାଇଣ୍ଡର୍, ଇଭେଣ୍ଟ ଏବଂ ଆପଣ ନିର୍ଦ୍ଦିଷ୍ଟ କରିଥିବା କଲର୍ଙ୍କ ବ୍ୟତୀତ ଆପଣଙ୍କ ଧ୍ୟାନ ଅନ୍ୟ କୌଣସି ଧ୍ୱନୀ ଏବଂ ଭାଇବ୍ରେଶନ୍ରେ ଆକର୍ଷଣ କରାଯିବନାହିଁ। ମ୍ୟୁଜିକ୍, ଭିଡିଓ ଏବଂ ଗେମ୍ ସମେତ ନିଜେ ଚଲାଇବାକୁ ବାଛିଥିବା ଅନ୍ୟ ସବୁକିଛି ଆପଣ ଶୁଣିପାରିବେ।"</string>
+ <string name="zen_alarms_introduction" msgid="4934328096749380201">"ଆଲାର୍ମ ବ୍ୟତୀତ ଆପଣଙ୍କ ଧ୍ୟାନ ଅନ୍ୟ କୌଣସି ଧ୍ୱନୀ ଏବଂ ଭାଇବ୍ରେଶନ୍ରେ ଆକର୍ଷଣ କରାଯିବନାହିଁ। ମ୍ୟୁଜିକ୍, ଭିଡିଓ ଏବଂ ଗେମ୍ ସମେତ ନିଜେ ଚଲାଇବାକୁ ବାଛିଥିବା ଅନ୍ୟ ସବୁକିଛି ଆପଣ ଶୁଣିପାରିବେ।"</string>
<string name="zen_priority_customize_button" msgid="7948043278226955063">"କଷ୍ଟମାଇଜ୍ କରନ୍ତୁ"</string>
- <!-- no translation found for zen_silence_introduction_voice (3948778066295728085) -->
- <skip />
+ <string name="zen_silence_introduction_voice" msgid="3948778066295728085">"ଆଲାର୍ମ, ମ୍ୟୁଜିକ୍, ଭିଡିଓ ଏବଂ ଗେମ୍ ସମେତ ଏହା ଦ୍ୱାରା ସମସ୍ତ ଧ୍ୱନୀ ଏବଂ ଭାଇବ୍ରେଶନ୍ ଅବରୋଧ ହୁଏ। ଆପଣ ତଥାପି ଫୋନ୍ କଲ୍ କରିପାରିବେ।"</string>
<string name="zen_silence_introduction" msgid="3137882381093271568">"ଆଲାର୍ମ, ମ୍ୟୁଜିକ୍, ଭିଡିଓ ଓ ଗେମ୍ସ ସମେତ ଏହାଦ୍ୱାରା ସମସ୍ତ ସାଉଣ୍ଡ ଓ ଭାଇବ୍ରେଶନ୍ ଅବରୋଧ ହୁଏ।"</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">"ନିମ୍ନରେ କମ୍ ଜରୁରୀ ବିଜ୍ଞପ୍ତି"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"ଖୋଲିବା ପାଇଁ ପୁଣି ଟାପ୍ କରନ୍ତୁ"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"ଅନଲକ୍ କରିବା ପାଇଁ ଉପରକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
- <!-- no translation found for do_disclosure_generic (5615898451805157556) -->
- <skip />
+ <string name="do_disclosure_generic" msgid="5615898451805157556">"ଏହି ଡିଭାଇସ୍ ଆପଣଙ୍କ ସଂସ୍ଥା ଦ୍ୱାରା ପରିଚାଳିତ।"</string>
<string name="do_disclosure_with_name" msgid="5640615509915445501">"ଏହି ଡିଭାଇସ୍ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ଦ୍ୱାରା ପରିଚାଳିତ ହେଉଛି"</string>
<string name="phone_hint" msgid="4872890986869209950">"ଫୋନ୍ ପାଇଁ ଆଇକନରୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
<string name="voice_hint" msgid="8939888732119726665">"ଭଏସ୍ ସହାୟକ ପାଇଁ ଆଇକନରୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
@@ -499,135 +469,94 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"ୟୁଜରଙ୍କୁ ବାହାର କରିବେ?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"ଏହି ୟୁଜରଙ୍କ ସମସ୍ତ ଆପ୍ ଓ ଡାଟା ଡିଲିଟ୍ ହେବ।"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"ବାହାର କରନ୍ତୁ"</string>
- <!-- no translation found for battery_saver_notification_title (8614079794522291840) -->
- <skip />
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"ବ୍ୟାଟେରୀ ସେଭର୍ ଅନ୍ ଅଛି"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"କାର୍ଯ୍ୟ ସମ୍ପାଦନ ଓ ବ୍ୟାକ୍ଗ୍ରାଉଣ୍ଡ ଡାଟା କମ୍ କରନ୍ତୁ"</string>
- <!-- no translation found for battery_saver_notification_action_text (132118784269455533) -->
- <skip />
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"ବ୍ୟାଟେରୀ ସେଭର୍ ଅଫ୍ କରନ୍ତୁ"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ଆପଣଙ୍କ ସ୍କ୍ରୀନ୍ରେ ପ୍ରଦର୍ଶିତ ହେଉଥିବା ସମସ୍ତ ବସ୍ତୁକୁ କ୍ୟାପଚର୍ କରିବା ଆରମ୍ଭ ହୋଇଯିବ।"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"ପୁଣି ଦେଖାନ୍ତୁ ନାହିଁ"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"ସମସ୍ତ ଖାଲି କରନ୍ତୁ"</string>
+ <!-- no translation found for manage_notifications_text (8035284146227267681) -->
+ <skip />
+ <!-- no translation found for dnd_suppressing_shade_text (7986451830430707907) -->
+ <skip />
<string name="media_projection_action_text" msgid="8470872969457985954">"ବର୍ତ୍ତମାନ ଆରମ୍ଭ କରନ୍ତୁ"</string>
<string name="empty_shade_text" msgid="708135716272867002">"କୌଣସି ବିଜ୍ଞପ୍ତି ନାହିଁ"</string>
<string name="profile_owned_footer" msgid="8021888108553696069">"ପ୍ରୋଫାଇଲ୍ ନିରୀକ୍ଷଣ କରାଯାଇପାରେ।"</string>
<string name="vpn_footer" msgid="2388611096129106812">"ନେଟ୍ୱର୍କ ନୀରିକ୍ଷଣ କରାଯାଇପାରେ"</string>
<string name="branded_vpn_footer" msgid="2168111859226496230">"ନେଟ୍ୱର୍କକୁ ନିରୀକ୍ଷଣ କରାଯାଇପାରେ"</string>
- <!-- no translation found for quick_settings_disclosure_management_monitoring (6645176135063957394) -->
- <skip />
- <!-- no translation found for quick_settings_disclosure_named_management_monitoring (370622174777570853) -->
- <skip />
- <!-- no translation found for quick_settings_disclosure_management_named_vpn (1085137869053332307) -->
- <skip />
- <!-- no translation found for quick_settings_disclosure_named_management_named_vpn (6290456493852584017) -->
- <skip />
- <!-- no translation found for quick_settings_disclosure_management (3294967280853150271) -->
- <skip />
- <!-- no translation found for quick_settings_disclosure_named_management (1059403025094542908) -->
- <skip />
- <!-- no translation found for quick_settings_disclosure_management_vpns (3698767349925266482) -->
- <skip />
- <!-- no translation found for quick_settings_disclosure_named_management_vpns (7777821385318891527) -->
- <skip />
- <!-- no translation found for quick_settings_disclosure_managed_profile_monitoring (5125463987558278215) -->
- <skip />
- <!-- no translation found for quick_settings_disclosure_named_managed_profile_monitoring (8973606847896650284) -->
- <skip />
- <!-- no translation found for quick_settings_disclosure_monitoring (679658227269205728) -->
- <skip />
- <!-- no translation found for quick_settings_disclosure_vpns (8170318392053156330) -->
- <skip />
- <!-- no translation found for quick_settings_disclosure_managed_profile_named_vpn (3494535754792751741) -->
- <skip />
- <!-- no translation found for quick_settings_disclosure_personal_profile_named_vpn (4467456202486569906) -->
- <skip />
- <!-- no translation found for quick_settings_disclosure_named_vpn (6943724064780847080) -->
- <skip />
- <!-- no translation found for monitoring_title_device_owned (1652495295941959815) -->
- <skip />
+ <string name="quick_settings_disclosure_management_monitoring" msgid="6645176135063957394">"ଆପଣଙ୍କ ସଂସ୍ଥା ଏହି ଡିଭାଇସକୁ ପରିଚାଳନା କରନ୍ତି ଏବଂ ନେଟୱର୍କ ଟ୍ରାଫିକ୍ ନୀରିକ୍ଷଣ କରିପାରନ୍ତି"</string>
+ <string name="quick_settings_disclosure_named_management_monitoring" msgid="370622174777570853">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ଏହି ଡିଭାଇସକୁ ପରିଚାଳନା କରନ୍ତି ଏବଂ ନେଟୱର୍କ ଟ୍ରାଫିକ୍ ନୀରିକ୍ଷଣ କରନ୍ତି"</string>
+ <string name="quick_settings_disclosure_management_named_vpn" msgid="1085137869053332307">"ଡିଭାଇସ୍ ଆପଣଙ୍କ ସଂସ୍ଥା ଦ୍ୱାରା ପରିଚାଳିତ ଏବଂ <xliff:g id="VPN_APP">%1$s</xliff:g>ରେ ସଂଯୁକ୍ତ"</string>
+ <string name="quick_settings_disclosure_named_management_named_vpn" msgid="6290456493852584017">"ଡିଭାଇସ୍ <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ଦ୍ୱାରା ପରିଚାଳିତ ଏବଂ <xliff:g id="VPN_APP">%2$s</xliff:g>ରେ ସଂଯୁକ୍ତ"</string>
+ <string name="quick_settings_disclosure_management" msgid="3294967280853150271">"ଡିଭାଇସ୍ ଆପଣଙ୍କ ସଂସ୍ଥା ଦ୍ୱାରା ପରିଚାଳିତ"</string>
+ <string name="quick_settings_disclosure_named_management" msgid="1059403025094542908">"ଡିଭାଇସ୍ <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ଦ୍ୱାରା ପରିଚାଳିତ ହେଉଛି"</string>
+ <string name="quick_settings_disclosure_management_vpns" msgid="3698767349925266482">"ଡିଭାଇସ୍ ଆପଣଙ୍କ ସଂସ୍ଥା ଦ୍ୱାରା ପରିଚାଳିତ ଏବଂ VPNଗୁଡ଼ିକରେ ସଂଯୁକ୍ତ"</string>
+ <string name="quick_settings_disclosure_named_management_vpns" msgid="7777821385318891527">"ଡିଭାଇସ୍ <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ଦ୍ୱାରା ପରିଚାଳିତ ଏବଂ VPNଗୁଡ଼ିକରେ ସଂଯୁକ୍ତ"</string>
+ <string name="quick_settings_disclosure_managed_profile_monitoring" msgid="5125463987558278215">"ଆପଣଙ୍କ ୱର୍କ ପ୍ରୋଫାଇଲରେ ଆପଣଙ୍କ ସଂସ୍ଥା ନେଟୱର୍କ ଟ୍ରାଫିକ୍ ନୀରିକ୍ଷଣ କରିପାରନ୍ତି"</string>
+ <string name="quick_settings_disclosure_named_managed_profile_monitoring" msgid="8973606847896650284">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ଆପଣଙ୍କ ୱର୍କ ପ୍ରୋଫାଇଲରେ ନେଟୱର୍କ ଟ୍ରାଫିକ୍ ନୀରିକ୍ଷଣ କରିପାରନ୍ତି"</string>
+ <string name="quick_settings_disclosure_monitoring" msgid="679658227269205728">"ନେଟୱର୍କ ନୀରିକ୍ଷଣ କରାଯାଇପାରେ"</string>
+ <string name="quick_settings_disclosure_vpns" msgid="8170318392053156330">"ଡିଭାଇସ୍ VPNଗୁଡ଼ିକରେ ସଂଯୁକ୍ତ"</string>
+ <string name="quick_settings_disclosure_managed_profile_named_vpn" msgid="3494535754792751741">"ୱର୍କ ପ୍ରୋଫାଇଲ୍ <xliff:g id="VPN_APP">%1$s</xliff:g>ରେ ସଂଯୁକ୍ତ"</string>
+ <string name="quick_settings_disclosure_personal_profile_named_vpn" msgid="4467456202486569906">"ବ୍ୟକ୍ତିଗତ ପ୍ରୋଫାଇଲ୍ <xliff:g id="VPN_APP">%1$s</xliff:g>ରେ ସଂଯୁକ୍ତ"</string>
+ <string name="quick_settings_disclosure_named_vpn" msgid="6943724064780847080">"ଡିଭାଇସ୍ <xliff:g id="VPN_APP">%1$s</xliff:g>ରେ ସଂଯୁକ୍ତ"</string>
+ <string name="monitoring_title_device_owned" msgid="1652495295941959815">"ଡିଭାଇସ୍ ପରିଚାଳନା"</string>
<string name="monitoring_title_profile_owned" msgid="6790109874733501487">"ପ୍ରୋଫାଇଲ୍ ନୀରିକ୍ଷଣ"</string>
<string name="monitoring_title" msgid="169206259253048106">"ନେଟ୍ୱର୍କ ନୀରିକ୍ଷଣ"</string>
- <!-- no translation found for monitoring_subtitle_vpn (876537538087857300) -->
- <skip />
- <!-- no translation found for monitoring_subtitle_network_logging (3341264304793193386) -->
- <skip />
- <!-- no translation found for monitoring_subtitle_ca_certificate (3874151893894355988) -->
- <skip />
+ <string name="monitoring_subtitle_vpn" msgid="876537538087857300">"VPN"</string>
+ <string name="monitoring_subtitle_network_logging" msgid="3341264304793193386">"ନେଟୱର୍କ ଲଗିଙ୍ଗ"</string>
+ <string name="monitoring_subtitle_ca_certificate" msgid="3874151893894355988">"CA ସର୍ଟିଫିକେଟ୍"</string>
<string name="disable_vpn" msgid="4435534311510272506">"VPN ଅକ୍ଷମ କରନ୍ତୁ"</string>
<string name="disconnect_vpn" msgid="1324915059568548655">"VPN ବିଛିନ୍ନ କରନ୍ତୁ"</string>
- <!-- no translation found for monitoring_button_view_policies (100913612638514424) -->
- <skip />
- <!-- no translation found for monitoring_description_named_management (5281789135578986303) -->
- <skip />
- <!-- no translation found for monitoring_description_management (4573721970278370790) -->
- <skip />
- <!-- no translation found for monitoring_description_management_ca_certificate (5202023784131001751) -->
- <skip />
- <!-- no translation found for monitoring_description_managed_profile_ca_certificate (4683248196789897964) -->
- <skip />
- <!-- no translation found for monitoring_description_ca_certificate (7886985418413598352) -->
- <skip />
- <!-- no translation found for monitoring_description_management_network_logging (7184005419733060736) -->
- <skip />
- <!-- no translation found for monitoring_description_named_vpn (7403457334088909254) -->
- <skip />
- <!-- no translation found for monitoring_description_two_named_vpns (4198511413729213802) -->
- <skip />
- <!-- no translation found for monitoring_description_managed_profile_named_vpn (1427905889862420559) -->
- <skip />
- <!-- no translation found for monitoring_description_personal_profile_named_vpn (3133980926929069283) -->
- <skip />
+ <string name="monitoring_button_view_policies" msgid="100913612638514424">"ପଲିସୀ ଦେଖନ୍ତୁ"</string>
+ <string name="monitoring_description_named_management" msgid="5281789135578986303">"ଆପଣଙ୍କ ଡିଭାଇସ୍ <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ଦ୍ୱାରା ପରିଚାଳନା କରାଯାଉଛି।.\n\nଆପଣଙ୍କ ଆଡମିନ୍ ସେଟିଙ୍ଗ, କର୍ପୋରେଟ୍ ଆକ୍ସେସ୍, ଆପ୍, ଆପଣଙ୍କ ଡିଭାଇସ୍ ସମ୍ବନ୍ଧୀୟ ଡାଟା ଏବଂ ଆପଣଙ୍କ ଡିଭାଇସର ଲୋକେଶନ୍ ନିରୀକ୍ଷଣ ଓ ପରିଚାଳନା କରିପାରନ୍ତି।\n\nଅଧିକ ସୂଚନା ପାଇଁ, ନିଜ ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
+ <string name="monitoring_description_management" msgid="4573721970278370790">"ଆପଣଙ୍କ ଡିଭାଇସ୍ ଆପଣଙ୍କ ସଂସ୍ଥା ଦ୍ୱାରା ପରିଚାଳନା କରାଯାଉଛି।\n\nଆପଣଙ୍କ ଆଡମିନ୍ ସେଟିଙ୍ଗ, କର୍ପୋରେଟ୍ ଆକ୍ସେସ୍, ଆପ୍, ଆପଣଙ୍କ ଡିଭାଇସ୍ ସମ୍ବନ୍ଧୀୟ ଡାଟା ଏବଂ ଆପଣଙ୍କ ଡିଭାଇସର ଲୋକେଶନ୍ ନିରୀକ୍ଷଣ ଓ ପରିଚାଳନା କରିପାରନ୍ତି।\n\nଅଧିକ ସୂଚନା ପାଇଁ, ନିଜ ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
+ <string name="monitoring_description_management_ca_certificate" msgid="5202023784131001751">"ଏହି ଡିଭାଇସରେ ଆପଣଙ୍କ ସଂସ୍ଥା ଏକ ସର୍ଟିଫିକେଟ୍ ଅଥରିଟି ଇନଷ୍ଟଲ୍ କରିଛନ୍ତି। ଆପଣଙ୍କ ସୁରକ୍ଷିତ ନେଟୱର୍କ ଟ୍ରାଫିକ୍ ନୀରିକ୍ଷଣ କିମ୍ବା ସଂଶୋଧନ କରାଯାଇ ପାରେ।"</string>
+ <string name="monitoring_description_managed_profile_ca_certificate" msgid="4683248196789897964">"ଆପଣଙ୍କ ୱର୍କ ପ୍ରୋଫାଇଲରେ ଆପଣଙ୍କ ସଂସ୍ଥା ଏକ ସର୍ଟିଫିକେଟ୍ ଅଥରିଟି ଇନଷ୍ଟଲ୍ କରିଛନ୍ତି। ଆପଣଙ୍କ ସୁରକ୍ଷିତ ନେଟୱର୍କ ଟ୍ରାଫିକ୍ ନୀରିକ୍ଷଣ କିମ୍ବା ସଂଶୋଧନ କରାଯାଇ ପାରେ।"</string>
+ <string name="monitoring_description_ca_certificate" msgid="7886985418413598352">"ଏହି ଡିଭାଇସରେ ଏକ ସର୍ଟିଫିକେଟ୍ ଅଥରିଟି ଇନଷ୍ଟଲ୍ କରାଯାଇଛି। ଆପଣଙ୍କ ସୁରକ୍ଷିତ ନେଟୱର୍କ ଟ୍ରାଫିକ୍ ନୀରିକ୍ଷଣ କିମ୍ବା ସଂଶୋଧନ କରାଯାଇ ପାରେ।"</string>
+ <string name="monitoring_description_management_network_logging" msgid="7184005419733060736">"ଆପଣଙ୍କ ଆଡମିନ୍ ନେଟୱର୍କ ଲଗଇନ୍ କରିବା ଅନ୍ କରିଛନ୍ତି, ଯାହା ଆପଣଙ୍କ ଡିଭାଇସରେ ଟ୍ରାଫିକ୍ ନୀରିକ୍ଷଣ କରେ।"</string>
+ <string name="monitoring_description_named_vpn" msgid="7403457334088909254">"ଆପଣ <xliff:g id="VPN_APP">%1$s</xliff:g>ରେ ସଂଯୁକ୍ତ, ଯାହା ଇମେଲ୍, ଆପ୍ ଓ ୱେବସାଇଟ୍ ସମେତ ଆପଣଙ୍କ ନେଟୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।"</string>
+ <string name="monitoring_description_two_named_vpns" msgid="4198511413729213802">"ଆପଣ <xliff:g id="VPN_APP_0">%1$s</xliff:g> ଏବଂ <xliff:g id="VPN_APP_1">%2$s</xliff:g>ରେ ସଂଯୁକ୍ତ, ଯାହା ଇମେଲ୍, ଆପ୍ ଓ ୱେବସାଇଟ୍ ସମେତ ଆପଣଙ୍କ ନେଟୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।"</string>
+ <string name="monitoring_description_managed_profile_named_vpn" msgid="1427905889862420559">"ଆପଣଙ୍କ ୱର୍କ ପ୍ରୋଫାଇଲ୍ <xliff:g id="VPN_APP">%1$s</xliff:g>ରେ ସଂଯୁକ୍ତ, ଯାହା ଇମେଲ୍, ଆପ୍ ଓ ୱେବସାଇଟ୍ ସମେତ ଆପଣଙ୍କ ନେଟୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।"</string>
+ <string name="monitoring_description_personal_profile_named_vpn" msgid="3133980926929069283">"ଆପଣଙ୍କ ବ୍ୟକ୍ତିଗତ ପ୍ରୋଫାଇଲ୍ <xliff:g id="VPN_APP">%1$s</xliff:g>ରେ ସଂଯୁକ୍ତ, ଯାହା ଇମେଲ୍, ଆପ୍ ଓ ୱେବସାଇଟ୍ ସମେତ ଆପଣଙ୍କ ନେଟୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"ଆପଣଙ୍କ ଡିଭାଇସ୍ <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> ଦ୍ୱାରା ପରିଚାଳିତ ହେଉଛି।"</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"ଆପଣଙ୍କ ଡିଭାଇସ୍ ପରିଚାଳନା କରିବାକୁ <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> ବ୍ୟବହାର କରନ୍ତି।"</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"ଆପଣଙ୍କ ଆଡମିନ୍ ସେଟିଙ୍ଗ, କର୍ପୋରେଟ୍ ଆକ୍ସେସ୍, ଆପ୍, ଆପଣଙ୍କ ଡିଭାଇସ୍ ସମ୍ବନ୍ଧୀୟ ଡାଟା ଏବଂ ଆପଣଙ୍କ ଡିଭାଇସର ଲୋକେଶନ୍ ନିରୀକ୍ଷଣ ଓ ପରିଚାଳନା କରିପାରନ୍ତି।"</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"ଅଧିକ ଜାଣନ୍ତୁ"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"ଆପଣ <xliff:g id="VPN_APP">%1$s</xliff:g>ରେ ସଂଯୁକ୍ତ ଅଛନ୍ତି, ଯାହା ଇମେଲ୍, ଆପ୍ ଓ ୱେବସାଇଟ୍ ସମେତ ଆପଣଙ୍କ ନେଟ୍ୱର୍କର ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।"</string>
- <!-- no translation found for monitoring_description_vpn_settings_separator (1933186756733474388) -->
- <skip />
- <!-- no translation found for monitoring_description_vpn_settings (6434859242636063861) -->
- <skip />
- <!-- no translation found for monitoring_description_ca_cert_settings_separator (4987350385906393626) -->
- <skip />
- <!-- no translation found for monitoring_description_ca_cert_settings (5489969458872997092) -->
- <skip />
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
+ <string name="monitoring_description_vpn_settings" msgid="6434859242636063861">"VPN ସେଟିଙ୍ଗ ଖୋଲନ୍ତୁ"</string>
+ <string name="monitoring_description_ca_cert_settings_separator" msgid="4987350385906393626">" "</string>
+ <string name="monitoring_description_ca_cert_settings" msgid="5489969458872997092">"ମୁକ୍ତ ବିଶ୍ୱସ୍ତ କ୍ରୀଡେନଶିଆଲ୍"</string>
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"ଆପଣଙ୍କ ଆଡମିନ୍ ନେଟ୍ୱର୍କ ଲଗଇନ୍ କରିବା ଅନ୍ କରିଛନ୍ତି, ଯାହା ଆପଣଙ୍କ ଡିଭାଇସରେ ଟ୍ରାଫିକ୍ ନିରୀକ୍ଷଣ କରେ।\n\nଅଧିକ ସୂଚନା ପାଇଁ, ନିଜ ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"ଏକ VPN ସଂଯୋଗ ସେଟ୍ ଅପ୍ କରିବା ପାଇଁ ଆପଣ ଗୋଟିଏ ଆପକୁ ଅନୁମତି ଦେଲେ।\n\nଏହି ଆପ୍ ଇମେଲ୍, ଆପ୍ ଓ ୱେବସାଇଟ୍ ସମେତ ଆପଣଙ୍କ ଡିଭାଇସ୍ ଓ ନେଟ୍ୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।"</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"ଆପଣଙ୍କ ୱର୍କ ପ୍ରୋଫାଇଲ୍ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ଦ୍ୱାରା ପରିଚାଳନା କରାଯାଉଛି।\n\nଆପଣଙ୍କ ଆଡମିନ୍ ଇମେଲ୍, ଆପ୍ ଓ ୱେବସାଇଟ୍ ସମେତ ଆପଣଙ୍କ ନେଟୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରିବେ।\n\nଅଧିକ ସୂଚନା ପାଇଁ, ନିଜ ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।.\n\nଆପଣ ଏକ VPNରେ ମଧ୍ୟ ସଂଯୁକ୍ତ, ଯାହା ଆପଣଙ୍କ ନେଟୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।"</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
- <!-- no translation found for monitoring_description_app (1828472472674709532) -->
- <skip />
+ <string name="monitoring_description_app" msgid="1828472472674709532">"ଆପଣ <xliff:g id="APPLICATION">%1$s</xliff:g>ରେ ସଂଯୁକ୍ତ, ଯାହା ଇମେଲ୍, ଆପ୍ ଓ ୱେବସାଇଟ୍ ସମେତ ଆପଣଙ୍କ ନେଟୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।"</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"ଆପଣ <xliff:g id="APPLICATION">%1$s</xliff:g>ରେ ସଂଯୁକ୍ତ, ଯାହା ଇମେଲ୍, ଆପ୍ ଓ ୱେବସାଇଟ୍ ସମେତ ଆପଣଙ୍କ ନେଟ୍ୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।"</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"ଆପଣ <xliff:g id="APPLICATION">%1$s</xliff:g>ରେ ସଂଯୁକ୍ତ ଅଛନ୍ତି, ଯାହା ଇମେଲ୍, ଆପ୍ ଓ ୱେବସାଇଟ୍ ସମେତ ଆପଣଙ୍କ ନେଟ୍ୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।"</string>
- <!-- no translation found for monitoring_description_app_work (4612997849787922906) -->
- <skip />
- <!-- no translation found for monitoring_description_app_personal_work (5664165460056859391) -->
- <skip />
- <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
- <skip />
- <!-- no translation found for keyguard_indication_trust_managed (8319646760022357585) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="4612997849787922906">"ଆପଣଙ୍କ ୱର୍କ ପ୍ରୋଫାଇଲ୍ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ଦ୍ୱାରା ପରିଚାଳନା କରାଯାଉଛି। ପ୍ରୋଫାଇଲଟି <xliff:g id="APPLICATION">%2$s</xliff:g> ସହ ସଂଯୁକ୍ତ ଅଛି, ଯାହା ଇମେଲ୍, ଆପ୍ ଓ ୱେବସାଇଟ୍ ସମେତ ଆପଣଙ୍କ ନେଟୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।\n\nଅଧିକ ସୂଚନା ପାଇଁ, ନିଜ ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
+ <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"ଆପଣଙ୍କ ୱର୍କ ପ୍ରୋଫାଇଲ୍ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ଦ୍ୱାରା ପରିଚାଳନା କରାଯାଉଛି। ପ୍ରୋଫାଇଲଟି <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ସହ ସଂଯୁକ୍ତ ଅଛି, ଯାହା ଇମେଲ୍, ଆପ୍ ଓ ୱେବସାଇଟ୍ ସମେତ ଆପଣଙ୍କ ନେଟୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।\n\nଆପଣ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>ରେ ମଧ୍ୟ ସଂଯୁକ୍ତ, ଯାହା ଆପଣଙ୍କ ବ୍ୟକ୍ତିଗତ ନେଟୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।"</string>
+ <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"<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> ଚାଲୁଛି"</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"ଯେତେବେଳ ପର୍ଯ୍ୟନ୍ତ ଆପଣ ମାନୁଆଲୀ ଅନଲକ୍ କରିନାହାନ୍ତି, ସେତେବେଳ ପର୍ଯ୍ୟନ୍ତ ଡିଭାଇସ୍ ଲକ୍ ରହିବ"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"ବିଜ୍ଞପ୍ତିକୁ ଶୀଘ୍ର ପ୍ରାପ୍ତ କରନ୍ତୁ"</string>
<string name="hidden_notifications_text" msgid="2326409389088668981">"ଅନଲକ୍ କରିବା ପୁର୍ବରୁ ସେମାନଙ୍କୁ ଦେଖନ୍ତୁ"</string>
<string name="hidden_notifications_cancel" msgid="3690709735122344913">"ନାହିଁ, ଥାଉ"</string>
<string name="hidden_notifications_setup" msgid="41079514801976810">"ସେଟ୍ ଅପ୍ କରନ୍ତୁ"</string>
<string name="zen_mode_and_condition" msgid="4462471036429759903">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
- <!-- no translation found for volume_zen_end_now (6930243045593601084) -->
+ <string name="volume_zen_end_now" msgid="6930243045593601084">"ବର୍ତ୍ତମାନ ଅଫ୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for accessibility_volume_settings (4915364006817819212) -->
<skip />
<string name="accessibility_volume_expand" msgid="5946812790999244205">"ବଢ଼ାନ୍ତୁ"</string>
<string name="accessibility_volume_collapse" msgid="3609549593031810875">"ଛୋଟ କରନ୍ତୁ"</string>
<!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
<skip />
<string name="screen_pinning_title" msgid="3273740381976175811">"ସ୍କ୍ରିନକୁ ପିନ୍ କରାଯାଇଛି"</string>
- <!-- no translation found for screen_pinning_description (8909878447196419623) -->
- <skip />
+ <string name="screen_pinning_description" msgid="8909878447196419623">"ଆପଣ ଅନପିନ୍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍ କରିବାକୁ ସ୍ପର୍ଶ କରି ଧରିରଖନ୍ତୁ ଓ ଦେଖନ୍ତୁ।"</string>
<!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
<skip />
- <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
- <skip />
+ <string name="screen_pinning_description_accessible" msgid="426190689254018656">"ଆପଣ ଅନପିନ୍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍ କରିବାକୁ ସ୍ପର୍ଶ କରନ୍ତୁ ଏବଂ ଓଭରଭ୍ୟୁକୁ ଧରିରଖନ୍ତୁ।"</string>
<!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
<skip />
<!-- no translation found for screen_pinning_toast (2266705122951934150) -->
@@ -646,67 +575,40 @@
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"ଆପଣ ନିଜ ୱର୍କ ପ୍ରୋଫାଇଲ୍ ବ୍ୟବହାର କରୁଛନ୍ତି"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"କଲ୍ କରନ୍ତୁ"</string>
<string name="stream_system" msgid="7493299064422163147">"ସିଷ୍ଟମ୍"</string>
- <!-- no translation found for stream_ring (8213049469184048338) -->
- <skip />
- <!-- no translation found for stream_music (9086982948697544342) -->
- <skip />
+ <string name="stream_ring" msgid="8213049469184048338">"ରିଙ୍ଗ"</string>
+ <string name="stream_music" msgid="9086982948697544342">"ମିଡିଆ"</string>
<string name="stream_alarm" msgid="5209444229227197703">"ଆଲାର୍ମ"</string>
- <!-- no translation found for stream_notification (2563720670905665031) -->
- <skip />
- <!-- no translation found for stream_bluetooth_sco (2055645746402746292) -->
- <skip />
- <!-- no translation found for stream_dtmf (2447177903892477915) -->
- <skip />
- <!-- no translation found for stream_accessibility (301136219144385106) -->
- <skip />
- <!-- no translation found for ring_toggle_title (3281244519428819576) -->
- <skip />
- <!-- no translation found for volume_ringer_status_normal (4273142424125855384) -->
- <skip />
- <!-- no translation found for volume_ringer_status_vibrate (1825615171021346557) -->
- <skip />
- <!-- no translation found for volume_ringer_status_silent (6896394161022916369) -->
- <skip />
- <!-- no translation found for volume_stream_content_description_unmute (4436631538779230857) -->
- <skip />
- <!-- no translation found for volume_stream_content_description_vibrate (1187944970457807498) -->
- <skip />
- <!-- no translation found for volume_stream_content_description_mute (3625049841390467354) -->
- <skip />
- <!-- no translation found for volume_stream_content_description_vibrate_a11y (6427727603978431301) -->
- <skip />
- <!-- no translation found for volume_stream_content_description_mute_a11y (8995013018414535494) -->
- <skip />
+ <string name="stream_notification" msgid="2563720670905665031">"ବିଜ୍ଞପ୍ତି"</string>
+ <string name="stream_bluetooth_sco" msgid="2055645746402746292">"ବ୍ଲୁ-ଟୁଥ୍"</string>
+ <string name="stream_dtmf" msgid="2447177903892477915">"ଡୁଆଲ୍ ମଲ୍ଟି ଟୋନ୍ ଫ୍ରିକ୍ୱେନ୍ସୀ"</string>
+ <string name="stream_accessibility" msgid="301136219144385106">"ଆକ୍ସେସିବିଲିଟୀ"</string>
+ <string name="ring_toggle_title" msgid="3281244519428819576">"କଲ୍"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"ରିଙ୍ଗ"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"ଭାଇବ୍ରେଟ୍"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"ମ୍ୟୁଟ୍"</string>
+ <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s। ଅନମ୍ୟୁଟ୍ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ।"</string>
+ <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s। ଭାଇବ୍ରେଟ୍ ସେଟ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ। ଆକ୍ସେସିବିଲିଟୀ ସର୍ଭିସ୍ ମ୍ୟୁଟ୍ କରାଯାଇପାରେ।"</string>
+ <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s। ମ୍ୟୁଟ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ। ଆକ୍ସେସିବିଲିଟୀ ସର୍ଭିସ୍ ମ୍ୟୁଟ୍ କରାଯାଇପାରେ।"</string>
+ <string name="volume_stream_content_description_vibrate_a11y" msgid="6427727603978431301">"%1$s। ଭାଇବ୍ରେଟରେ ସେଟ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string>
+ <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s। ମ୍ୟୁଟ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string>
<!-- no translation found for volume_dialog_title (7272969888820035876) -->
<skip />
- <!-- no translation found for volume_dialog_ringer_guidance_vibrate (8902050240801159042) -->
- <skip />
- <!-- no translation found for volume_dialog_ringer_guidance_silent (2128975224280276122) -->
- <skip />
<!-- no translation found for volume_dialog_ringer_guidance_ring (6144469689490528338) -->
<skip />
- <!-- no translation found for output_title (5355078100792942802) -->
- <skip />
- <!-- no translation found for output_calls_title (8717692905017206161) -->
- <skip />
- <!-- no translation found for output_none_found (5544982839808921091) -->
- <skip />
- <!-- no translation found for output_none_found_service_off (8631969668659757069) -->
- <skip />
- <!-- no translation found for output_service_bt (6224213415445509542) -->
- <skip />
- <!-- no translation found for output_service_wifi (3749735218931825054) -->
- <skip />
- <!-- no translation found for output_service_bt_wifi (4486837869988770896) -->
- <skip />
+ <string name="output_title" msgid="5355078100792942802">"ମିଡିଆ ଆଉଟପୁଟ୍"</string>
+ <string name="output_calls_title" msgid="8717692905017206161">"ଫୋନ୍ କଲ୍ ଆଉଟପୁଟ୍"</string>
+ <string name="output_none_found" msgid="5544982839808921091">"କୌଣସି ଡିଭାଇସ୍ ମିଳିଲା ନାହିଁ"</string>
+ <string name="output_none_found_service_off" msgid="8631969668659757069">"କୌଣସି ଡିଭାଇସ୍ ମିଳିଲା ନାହିଁ। <xliff:g id="SERVICE">%1$s</xliff:g> ଅନ୍ କରି ଦେଖନ୍ତୁ"</string>
+ <string name="output_service_bt" msgid="6224213415445509542">"ବ୍ଲୁ-ଟୁଥ୍"</string>
+ <string name="output_service_wifi" msgid="3749735218931825054">"ୱାଇ-ଫାଇ"</string>
+ <string name="output_service_bt_wifi" msgid="4486837869988770896">"ବ୍ଲୁ-ଟୁଥ୍ ଓ ୱାଇ-ଫାଇ"</string>
<string name="system_ui_tuner" msgid="708224127392452018">"ସିଷ୍ଟମ୍ UI ଟ୍ୟୁନର୍"</string>
<string name="show_battery_percentage" msgid="5444136600512968798">"ଏମ୍ବେଡ୍ ହୋଇଥିବା ବ୍ୟାଟେରୀ ଶତକଡ଼ା ଦେଖାନ୍ତୁ"</string>
<string name="show_battery_percentage_summary" msgid="3215025775576786037">"ଚାର୍ଜ ହେଉନଥିବାବେଳେ ଷ୍ଟାଟସ୍ ବାର୍ ଆଇକନ୍ ଭିତରେ ବ୍ୟାଟେରୀ ସ୍ତର ଶତକଡ଼ା ଦେଖାନ୍ତୁ"</string>
<string name="quick_settings" msgid="10042998191725428">"ଦ୍ରୁତ ସେଟିଙ୍ଗ"</string>
<string name="status_bar" msgid="4877645476959324760">"ଷ୍ଟାଟସ୍ ବାର୍"</string>
<string name="overview" msgid="4018602013895926956">"ଅବଲୋକନ"</string>
- <!-- no translation found for demo_mode (2532177350215638026) -->
- <skip />
+ <string name="demo_mode" msgid="2532177350215638026">"ସିଷ୍ଟମ୍ UI ଡେମୋ ମୋଡ୍"</string>
<string name="enable_demo_mode" msgid="4844205668718636518">"ଡେମୋ ମୋଡ୍ ସକ୍ଷମ କରନ୍ତୁ"</string>
<string name="show_demo_mode" msgid="2018336697782464029">"ଡେମୋ ମୋଡ୍ ଦେଖାନ୍ତୁ"</string>
<string name="status_bar_ethernet" msgid="5044290963549500128">"ଇଥରନେଟ୍"</string>
@@ -738,26 +640,19 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"ବ୍ଲୁ-ଟୁଥ୍ ଅନ୍ କରିବେ?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"ଆପଣଙ୍କ ଟାବଲେଟ୍ରେ କୀ’ବୋର୍ଡ ସଂଯୋଗ କରିବା ପାଇଁ ଆପଣଙ୍କୁ ପ୍ରଥମେ ବ୍ଲୁ-ଟୁଥ୍ ଅନ୍ କରିବାକୁ ହେବ।"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ଅନ୍ କରନ୍ତୁ"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (3207312268609236827) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings_on (7545060756610299966) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings_off (8208165412614935229) -->
- <skip />
- <!-- no translation found for power_notification_controls_description (4372459941671353358) -->
- <skip />
- <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ନିରବରେ ଦେଖାନ୍ତୁ"</string>
+ <string name="block" msgid="2734508760962682611">"ସମସ୍ତ ବିଜ୍ଞପ୍ତି ବ୍ଲକ୍ କରନ୍ତୁ"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"ନିରବ କରନ୍ତୁ ନାହିଁ"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"ନିରବ କିମ୍ବା ବ୍ଲକ୍ କରନ୍ତୁ ନାହିଁ"</string>
+ <string name="tuner_full_importance_settings" msgid="3207312268609236827">"ପାୱାର୍ ବିଜ୍ଞପ୍ତି କଣ୍ଟ୍ରୋଲ୍"</string>
+ <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"ଅନ୍"</string>
+ <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ଅଫ୍"</string>
+ <string name="power_notification_controls_description" msgid="4372459941671353358">"ପାୱାର୍ ବିଜ୍ଞପ୍ତି କଣ୍ଟ୍ରୋଲ୍ରେ, ଆପଣ ଏକ ଆପ୍ ବିଜ୍ଞପ୍ତି ପାଇଁ 0 ରୁ 5 ଗୁରୁତ୍ୱ ସ୍ତର ସେଟ୍ କରିହେବେ। \n\n"<b>"ସ୍ତର 5"</b>" \n- ବିଜ୍ଞପ୍ତି ତାଲିକାର ଶୀର୍ଷରେ ଦେଖାନ୍ତୁ \n- ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନରେ ବାଧା ଦେବାକୁ ଅନୁମତି ଦିଅନ୍ତୁ \n- ସର୍ବଦା ପିକ୍ କରନ୍ତୁ \n\n"<b>"ସ୍ତର 4"</b>" \n- ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନରେ ବାଧା ଦେବା ବ୍ଲକ୍ କରନ୍ତୁ \n- ସର୍ବଦା ପିକ୍ କରନ୍ତୁ \n\n"<b>"ସ୍ତର 3"</b>" \n- ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନରେ ବାଧା ଦେବା ବ୍ଲକ୍ କରନ୍ତୁ \n- କଦାପି ପିକ୍ କରନ୍ତୁ ନାହିଁ \n\n"<b>"ସ୍ତର 2"</b>" \n- ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନରେ ବାଧା ଦେବା ବ୍ଲକ୍ କରନ୍ତୁ \n- କଦାପି ପିକ୍ କରନ୍ତୁ ନାହିଁ \n- କଦାପି ସାଉଣ୍ଡ ଓ ଭାଇବ୍ରେଟ୍ କରନ୍ତୁ ନାହିଁ \n\n"<b>"ସ୍ତର 1"</b>" \n- ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନରେ ବାଧା ଦେବା ବ୍ଲକ୍ କରନ୍ତୁ \n- କଦାପି ପିକ୍ କରନ୍ତୁ ନାହିଁ \n- କଦାପି ସାଉଣ୍ଡ ଓ ଭାଇବ୍ରେଟ୍ କରନ୍ତୁ ନାହିଁ \n- ଲକ୍ ସ୍କ୍ରୀନ୍ ଓ ଷ୍ଟାଟସ୍ ବାର୍ରୁ ଲୁଚାନ୍ତୁ \n- ବିଜ୍ଞପ୍ତି ତାଲିକାର ନିମ୍ନରେ ଦେଖାନ୍ତୁ \n\n"<b>"ସ୍ତର 0"</b>" \n- ଆପରୁ ସମସ୍ତ ବିଜ୍ଞପ୍ତି ବ୍ଲକ୍ କରନ୍ତୁ"</string>
+ <string name="notification_header_default_channel" msgid="7506845022070889909">"ବିଜ୍ଞପ୍ତି"</string>
<!-- no translation found for notification_channel_disabled (344536703863700565) -->
<skip />
+ <!-- no translation found for notification_channel_minimized (1664411570378910931) -->
+ <skip />
<!-- no translation found for inline_blocking_helper (3055064577771478591) -->
<skip />
<!-- no translation found for inline_keep_showing (8945102997083836858) -->
@@ -766,124 +661,97 @@
<skip />
<!-- no translation found for inline_keep_button (6665940297019018232) -->
<skip />
+ <!-- no translation found for inline_minimize_button (966233327974702195) -->
+ <skip />
<!-- no translation found for inline_keep_showing_app (1723113469580031041) -->
<skip />
<!-- no translation found for notification_unblockable_desc (1037434112919403708) -->
<skip />
- <!-- no translation found for notification_channel_controls_opened_accessibility (6553950422055908113) -->
+ <!-- no translation found for notification_appops_camera_active (730959943016785931) -->
<skip />
- <!-- no translation found for notification_channel_controls_closed_accessibility (7521619812603693144) -->
+ <!-- no translation found for notification_appops_microphone_active (1546319728924580686) -->
<skip />
- <!-- no translation found for notification_channel_switch_accessibility (3420796005601900717) -->
+ <!-- no translation found for notification_appops_overlay_active (633813008357934729) -->
<skip />
+ <!-- no translation found for notification_appops (1258122060887196817) -->
+ <!-- no translation found for notification_using (2211008461429037973) -->
+ <!-- no translation found for notification_appops_settings (1028328314935908050) -->
+ <skip />
+ <!-- no translation found for notification_appops_ok (602562195588819631) -->
+ <skip />
+ <string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"<xliff:g id="APP_NAME">%1$s</xliff:g> ପାଇଁ ବିଜ୍ଞପ୍ତି ନିୟନ୍ତ୍ରଣ ଖୋଲା ଯାଇଛି"</string>
+ <string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"<xliff:g id="APP_NAME">%1$s</xliff:g> ପାଇଁ ବିଜ୍ଞପ୍ତି ନିୟନ୍ତ୍ରଣ ବନ୍ଦ ହୋଇଛି"</string>
+ <string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"ଏହି ଚ୍ୟାନେଲରୁ ବିଜ୍ଞପ୍ତିକୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="notification_more_settings" msgid="816306283396553571">"ଅଧିକ ସେଟିଙ୍ଗ"</string>
<!-- no translation found for notification_app_settings (420348114670768449) -->
<skip />
<string name="notification_done" msgid="5279426047273930175">"ହୋଇଗଲା"</string>
<!-- no translation found for inline_undo (558916737624706010) -->
<skip />
- <!-- no translation found for notification_menu_accessibility (2046162834248888553) -->
+ <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">"ବିଜ୍ଞପ୍ତି ନିୟନ୍ତ୍ରଣ"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"ବିଜ୍ଞପ୍ତି ସ୍ନୁଜ୍ ବିକଳ୍ପ"</string>
+ <!-- no translation found for notification_menu_snooze_action (1112254519029621372) -->
<skip />
- <!-- no translation found for notification_menu_gear_description (2204480013726775108) -->
- <skip />
- <!-- no translation found for notification_menu_snooze_description (3653669438131034525) -->
- <skip />
- <!-- no translation found for snooze_undo (6074877317002985129) -->
- <skip />
- <!-- no translation found for snoozed_for_time (2390718332980204462) -->
- <skip />
- <!-- no translation found for snoozeHourOptions (2124335842674413030) -->
- <!-- no translation found for snoozeMinuteOptions (4127251700591510196) -->
- <!-- no translation found for battery_panel_title (7944156115535366613) -->
- <skip />
+ <string name="snooze_undo" msgid="6074877317002985129">"ପୂର୍ବାବସ୍ଥାକୁ ଫେରାଇ ଆଣନ୍ତୁ"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> ପାଇଁ ସ୍ନୁଜ୍ କରାଗଲା"</string>
+ <plurals name="snoozeHourOptions" formatted="false" msgid="2124335842674413030">
+ <item quantity="other">%d ଘଣ୍ଟା</item>
+ <item quantity="one">%d ଘଣ୍ଟା</item>
+ </plurals>
+ <plurals name="snoozeMinuteOptions" formatted="false" msgid="4127251700591510196">
+ <item quantity="other">%d ମିନିଟ୍</item>
+ <item quantity="one">%d ମିନିଟ୍</item>
+ </plurals>
+ <string name="battery_panel_title" msgid="7944156115535366613">"ବ୍ୟାଟେରୀ ବ୍ୟବହାର"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"ଚାର୍ଜ କରାଯିବାବେଳେ ବ୍ୟାଟେରୀ ସେଭର୍ ଉପଲବ୍ଧ ନଥାଏ"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"ବ୍ୟାଟେରୀ ସେଭର୍"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"କାର୍ଯ୍ୟଦକ୍ଷତା ଓ ବ୍ୟାକ୍ଗ୍ରାଉଣ୍ଡ ଡାଟା କମ୍ କରେ"</string>
- <!-- no translation found for keyboard_key_button_template (6230056639734377300) -->
- <skip />
- <!-- no translation found for keyboard_key_home (2243500072071305073) -->
- <skip />
- <!-- no translation found for keyboard_key_back (2337450286042721351) -->
- <skip />
- <!-- no translation found for keyboard_key_dpad_up (5584144111755734686) -->
- <skip />
- <!-- no translation found for keyboard_key_dpad_down (7331518671788337815) -->
- <skip />
- <!-- no translation found for keyboard_key_dpad_left (1346446024676962251) -->
- <skip />
- <!-- no translation found for keyboard_key_dpad_right (3317323247127515341) -->
- <skip />
- <!-- no translation found for keyboard_key_dpad_center (2566737770049304658) -->
- <skip />
- <!-- no translation found for keyboard_key_tab (3871485650463164476) -->
- <skip />
- <!-- no translation found for keyboard_key_space (2499861316311153293) -->
- <skip />
- <!-- no translation found for keyboard_key_enter (5739632123216118137) -->
- <skip />
- <!-- no translation found for keyboard_key_backspace (1559580097512385854) -->
- <skip />
- <!-- no translation found for keyboard_key_media_play_pause (3861975717393887428) -->
- <skip />
- <!-- no translation found for keyboard_key_media_stop (2859963958595908962) -->
- <skip />
- <!-- no translation found for keyboard_key_media_next (1894394911630345607) -->
- <skip />
- <!-- no translation found for keyboard_key_media_previous (4256072387192967261) -->
- <skip />
- <!-- no translation found for keyboard_key_media_rewind (2654808213360820186) -->
- <skip />
- <!-- no translation found for keyboard_key_media_fast_forward (3849417047738200605) -->
- <skip />
- <!-- no translation found for keyboard_key_page_up (5654098530106845603) -->
- <skip />
- <!-- no translation found for keyboard_key_page_down (8720502083731906136) -->
- <skip />
- <!-- no translation found for keyboard_key_forward_del (1391451334716490176) -->
- <skip />
- <!-- no translation found for keyboard_key_move_home (2765693292069487486) -->
- <skip />
- <!-- no translation found for keyboard_key_move_end (5901174332047975247) -->
- <skip />
- <!-- no translation found for keyboard_key_insert (8530501581636082614) -->
- <skip />
- <!-- no translation found for keyboard_key_num_lock (5052537581246772117) -->
- <skip />
- <!-- no translation found for keyboard_key_numpad_template (8729216555174634026) -->
- <skip />
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"ବଟନ୍ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"ହୋମ୍"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"ଫେରନ୍ତୁ"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"ଉପର"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"ତଳ"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"ବାମ"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"ଡାହାଣ"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"କେନ୍ଦ୍ର"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"ଟ୍ୟାବ୍"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"ସ୍ପେସ୍"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"ଏଣ୍ଟର୍"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"ବ୍ୟାକସ୍ପେସ୍"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"ପ୍ଲେ କରନ୍ତୁ/ପଜ୍ କରନ୍ତୁ"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"ବନ୍ଦ କରନ୍ତୁ"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"ପରବର୍ତ୍ତୀ"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"ପୂର୍ବବର୍ତ୍ତୀ"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"ରିୱାଇଣ୍ଡ"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"ଫାଷ୍ଟ ଫର୍ୱାର୍ଡ"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"ଉପର ପୃଷ୍ଠା"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"ତଳ ପୃଷ୍ଠା"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"ଡିଲିଟ୍"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"ହୋମ୍"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"ସମାପ୍ତ"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"ଇନ୍ସର୍ଟ"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"ନମ୍ବର ଲକ୍"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"ନମ୍ବରପ୍ୟାଡ୍ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"ସିଷ୍ଟମ୍"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ହୋମ୍"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ସମ୍ପ୍ରତି"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ଫେରନ୍ତୁ"</string>
- <!-- no translation found for keyboard_shortcut_group_system_notifications (8366964080041773224) -->
- <skip />
- <!-- no translation found for keyboard_shortcut_group_system_shortcuts_helper (4892255911160332762) -->
- <skip />
- <!-- no translation found for keyboard_shortcut_group_system_switch_input (2334164096341310324) -->
- <skip />
- <!-- no translation found for keyboard_shortcut_group_applications (9129465955073449206) -->
- <skip />
- <!-- no translation found for keyboard_shortcut_group_applications_assist (9095441910537146013) -->
- <skip />
- <!-- no translation found for keyboard_shortcut_group_applications_browser (6465985474000766533) -->
- <skip />
- <!-- no translation found for keyboard_shortcut_group_applications_contacts (2064197111278436375) -->
- <skip />
- <!-- no translation found for keyboard_shortcut_group_applications_email (6257036897441939004) -->
- <skip />
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"ବିଜ୍ଞପ୍ତି"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"କୀ\'ବୋର୍ଡ ଶର୍ଟକଟ୍"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ଇନପୁଟ୍ ପଦ୍ଧତି ବଦଳାନ୍ତୁ"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"ଆପ୍ଲିକେଶନ୍"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"ସହାୟତା"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ବ୍ରାଉଜର୍"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"ଯୋଗାଯୋଗ"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ଇମେଲ୍"</string>
<string name="keyboard_shortcut_group_applications_sms" msgid="638701213803242744">"SMS"</string>
- <!-- no translation found for keyboard_shortcut_group_applications_music (4775559515850922780) -->
- <skip />
- <!-- no translation found for keyboard_shortcut_group_applications_youtube (6555453761294723317) -->
- <skip />
- <!-- no translation found for keyboard_shortcut_group_applications_calendar (9043614299194991263) -->
- <skip />
- <!-- no translation found for tuner_full_zen_title (4540823317772234308) -->
- <skip />
- <!-- no translation found for volume_and_do_not_disturb (3373784330208603030) -->
- <skip />
- <!-- no translation found for volume_dnd_silent (4363882330723050727) -->
- <skip />
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"ମ୍ୟୁଜିକ୍"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"କ୍ୟାଲେଣ୍ଡର୍"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"ଭଲ୍ୟୁମ୍ କଣ୍ଟ୍ରୋଲ୍ ସହ ଦେଖାନ୍ତୁ"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"ଭଲ୍ୟୁମ ବଟନ୍ ଶର୍ଟକଟ୍"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"ଭଲ୍ୟୁମ୍ ବଢ଼ାଇ \"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\"ରୁ ବାହାରି ଯାଆନ୍ତୁ"</string>
<string name="battery" msgid="7498329822413202973">"ବ୍ୟାଟେରୀ"</string>
<string name="clock" msgid="7416090374234785905">"ଘଣ୍ଟା"</string>
@@ -893,232 +761,149 @@
<string name="data_saver" msgid="5037565123367048522">"ଡାଟା ସେଭର୍"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"ଡାଟା ସେଭର୍ ଅନ୍ ଅଛି"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"ଡାଟା ସେଭର୍ ଅଫ୍ ଅଛି"</string>
- <!-- no translation found for switch_bar_on (1142437840752794229) -->
- <skip />
- <!-- no translation found for switch_bar_off (8803270596930432874) -->
- <skip />
- <!-- no translation found for nav_bar (1993221402773877607) -->
- <skip />
- <!-- no translation found for nav_bar_layout (3664072994198772020) -->
- <skip />
- <!-- no translation found for left_nav_bar_button_type (8555981238887546528) -->
- <skip />
- <!-- no translation found for right_nav_bar_button_type (2481056627065649656) -->
- <skip />
- <!-- no translation found for nav_bar_default (8587114043070993007) -->
- <skip />
- <!-- no translation found for nav_bar_buttons:0 (1545641631806817203) -->
- <!-- no translation found for nav_bar_buttons:1 (5742013440802239414) -->
+ <string name="switch_bar_on" msgid="1142437840752794229">"ଅନ୍"</string>
+ <string name="switch_bar_off" msgid="8803270596930432874">"ଅଫ୍"</string>
+ <string name="nav_bar" msgid="1993221402773877607">"ନାଭିଗେଶନ୍ ବାର୍"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"ଲେଆଉଟ୍"</string>
+ <string name="left_nav_bar_button_type" msgid="8555981238887546528">"ସମ୍ପୂର୍ଣ୍ଣ ବାମ ବଟନ୍ ପ୍ରକାର"</string>
+ <string name="right_nav_bar_button_type" msgid="2481056627065649656">"ସମ୍ପୂର୍ଣ୍ଣ ଡାହାଣ ବଟନ୍ ପ୍ରକାର"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(ଡିଫଲ୍ଟ)"</string>
<!-- no translation found for nav_bar_buttons:2 (1951959982985094069) -->
- <!-- no translation found for nav_bar_buttons:3 (8175437057325747277) -->
- <!-- no translation found for nav_bar_layouts:0 (8077901629964902399) -->
- <!-- no translation found for nav_bar_layouts:1 (8256205964297588988) -->
- <!-- no translation found for nav_bar_layouts:2 (8719936228094005878) -->
- <!-- no translation found for nav_bar_layouts:3 (586019486955594690) -->
- <!-- no translation found for menu_ime (4998010205321292416) -->
- <skip />
- <!-- no translation found for save (2311877285724540644) -->
- <skip />
+ <string-array name="nav_bar_layouts">
+ <item msgid="8077901629964902399">"ସାମାନ୍ୟ"</item>
+ <item msgid="8256205964297588988">"କମ୍ପାକ୍ଟ"</item>
+ <item msgid="8719936228094005878">"ବାମକୁ-ଆଉଜେଇବା"</item>
+ <item msgid="586019486955594690">"ଡାହାଣକୁ-ଆଉଜେଇବା"</item>
+ </string-array>
+ <string name="menu_ime" msgid="4998010205321292416">"କୀ\'ବୋର୍ଡ ବଦଳକାରୀ"</string>
+ <string name="save" msgid="2311877285724540644">"ସେଭ୍ କରନ୍ତୁ"</string>
<string name="reset" msgid="2448168080964209908">"ରିସେଟ୍ କରନ୍ତୁ"</string>
- <!-- no translation found for adjust_button_width (6138616087197632947) -->
+ <string name="adjust_button_width" msgid="6138616087197632947">"ବଟନ୍ର ମୋଟେଇ ଆଡ୍ଜଷ୍ଟ କରନ୍ତୁ"</string>
+ <string name="clipboard" msgid="1313879395099896312">"କ୍ଲିପ୍ବୋର୍ଡ"</string>
+ <string name="accessibility_key" msgid="5701989859305675896">"କଷ୍ଟମ୍ ନାଭିଗେଶନ୍ ବଟନ୍"</string>
+ <string name="left_keycode" msgid="2010948862498918135">"ବାମ କୀ\'କୋଡ୍"</string>
+ <string name="right_keycode" msgid="708447961000848163">"ଡାହାଣ କୀ\'କୋଡ୍"</string>
+ <string name="left_icon" msgid="3096287125959387541">"ବାମ ଆଇକନ୍"</string>
+ <string name="right_icon" msgid="3952104823293824311">"ଡାହାଣ ଆଇକନ୍"</string>
+ <!-- no translation found for drag_to_add_tiles (230586591689084925) -->
<skip />
- <!-- no translation found for clipboard (1313879395099896312) -->
+ <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ବାହାର କରିବାକୁ ଏଠାକୁ ଡ୍ରାଗ୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for drag_to_remove_disabled (2390968976638993382) -->
<skip />
- <!-- no translation found for accessibility_key (5701989859305675896) -->
- <skip />
- <!-- no translation found for left_keycode (2010948862498918135) -->
- <skip />
- <!-- no translation found for right_keycode (708447961000848163) -->
- <skip />
- <!-- no translation found for left_icon (3096287125959387541) -->
- <skip />
- <!-- no translation found for right_icon (3952104823293824311) -->
- <skip />
- <!-- no translation found for drag_to_add_tiles (7058945779098711293) -->
- <skip />
- <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
- <skip />
- <!-- no translation found for qs_edit (2232596095725105230) -->
- <skip />
- <!-- no translation found for tuner_time (6572217313285536011) -->
- <skip />
- <!-- no translation found for clock_options:0 (5965318737560463480) -->
- <!-- no translation found for clock_options:1 (1427801730816895300) -->
- <!-- no translation found for clock_options:2 (3830170141562534721) -->
- <!-- no translation found for battery_options:0 (3160236755818672034) -->
- <!-- no translation found for battery_options:1 (2139628951880142927) -->
- <!-- no translation found for battery_options:2 (3327323682209964956) -->
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
- <!-- no translation found for accessibility_divider (5903423481953635044) -->
- <skip />
- <!-- no translation found for accessibility_action_divider_left_full (2801570521881574972) -->
- <skip />
- <!-- no translation found for accessibility_action_divider_left_70 (3612060638991687254) -->
- <skip />
- <!-- no translation found for accessibility_action_divider_left_50 (1248083470322193075) -->
- <skip />
- <!-- no translation found for accessibility_action_divider_left_30 (543324403127069386) -->
- <skip />
- <!-- no translation found for accessibility_action_divider_right_full (4639381073802030463) -->
- <skip />
- <!-- no translation found for accessibility_action_divider_top_full (5357010904067731654) -->
- <skip />
- <!-- no translation found for accessibility_action_divider_top_70 (5090779195650364522) -->
- <skip />
- <!-- no translation found for accessibility_action_divider_top_50 (6385859741925078668) -->
- <skip />
- <!-- no translation found for accessibility_action_divider_top_30 (6201455163864841205) -->
- <skip />
- <!-- no translation found for accessibility_action_divider_bottom_full (301433196679548001) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_label (8374924053307764245) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_add_tile_label (8133209638023882667) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position_label (5055306305919289819) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_move_tile (2461819993780159542) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_remove_tile (7484493384665907197) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_added (8050200862063548309) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_removed (8584304916627913440) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_moved (4343693412689365038) -->
- <skip />
- <!-- no translation found for accessibility_desc_quick_settings_edit (8073587401747016103) -->
- <skip />
+ <string name="qs_edit" msgid="2232596095725105230">"ଏଡିଟ୍ କରନ୍ତୁ"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"ସମୟ"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"ଘଣ୍ଟା, ମିନିଟ୍ ଏବଂ ସେକେଣ୍ଡ ଦେଖାନ୍ତୁ"</item>
+ <item msgid="1427801730816895300">"ଘଣ୍ଟା ଏବଂ ମିନିଟ୍ ଦେଖାନ୍ତୁ (ଡିଫଲ୍ଟ)"</item>
+ <item msgid="3830170141562534721">"ଏହି ଆଇକନ୍ ଦେଖାନ୍ତୁ ନାହିଁ"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"ସର୍ବଦା ଶତକଡ଼ା ଦେଖାନ୍ତୁ"</item>
+ <item msgid="2139628951880142927">"ଚାର୍ଜ କରାଯିବାବେଳେ ଶତକଡ଼ା ଦେଖାନ୍ତୁ (ଡିଫଲ୍ଟ)"</item>
+ <item msgid="3327323682209964956">"ଏହି ଆଇକନ୍ ଦେଖାନ୍ତୁ ନାହିଁ"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"ଅନ୍ୟାନ୍ୟ"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"ସ୍ପ୍ଲିଟ୍-ସ୍କ୍ରୀନ ବିଭାଜକ"</string>
+ <string name="accessibility_action_divider_left_full" msgid="2801570521881574972">"ବାମ ପଟକୁ ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍ କରନ୍ତୁ"</string>
+ <string name="accessibility_action_divider_left_70" msgid="3612060638991687254">"ବାମ ପଟକୁ 70% କରନ୍ତୁ"</string>
+ <string name="accessibility_action_divider_left_50" msgid="1248083470322193075">"ବାମ ପଟକୁ 50% କରନ୍ତୁ"</string>
+ <string name="accessibility_action_divider_left_30" msgid="543324403127069386">"ବାମ ପଟେ 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="4639381073802030463">"ଡାହାଣ ପଟକୁ ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍ କରନ୍ତୁ"</string>
+ <string name="accessibility_action_divider_top_full" msgid="5357010904067731654">"ଉପର ଆଡ଼କୁ ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍ କରନ୍ତୁ"</string>
+ <string name="accessibility_action_divider_top_70" msgid="5090779195650364522">"ଉପର ଆଡ଼କୁ 70% କରନ୍ତୁ"</string>
+ <string name="accessibility_action_divider_top_50" msgid="6385859741925078668">"ଉପର ଆଡ଼କୁ 50% କରନ୍ତୁ"</string>
+ <string name="accessibility_action_divider_top_30" msgid="6201455163864841205">"ଉପର ଆଡ଼କୁ 30% କରନ୍ତୁ"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="301433196679548001">"ତଳ ଅଂଶର ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ଅବସ୍ଥାନ <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>। ଏଡିଟ୍ କରିବାକୁ ଡବଲ୍-ଟାପ୍ କରନ୍ତୁ।"</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>। ଯୋଡ଼ିବା ପାଇଁ ଡବଲ୍-ଟାପ୍ କରନ୍ତୁ।"</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ଅବସ୍ଥିତି <xliff:g id="POSITION">%1$d</xliff:g>। ଚୟନ କରିବାକୁ ଡବଲ୍-ଟାପ୍ କରନ୍ତୁ।"</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ନିଅନ୍ତୁ"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ବାହାର କରିଦିଅନ୍ତୁ"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g>କୁ ଅବସ୍ଥାନ <xliff:g id="POSITION">%2$d</xliff:g>ରେ ଯୋଡ଼ାଗଲା"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ବାହାର କରିଦିଆଗଲା"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> କୁ ଅବସ୍ଥାନ <xliff:g id="POSITION">%2$d</xliff:g> କୁ ନିଆଗଲା"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ଦ୍ରୁତ ସେଟିଙ୍ଗ ଏଡିଟର୍।"</string>
<string name="accessibility_desc_notification_icon" msgid="8352414185263916335">"<xliff:g id="ID_1">%1$s</xliff:g> ବିଜ୍ଞପ୍ତି: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
- <!-- no translation found for dock_forced_resizable (5914261505436217520) -->
- <skip />
- <!-- no translation found for dock_non_resizeble_failed_to_dock_text (3871617304250207291) -->
- <skip />
- <!-- no translation found for forced_resizable_secondary_display (4230857851756391925) -->
- <skip />
- <!-- no translation found for activity_launch_on_secondary_display_failed_text (7793821742158306742) -->
- <skip />
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"ସ୍ପ୍ଲିଟ୍-ସ୍କ୍ରୀନରେ ଆପ୍ କାମ କରିନପାରେ।"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"ଆପ୍ ସ୍ପ୍ଲିଟ୍-ସ୍କ୍ରୀନକୁ ସପୋର୍ଟ କରେ ନାହିଁ।"</string>
+ <string name="forced_resizable_secondary_display" msgid="4230857851756391925">"ସେକେଣ୍ଡାରୀ ଡିସପ୍ଲେରେ ଆପ୍ କାମ ନକରିପାରେ।"</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="7793821742158306742">"ସେକେଣ୍ଡାରୀ ଡିସପ୍ଲେରେ ଆପ୍ ଲଞ୍ଚ ସପୋର୍ଟ କରେ ନାହିଁ।"</string>
<string name="accessibility_quick_settings_settings" msgid="6132460890024942157">"ସେଟିଙ୍ଗ ଖୋଲନ୍ତୁ।"</string>
<string name="accessibility_quick_settings_expand" msgid="2375165227880477530">"ଦ୍ରୁତ ସେଟିଙ୍ଗ ଖୋଲନ୍ତୁ।"</string>
<string name="accessibility_quick_settings_collapse" msgid="1792625797142648105">"ଦ୍ରୁତ ସେଟିଙ୍ଗ ବନ୍ଦ କରନ୍ତୁ।"</string>
<string name="accessibility_quick_settings_alarm_set" msgid="1863000242431528676">"ଆଲାର୍ମ ସେଟ୍।"</string>
<string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> ଭାବରେ ସାଇନ୍ ଇନ୍ କରିଛନ୍ତି"</string>
- <string name="accessibility_quick_settings_no_internet" msgid="31890692343084075">"କୌଣସି ଇଣ୍ଟରନେଟ୍ ନାହିଁ"</string>
+ <!-- no translation found for data_connection_no_internet (4503302451650972989) -->
+ <skip />
<string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"ବିବରଣୀ ଖୋଲନ୍ତୁ"</string>
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ସେଟିଙ୍ଗ ଖୋଲନ୍ତୁ।"</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ସେଟିଙ୍ଗର କ୍ରମ ସଂଶୋଧନ କରନ୍ତୁ।"</string>
- <!-- no translation found for accessibility_quick_settings_page (5032979051755200721) -->
- <skip />
- <!-- no translation found for tuner_lock_screen (5755818559638850294) -->
- <skip />
+ <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ପୃଷ୍ଠା <xliff:g id="ID_1">%1$d</xliff:g> ମୋଟ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+ <string name="tuner_lock_screen" msgid="5755818559638850294">"ଲକ୍ ସ୍କ୍ରୀନ୍"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"ବଢ଼ାନ୍ତୁ"</string>
- <!-- no translation found for pip_phone_minimize (1079119422589131792) -->
+ <string name="pip_phone_minimize" msgid="1079119422589131792">"ଛୋଟ କରନ୍ତୁ"</string>
+ <string name="pip_phone_close" msgid="8416647892889710330">"ବନ୍ଦ କରନ୍ତୁ"</string>
+ <string name="pip_phone_settings" msgid="8080777499521528521">"ସେଟିଙ୍ଗ"</string>
+ <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"ଖାରଜ କରିବାକୁ ତଳକୁ ଟାଣନ୍ତୁ"</string>
+ <string name="pip_menu_title" msgid="4707292089961887657">"ମେନୁ"</string>
+ <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> \"ଛବି-ଭିତରେ-ଛବି\"ରେ ଅଛି"</string>
+ <string name="pip_notification_message" msgid="5619512781514343311">"ଏହି ବୈଶିଷ୍ଟ୍ୟ <xliff:g id="NAME">%s</xliff:g> ବ୍ୟବହାର ନକରିବାକୁ ଯଦି ଆପଣ ଚାହାଁନ୍ତି, ସେଟିଙ୍ଗ ଖୋଲିବାକୁ ଟାପ୍ କରନ୍ତୁ ଏବଂ ଏହା ଅଫ୍ କରିଦିଅନ୍ତୁ।"</string>
+ <string name="pip_play" msgid="1417176722760265888">"ପ୍ଲେ କରନ୍ତୁ"</string>
+ <string name="pip_pause" msgid="8881063404466476571">"ପଜ୍ କରନ୍ତୁ"</string>
+ <string name="pip_skip_to_next" msgid="1948440006726306284">"ପରବର୍ତ୍ତୀକୁ ଯାଆନ୍ତୁ"</string>
+ <string name="pip_skip_to_prev" msgid="1955311326688637914">"ପୂର୍ବବର୍ତ୍ତୀକୁ ଛାଡ଼ନ୍ତୁ"</string>
+ <string name="thermal_shutdown_title" msgid="4458304833443861111">"ଗରମ ହେତୁ ଫୋନ୍ ଅଫ୍ କରିଦିଆଗଲା"</string>
+ <string name="thermal_shutdown_message" msgid="9006456746902370523">"ଆପଣଙ୍କ ଫୋନ୍ ବର୍ତ୍ତମାନ ସାମାନ୍ୟ ଅବସ୍ଥାରେ ଚାଲୁଛି"</string>
+ <string name="thermal_shutdown_dialog_message" msgid="566347880005304139">"ଆପଣଙ୍କ ଫୋନ୍ ବହୁତ ଗରମ ଥିଲା, ତେଣୁ ଏହାକୁ ଥଣ୍ଡା କରାଯିବାକୁ ଅଫ୍ କରିଦିଆଗଲା। ଆପଣଙ୍କ ଫୋନ୍ ବର୍ତ୍ତମାନ ସାମାନ୍ୟ ଅବସ୍ଥାରେ ଚାଲୁଛି।\n\nଆପଣଙ୍କ ଫୋନ୍ ଅଧିକ ଗରମ ହୋଇଯାଇପାରେ ଯଦି ଆପଣ:\n • ରିସୋର୍ସ-ଇଣ୍ଟେନସିଭ୍ ଆପ୍ (ଯେପରିକି ଗେମିଙ୍ଗ, ଭିଡିଓ, କିମ୍ବା ନେଭିଗେସନ୍ ଆପ୍) ବ୍ୟବହାର କରନ୍ତି\n • ବଡ ଫାଇଲ୍ ଡାଉନଲୋଡ୍ କିମ୍ବା ଅପଲୋଡ୍ କରନ୍ତି\n • ଅଧିକ ତାପମାତ୍ରାରେ ଆପଣଙ୍କ ଫୋନ୍ ବ୍ୟବହାର କରନ୍ତି"</string>
+ <string name="high_temp_title" msgid="4589508026407318374">"ଫୋନ୍ ଗରମ ହୋଇଯାଉଛି"</string>
+ <string name="high_temp_notif_message" msgid="5642466103153429279">"ଫୋନ୍ ଥଣ୍ଡା ହେବା ସମୟରେ କିଛି ଫିଚର୍ ସୀମିତ ଭାବେ କାମ କରିଥାଏ"</string>
+ <string name="high_temp_dialog_message" msgid="6840700639374113553">"ଆପଣଙ୍କ ଫୋନ୍ ସ୍ୱଚାଳିତ ଭାବେ ଥଣ୍ଡା ହେବାକୁ ଚେଷ୍ଟା କରିବ। ଆପଣ ତଥାପି ନିଜ ଫୋନ୍ ବ୍ୟବହାର କରିପାରିବେ, କିନ୍ତୁ ଏହା ଧୀରେ ଚାଲିପାରେ।\n\nଆପଣଙ୍କ ଫୋନ୍ ଥଣ୍ଡା ହୋଇଯିବାପରେ, ଏହା ସାମାନ୍ୟ ଭାବେ ଚାଲିବ।"</string>
+ <string name="lockscreen_shortcut_left" msgid="2182769107618938629">"ବାମ ଶର୍ଟକଟ୍"</string>
+ <string name="lockscreen_shortcut_right" msgid="3328683699505226536">"ଡାହାଣ ଶର୍ଟକଟ୍"</string>
+ <string name="lockscreen_unlock_left" msgid="2043092136246951985">"ବାମ ଶର୍ଟକଟ୍ ମଧ୍ୟ ଅନଲକ୍ କରେ"</string>
+ <string name="lockscreen_unlock_right" msgid="1529992940510318775">"ଡାହାଣ ଶର୍ଟକଟ୍ ମଧ୍ୟ ଅନଲକ୍ କରେ"</string>
+ <string name="lockscreen_none" msgid="4783896034844841821">"କିଛିନୁହେଁ"</string>
+ <string name="tuner_launch_app" msgid="1527264114781925348">"<xliff:g id="APP">%1$s</xliff:g> ଲଞ୍ଚ କରନ୍ତୁ"</string>
+ <string name="tuner_other_apps" msgid="4726596850501162493">"ଅନ୍ୟାନ୍ୟ ଆପ୍"</string>
+ <string name="tuner_circle" msgid="2340998864056901350">"ବୃତ୍ତ"</string>
+ <string name="tuner_plus" msgid="6792960658533229675">"ଯୁକ୍ତ"</string>
+ <string name="tuner_minus" msgid="4806116839519226809">"ବିଯୁକ୍ତ"</string>
+ <string name="tuner_left" msgid="8404287986475034806">"ବାମ"</string>
+ <string name="tuner_right" msgid="6222734772467850156">"ଡାହାଣ"</string>
+ <string name="tuner_menu" msgid="191640047241552081">"ମେନୁ"</string>
+ <string name="tuner_app" msgid="3507057938640108777">"<xliff:g id="APP">%1$s</xliff:g> ଆପ୍"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"ଆଲର୍ଟ"</string>
+ <string name="notification_channel_battery" msgid="5786118169182888462">"ବ୍ୟାଟେରୀ"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"ସ୍କ୍ରୀନଶଟ୍"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"ସାଧାରଣ ମେସେଜ୍"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"ଷ୍ଟୋରେଜ୍"</string>
+ <!-- no translation found for notification_channel_hints (7323870212489152689) -->
<skip />
- <!-- no translation found for pip_phone_close (8416647892889710330) -->
- <skip />
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
- <!-- no translation found for pip_phone_dismiss_hint (6351678169095923899) -->
- <skip />
- <!-- no translation found for pip_menu_title (4707292089961887657) -->
- <skip />
- <!-- no translation found for pip_notification_title (3204024940158161322) -->
- <skip />
- <!-- no translation found for pip_notification_message (5619512781514343311) -->
- <skip />
- <!-- no translation found for pip_play (1417176722760265888) -->
- <skip />
- <!-- no translation found for pip_pause (8881063404466476571) -->
- <skip />
- <!-- no translation found for pip_skip_to_next (1948440006726306284) -->
- <skip />
- <!-- no translation found for pip_skip_to_prev (1955311326688637914) -->
- <skip />
- <!-- no translation found for thermal_shutdown_title (4458304833443861111) -->
- <skip />
- <!-- no translation found for thermal_shutdown_message (9006456746902370523) -->
- <skip />
- <!-- no translation found for thermal_shutdown_dialog_message (566347880005304139) -->
- <skip />
- <!-- no translation found for high_temp_title (4589508026407318374) -->
- <skip />
- <!-- no translation found for high_temp_notif_message (5642466103153429279) -->
- <skip />
- <!-- no translation found for high_temp_dialog_message (6840700639374113553) -->
- <skip />
- <!-- no translation found for lockscreen_shortcut_left (2182769107618938629) -->
- <skip />
- <!-- no translation found for lockscreen_shortcut_right (3328683699505226536) -->
- <skip />
- <!-- no translation found for lockscreen_unlock_left (2043092136246951985) -->
- <skip />
- <!-- no translation found for lockscreen_unlock_right (1529992940510318775) -->
- <skip />
- <!-- no translation found for lockscreen_none (4783896034844841821) -->
- <skip />
- <!-- no translation found for tuner_launch_app (1527264114781925348) -->
- <skip />
- <!-- no translation found for tuner_other_apps (4726596850501162493) -->
- <skip />
- <!-- no translation found for tuner_circle (2340998864056901350) -->
- <skip />
- <!-- no translation found for tuner_plus (6792960658533229675) -->
- <skip />
- <!-- no translation found for tuner_minus (4806116839519226809) -->
- <skip />
- <!-- no translation found for tuner_left (8404287986475034806) -->
- <skip />
- <!-- no translation found for tuner_right (6222734772467850156) -->
- <skip />
- <!-- no translation found for tuner_menu (191640047241552081) -->
- <skip />
- <!-- no translation found for tuner_app (3507057938640108777) -->
- <skip />
- <!-- no translation found for notification_channel_alerts (4496839309318519037) -->
- <skip />
- <!-- no translation found for notification_channel_battery (5786118169182888462) -->
- <skip />
- <!-- no translation found for notification_channel_screenshot (6314080179230000938) -->
- <skip />
- <!-- no translation found for notification_channel_general (4525309436693914482) -->
- <skip />
- <!-- no translation found for notification_channel_storage (3077205683020695313) -->
- <skip />
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"ଇନଷ୍ଟାଣ୍ଟ ଆପ୍"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"ଇନଷ୍ଟାଣ୍ଟ ଆପ୍ ଇନଷ୍ଟଲ୍ କରିବାର ଆବଶ୍ୟକତା ନାହିଁ"</string>
<string name="app_info" msgid="6856026610594615344">"ଆପ୍ ସୂଚନା"</string>
- <!-- no translation found for go_to_web (2650669128861626071) -->
+ <string name="go_to_web" msgid="2650669128861626071">"ବ୍ରାଉଜର୍କୁ ଯାଆନ୍ତୁ"</string>
+ <string name="mobile_data" msgid="7094582042819250762">"ମୋବାଇଲ୍ ଡାଟା"</string>
+ <!-- no translation found for mobile_data_text_format (3526214522670876454) -->
<skip />
- <!-- no translation found for mobile_data (7094582042819250762) -->
+ <string name="wifi_is_off" msgid="1838559392210456893">"ୱାଇ-ଫାଇ ଅଫ୍ ଅଛି"</string>
+ <string name="bt_is_off" msgid="2640685272289706392">"ବ୍ଲୁ-ଟୁଥ୍ ଅଫ୍ ଅଛି"</string>
+ <string name="dnd_is_off" msgid="6167780215212497572">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଅଫ୍ ଅଛି"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="862559028345233052">"ଏକ (<xliff:g id="ID_1">%s</xliff:g>) ନିୟମ ଦ୍ୱାରା \"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ସ୍ୱଚାଳିତ ଭାବେ ଅନ୍ କରାଗଲା।"</string>
+ <string name="qs_dnd_prompt_app" msgid="7978037419334156034">"ଏକ ଆପ୍ (<xliff:g id="ID_1">%s</xliff:g>) ଦ୍ୱାରା \"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଅନ୍ କରାଗଲା।"</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="2599343675391111951">"ଏକ ସ୍ୱଚାଳିତ ନିୟମ କିମ୍ବା ଆପ୍ ଦ୍ୱାରା \"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଅନ୍ କରାଗଲା।"</string>
+ <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> ପର୍ଯ୍ୟନ୍ତ"</string>
+ <string name="qs_dnd_keep" msgid="1825009164681928736">"ଧରି ରଖନ୍ତୁ"</string>
+ <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>
+ <!-- no translation found for mobile_data_disable_title (1068272097382942231) -->
<skip />
- <!-- no translation found for wifi_is_off (1838559392210456893) -->
+ <!-- no translation found for mobile_data_disable_message (4756541658791493506) -->
<skip />
- <!-- no translation found for bt_is_off (2640685272289706392) -->
+ <!-- no translation found for mobile_data_disable_message_default_carrier (6078110473451946831) -->
<skip />
- <!-- no translation found for dnd_is_off (6167780215212497572) -->
- <skip />
- <!-- no translation found for qs_dnd_prompt_auto_rule (862559028345233052) -->
- <skip />
- <!-- no translation found for qs_dnd_prompt_app (7978037419334156034) -->
- <skip />
- <!-- no translation found for qs_dnd_prompt_auto_rule_app (2599343675391111951) -->
- <skip />
- <!-- no translation found for qs_dnd_until (3469471136280079874) -->
- <skip />
- <!-- no translation found for qs_dnd_keep (1825009164681928736) -->
- <skip />
- <!-- no translation found for qs_dnd_replace (8019520786644276623) -->
- <skip />
- <!-- no translation found for running_foreground_services_title (381024150898615683) -->
- <skip />
- <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
- <skip />
- <string name="data_usage_disable_mobile" msgid="5116269981510015864">"ମୋବାଇଲ୍ ଡାଟା ଅଫ୍ କରିବେ?"</string>
- <!-- no translation found for touch_filtered_warning (8671693809204767551) -->
- <skip />
+ <string name="touch_filtered_warning" msgid="8671693809204767551">"ଗୋଟିଏ ଆପ୍ ଏକ ଅନୁମତି ଅନୁରୋଧକୁ ଦେଖିବାରେ ବାଧା ଦେଉଥିବାରୁ, ସେଟିଙ୍ଗ ଆପଣଙ୍କ ଉତ୍ତରକୁ ଯାଞ୍ଚ କରିପାରିବ ନାହିଁ।"</string>
<!-- no translation found for slice_permission_title (7465009437851044444) -->
<skip />
<!-- no translation found for slice_permission_text_1 (3514586565609596523) -->
@@ -1131,4 +916,18 @@
<skip />
<!-- no translation found for slice_permission_deny (7683681514008048807) -->
<skip />
+ <!-- no translation found for auto_saver_title (1217959994732964228) -->
+ <skip />
+ <!-- no translation found for auto_saver_text (6324376061044218113) -->
+ <skip />
+ <!-- no translation found for no_auto_saver_action (8086002101711328500) -->
+ <skip />
+ <!-- no translation found for auto_saver_enabled_title (6726474226058316862) -->
+ <skip />
+ <!-- no translation found for auto_saver_enabled_text (874711029884777579) -->
+ <skip />
+ <!-- no translation found for open_saver_setting_action (8314624730997322529) -->
+ <skip />
+ <!-- no translation found for auto_saver_okay_action (2701221740227683650) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 080f7e4..c52de5a 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -33,7 +33,6 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Em andamento"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificações"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Bateria fraca"</string>
- <string name="battery_low_title_hybrid" msgid="6268991275887381595">"A bateria está com pouca carga. Ative a Economia de bateria"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> restantes"</string>
<string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> restante(s), cerca de <xliff:g id="TIME">%s</xliff:g> com base no seu uso"</string>
<string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> restante(s), cerca de <xliff:g id="TIME">%s</xliff:g>"</string>
@@ -73,11 +72,12 @@
<string name="global_action_screenshot" msgid="8329831278085426283">"Captura de tela"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Salvando captura de tela..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Salvando captura de tela..."</string>
- <string name="screenshot_saving_text" msgid="2545047868936087248">"A captura de tela está sendo salva"</string>
<string name="screenshot_saved_title" msgid="5637073968117370753">"Captura de tela salva"</string>
<string name="screenshot_saved_text" msgid="7574667448002050363">"Toque para ver sua captura de tela"</string>
- <string name="screenshot_failed_title" msgid="9096484883063264803">"Não foi possível fazer a captura de tela"</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Problema encontrado ao salvar captura de tela"</string>
+ <!-- no translation found for screenshot_failed_title (7612509838919089748) -->
+ <skip />
+ <!-- no translation found for screenshot_failed_to_save_unknown_text (3637758096565605541) -->
+ <skip />
<string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Não é possível salvar a captura de tela, porque não há espaço suficiente"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"O app ou a organização não permitem capturas de tela"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opções transf. arq. por USB"</string>
@@ -275,8 +275,7 @@
<string name="dessert_case" msgid="1295161776223959221">"Mostruário de sobremesas"</string>
<string name="start_dreams" msgid="5640361424498338327">"Protetor de tela"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
- <!-- no translation found for quick_settings_header_onboarding_text (8030309023792936283) -->
- <skip />
+ <string name="quick_settings_header_onboarding_text" msgid="8030309023792936283">"Toque nos ícones e mantenha-os pressionados para ver mais opções"</string>
<string name="quick_settings_dnd_label" msgid="8735855737575028208">"Não perturbe"</string>
<string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Somente prioridade"</string>
<string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Somente alarmes"</string>
@@ -351,7 +350,8 @@
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"Ativ. ao pôr do sol"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Até o nascer do sol"</string>
<string name="quick_settings_night_secondary_label_on_at" msgid="6256314040368487637">"Ativado às <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_night_secondary_label_until" msgid="8664820079774824618">"Até <xliff:g id="TIME">%s</xliff:g>"</string>
+ <!-- no translation found for quick_settings_secondary_label_until (2749196569462600150) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="6883274004315134333">"A NFC está desativada"</string>
<string name="quick_settings_nfc_on" msgid="6680317193676884311">"A NFC está ativada"</string>
@@ -435,6 +435,8 @@
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> começará a capturar tudo o que for exibido na tela."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Não mostrar novamente"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Limpar tudo"</string>
+ <!-- no translation found for manage_notifications_text (8035284146227267681) -->
+ <skip />
<string name="dnd_suppressing_shade_text" msgid="7986451830430707907">"O modo \"Não perturbe\" está ocultando as notificações"</string>
<string name="media_projection_action_text" msgid="8470872969457985954">"Iniciar agora"</string>
<string name="empty_shade_text" msgid="708135716272867002">"Sem notificações"</string>
@@ -628,6 +630,8 @@
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g> do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"controles de notificação"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"opções de adiamento de notificação"</string>
+ <!-- no translation found for notification_menu_snooze_action (1112254519029621372) -->
+ <skip />
<string name="snooze_undo" msgid="6074877317002985129">"DESFAZER"</string>
<string name="snoozed_for_time" msgid="2390718332980204462">"Adiada para <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<plurals name="snoozeHourOptions" formatted="false" msgid="2124335842674413030">
@@ -725,11 +729,9 @@
<string name="right_keycode" msgid="708447961000848163">"Código de tecla à direita"</string>
<string name="left_icon" msgid="3096287125959387541">"Ícone à esquerda"</string>
<string name="right_icon" msgid="3952104823293824311">"Ícone à direita"</string>
- <!-- no translation found for drag_to_add_tiles (230586591689084925) -->
- <skip />
+ <string name="drag_to_add_tiles" msgid="230586591689084925">"Mantenha pressionado e arraste para adicionar blocos"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arraste aqui para remover"</string>
- <!-- no translation found for drag_to_remove_disabled (2390968976638993382) -->
- <skip />
+ <string name="drag_to_remove_disabled" msgid="2390968976638993382">"É preciso haver pelo menos seis blocos"</string>
<string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
<string name="tuner_time" msgid="6572217313285536011">"Horas"</string>
<string-array name="clock_options">
@@ -816,6 +818,8 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Capturas de tela"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Mensagens gerais"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Armazenamento"</string>
+ <!-- no translation found for notification_channel_hints (7323870212489152689) -->
+ <skip />
<string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Os Instant Apps não requerem instalação."</string>
<string name="app_info" msgid="6856026610594615344">"Informações do app"</string>
@@ -833,12 +837,9 @@
<string name="qs_dnd_replace" msgid="8019520786644276623">"Substituir"</string>
<string name="running_foreground_services_title" msgid="381024150898615683">"Apps sendo executados em segundo plano"</string>
<string name="running_foreground_services_msg" msgid="6326247670075574355">"Tocar para ver detalhes sobre a bateria e o uso de dados"</string>
- <!-- no translation found for mobile_data_disable_title (1068272097382942231) -->
- <skip />
- <!-- no translation found for mobile_data_disable_message (4756541658791493506) -->
- <skip />
- <!-- no translation found for mobile_data_disable_message_default_carrier (6078110473451946831) -->
- <skip />
+ <string name="mobile_data_disable_title" msgid="1068272097382942231">"Desativar os dados móveis?"</string>
+ <string name="mobile_data_disable_message" msgid="4756541658791493506">"Você não terá acesso a dados ou à Internet por meio da operadora <xliff:g id="CARRIER">%s</xliff:g>. A Internet só estará disponível via Wi-Fi."</string>
+ <string name="mobile_data_disable_message_default_carrier" msgid="6078110473451946831">"sua operadora"</string>
<string name="touch_filtered_warning" msgid="8671693809204767551">"Como um app está ocultando uma solicitação de permissão, as configurações não podem verificar sua resposta."</string>
<string name="slice_permission_title" msgid="7465009437851044444">"Permitir que <xliff:g id="APP_0">%1$s</xliff:g> mostre partes do app <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="3514586565609596523">"- Pode ler informações do app <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -846,4 +847,18 @@
<string name="slice_permission_checkbox" msgid="7986504458640562900">"Permitir que <xliff:g id="APP">%1$s</xliff:g> mostre partes de qualquer app"</string>
<string name="slice_permission_allow" msgid="2340244901366722709">"Permitir"</string>
<string name="slice_permission_deny" msgid="7683681514008048807">"Negar"</string>
+ <!-- no translation found for auto_saver_title (1217959994732964228) -->
+ <skip />
+ <!-- no translation found for auto_saver_text (6324376061044218113) -->
+ <skip />
+ <!-- no translation found for no_auto_saver_action (8086002101711328500) -->
+ <skip />
+ <!-- no translation found for auto_saver_enabled_title (6726474226058316862) -->
+ <skip />
+ <!-- no translation found for auto_saver_enabled_text (874711029884777579) -->
+ <skip />
+ <!-- no translation found for open_saver_setting_action (8314624730997322529) -->
+ <skip />
+ <!-- no translation found for auto_saver_okay_action (2701221740227683650) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index f76603b..711d550 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -45,9 +45,6 @@
interface. This name is in the ComponentName flattened format (package/class) -->
<string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.StatusBar</string>
- <!-- Component name of launcher service for overview to connect to -->
- <string name="config_overviewServiceComponent" translatable="false">com.android.launcher3/com.android.quickstep.TouchInteractionService</string>
-
<!-- Whether or not we show the number in the bar. -->
<bool name="config_statusBarShowNumber">false</bool>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8c00af6..419e9d2 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1057,7 +1057,7 @@
<string name="manage_notifications_text">Manage notifications</string>
<!-- The text to show in the notifications shade when dnd is suppressing notifications. [CHAR LIMIT=100] -->
- <string name="dnd_suppressing_shade_text">Do Not disturb is hiding notifications</string>
+ <string name="dnd_suppressing_shade_text">Do Not Disturb is hiding notifications</string>
<!-- Media projection permission dialog action text. [CHAR LIMIT=60] -->
<string name="media_projection_action_text">Start now</string>
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index a59c97e..a4f8d8c 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -24,11 +24,13 @@
import android.graphics.RectF;
import android.graphics.Region.Op;
import android.os.AsyncTask;
+import android.os.Handler;
import android.os.Trace;
import android.service.wallpaper.WallpaperService;
import android.util.Log;
import android.view.Display;
import android.view.DisplayInfo;
+import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.WindowManager;
@@ -45,6 +47,7 @@
private static final String GL_LOG_TAG = "ImageWallpaperGL";
private static final boolean DEBUG = false;
private static final String PROPERTY_KERNEL_QEMU = "ro.kernel.qemu";
+ private static final long DELAY_FORGET_WALLPAPER = 5000;
private WallpaperManager mWallpaperManager;
private DrawableEngine mEngine;
@@ -69,6 +72,10 @@
}
class DrawableEngine extends Engine {
+ private final Runnable mUnloadWallpaperCallback = () -> {
+ unloadWallpaper(false /* forgetSize */);
+ };
+
Bitmap mBackground;
int mBackgroundWidth = -1, mBackgroundHeight = -1;
int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
@@ -331,6 +338,7 @@
}
drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels);
+ scheduleUnloadWallpaper();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
@@ -433,6 +441,9 @@
mBackgroundHeight = -1;
}
+ final Surface surface = getSurfaceHolder().getSurface();
+ surface.hwuiDestroy();
+
mLoader = new AsyncTask<Void, Void, Bitmap>() {
@Override
protected Bitmap doInBackground(Void... params) {
@@ -442,6 +453,12 @@
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
+ private void scheduleUnloadWallpaper() {
+ Handler handler = getMainThreadHandler();
+ handler.removeCallbacks(mUnloadWallpaperCallback);
+ handler.postDelayed(mUnloadWallpaperCallback, DELAY_FORGET_WALLPAPER);
+ }
+
@Override
protected void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) {
super.dump(prefix, fd, out, args);
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index a4af6b2..2983df6 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -57,6 +57,8 @@
*/
public class OverviewProxyService implements CallbackController<OverviewProxyListener>, Dumpable {
+ private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
+
public static final String TAG_OPS = "OverviewProxyService";
public static final boolean DEBUG_OVERVIEW_PROXY = false;
private static final long BACKOFF_MILLIS = 5000;
@@ -64,7 +66,7 @@
private final Context mContext;
private final Handler mHandler;
private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser;
- private final ComponentName mLauncherComponentName;
+ private final ComponentName mRecentsComponentName;
private final DeviceProvisionedController mDeviceProvisionedController
= Dependency.get(DeviceProvisionedController.class);
private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
@@ -191,8 +193,8 @@
mContext = context;
mHandler = new Handler();
mConnectionBackoffAttempts = 0;
- mLauncherComponentName = ComponentName
- .unflattenFromString(context.getString(R.string.config_overviewServiceComponent));
+ mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
+ com.android.internal.R.string.config_recentsComponentName));
// Listen for the package update changes.
if (SystemServicesProxy.getInstance(context)
@@ -200,7 +202,7 @@
mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addDataScheme("package");
- filter.addDataSchemeSpecificPart(mLauncherComponentName.getPackageName(),
+ filter.addDataSchemeSpecificPart(mRecentsComponentName.getPackageName(),
PatternMatcher.PATTERN_LITERAL);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
mContext.registerReceiver(mLauncherAddedReceiver, filter);
@@ -223,8 +225,8 @@
return;
}
mHandler.removeCallbacks(mConnectionRunnable);
- Intent launcherServiceIntent = new Intent();
- launcherServiceIntent.setComponent(mLauncherComponentName);
+ Intent launcherServiceIntent = new Intent(ACTION_QUICKSTEP)
+ .setPackage(mRecentsComponentName.getPackageName());
boolean bound = mContext.bindServiceAsUser(launcherServiceIntent,
mOverviewServiceConnection, Context.BIND_AUTO_CREATE,
UserHandle.of(mDeviceProvisionedController.getCurrentUser()));
diff --git a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
index 4b15fbc..3577c0f 100644
--- a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
@@ -18,8 +18,8 @@
import android.content.Context;
import android.content.pm.PackageManager;
-import android.hardware.fingerprint.FingerprintDialog;
-import android.hardware.fingerprint.IFingerprintDialogReceiver;
+import android.hardware.biometrics.BiometricDialog;
+import android.hardware.biometrics.IBiometricDialogReceiver;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -48,7 +48,7 @@
private FingerprintDialogView mDialogView;
private WindowManager mWindowManager;
- private IFingerprintDialogReceiver mReceiver;
+ private IBiometricDialogReceiver mReceiver;
private boolean mDialogShowing;
private Handler mHandler = new Handler() {
@@ -97,7 +97,7 @@
}
@Override
- public void showFingerprintDialog(Bundle bundle, IFingerprintDialogReceiver receiver) {
+ public void showFingerprintDialog(Bundle bundle, IBiometricDialogReceiver receiver) {
if (DEBUG) Log.d(TAG, "showFingerprintDialog");
// Remove these messages as they are part of the previous client
mHandler.removeMessages(MSG_FINGERPRINT_ERROR);
@@ -139,7 +139,7 @@
Log.w(TAG, "Dialog already showing");
return;
}
- mReceiver = (IFingerprintDialogReceiver) args.arg2;
+ mReceiver = (IBiometricDialogReceiver) args.arg2;
mDialogView.setBundle((Bundle)args.arg1);
mWindowManager.addView(mDialogView, mDialogView.getLayoutParams());
mDialogShowing = true;
@@ -147,6 +147,9 @@
private void handleFingerprintAuthenticated() {
if (DEBUG) Log.d(TAG, "handleFingerprintAuthenticated");
+ mDialogView.announceForAccessibility(
+ mContext.getResources().getText(
+ com.android.internal.R.string.fingerprint_authenticated));
handleHideDialog(false /* userCanceled */);
}
@@ -174,7 +177,7 @@
}
if (userCanceled) {
try {
- mReceiver.onDialogDismissed(FingerprintDialog.DISMISSED_REASON_USER_CANCEL);
+ mReceiver.onDialogDismissed(BiometricDialog.DISMISSED_REASON_USER_CANCEL);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException when hiding dialog", e);
}
@@ -190,7 +193,7 @@
return;
}
try {
- mReceiver.onDialogDismissed(FingerprintDialog.DISMISSED_REASON_NEGATIVE);
+ mReceiver.onDialogDismissed(BiometricDialog.DISMISSED_REASON_NEGATIVE);
} catch (RemoteException e) {
Log.e(TAG, "Remote exception when handling negative button", e);
}
@@ -203,7 +206,7 @@
return;
}
try {
- mReceiver.onDialogDismissed(FingerprintDialog.DISMISSED_REASON_POSITIVE);
+ mReceiver.onDialogDismissed(BiometricDialog.DISMISSED_REASON_POSITIVE);
} catch (RemoteException e) {
Log.e(TAG, "Remote exception when handling positive button", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
index 05906f7..95258b0 100644
--- a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
@@ -23,7 +23,7 @@
import android.graphics.PorterDuff;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
-import android.hardware.fingerprint.FingerprintDialog;
+import android.hardware.biometrics.BiometricDialog;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -163,10 +163,10 @@
mLastState = STATE_NONE;
updateFingerprintIcon(STATE_FINGERPRINT);
- title.setText(mBundle.getCharSequence(FingerprintDialog.KEY_TITLE));
+ title.setText(mBundle.getCharSequence(BiometricDialog.KEY_TITLE));
title.setSelected(true);
- final CharSequence subtitleText = mBundle.getCharSequence(FingerprintDialog.KEY_SUBTITLE);
+ final CharSequence subtitleText = mBundle.getCharSequence(BiometricDialog.KEY_SUBTITLE);
if (subtitleText == null) {
subtitle.setVisibility(View.GONE);
} else {
@@ -174,18 +174,18 @@
subtitle.setText(subtitleText);
}
- final CharSequence descriptionText = mBundle.getCharSequence(FingerprintDialog.KEY_DESCRIPTION);
+ final CharSequence descriptionText = mBundle.getCharSequence(BiometricDialog.KEY_DESCRIPTION);
if (descriptionText == null) {
subtitle.setVisibility(View.VISIBLE);
description.setVisibility(View.GONE);
} else {
- description.setText(mBundle.getCharSequence(FingerprintDialog.KEY_DESCRIPTION));
+ description.setText(mBundle.getCharSequence(BiometricDialog.KEY_DESCRIPTION));
}
- negative.setText(mBundle.getCharSequence(FingerprintDialog.KEY_NEGATIVE_TEXT));
+ negative.setText(mBundle.getCharSequence(BiometricDialog.KEY_NEGATIVE_TEXT));
final CharSequence positiveText =
- mBundle.getCharSequence(FingerprintDialog.KEY_POSITIVE_TEXT);
+ mBundle.getCharSequence(BiometricDialog.KEY_POSITIVE_TEXT);
positive.setText(positiveText); // needs to be set for marquee to work
if (positiveText != null) {
positive.setVisibility(View.VISIBLE);
@@ -271,7 +271,7 @@
mErrorText.setTextColor(mErrorTextColor);
mErrorText.setContentDescription(message);
mHandler.sendMessageDelayed(mHandler.obtainMessage(FingerprintDialogImpl.MSG_CLEAR_MESSAGE),
- FingerprintDialog.HIDE_DIALOG_DELAY);
+ BiometricDialog.HIDE_DIALOG_DELAY);
}
public void showHelpMessage(String message) {
@@ -281,7 +281,7 @@
public void showErrorMessage(String error) {
showTemporaryMessage(error);
mHandler.sendMessageDelayed(mHandler.obtainMessage(FingerprintDialogImpl.MSG_HIDE_DIALOG,
- false /* userCanceled */), FingerprintDialog.HIDE_DIALOG_DELAY);
+ false /* userCanceled */), BiometricDialog.HIDE_DIALOG_DELAY);
}
private void updateFingerprintIcon(int newState) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index a1b17e4..d6e59c7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -27,7 +27,6 @@
import android.app.ActivityManager;
import android.app.AlarmManager;
-import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.StatusBarManager;
import android.app.trust.TrustManager;
@@ -235,6 +234,9 @@
// answer whether the input should be restricted)
private boolean mShowing;
+ // AOD is enabled and status bar is in AOD state.
+ private boolean mAodShowing;
+
// display id of the secondary display on which we have put a keyguard window
private int mSecondaryDisplayShowing = INVALID_DISPLAY;
@@ -664,7 +666,7 @@
@Override
public void onSecondaryDisplayShowingChanged(int displayId) {
synchronized (KeyguardViewMediator.this) {
- setShowingLocked(mShowing, displayId, false);
+ setShowingLocked(mShowing, mAodShowing, displayId, false);
}
}
};
@@ -707,10 +709,10 @@
setShowingLocked(!shouldWaitForProvisioning()
&& !mLockPatternUtils.isLockScreenDisabled(
KeyguardUpdateMonitor.getCurrentUser()),
- mSecondaryDisplayShowing, true /* forceCallbacks */);
+ mAodShowing, mSecondaryDisplayShowing, true /* forceCallbacks */);
} else {
// The system's keyguard is disabled or missing.
- setShowingLocked(false, mSecondaryDisplayShowing, true);
+ setShowingLocked(false, mAodShowing, mSecondaryDisplayShowing, true);
}
mStatusBarKeyguardViewManager =
@@ -1311,7 +1313,7 @@
if (mLockPatternUtils.checkVoldPassword(KeyguardUpdateMonitor.getCurrentUser())) {
if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted");
// Without this, settings is not enabled until the lock screen first appears
- setShowingLocked(false);
+ setShowingLocked(false, mAodShowing);
hideLocked();
return;
}
@@ -1713,10 +1715,12 @@
playSound(mTrustedSoundId);
}
- private void updateActivityLockScreenState(boolean showing, int secondaryDisplayShowing) {
+ private void updateActivityLockScreenState(boolean showing, boolean aodShowing,
+ int secondaryDisplayShowing) {
mUiOffloadThread.submit(() -> {
try {
- ActivityManager.getService().setLockScreenShown(showing, secondaryDisplayShowing);
+ ActivityManager.getService().setLockScreenShown(showing, aodShowing,
+ secondaryDisplayShowing);
} catch (RemoteException e) {
}
});
@@ -1740,7 +1744,7 @@
if (DEBUG) Log.d(TAG, "handleShow");
}
- setShowingLocked(true);
+ setShowingLocked(true, mAodShowing);
mStatusBarKeyguardViewManager.show(options);
mHiding = false;
mWakeAndUnlocking = false;
@@ -1849,7 +1853,7 @@
}
mWakeAndUnlocking = false;
- setShowingLocked(false);
+ setShowingLocked(false, mAodShowing);
mDismissCallbackRegistry.notifyDismissSucceeded();
mStatusBarKeyguardViewManager.hide(startTime, fadeoutDuration);
resetKeyguardDonePendingLocked();
@@ -1909,7 +1913,7 @@
Trace.beginSection("KeyguardViewMediator#handleVerifyUnlock");
synchronized (KeyguardViewMediator.this) {
if (DEBUG) Log.d(TAG, "handleVerifyUnlock");
- setShowingLocked(true);
+ setShowingLocked(true, mAodShowing);
mStatusBarKeyguardViewManager.dismissAndCollapse();
}
Trace.endSection();
@@ -2064,6 +2068,10 @@
pw.print(" mDrawnCallback: "); pw.println(mDrawnCallback);
}
+ public void setAodShowing(boolean aodShowing) {
+ setShowingLocked(mShowing, aodShowing);
+ }
+
private static class StartKeyguardExitAnimParams {
long startTime;
@@ -2075,20 +2083,23 @@
}
}
- private void setShowingLocked(boolean showing) {
- setShowingLocked(showing, mSecondaryDisplayShowing, false /* forceCallbacks */);
+ private void setShowingLocked(boolean showing, boolean aodShowing) {
+ setShowingLocked(showing, aodShowing, mSecondaryDisplayShowing,
+ false /* forceCallbacks */);
}
- private void setShowingLocked(
- boolean showing, int secondaryDisplayShowing, boolean forceCallbacks) {
- final boolean notifyDefaultDisplayCallbacks = showing != mShowing || forceCallbacks;
+ private void setShowingLocked(boolean showing, boolean aodShowing, int secondaryDisplayShowing,
+ boolean forceCallbacks) {
+ final boolean notifyDefaultDisplayCallbacks = showing != mShowing
+ || aodShowing != mAodShowing || forceCallbacks;
if (notifyDefaultDisplayCallbacks || secondaryDisplayShowing != mSecondaryDisplayShowing) {
mShowing = showing;
+ mAodShowing = aodShowing;
mSecondaryDisplayShowing = secondaryDisplayShowing;
if (notifyDefaultDisplayCallbacks) {
notifyDefaultDisplayCallbacks(showing);
}
- updateActivityLockScreenState(showing, secondaryDisplayShowing);
+ updateActivityLockScreenState(showing, aodShowing, secondaryDisplayShowing);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 1596d12..3d8e037 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -592,7 +592,16 @@
// Record last snap target the divider moved to
if (mHomeStackResizable && !mIsInMinimizeInteraction) {
- saveSnapTargetBeforeMinimized(snapTarget);
+ // The last snapTarget position can be negative when the last divider position was
+ // offscreen. In that case, save the middle (default) SnapTarget so calculating next
+ // position isn't negative.
+ final SnapTarget saveTarget;
+ if (snapTarget.position < 0) {
+ saveTarget = mSnapAlgorithm.getMiddleTarget();
+ } else {
+ saveTarget = snapTarget;
+ }
+ saveSnapTargetBeforeMinimized(saveTarget);
}
};
Runnable notCancelledEndAction = () -> {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index fa177f2..65037f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -18,7 +18,7 @@
import android.content.ComponentName;
import android.graphics.Rect;
-import android.hardware.fingerprint.IFingerprintDialogReceiver;
+import android.hardware.biometrics.IBiometricDialogReceiver;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -160,7 +160,7 @@
default void onRotationProposal(int rotation, boolean isValid) { }
- default void showFingerprintDialog(Bundle bundle, IFingerprintDialogReceiver receiver) { }
+ default void showFingerprintDialog(Bundle bundle, IBiometricDialogReceiver receiver) { }
default void onFingerprintAuthenticated() { }
default void onFingerprintHelp(String message) { }
default void onFingerprintError(String error) { }
@@ -513,7 +513,7 @@
}
@Override
- public void showFingerprintDialog(Bundle bundle, IFingerprintDialogReceiver receiver) {
+ public void showFingerprintDialog(Bundle bundle, IBiometricDialogReceiver receiver) {
synchronized (mLock) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = bundle;
@@ -759,7 +759,7 @@
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).showFingerprintDialog(
(Bundle)((SomeArgs)msg.obj).arg1,
- (IFingerprintDialogReceiver)((SomeArgs)msg.obj).arg2);
+ (IBiometricDialogReceiver)((SomeArgs)msg.obj).arg2);
}
break;
case MSG_FINGERPRINT_AUTHENTICATED:
@@ -810,4 +810,3 @@
}
}
}
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
index a2b1013..6576eb7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
@@ -399,4 +399,11 @@
pw.print(" mMode="); pw.println(mMode);
pw.print(" mWakeLock="); pw.println(mWakeLock);
}
+
+ public boolean isWakeAndUnlock() {
+ return mMode == MODE_UNLOCK
+ || mMode == MODE_WAKE_AND_UNLOCK
+ || mMode == MODE_WAKE_AND_UNLOCK_PULSING
+ || mMode == MODE_WAKE_AND_UNLOCK_FROM_DREAM;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 7aabc56..4e12936 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -347,7 +347,9 @@
if (mExpansionFraction != fraction) {
mExpansionFraction = fraction;
- if (!(mState == ScrimState.UNLOCKED || mState == ScrimState.KEYGUARD)) {
+ final boolean keyguardOrUnlocked = mState == ScrimState.UNLOCKED
+ || mState == ScrimState.KEYGUARD;
+ if (!keyguardOrUnlocked || !mExpansionAffectsAlpha) {
return;
}
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 5b734eb..f4b6c38 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -156,7 +156,6 @@
mCurrentBehindTint = Color.BLACK;
mBlankScreen = true;
} else {
- // Scrims should still be black at the end of the transition.
mCurrentInFrontTint = Color.TRANSPARENT;
mCurrentBehindTint = Color.TRANSPARENT;
mBlankScreen = false;
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 ddb67df..c03ecb3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -408,6 +408,7 @@
protected NotificationEntryManager mEntryManager;
protected NotificationViewHierarchyManager mViewHierarchyManager;
protected AppOpsListener mAppOpsListener;
+ protected KeyguardViewMediator mKeyguardViewMediator;
private ZenModeController mZenController;
/**
@@ -632,6 +633,7 @@
mAppOpsListener = Dependency.get(AppOpsListener.class);
mAppOpsListener.setUpWithPresenter(this, mEntryManager);
mZenController = Dependency.get(ZenModeController.class);
+ mKeyguardViewMediator = getComponent(KeyguardViewMediator.class);
mColorExtractor = Dependency.get(SysuiColorExtractor.class);
mColorExtractor.addOnColorsChangedListener(this);
@@ -4628,6 +4630,7 @@
boolean dozing = mDozingRequested && mState == StatusBarState.KEYGUARD
|| mFingerprintUnlockController.getMode()
== FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
+ final boolean alwaysOn = DozeParameters.getInstance(mContext).getAlwaysOn();
// When in wake-and-unlock we may not have received a change to mState
// but we still should not be dozing, manually set to false.
if (mFingerprintUnlockController.getMode() ==
@@ -4635,6 +4638,7 @@
dozing = false;
}
mDozing = dozing;
+ mKeyguardViewMediator.setAodShowing(mDozing && alwaysOn);
mStatusBarWindowManager.setDozing(mDozing);
mStatusBarKeyguardViewManager.setDozing(mDozing);
if (mAmbientIndicationContainer instanceof DozeReceiver) {
@@ -4655,9 +4659,8 @@
final boolean wakeAndUnlocking = mFingerprintUnlockController.getMode()
== FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
- // Do not animate the scrim expansion when it's triggered by the fingerprint sensor.
- mScrimController.setExpansionAffectsAlpha(mFingerprintUnlockController.getMode()
- != FingerprintUnlockController.MODE_UNLOCK);
+ // Do not animate the scrim expansion when triggered by the fingerprint sensor.
+ mScrimController.setExpansionAffectsAlpha(!mFingerprintUnlockController.isWakeAndUnlock());
if (mBouncerShowing) {
// Bouncer needs the front scrim when it's on top of an activity,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 309a1a7..2437c51 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -143,7 +143,9 @@
final boolean scrimsOccludingWallpaper =
state.scrimsVisibility == ScrimController.VISIBILITY_FULLY_OPAQUE;
- if (state.keyguardShowing && !state.backdropShowing && !scrimsOccludingWallpaper) {
+ final boolean keyguardOrAod = state.keyguardShowing
+ || (state.dozing && mDozeParameters.getAlwaysOn());
+ if (keyguardOrAod && !state.backdropShowing && !scrimsOccludingWallpaper) {
mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
} else {
mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index d9cad0e..71c7f80 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -36,6 +36,7 @@
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.ColorStateList;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.PixelFormat;
@@ -60,6 +61,7 @@
import android.view.View.AccessibilityDelegate;
import android.view.View.OnAttachStateChangeListener;
import android.view.ViewGroup;
+import android.view.ViewPropertyAnimator;
import android.view.Window;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
@@ -192,7 +194,7 @@
mDialog.setCanceledOnTouchOutside(true);
mDialog.setContentView(R.layout.volume_dialog);
mDialog.setOnShowListener(dialog -> {
- mDialogView.setTranslationX(mDialogView.getWidth() / 2);
+ if (!isLandscape()) mDialogView.setTranslationX(mDialogView.getWidth() / 2);
mDialogView.setAlpha(0);
mDialogView.animate()
.alpha(1)
@@ -254,6 +256,11 @@
return ColorStateList.valueOf(mContext.getColor(colorResId));
}
+ private boolean isLandscape() {
+ return mContext.getResources().getConfiguration().orientation ==
+ Configuration.ORIENTATION_LANDSCAPE;
+ }
+
public void setStreamImportant(int stream, boolean important) {
mHandler.obtainMessage(H.SET_STREAM_IMPORTANT, stream, important ? 1 : 0).sendToTarget();
}
@@ -509,16 +516,16 @@
mDialogView.setTranslationX(0);
mDialogView.setAlpha(1);
- mDialogView.animate()
+ ViewPropertyAnimator animator = mDialogView.animate()
.alpha(0)
- .translationX(mDialogView.getWidth() / 2)
.setDuration(250)
.setInterpolator(new SystemUIInterpolators.LogAccelerateInterpolator())
.withEndAction(() -> mHandler.postDelayed(() -> {
if (D.BUG) Log.d(TAG, "mDialog.dismiss()");
mDialog.dismiss();
- }, 50))
- .start();
+ }, 50));
+ if (!isLandscape()) animator.translationX(mDialogView.getWidth() / 2);
+ animator.start();
Events.writeEvent(mContext, Events.EVENT_DISMISS_DIALOG, reason);
mController.notifyVisible(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 7743c6b..a88f31a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -26,6 +26,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
@@ -73,7 +74,7 @@
@Before
public void setup() {
mLightBarController = mock(LightBarController.class);
- mScrimBehind = new ScrimView(getContext());
+ mScrimBehind = spy(new ScrimView(getContext()));
mScrimInFront = new ScrimView(getContext());
mWakeLock = mock(WakeLock.class);
mAlarmManager = mock(AlarmManager.class);
@@ -210,8 +211,10 @@
mScrimController.finishAnimationsImmediately();
final float scrimAlpha = mScrimBehind.getViewAlpha();
+ reset(mScrimBehind);
mScrimController.setExpansionAffectsAlpha(false);
mScrimController.setPanelExpansion(0.8f);
+ verifyZeroInteractions(mScrimBehind);
Assert.assertEquals("Scrim opacity shouldn't change when setExpansionAffectsAlpha "
+ "is false", scrimAlpha, mScrimBehind.getViewAlpha(), 0.01f);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index f81ffd8..4a66bb7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -70,6 +70,7 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.statusbar.ActivatableNotificationView;
@@ -132,6 +133,7 @@
@Mock private NotificationViewHierarchyManager mViewHierarchyManager;
@Mock private VisualStabilityManager mVisualStabilityManager;
@Mock private NotificationListener mNotificationListener;
+ @Mock private KeyguardViewMediator mKeyguardViewMediator;
private TestableStatusBar mStatusBar;
private FakeMetricsLogger mMetricsLogger;
@@ -200,7 +202,7 @@
mPowerManager, mNotificationPanelView, mBarService, mNotificationListener,
mNotificationLogger, mVisualStabilityManager, mViewHierarchyManager,
mEntryManager, mScrimController, mFingerprintUnlockController,
- mock(ActivityLaunchAnimator.class));
+ mock(ActivityLaunchAnimator.class), mKeyguardViewMediator);
mStatusBar.mContext = mContext;
mStatusBar.mComponents = mContext.getComponents();
mEntryManager.setUpForTest(mStatusBar, mStackScroller, mStatusBar, mHeadsUpManager,
@@ -638,7 +640,7 @@
NotificationViewHierarchyManager viewHierarchyManager,
TestableNotificationEntryManager entryManager, ScrimController scrimController,
FingerprintUnlockController fingerprintUnlockController,
- ActivityLaunchAnimator launchAnimator) {
+ ActivityLaunchAnimator launchAnimator, KeyguardViewMediator keyguardViewMediator) {
mStatusBarKeyguardViewManager = man;
mUnlockMethodCache = unlock;
mKeyguardIndicationController = key;
@@ -656,6 +658,7 @@
mScrimController = scrimController;
mFingerprintUnlockController = fingerprintUnlockController;
mActivityLaunchAnimator = launchAnimator;
+ mKeyguardViewMediator = keyguardViewMediator;
mClearAllEnabled = true;
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 5114308..9c421c6 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -21,6 +21,7 @@
import static com.android.server.autofill.Helper.bundleToString;
import static com.android.server.autofill.Helper.sDebug;
+import static com.android.server.autofill.Helper.sFullScreenMode;
import static com.android.server.autofill.Helper.sPartitionMaxCount;
import static com.android.server.autofill.Helper.sVisibleDatasetsMaxCount;
import static com.android.server.autofill.Helper.sVerbose;
@@ -449,7 +450,7 @@
}
// Called by Shell command.
- public int getMaxPartitions() {
+ int getMaxPartitions() {
mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
synchronized (mLock) {
@@ -458,7 +459,7 @@
}
// Called by Shell command.
- public void setMaxPartitions(int max) {
+ void setMaxPartitions(int max) {
mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
Slog.i(TAG, "setMaxPartitions(): " + max);
synchronized (mLock) {
@@ -467,7 +468,7 @@
}
// Called by Shell command.
- public int getMaxVisibleDatasets() {
+ int getMaxVisibleDatasets() {
mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
synchronized (mLock) {
@@ -476,7 +477,7 @@
}
// Called by Shell command.
- public void setMaxVisibleDatasets(int max) {
+ void setMaxVisibleDatasets(int max) {
mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
Slog.i(TAG, "setMaxVisibleDatasets(): " + max);
synchronized (mLock) {
@@ -485,7 +486,7 @@
}
// Called by Shell command.
- public void getScore(@Nullable String algorithmName, @NonNull String value1,
+ void getScore(@Nullable String algorithmName, @NonNull String value1,
@NonNull String value2, @NonNull RemoteCallback callback) {
mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
@@ -496,6 +497,18 @@
Arrays.asList(AutofillValue.forText(value1)), new String[] { value2 });
}
+ // Called by Shell command.
+ Boolean getFullScreenMode() {
+ mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+ return sFullScreenMode;
+ }
+
+ // Called by Shell command.
+ void setFullScreenMode(@Nullable Boolean mode) {
+ mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+ sFullScreenMode = mode;
+ }
+
private void setDebugLocked(boolean debug) {
com.android.server.autofill.Helper.sDebug = debug;
android.view.autofill.Helper.sDebug = debug;
@@ -1159,6 +1172,9 @@
pw.print("Disabled users: "); pw.println(mDisabledUsers);
pw.print("Max partitions per session: "); pw.println(sPartitionMaxCount);
pw.print("Max visible datasets: "); pw.println(sVisibleDatasetsMaxCount);
+ if (sFullScreenMode != null) {
+ pw.print("Overridden full-screen mode: "); pw.println(sFullScreenMode);
+ }
pw.println("User data constraints: "); UserData.dumpConstraints(prefix, pw);
final int size = mServicesCache.size();
pw.print("Cached services: ");
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
index 1904061..c76c8ac 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
@@ -80,6 +80,12 @@
pw.println(" get max_visible_datasets");
pw.println(" Gets the maximum number of visible datasets in the UI.");
pw.println("");
+ pw.println(" get full_screen_mode");
+ pw.println(" Gets the Fill UI full screen mode");
+ pw.println("");
+ pw.println(" get fc_score [--algorithm ALGORITHM] value1 value2");
+ pw.println(" Gets the field classification score for 2 fields.");
+ pw.println("");
pw.println(" set log_level [off | debug | verbose]");
pw.println(" Sets the Autofill log level.");
pw.println("");
@@ -89,6 +95,9 @@
pw.println(" set max_visible_datasets number");
pw.println(" Sets the maximum number of visible datasets in the UI.");
pw.println("");
+ pw.println(" set full_screen_mode [true | false | default]");
+ pw.println(" Sets the Fill UI full screen mode");
+ pw.println("");
pw.println(" list sessions [--user USER_ID]");
pw.println(" Lists all pending sessions.");
pw.println("");
@@ -98,9 +107,6 @@
pw.println(" reset");
pw.println(" Resets all pending sessions and cached service connections.");
pw.println("");
- pw.println(" get fc_score [--algorithm ALGORITHM] value1 value2");
- pw.println(" Gets the field classification score for 2 fields.");
- pw.println("");
}
}
@@ -115,6 +121,8 @@
return getMaxVisibileDatasets(pw);
case "fc_score":
return getFieldClassificationScore(pw);
+ case "full_screen_mode":
+ return getFullScreenMode(pw);
default:
pw.println("Invalid set: " + what);
return -1;
@@ -131,6 +139,8 @@
return setMaxPartitions();
case "max_visible_datasets":
return setMaxVisibileDatasets();
+ case "full_screen_mode":
+ return setFullScreenMode(pw);
default:
pw.println("Invalid set: " + what);
return -1;
@@ -219,6 +229,36 @@
return waitForLatch(pw, latch);
}
+ private int getFullScreenMode(PrintWriter pw) {
+ final Boolean mode = mService.getFullScreenMode();
+ if (mode == null) {
+ pw.println("default");
+ } else if (mode) {
+ pw.println("true");
+ } else {
+ pw.println("false");
+ }
+ return 0;
+ }
+
+ private int setFullScreenMode(PrintWriter pw) {
+ final String mode = getNextArgRequired();
+ switch (mode.toLowerCase()) {
+ case "true":
+ mService.setFullScreenMode(Boolean.TRUE);
+ return 0;
+ case "false":
+ mService.setFullScreenMode(Boolean.FALSE);
+ return 0;
+ case "default":
+ mService.setFullScreenMode(null);
+ return 0;
+ default:
+ pw.println("Invalid mode: " + mode);
+ return -1;
+ }
+ }
+
private int requestDestroy(PrintWriter pw) {
if (!isNextArgSessions(pw)) {
return -1;
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 58f78ec..a202aaf 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -70,6 +70,11 @@
*/
public static int sVisibleDatasetsMaxCount = 3;
+ /**
+ * When non-null, overrides whether the UI should be shown on full-screen mode.
+ */
+ public static Boolean sFullScreenMode = null;
+
private Helper() {
throw new UnsupportedOperationException("contains static members only");
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index edfc412..25d0d5c 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -17,6 +17,7 @@
import static com.android.server.autofill.Helper.paramsToString;
import static com.android.server.autofill.Helper.sDebug;
+import static com.android.server.autofill.Helper.sFullScreenMode;
import static com.android.server.autofill.Helper.sVerbose;
import android.annotation.AttrRes;
@@ -51,6 +52,7 @@
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.FrameLayout;
+import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RemoteViews;
@@ -118,7 +120,9 @@
private final @NonNull Callback mCallback;
+ private final @Nullable View mHeader;
private final @NonNull ListView mListView;
+ private final @Nullable View mFooter;
private final @Nullable ItemsAdapter mAdapter;
@@ -133,6 +137,10 @@
private boolean mDestroyed;
public static boolean isFullScreen(Context context) {
+ if (sFullScreenMode != null) {
+ if (sVerbose) Slog.v(TAG, "forcing full-screen mode to " + sFullScreenMode);
+ return sFullScreenMode;
+ }
return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
}
@@ -145,9 +153,18 @@
final LayoutInflater inflater = LayoutInflater.from(context);
- final ViewGroup decor = (ViewGroup) inflater.inflate(
- mFullScreen ? R.layout.autofill_dataset_picker_fullscreen
- : R.layout.autofill_dataset_picker, null);
+ final RemoteViews headerPresentation = response.getHeader();
+ final RemoteViews footerPresentation = response.getFooter();
+ final ViewGroup decor;
+ if (headerPresentation != null || footerPresentation != null) {
+ decor = (ViewGroup) inflater.inflate(
+ mFullScreen ? R.layout.autofill_dataset_picker_header_footer_fullscreen
+ : R.layout.autofill_dataset_picker_header_footer, null);
+ } else {
+ decor = (ViewGroup) inflater.inflate(
+ mFullScreen ? R.layout.autofill_dataset_picker_fullscreen
+ : R.layout.autofill_dataset_picker, null);
+ }
// if autofill ui is not fullscreen, send unhandled keyevent to app window.
if (!mFullScreen) {
@@ -186,7 +203,9 @@
};
if (response.getAuthentication() != null) {
+ mHeader = null;
mListView = null;
+ mFooter = null;
mAdapter = null;
// insert authentication item under autofill_dataset_container or decor
@@ -207,7 +226,7 @@
decor.setFocusable(true);
decor.setOnClickListener(v -> mCallback.onResponsePicked(response));
- Point maxSize = mTempPoint;
+ final Point maxSize = mTempPoint;
resolveMaxWindowSize(context, maxSize);
// fullScreen mode occupy the full width defined by autofill_dataset_picker_max_width
content.getLayoutParams().width = mFullScreen ? maxSize.x
@@ -226,38 +245,39 @@
requestShowFillUi();
} else {
final int datasetCount = response.getDatasets().size();
-
- // Total items include the (optional) header and footer - we cannot use listview's
- // addHeader() and addFooter() because it would complicate the scrolling logic.
- int totalItems = datasetCount;
-
- RemoteViews.OnClickHandler clickBlocker = null;
- final RemoteViews headerPresentation = response.getHeader();
- View header = null;
- if (headerPresentation != null) {
- clickBlocker = newClickBlocker();
- header = headerPresentation.apply(context, null, clickBlocker);
- totalItems++;
+ if (sVerbose) {
+ Slog.v(TAG, "Number datasets: " + datasetCount + " max visible: "
+ + sVisibleDatasetsMaxCount);
}
- final RemoteViews footerPresentation = response.getFooter();
- View footer = null;
+ RemoteViews.OnClickHandler clickBlocker = null;
+ if (headerPresentation != null) {
+ clickBlocker = newClickBlocker();
+ mHeader = headerPresentation.apply(context, null, clickBlocker);
+ final LinearLayout headerContainer =
+ decor.findViewById(R.id.autofill_dataset_header);
+ if (sVerbose) Slog.v(TAG, "adding header");
+ headerContainer.addView(mHeader);
+ headerContainer.setVisibility(View.VISIBLE);
+ } else {
+ mHeader = null;
+ }
+
if (footerPresentation != null) {
if (clickBlocker == null) { // already set for header
clickBlocker = newClickBlocker();
}
- footer = footerPresentation.apply(context, null, clickBlocker);
- totalItems++;
- }
- if (sVerbose) {
- Slog.v(TAG, "Number datasets: " + datasetCount + " Total items: " + totalItems);
+ mFooter = footerPresentation.apply(context, null, clickBlocker);
+ final LinearLayout footerContainer =
+ decor.findViewById(R.id.autofill_dataset_footer);
+ if (sVerbose) Slog.v(TAG, "adding footer");
+ footerContainer.addView(mFooter);
+ footerContainer.setVisibility(View.VISIBLE);
+ } else {
+ mFooter = null;
}
- final ArrayList<ViewItem> items = new ArrayList<>(totalItems);
- if (header != null) {
- if (sVerbose) Slog.v(TAG, "adding header");
- items.add(new ViewItem(null, null, false, null, header));
- }
+ final ArrayList<ViewItem> items = new ArrayList<>(datasetCount);
for (int i = 0; i < datasetCount; i++) {
final Dataset dataset = response.getDatasets().get(i);
final int index = dataset.getFieldIds().indexOf(focusedViewId);
@@ -299,10 +319,6 @@
items.add(new ViewItem(dataset, filterPattern, filterable, valueText, view));
}
}
- if (footer != null) {
- if (sVerbose) Slog.v(TAG, "adding footer");
- items.add(new ViewItem(null, null, false, null, footer));
- }
mAdapter = new ItemsAdapter(items);
@@ -311,11 +327,6 @@
mListView.setVisibility(View.VISIBLE);
mListView.setOnItemClickListener((adapter, view, position, id) -> {
final ViewItem vi = mAdapter.getItem(position);
- if (vi.dataset == null) {
- // Clicked on header or footer; ignore.
- if (sDebug) Slog.d(TAG, "Ignoring click on item " + position + ": " + view);
- return;
- }
mCallback.onDatasetPicked(vi.dataset);
});
@@ -460,6 +471,13 @@
changed = true;
mContentWidth = maxSize.x;
}
+
+ if (mHeader != null) {
+ mHeader.measure(widthMeasureSpec, heightMeasureSpec);
+ changed |= updateWidth(mHeader, maxSize);
+ changed |= updateHeight(mHeader, maxSize);
+ }
+
for (int i = 0; i < itemCount; i++) {
final View view = mAdapter.getItem(i).view;
view.measure(widthMeasureSpec, heightMeasureSpec);
@@ -473,23 +491,40 @@
break;
}
} else {
- final int clampedMeasuredWidth = Math.min(view.getMeasuredWidth(), maxSize.x);
- final int newContentWidth = Math.max(mContentWidth, clampedMeasuredWidth);
- if (newContentWidth != mContentWidth) {
- mContentWidth = newContentWidth;
- changed = true;
- }
- // Update the width to fit only the first items up to max count
+ changed |= updateWidth(view, maxSize);
if (i < sVisibleDatasetsMaxCount) {
- final int clampedMeasuredHeight = Math.min(view.getMeasuredHeight(), maxSize.y);
- final int newContentHeight = mContentHeight + clampedMeasuredHeight;
- if (newContentHeight != mContentHeight) {
- mContentHeight = newContentHeight;
- changed = true;
- }
+ changed |= updateHeight(view, maxSize);
}
}
}
+
+ if (mFooter != null) {
+ mFooter.measure(widthMeasureSpec, heightMeasureSpec);
+ changed |= updateWidth(mFooter, maxSize);
+ changed |= updateHeight(mFooter, maxSize);
+ }
+ return changed;
+ }
+
+ private boolean updateWidth(View view, Point maxSize) {
+ boolean changed = false;
+ final int clampedMeasuredWidth = Math.min(view.getMeasuredWidth(), maxSize.x);
+ final int newContentWidth = Math.max(mContentWidth, clampedMeasuredWidth);
+ if (newContentWidth != mContentWidth) {
+ mContentWidth = newContentWidth;
+ changed = true;
+ }
+ return changed;
+ }
+
+ private boolean updateHeight(View view, Point maxSize) {
+ boolean changed = false;
+ final int clampedMeasuredHeight = Math.min(view.getMeasuredHeight(), maxSize.y);
+ final int newContentHeight = mContentHeight + clampedMeasuredHeight;
+ if (newContentHeight != mContentHeight) {
+ mContentHeight = newContentHeight;
+ changed = true;
+ }
return changed;
}
@@ -501,7 +536,7 @@
private static void resolveMaxWindowSize(Context context, Point outPoint) {
context.getDisplay().getSize(outPoint);
- TypedValue typedValue = sTempTypedValue;
+ final TypedValue typedValue = sTempTypedValue;
context.getTheme().resolveAttribute(R.attr.autofillDatasetPickerMaxWidth,
typedValue, true);
outPoint.x = (int) typedValue.getFraction(outPoint.x, outPoint.x);
@@ -688,17 +723,27 @@
public void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("mCallback: "); pw.println(mCallback != null);
pw.print(prefix); pw.print("mFullScreen: "); pw.println(mFullScreen);
- pw.print(prefix); pw.print("mListView: "); pw.println(mListView);
- pw.print(prefix); pw.print("mAdapter: "); pw.println(mAdapter);
- pw.print(prefix); pw.print("mFilterText: ");
- Helper.printlnRedactedText(pw, mFilterText);
+ if (mHeader != null) {
+ pw.print(prefix); pw.print("mHeader: "); pw.println(mHeader);
+ }
+ if (mListView != null) {
+ pw.print(prefix); pw.print("mListView: "); pw.println(mListView);
+ }
+ if (mFooter != null) {
+ pw.print(prefix); pw.print("mFooter: "); pw.println(mFooter);
+ }
+ if (mAdapter != null) {
+ pw.print(prefix); pw.print("mAdapter: "); pw.println(mAdapter);
+ }
+ if (mFilterText != null) {
+ pw.print(prefix); pw.print("mFilterText: ");
+ Helper.printlnRedactedText(pw, mFilterText);
+ }
pw.print(prefix); pw.print("mContentWidth: "); pw.println(mContentWidth);
pw.print(prefix); pw.print("mContentHeight: "); pw.println(mContentHeight);
pw.print(prefix); pw.print("mDestroyed: "); pw.println(mDestroyed);
- pw.print(prefix); pw.print("mWindow: ");
- if (mWindow == null) {
- pw.println("N/A");
- } else {
+ if (mWindow != null) {
+ pw.print(prefix); pw.print("mWindow: ");
final String prefix2 = prefix + " ";
pw.println();
pw.print(prefix2); pw.print("showing: "); pw.println(mWindow.mShowing);
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 539c001..83fe976 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1753,7 +1753,8 @@
long token = Binder.clearCallingIdentity();
try {
return LocationAccessPolicy.canAccessCellLocation(mContext,
- r.callingPackage, r.callerUid, r.callerPid);
+ r.callingPackage, r.callerUid, r.callerPid,
+ /*throwOnDeniedPermission*/ false);
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5b5b80b..e3584e6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -820,7 +820,7 @@
public boolean canShowErrorDialogs() {
return mShowDialogs && !mSleeping && !mShuttingDown
- && !mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY)
+ && !mKeyguardController.isKeyguardOrAodShowing(DEFAULT_DISPLAY)
&& !mUserController.hasUserRestriction(UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS,
mUserController.getCurrentUserId())
&& !(UserManager.isDeviceInDemoMode(mContext)
@@ -10605,8 +10605,8 @@
intent.addFlags(Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS);
}
}
- final ActivityInfo ainfo = AppGlobals.getPackageManager().getActivityInfo(comp, 0,
- UserHandle.getUserId(callingUid));
+ final ActivityInfo ainfo = AppGlobals.getPackageManager().getActivityInfo(comp,
+ STOCK_PM_FLAGS, UserHandle.getUserId(callingUid));
if (ainfo.applicationInfo.uid != callingUid) {
throw new SecurityException(
"Can't add task for another application: target uid="
@@ -13050,6 +13050,22 @@
return mSleeping;
}
+ void reportGlobalUsageEventLocked(int event) {
+ mUsageStatsService.reportEvent("android", mUserController.getCurrentUserId(), event);
+ int[] profiles = mUserController.getCurrentProfileIds();
+ if (profiles != null) {
+ for (int i = profiles.length - 1; i >= 0; i--) {
+ mUsageStatsService.reportEvent((String)null, profiles[i], event);
+ }
+ }
+ }
+
+ void reportCurWakefulnessUsageEventLocked() {
+ reportGlobalUsageEventLocked(mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE
+ ? UsageEvents.Event.SCREEN_INTERACTIVE
+ : UsageEvents.Event.SCREEN_NON_INTERACTIVE);
+ }
+
void onWakefulnessChanged(int wakefulness) {
synchronized(this) {
boolean wasAwake = mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE;
@@ -13059,6 +13075,7 @@
if (wasAwake != isAwake) {
// Also update state in a special way for running foreground services UI.
mServices.updateScreenStateLocked(isAwake);
+ reportCurWakefulnessUsageEventLocked();
mHandler.obtainMessage(DISPATCH_SCREEN_AWAKE_MSG, isAwake ? 1 : 0, 0)
.sendToTarget();
}
@@ -13206,7 +13223,8 @@
}
@Override
- public void setLockScreenShown(boolean showing, int secondaryDisplayShowing) {
+ public void setLockScreenShown(boolean keyguardShowing, boolean aodShowing,
+ int secondaryDisplayShowing) {
if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires permission "
@@ -13216,13 +13234,14 @@
synchronized(this) {
long ident = Binder.clearCallingIdentity();
try {
- mKeyguardController.setKeyguardShown(showing, secondaryDisplayShowing);
+ mKeyguardController.setKeyguardShown(keyguardShowing, aodShowing,
+ secondaryDisplayShowing);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
- mHandler.obtainMessage(DISPATCH_SCREEN_KEYGUARD_MSG, showing ? 1 : 0, 0)
+ mHandler.obtainMessage(DISPATCH_SCREEN_KEYGUARD_MSG, keyguardShowing ? 1 : 0, 0)
.sendToTarget();
}
@@ -14033,6 +14052,18 @@
}
@Override
+ public boolean isUidActive(int uid, String callingPackage) {
+ if (!hasUsageStatsPermission(callingPackage)) {
+ enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
+ "getPackageProcessState");
+ }
+ synchronized (this) {
+ final UidRecord uidRecord = mActiveUids.get(uid);
+ return uidRecord != null && !uidRecord.setIdle;
+ }
+ }
+
+ @Override
public boolean convertFromTranslucent(IBinder token) {
final long origId = Binder.clearCallingIdentity();
try {
@@ -21194,7 +21225,7 @@
ApplicationInfo aInfo = null;
try {
aInfo = AppGlobals.getPackageManager()
- .getApplicationInfo(ssp, 0 /*flags*/, userId);
+ .getApplicationInfo(ssp, STOCK_PM_FLAGS, userId);
} catch (RemoteException ignore) {}
if (aInfo == null) {
Slog.w(TAG, "Dropping ACTION_PACKAGE_REPLACED for non-existent pkg:"
@@ -21219,7 +21250,7 @@
try {
ApplicationInfo ai = AppGlobals.getPackageManager().
- getApplicationInfo(ssp, 0, 0);
+ getApplicationInfo(ssp, STOCK_PM_FLAGS, 0);
mBatteryStatsService.notePackageInstalled(ssp,
ai != null ? ai.versionCode : 0);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index ccc17a3..1af4114 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -236,7 +236,8 @@
final IApplicationToken.Stub appToken; // window manager token
AppWindowContainerController mWindowContainerController;
final ActivityInfo info; // all about me
- final ApplicationInfo appInfo; // information about activity's app
+ // TODO: This is duplicated state already contained in info.applicationInfo - remove
+ ApplicationInfo appInfo; // information about activity's app
final int launchedFromPid; // always the pid who started the activity.
final int launchedFromUid; // always the uid who started the activity.
final String launchedFromPackage; // always the package who started the activity.
@@ -605,6 +606,11 @@
}
}
+ void updateApplicationInfo(ApplicationInfo aInfo) {
+ appInfo = aInfo;
+ info.applicationInfo = aInfo;
+ }
+
private boolean crossesHorizontalSizeThreshold(int firstDp, int secondDp) {
return crossesSizeThreshold(mHorizontalSizeConfigurations, firstDp, secondDp);
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index aa462ec..00ebcbd 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1324,7 +1324,7 @@
final ActivityRecord ar = activities.get(activityNdx);
if ((userId == ar.userId) && packageName.equals(ar.packageName)) {
- ar.info.applicationInfo = aInfo;
+ ar.updateApplicationInfo(aInfo);
}
}
}
@@ -2019,8 +2019,9 @@
* @return true if {@param r} is visible taken Keyguard state into account, false otherwise
*/
boolean checkKeyguardVisibility(ActivityRecord r, boolean shouldBeVisible, boolean isTop) {
- final boolean keyguardShowing = mStackSupervisor.getKeyguardController().isKeyguardShowing(
- mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY);
+ final int displayId = mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY;
+ final boolean keyguardOrAodShowing = mStackSupervisor.getKeyguardController()
+ .isKeyguardOrAodShowing(displayId);
final boolean keyguardLocked = mStackSupervisor.getKeyguardController().isKeyguardLocked();
final boolean showWhenLocked = r.canShowWhenLocked();
final boolean dismissKeyguard = r.hasDismissKeyguardWindows();
@@ -2041,10 +2042,9 @@
return true;
}
}
- if (keyguardShowing) {
-
+ if (keyguardOrAodShowing) {
// If keyguard is showing, nothing is visible, except if we are able to dismiss Keyguard
- // right away.
+ // right away and AOD isn't visible.
return shouldBeVisible && mStackSupervisor.getKeyguardController()
.canShowActivityWhileKeyguardShowing(r, dismissKeyguard);
} else if (keyguardLocked) {
@@ -3987,7 +3987,8 @@
} else {
try {
ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
- destIntent.getComponent(), 0, srec.userId);
+ destIntent.getComponent(), ActivityManagerService.STOCK_PM_FLAGS,
+ srec.userId);
// TODO(b/64750076): Check if calling pid should really be -1.
final int res = mService.getActivityStartController()
.obtainStarter(destIntent, "navigateUpTo")
@@ -5139,8 +5140,9 @@
mService, taskId, info, intent, voiceSession, voiceInteractor);
// add the task to stack first, mTaskPositioner might need the stack association
addTask(task, toTop, "createTaskRecord");
+ final int displayId = mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY;
final boolean isLockscreenShown = mService.mStackSupervisor.getKeyguardController()
- .isKeyguardShowing(mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY);
+ .isKeyguardOrAodShowing(displayId);
if (!mStackSupervisor.getLaunchParamsController()
.layoutTask(task, info.windowLayout, activity, source, options)
&& !matchParentBounds() && task.isResizeable() && !isLockscreenShown) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 265e4fa..d5dfdcf 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -3382,8 +3382,8 @@
stack.goToSleepIfPossible(false /* shuttingDown */);
} else {
stack.awakeFromSleepingLocked();
- if (isFocusedStack(stack)
- && !getKeyguardController().isKeyguardShowing(display.mDisplayId)) {
+ if (isFocusedStack(stack) && !getKeyguardController().isKeyguardOrAodShowing(
+ display.mDisplayId)) {
// If the keyguard is unlocked - resume immediately.
// It is possible that the display will not be awake at the time we
// process the keyguard going away, which can happen before the sleep token
diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java
index 868f90d..fb78838 100644
--- a/services/core/java/com/android/server/am/ActivityStartController.java
+++ b/services/core/java/com/android/server/am/ActivityStartController.java
@@ -198,9 +198,10 @@
// See if we should be showing the platform update setup UI.
final Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
- final List<ResolveInfo> ris = mService.mContext.getPackageManager()
- .queryIntentActivities(intent,
- PackageManager.MATCH_SYSTEM_ONLY | PackageManager.GET_META_DATA);
+ final List<ResolveInfo> ris =
+ mService.mContext.getPackageManager().queryIntentActivities(intent,
+ PackageManager.MATCH_SYSTEM_ONLY | PackageManager.GET_META_DATA
+ | ActivityManagerService.STOCK_PM_FLAGS);
if (!ris.isEmpty()) {
final ResolveInfo ri = ris.get(0);
String vers = ri.activityInfo.metaData != null
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index b67dd0d..1b7f75b 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -62,6 +62,7 @@
private final ActivityStackSupervisor mStackSupervisor;
private WindowManagerService mWindowManager;
private boolean mKeyguardShowing;
+ private boolean mAodShowing;
private boolean mKeyguardGoingAway;
private boolean mOccluded;
private boolean mDismissalRequested;
@@ -82,6 +83,15 @@
}
/**
+ * @return true if either Keyguard or AOD are showing, not going away, and not being occluded
+ * on the given display, false otherwise
+ */
+ boolean isKeyguardOrAodShowing(int displayId) {
+ return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway &&
+ (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing);
+ }
+
+ /**
* @return true if Keyguard is showing, not going away, and not being occluded on the given
* display, false otherwise
*/
@@ -108,17 +118,19 @@
/**
* Update the Keyguard showing state.
*/
- void setKeyguardShown(boolean showing, int secondaryDisplayShowing) {
- boolean showingChanged = showing != mKeyguardShowing;
+ void setKeyguardShown(boolean keyguardShowing, boolean aodShowing,
+ int secondaryDisplayShowing) {
+ boolean showingChanged = keyguardShowing != mKeyguardShowing || aodShowing != mAodShowing;
if (!showingChanged && secondaryDisplayShowing == mSecondaryDisplayShowing) {
return;
}
- mKeyguardShowing = showing;
+ mKeyguardShowing = keyguardShowing;
+ mAodShowing = aodShowing;
mSecondaryDisplayShowing = secondaryDisplayShowing;
if (showingChanged) {
dismissDockedStackIfNeeded();
setKeyguardGoingAway(false);
- if (showing) {
+ if (keyguardShowing) {
mDismissalRequested = false;
}
}
@@ -230,8 +242,8 @@
// Allow to show it when we are about to dismiss Keyguard. This isn't allowed if r is
// already the dismissing activity, in which case we don't allow it to repeatedly dismiss
// Keyguard.
- return dismissKeyguard && canDismissKeyguard() &&
- (mDismissalRequested || r != mDismissingKeyguardActivity);
+ return dismissKeyguard && canDismissKeyguard() && !mAodShowing
+ && (mDismissalRequested || r != mDismissingKeyguardActivity);
}
/**
@@ -369,9 +381,9 @@
}
private void updateKeyguardSleepToken() {
- if (mSleepToken == null && isKeyguardShowing(DEFAULT_DISPLAY)) {
+ if (mSleepToken == null && isKeyguardOrAodShowing(DEFAULT_DISPLAY)) {
mSleepToken = mService.acquireSleepToken("Keyguard", DEFAULT_DISPLAY);
- } else if (mSleepToken != null && !isKeyguardShowing(DEFAULT_DISPLAY)) {
+ } else if (mSleepToken != null && !isKeyguardOrAodShowing(DEFAULT_DISPLAY)) {
mSleepToken.release();
mSleepToken = null;
}
@@ -380,6 +392,7 @@
void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "KeyguardController:");
pw.println(prefix + " mKeyguardShowing=" + mKeyguardShowing);
+ pw.println(prefix + " mAodShowing=" + mAodShowing);
pw.println(prefix + " mKeyguardGoingAway=" + mKeyguardGoingAway);
pw.println(prefix + " mOccluded=" + mOccluded);
pw.println(prefix + " mDismissingKeyguardActivity=" + mDismissingKeyguardActivity);
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index efd8153..fcf00ce 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -600,7 +600,8 @@
// activities that are fully runnable based on
// current system state.
ai = pm.getActivityInfo(task.realActivity,
- PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
+ PackageManager.MATCH_DEBUG_TRIAGED_MISSING
+ | ActivityManagerService.STOCK_PM_FLAGS, userId);
} catch (RemoteException e) {
// Will never happen.
continue;
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 0d125e0..f710690 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -47,6 +47,7 @@
import android.app.IStopUserCallback;
import android.app.IUserSwitchObserver;
import android.app.KeyguardManager;
+import android.app.usage.UsageEvents;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
@@ -959,6 +960,8 @@
mInjector.getUserManagerInternal().setUserState(userId, uss.state);
}
if (foreground) {
+ // Make sure the old user is no longer considering the display to be on.
+ mInjector.reportGlobalUsageEventLocked(UsageEvents.Event.SCREEN_NON_INTERACTIVE);
synchronized (mLock) {
mCurrentUserId = userId;
mTargetUserId = UserHandle.USER_NULL; // reset, mCurrentUserId has caught up
@@ -966,6 +969,7 @@
mInjector.updateUserConfiguration();
updateCurrentProfileIds();
mInjector.getWindowManager().setCurrentUser(userId, getCurrentProfileIds());
+ mInjector.reportCurWakefulnessUsageEvent();
// Once the internal notion of the active user has switched, we lock the device
// with the option to show the user switcher on the keyguard.
if (mUserSwitchUiEnabled) {
@@ -2183,6 +2187,18 @@
d.show();
}
+ void reportGlobalUsageEventLocked(int event) {
+ synchronized (mService) {
+ mService.reportGlobalUsageEventLocked(event);
+ }
+ }
+
+ void reportCurWakefulnessUsageEvent() {
+ synchronized (mService) {
+ mService.reportCurWakefulnessUsageEventLocked();
+ }
+ }
+
void stackSupervisorRemoveUser(int userId) {
synchronized (mService) {
mService.mStackSupervisor.removeUserLocked(userId);
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index 711d40b..4313d17 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -60,14 +60,8 @@
int[] backlightRange = resources.getIntArray(
com.android.internal.R.array.config_screenBrightnessBacklight);
- float[] minimumBrightnessCurveLux = getLuxLevels(resources.getIntArray(
- com.android.internal.R.array.config_autoBrightnessMinimumBrightnessCurveLux));
- float[] minimumBrightnessCurveNits = getFloatArray(resources.obtainTypedArray(
- com.android.internal.R.array.config_autoBrightnessMinimumBrightnessCurveNits));
-
if (isValidMapping(nitsRange, backlightRange)
- && isValidMapping(luxLevels, brightnessLevelsNits)
- && isValidMapping(minimumBrightnessCurveLux, minimumBrightnessCurveNits)) {
+ && isValidMapping(luxLevels, brightnessLevelsNits)) {
int minimumBacklight = resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessSettingMinimum);
int maximumBacklight = resources.getInteger(
@@ -79,8 +73,7 @@
}
BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
builder.setCurve(luxLevels, brightnessLevelsNits);
- return new PhysicalMappingStrategy(builder.build(), nitsRange, backlightRange,
- minimumBrightnessCurveLux, minimumBrightnessCurveNits);
+ return new PhysicalMappingStrategy(builder.build(), nitsRange, backlightRange);
} else if (isValidMapping(luxLevels, brightnessLevelsBacklight)) {
return new SimpleMappingStrategy(luxLevels, brightnessLevelsBacklight);
} else {
@@ -455,11 +448,8 @@
private float mUserLux;
private float mUserBrightness;
- private final Spline mMinimumBrightnessCurve;
-
public PhysicalMappingStrategy(BrightnessConfiguration config,
- float[] nits, int[] backlight, float[] minimumBrightnessCurveLux,
- float[] minimumBrightnessCurveNits) {
+ float[] nits, int[] backlight) {
Preconditions.checkArgument(nits.length != 0 && backlight.length != 0,
"Nits and backlight arrays must not be empty!");
Preconditions.checkArgument(nits.length == backlight.length,
@@ -479,9 +469,6 @@
normalizedBacklight[i] = normalizeAbsoluteBrightness(backlight[i]);
}
- mMinimumBrightnessCurve = Spline.createSpline(
- minimumBrightnessCurveLux, minimumBrightnessCurveNits);
-
mNitsToBacklightSpline = createSpline(nits, normalizedBacklight);
mBacklightToNitsSpline = createSpline(normalizedBacklight, nits);
@@ -497,7 +484,7 @@
if (config.equals(mConfig)) {
return false;
}
- validateBrightnessConfiguration(config);
+
Pair<float[], float[]> curve = config.getCurve();
mBrightnessSpline = createSpline(curve.first /*lux*/, curve.second /*nits*/);
mConfig = config;
@@ -562,24 +549,5 @@
pw.println(" mUserLux=" + mUserLux);
pw.println(" mUserBrightness=" + mUserBrightness);
}
-
- private void validateBrightnessConfiguration(BrightnessConfiguration config) {
- Pair<float[], float[]> curve = config.getCurve();
- Spline brightnessSpline = Spline.createSpline(curve.first, curve.second);
- if (isBrightnessSplineTooDark(brightnessSpline)) {
- throw new IllegalArgumentException("brightness curve is too dark");
- }
- }
-
- private boolean isBrightnessSplineTooDark(Spline brightnessSpline) {
- float[] lux = mDefaultConfig.getCurve().first;
- for (int i = 0; i < lux.length; i++) {
- if (brightnessSpline.interpolate(lux[i]) <
- mMinimumBrightnessCurve.interpolate(lux[i])) {
- return true;
- }
- }
- return false;
- }
}
}
diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
index 644e0a8..8be2c9e 100644
--- a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
+++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
@@ -18,10 +18,10 @@
import android.content.Context;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
+import android.hardware.biometrics.BiometricDialog;
+import android.hardware.biometrics.IBiometricDialogReceiver;
import android.hardware.fingerprint.Fingerprint;
-import android.hardware.fingerprint.FingerprintDialog;
import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.IFingerprintDialogReceiver;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.os.Bundle;
import android.os.IBinder;
@@ -46,8 +46,8 @@
public static final int LOCKOUT_PERMANENT = 2;
// Callback mechanism received from the client
- // (FingerprintDialog -> FingerprintManager -> FingerprintService -> AuthenticationClient)
- private IFingerprintDialogReceiver mDialogReceiverFromClient;
+ // (BiometricDialog -> FingerprintManager -> FingerprintService -> AuthenticationClient)
+ private IBiometricDialogReceiver mDialogReceiverFromClient;
private Bundle mBundle;
private IStatusBarService mStatusBarService;
private boolean mInLockout;
@@ -55,13 +55,13 @@
protected boolean mDialogDismissed;
// Receives events from SystemUI and handles them before forwarding them to FingerprintDialog
- protected IFingerprintDialogReceiver mDialogReceiver = new IFingerprintDialogReceiver.Stub() {
+ protected IBiometricDialogReceiver mDialogReceiver = new IBiometricDialogReceiver.Stub() {
@Override // binder call
public void onDialogDismissed(int reason) {
if (mBundle != null && mDialogReceiverFromClient != null) {
try {
mDialogReceiverFromClient.onDialogDismissed(reason);
- if (reason == FingerprintDialog.DISMISSED_REASON_USER_CANCEL) {
+ if (reason == BiometricDialog.DISMISSED_REASON_USER_CANCEL) {
onError(FingerprintManager.FINGERPRINT_ERROR_USER_CANCELED,
0 /* vendorCode */);
}
@@ -88,7 +88,7 @@
public AuthenticationClient(Context context, long halDeviceId, IBinder token,
IFingerprintServiceReceiver receiver, int targetUserId, int groupId, long opId,
boolean restricted, String owner, Bundle bundle,
- IFingerprintDialogReceiver dialogReceiver, IStatusBarService statusBarService) {
+ IBiometricDialogReceiver dialogReceiver, IStatusBarService statusBarService) {
super(context, halDeviceId, token, receiver, targetUserId, groupId, restricted, owner);
mOpId = opId;
mBundle = bundle;
@@ -299,7 +299,7 @@
// If the user already cancelled authentication (via some interaction with the
// dialog, we do not need to hide it since it's already hidden.
// If the device is in lockout, don't hide the dialog - it will automatically hide
- // after FingerprintDialog.HIDE_DIALOG_DELAY
+ // after BiometricDialog.HIDE_DIALOG_DELAY
if (mBundle != null && !mDialogDismissed && !mInLockout) {
try {
mStatusBarService.hideFingerprintDialog();
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index fc8aace..530b6f6 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -19,6 +19,7 @@
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.MANAGE_FINGERPRINT;
import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
+import static android.Manifest.permission.USE_BIOMETRIC;
import static android.Manifest.permission.USE_FINGERPRINT;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
@@ -37,12 +38,12 @@
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.hardware.biometrics.IBiometricDialogReceiver;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprintClientCallback;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.IFingerprintClientActiveCallback;
-import android.hardware.fingerprint.IFingerprintDialogReceiver;
import android.hardware.fingerprint.IFingerprintService;
import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
@@ -778,7 +779,11 @@
*/
private boolean canUseFingerprint(String opPackageName, boolean requireForeground, int uid,
int pid, int userId) {
- checkPermission(USE_FINGERPRINT);
+ if (getContext().checkCallingPermission(USE_FINGERPRINT)
+ != PackageManager.PERMISSION_GRANTED) {
+ checkPermission(USE_BIOMETRIC);
+ }
+
if (isKeyguard(opPackageName)) {
return true; // Keyguard is always allowed
}
@@ -845,7 +850,7 @@
private void startAuthentication(IBinder token, long opId, int callingUserId, int groupId,
IFingerprintServiceReceiver receiver, int flags, boolean restricted,
- String opPackageName, Bundle bundle, IFingerprintDialogReceiver dialogReceiver) {
+ String opPackageName, Bundle bundle, IBiometricDialogReceiver dialogReceiver) {
updateActiveGroup(groupId, opPackageName);
if (DEBUG) Slog.v(TAG, "startAuthentication(" + opPackageName + ")");
@@ -1156,7 +1161,7 @@
public void authenticate(final IBinder token, final long opId, final int groupId,
final IFingerprintServiceReceiver receiver, final int flags,
final String opPackageName, final Bundle bundle,
- final IFingerprintDialogReceiver dialogReceiver) {
+ final IBiometricDialogReceiver dialogReceiver) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final int callingUserId = UserHandle.getCallingUserId();
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
index a87adbd..050c1f4 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
@@ -19,10 +19,12 @@
import static android.security.keystore.recovery.KeyChainProtectionParams.TYPE_LOCKSCREEN;
import android.annotation.Nullable;
+import android.annotation.NonNull;
import android.content.Context;
-import android.security.keystore.recovery.KeyDerivationParams;
import android.security.keystore.recovery.KeyChainProtectionParams;
import android.security.keystore.recovery.KeyChainSnapshot;
+import android.security.keystore.recovery.KeyDerivationParams;
+import android.security.keystore.recovery.TrustedRootCertificates;
import android.security.keystore.recovery.WrappedApplicationKey;
import android.util.Log;
@@ -185,8 +187,12 @@
}
PublicKey publicKey;
+ String rootCertAlias =
+ mRecoverableKeyStoreDb.getActiveRootOfTrust(mUserId, recoveryAgentUid);
+
+ rootCertAlias = replaceEmptyValueWithSecureDefault(rootCertAlias);
CertPath certPath = mRecoverableKeyStoreDb.getRecoveryServiceCertPath(mUserId,
- recoveryAgentUid);
+ recoveryAgentUid, rootCertAlias);
if (certPath != null) {
Log.d(TAG, "Using the public key in stored CertPath for syncing");
publicKey = certPath.getCertificates().get(0).getPublicKey();
@@ -206,6 +212,14 @@
return;
}
+ // The only place in this class which uses credential value
+ if (!TrustedRootCertificates.GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS.equals(
+ rootCertAlias)) {
+ // TODO: allow only whitelisted LSKF usage
+ Log.w(TAG, "Untrusted root certificate is used by recovery agent "
+ + recoveryAgentUid);
+ }
+
byte[] salt = generateSalt();
byte[] localLskfHash = hashCredentials(salt, mCredential);
@@ -225,6 +239,8 @@
return;
}
+ // TODO: filter raw keys based on the root of trust.
+ // It is the only place in the class where raw key material is used.
SecretKey recoveryKey;
try {
recoveryKey = generateRecoveryKey();
@@ -451,4 +467,14 @@
}
return keyEntries;
}
+
+ private @NonNull String replaceEmptyValueWithSecureDefault(
+ @Nullable String rootCertificateAlias) {
+ if (rootCertificateAlias == null || rootCertificateAlias.isEmpty()) {
+ Log.e(TAG, "rootCertificateAlias is null or empty");
+ // Use the default Google Key Vault Service CA certificate if the alias is not provided
+ rootCertificateAlias = TrustedRootCertificates.GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS;
+ }
+ return rootCertificateAlias;
+ }
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index 6d2bec8..30125f8 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -176,6 +176,20 @@
checkRecoverKeyStorePermission();
int userId = UserHandle.getCallingUserId();
int uid = Binder.getCallingUid();
+ rootCertificateAlias = replaceEmptyValueWithSecureDefault(rootCertificateAlias);
+
+ // Always set active alias to the argument of the last call to initRecoveryService method,
+ // even if cert file is incorrect.
+ String activeRootAlias = mDatabase.getActiveRootOfTrust(userId, uid);
+ if (activeRootAlias == null) {
+ Log.d(TAG, "Root of trust for recovery agent + " + uid
+ + " is assigned for the first time to " + rootCertificateAlias);
+ mDatabase.setActiveRootOfTrust(userId, uid, rootCertificateAlias);
+ } else if (!activeRootAlias.equals(rootCertificateAlias)) {
+ Log.i(TAG, "Root of trust for recovery agent " + uid + " is changed to "
+ + rootCertificateAlias + " from " + activeRootAlias);
+ mDatabase.setActiveRootOfTrust(userId, uid, rootCertificateAlias);
+ }
CertXml certXml;
try {
@@ -194,7 +208,7 @@
// Check serial number
long newSerial = certXml.getSerial();
- Long oldSerial = mDatabase.getRecoveryServiceCertSerial(userId, uid);
+ Long oldSerial = mDatabase.getRecoveryServiceCertSerial(userId, uid, rootCertificateAlias);
if (oldSerial != null && oldSerial >= newSerial) {
if (oldSerial == newSerial) {
Log.i(TAG, "The cert file serial number is the same, so skip updating.");
@@ -217,13 +231,16 @@
ERROR_INVALID_CERTIFICATE, "Failed to validate certificate.");
}
- boolean wasInitialized = mDatabase.getRecoveryServiceCertPath(userId, uid) != null;
+ boolean wasInitialized = mDatabase.getRecoveryServiceCertPath(userId, uid,
+ rootCertificateAlias) != null;
// Save the chosen and validated certificate into database
try {
Log.d(TAG, "Saving the randomly chosen endpoint certificate to database");
- if (mDatabase.setRecoveryServiceCertPath(userId, uid, certPath) > 0) {
- mDatabase.setRecoveryServiceCertSerial(userId, uid, newSerial);
+ if (mDatabase.setRecoveryServiceCertPath(userId, uid, rootCertificateAlias,
+ certPath) > 0) {
+ mDatabase.setRecoveryServiceCertSerial(userId, uid, rootCertificateAlias,
+ newSerial);
if (wasInitialized) {
Log.i(TAG, "This is a certificate change. Snapshot pending.");
mDatabase.setShouldCreateSnapshot(userId, uid, true);
@@ -253,9 +270,7 @@
@NonNull byte[] recoveryServiceSigFile)
throws RemoteException {
checkRecoverKeyStorePermission();
- if (rootCertificateAlias == null) {
- Log.e(TAG, "rootCertificateAlias is null");
- }
+ rootCertificateAlias = replaceEmptyValueWithSecureDefault(rootCertificateAlias);
Preconditions.checkNotNull(recoveryServiceCertFile, "recoveryServiceCertFile is null");
Preconditions.checkNotNull(recoveryServiceSigFile, "recoveryServiceSigFile is null");
@@ -509,9 +524,7 @@
@NonNull List<KeyChainProtectionParams> secrets)
throws RemoteException {
checkRecoverKeyStorePermission();
- if (rootCertificateAlias == null) {
- Log.e(TAG, "rootCertificateAlias is null");
- }
+ rootCertificateAlias = replaceEmptyValueWithSecureDefault(rootCertificateAlias);
Preconditions.checkNotNull(sessionId, "invalid session");
Preconditions.checkNotNull(verifierCertPath, "verifierCertPath is null");
Preconditions.checkNotNull(vaultParams, "vaultParams is null");
@@ -953,11 +966,7 @@
}
private X509Certificate getRootCertificate(String rootCertificateAlias) throws RemoteException {
- if (rootCertificateAlias == null || rootCertificateAlias.isEmpty()) {
- // Use the default Google Key Vault Service CA certificate if the alias is not provided
- rootCertificateAlias = TrustedRootCertificates.GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS;
- }
-
+ rootCertificateAlias = replaceEmptyValueWithSecureDefault(rootCertificateAlias);
X509Certificate rootCertificate =
TrustedRootCertificates.getRootCertificate(rootCertificateAlias);
if (rootCertificate == null) {
@@ -967,6 +976,16 @@
return rootCertificate;
}
+ private @NonNull String replaceEmptyValueWithSecureDefault(
+ @Nullable String rootCertificateAlias) {
+ if (rootCertificateAlias == null || rootCertificateAlias.isEmpty()) {
+ Log.e(TAG, "rootCertificateAlias is null or empty");
+ // Use the default Google Key Vault Service CA certificate if the alias is not provided
+ rootCertificateAlias = TrustedRootCertificates.GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS;
+ }
+ return rootCertificateAlias;
+ }
+
private void checkRecoverKeyStorePermission() {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.RECOVER_KEYSTORE,
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
index 2676ee8..38834ac 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
@@ -29,6 +29,7 @@
import com.android.server.locksettings.recoverablekeystore.WrappedKey;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.KeysEntry;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RecoveryServiceMetadataEntry;
+import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RootOfTrustEntry;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.UserMetadataEntry;
import java.io.ByteArrayInputStream;
@@ -385,13 +386,15 @@
*
* @param userId The userId of the profile the application is running under.
* @param uid The uid of the application who initializes the local recovery components.
+ * @param rootAlias The root of trust alias.
* @return The value that were previously set, or null if there's none.
*
* @hide
*/
@Nullable
- public Long getRecoveryServiceCertSerial(int userId, int uid) {
- return getLong(userId, uid, RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL);
+ public Long getRecoveryServiceCertSerial(int userId, int uid, @NonNull String rootAlias) {
+ return getLong(userId, uid, rootAlias,
+ RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL);
}
/**
@@ -399,13 +402,16 @@
*
* @param userId The userId of the profile the application is running under.
* @param uid The uid of the application who initializes the local recovery components.
+ * @param rootAlias The root of trust alias.
* @param serial The serial number contained in the XML file for recovery service certificates.
* @return The primary key of the inserted row, or -1 if failed.
*
* @hide
*/
- public long setRecoveryServiceCertSerial(int userId, int uid, long serial) {
- return setLong(userId, uid, RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL, serial);
+ public long setRecoveryServiceCertSerial(int userId, int uid, @NonNull String rootAlias,
+ long serial) {
+ return setLong(userId, uid, rootAlias, RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL,
+ serial);
}
/**
@@ -413,13 +419,15 @@
*
* @param userId The userId of the profile the application is running under.
* @param uid The uid of the application who initializes the local recovery components.
+ * @param rootAlias The root of trust alias.
* @return The value that were previously set, or null if there's none.
*
* @hide
*/
@Nullable
- public CertPath getRecoveryServiceCertPath(int userId, int uid) {
- byte[] bytes = getBytes(userId, uid, RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH);
+ public CertPath getRecoveryServiceCertPath(int userId, int uid, @NonNull String rootAlias) {
+ byte[] bytes = getBytes(userId, uid, rootAlias,
+ RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH);
if (bytes == null) {
return null;
}
@@ -440,16 +448,17 @@
*
* @param userId The userId of the profile the application is running under.
* @param uid The uid of the application who initializes the local recovery components.
+ * @param rootAlias The root of trust alias.
* @param certPath The certificate path of the recovery service.
* @return The primary key of the inserted row, or -1 if failed.
* @hide
*/
- public long setRecoveryServiceCertPath(int userId, int uid, CertPath certPath) throws
- CertificateEncodingException {
+ public long setRecoveryServiceCertPath(int userId, int uid, @NonNull String rootAlias,
+ CertPath certPath) throws CertificateEncodingException {
if (certPath.getCertificates().size() == 0) {
throw new CertificateEncodingException("No certificate contained in the cert path.");
}
- return setBytes(userId, uid, RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH,
+ return setBytes(userId, uid, rootAlias, RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH,
certPath.getEncoded(CERT_PATH_ENCODING));
}
@@ -608,6 +617,85 @@
}
/**
+ * Active root of trust for the recovery agent.
+ *
+ * @param userId The userId of the profile the application is running under.
+ * @param uid The uid of the application.
+ * @param rootAlias The root of trust alias.
+ * @return The primary key of the updated row, or -1 if failed.
+ *
+ * @hide
+ */
+ public long setActiveRootOfTrust(int userId, int uid, @Nullable String rootAlias) {
+ SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_ACTIVE_ROOT_OF_TRUST, rootAlias);
+ String selection =
+ RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID + " = ? AND "
+ + RecoveryServiceMetadataEntry.COLUMN_NAME_UID + " = ?";
+ ensureRecoveryServiceMetadataEntryExists(userId, uid);
+ return db.update(RecoveryServiceMetadataEntry.TABLE_NAME, values,
+ selection, new String[] {String.valueOf(userId), String.valueOf(uid)});
+ }
+
+ /**
+ * Active root of trust for the recovery agent.
+ *
+ * @param userId The userId of the profile the application is running under.
+ * @param uid The uid of the application who initialized the local recovery components.
+ * @return Active root of trust alias of null if it was not set
+ *
+ * @hide
+ */
+ public @Nullable String getActiveRootOfTrust(int userId, int uid) {
+ SQLiteDatabase db = mKeyStoreDbHelper.getReadableDatabase();
+
+ String[] projection = {
+ RecoveryServiceMetadataEntry._ID,
+ RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID,
+ RecoveryServiceMetadataEntry.COLUMN_NAME_UID,
+ RecoveryServiceMetadataEntry.COLUMN_NAME_ACTIVE_ROOT_OF_TRUST};
+ String selection =
+ RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID + " = ? AND "
+ + RecoveryServiceMetadataEntry.COLUMN_NAME_UID + " = ?";
+ String[] selectionArguments = {Integer.toString(userId), Integer.toString(uid)};
+
+ try (
+ Cursor cursor = db.query(
+ RecoveryServiceMetadataEntry.TABLE_NAME,
+ projection,
+ selection,
+ selectionArguments,
+ /*groupBy=*/ null,
+ /*having=*/ null,
+ /*orderBy=*/ null)
+ ) {
+ int count = cursor.getCount();
+ if (count == 0) {
+ return null;
+ }
+ if (count > 1) {
+ Log.wtf(TAG,
+ String.format(Locale.US,
+ "%d deviceId entries found for userId=%d uid=%d. "
+ + "Should only ever be 0 or 1.", count, userId, uid));
+ return null;
+ }
+ cursor.moveToFirst();
+ int idx = cursor.getColumnIndexOrThrow(
+ RecoveryServiceMetadataEntry.COLUMN_NAME_ACTIVE_ROOT_OF_TRUST);
+ if (cursor.isNull(idx)) {
+ return null;
+ }
+ String result = cursor.getString(idx);
+ if (TextUtils.isEmpty(result)) {
+ return null;
+ }
+ return result;
+ }
+ }
+
+ /**
* Updates the counterId
*
* @param userId The userId of the profile the application is running under.
@@ -874,7 +962,6 @@
*
* @hide
*/
-
private long setBytes(int userId, int uid, String key, byte[] value) {
SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
@@ -890,6 +977,176 @@
}
/**
+ * Returns given binary value from the database.
+ *
+ * @param userId The userId of the profile the application is running under.
+ * @param uid The uid of the application who initialized the local recovery components.
+ * @param rootAlias The root of trust alias.
+ * @param key from {@code RootOfTrustEntry}
+ * @return The value that were previously set, or null if there's none.
+ *
+ * @hide
+ */
+ private byte[] getBytes(int userId, int uid, String rootAlias, String key) {
+ SQLiteDatabase db = mKeyStoreDbHelper.getReadableDatabase();
+
+ String[] projection = {
+ RootOfTrustEntry._ID,
+ RootOfTrustEntry.COLUMN_NAME_USER_ID,
+ RootOfTrustEntry.COLUMN_NAME_UID,
+ RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS,
+ key};
+ String selection =
+ RootOfTrustEntry.COLUMN_NAME_USER_ID + " = ? AND "
+ + RootOfTrustEntry.COLUMN_NAME_UID + " = ? AND "
+ + RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS + " = ?";
+ String[] selectionArguments = {Integer.toString(userId), Integer.toString(uid), rootAlias};
+
+ try (
+ Cursor cursor = db.query(
+ RootOfTrustEntry.TABLE_NAME,
+ projection,
+ selection,
+ selectionArguments,
+ /*groupBy=*/ null,
+ /*having=*/ null,
+ /*orderBy=*/ null)
+ ) {
+ int count = cursor.getCount();
+ if (count == 0) {
+ return null;
+ }
+ if (count > 1) {
+ Log.wtf(TAG,
+ String.format(Locale.US,
+ "%d entries found for userId=%d uid=%d. "
+ + "Should only ever be 0 or 1.", count, userId, uid));
+ return null;
+ }
+ cursor.moveToFirst();
+ int idx = cursor.getColumnIndexOrThrow(key);
+ if (cursor.isNull(idx)) {
+ return null;
+ } else {
+ return cursor.getBlob(idx);
+ }
+ }
+ }
+
+ /**
+ * Sets a binary value in the database.
+ *
+ * @param userId The userId of the profile the application is running under.
+ * @param uid The uid of the application who initialized the local recovery components.
+ * @param rootAlias The root of trust alias.
+ * @param key defined in {@code RootOfTrustEntry}
+ * @param value new value.
+ * @return The primary key of the inserted row, or -1 if failed.
+ *
+ * @hide
+ */
+ private long setBytes(int userId, int uid, String rootAlias, String key, byte[] value) {
+ SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(key, value);
+ String selection =
+ RootOfTrustEntry.COLUMN_NAME_USER_ID + " = ? AND "
+ + RootOfTrustEntry.COLUMN_NAME_UID + " = ? AND "
+ + RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS + " = ?";
+ String[] selectionArguments = {Integer.toString(userId), Integer.toString(uid), rootAlias};
+
+ ensureRootOfTrustEntryExists(userId, uid, rootAlias);
+ return db.update(
+ RootOfTrustEntry.TABLE_NAME, values, selection, selectionArguments);
+ }
+
+ /**
+ * Returns given long value from the database.
+ *
+ * @param userId The userId of the profile the application is running under.
+ * @param uid The uid of the application who initialized the local recovery components.
+ * @param rootAlias The root of trust alias.
+ * @param key from {@code RootOfTrustEntry}
+ * @return The value that were previously set, or null if there's none.
+ *
+ * @hide
+ */
+ private Long getLong(int userId, int uid, String rootAlias, String key) {
+ SQLiteDatabase db = mKeyStoreDbHelper.getReadableDatabase();
+
+ String[] projection = {
+ RootOfTrustEntry._ID,
+ RootOfTrustEntry.COLUMN_NAME_USER_ID,
+ RootOfTrustEntry.COLUMN_NAME_UID,
+ RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS,
+ key};
+ String selection =
+ RootOfTrustEntry.COLUMN_NAME_USER_ID + " = ? AND "
+ + RootOfTrustEntry.COLUMN_NAME_UID + " = ? AND "
+ + RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS + " = ?";
+ String[] selectionArguments = {Integer.toString(userId), Integer.toString(uid), rootAlias};
+
+ try (
+ Cursor cursor = db.query(
+ RootOfTrustEntry.TABLE_NAME,
+ projection,
+ selection,
+ selectionArguments,
+ /*groupBy=*/ null,
+ /*having=*/ null,
+ /*orderBy=*/ null)
+ ) {
+ int count = cursor.getCount();
+ if (count == 0) {
+ return null;
+ }
+ if (count > 1) {
+ Log.wtf(TAG,
+ String.format(Locale.US,
+ "%d entries found for userId=%d uid=%d. "
+ + "Should only ever be 0 or 1.", count, userId, uid));
+ return null;
+ }
+ cursor.moveToFirst();
+ int idx = cursor.getColumnIndexOrThrow(key);
+ if (cursor.isNull(idx)) {
+ return null;
+ } else {
+ return cursor.getLong(idx);
+ }
+ }
+ }
+
+ /**
+ * Sets a long value in the database.
+ *
+ * @param userId The userId of the profile the application is running under.
+ * @param uid The uid of the application who initialized the local recovery components.
+ * @param rootAlias The root of trust alias.
+ * @param key defined in {@code RootOfTrustEntry}
+ * @param value new value.
+ * @return The primary key of the inserted row, or -1 if failed.
+ *
+ * @hide
+ */
+
+ private long setLong(int userId, int uid, String rootAlias, String key, long value) {
+ SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(key, value);
+ String selection =
+ RootOfTrustEntry.COLUMN_NAME_USER_ID + " = ? AND "
+ + RootOfTrustEntry.COLUMN_NAME_UID + " = ? AND "
+ + RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS + " = ?";
+ String[] selectionArguments = {Integer.toString(userId), Integer.toString(uid), rootAlias};
+
+ ensureRootOfTrustEntryExists(userId, uid, rootAlias);
+ return db.update(
+ RootOfTrustEntry.TABLE_NAME, values, selection, selectionArguments);
+ }
+
+
+ /**
* Creates an empty row in the recovery service metadata table if such a row doesn't exist for
* the given userId and uid, so db.update will succeed.
*/
@@ -903,6 +1160,20 @@
}
/**
+ * Creates an empty row in the root of trust table if such a row doesn't exist for
+ * the given userId and uid, so db.update will succeed.
+ */
+ private void ensureRootOfTrustEntryExists(int userId, int uid, String rootAlias) {
+ SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(RootOfTrustEntry.COLUMN_NAME_USER_ID, userId);
+ values.put(RootOfTrustEntry.COLUMN_NAME_UID, uid);
+ values.put(RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS, rootAlias);
+ db.insertWithOnConflict(RootOfTrustEntry.TABLE_NAME, /*nullColumnHack=*/ null,
+ values, SQLiteDatabase.CONFLICT_IGNORE);
+ }
+
+ /**
* Closes all open connections to the database.
*/
public void close() {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
index 2c3d3ab..1eff2d4 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
@@ -230,16 +230,19 @@
/**
* The public key of the recovery service.
+ * Deprecated.
*/
static final String COLUMN_NAME_PUBLIC_KEY = "public_key";
/**
* The certificate path of the recovery service.
+ * Deprecated.
*/
static final String COLUMN_NAME_CERT_PATH = "cert_path";
/**
* The serial number contained in the certificate XML file of the recovery service.
+ * Deprecated.
*/
static final String COLUMN_NAME_CERT_SERIAL = "cert_serial";
@@ -257,5 +260,42 @@
* The server parameters of the recovery service.
*/
static final String COLUMN_NAME_SERVER_PARAMS = "server_params";
+
+ /**
+ * Active root of trust
+ */
+ static final String COLUMN_NAME_ACTIVE_ROOT_OF_TRUST = "active_root_of_trust";
+ }
+
+ /**
+ * Table data for given recovery agent and root of trust pair.
+ */
+ static class RootOfTrustEntry implements BaseColumns {
+ static final String TABLE_NAME = "root_of_trust";
+
+ /**
+ * The user id of the profile the application is running under.
+ */
+ static final String COLUMN_NAME_USER_ID = "user_id";
+
+ /**
+ * The uid of the application that initializes the local recovery components.
+ */
+ static final String COLUMN_NAME_UID = "uid";
+
+ /**
+ * Root of trust alias
+ */
+ static final String COLUMN_NAME_ROOT_ALIAS = "root_alias";
+
+ /**
+ * The certificate path of the recovery service.
+ */
+ static final String COLUMN_NAME_CERT_PATH = "cert_path";
+
+ /**
+ * The serial number contained in the certificate XML file of the recovery service.
+ */
+ static final String COLUMN_NAME_CERT_SERIAL = "cert_serial";
}
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java
index 8a89f2d..43efe9c 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java
@@ -23,6 +23,7 @@
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.KeysEntry;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RecoveryServiceMetadataEntry;
+import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RootOfTrustEntry;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.UserMetadataEntry;
/**
@@ -31,7 +32,7 @@
class RecoverableKeyStoreDbHelper extends SQLiteOpenHelper {
private static final String TAG = "RecoverableKeyStoreDbHp";
- static final int DATABASE_VERSION = 3;
+ static final int DATABASE_VERSION = 4;
private static final String DATABASE_NAME = "recoverablekeystore.db";
private static final String SQL_CREATE_KEYS_ENTRY =
@@ -61,6 +62,7 @@
+ RecoveryServiceMetadataEntry.COLUMN_NAME_UID + " INTEGER,"
+ RecoveryServiceMetadataEntry.COLUMN_NAME_SNAPSHOT_VERSION + " INTEGER,"
+ RecoveryServiceMetadataEntry.COLUMN_NAME_SHOULD_CREATE_SNAPSHOT + " INTEGER,"
+ + RecoveryServiceMetadataEntry.COLUMN_NAME_ACTIVE_ROOT_OF_TRUST + " TEXT,"
+ RecoveryServiceMetadataEntry.COLUMN_NAME_PUBLIC_KEY + " BLOB,"
+ RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH + " BLOB,"
+ RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL + " INTEGER,"
@@ -71,6 +73,19 @@
+ RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID + ","
+ RecoveryServiceMetadataEntry.COLUMN_NAME_UID + "))";
+ private static final String SQL_CREATE_ROOT_OF_TRUST_ENTRY =
+ "CREATE TABLE " + RootOfTrustEntry.TABLE_NAME + " ("
+ + RootOfTrustEntry._ID + " INTEGER PRIMARY KEY,"
+ + RootOfTrustEntry.COLUMN_NAME_USER_ID + " INTEGER,"
+ + RootOfTrustEntry.COLUMN_NAME_UID + " INTEGER,"
+ + RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS + " TEST,"
+ + RootOfTrustEntry.COLUMN_NAME_CERT_PATH + " BLOB,"
+ + RootOfTrustEntry.COLUMN_NAME_CERT_SERIAL + " INTEGER,"
+ + "UNIQUE("
+ + RootOfTrustEntry.COLUMN_NAME_USER_ID + ","
+ + RootOfTrustEntry.COLUMN_NAME_UID + ","
+ + RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS + "))";
+
private static final String SQL_DELETE_KEYS_ENTRY =
"DROP TABLE IF EXISTS " + KeysEntry.TABLE_NAME;
@@ -80,6 +95,9 @@
private static final String SQL_DELETE_RECOVERY_SERVICE_METADATA_ENTRY =
"DROP TABLE IF EXISTS " + RecoveryServiceMetadataEntry.TABLE_NAME;
+ private static final String SQL_DELETE_ROOT_OF_TRUST_ENTRY =
+ "DROP TABLE IF EXISTS " + RootOfTrustEntry.TABLE_NAME;
+
RecoverableKeyStoreDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@@ -89,21 +107,44 @@
db.execSQL(SQL_CREATE_KEYS_ENTRY);
db.execSQL(SQL_CREATE_USER_METADATA_ENTRY);
db.execSQL(SQL_CREATE_RECOVERY_SERVICE_METADATA_ENTRY);
+ db.execSQL(SQL_CREATE_ROOT_OF_TRUST_ENTRY);
+ }
+
+ @Override
+ public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ Log.e(TAG, "Recreating recoverablekeystore after unexpected version downgrade.");
+ dropAllKnownTables(db); // Wipe database.
+ onCreate(db);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < 2) {
- db.execSQL(SQL_DELETE_KEYS_ENTRY);
- db.execSQL(SQL_DELETE_USER_METADATA_ENTRY);
- db.execSQL(SQL_DELETE_RECOVERY_SERVICE_METADATA_ENTRY);
+ dropAllKnownTables(db); // Wipe database.
onCreate(db);
return;
}
- if (oldVersion < 3) {
+ if (oldVersion < 3 && newVersion >= 3) {
upgradeDbForVersion3(db);
+ oldVersion = 3;
}
+
+ if (oldVersion < 4 && newVersion >= 4) {
+ upgradeDbForVersion4(db);
+ oldVersion = 4;
+ }
+
+ if (oldVersion != newVersion) {
+ Log.e(TAG, "Failed to update recoverablekeystore database to the most recent version");
+ }
+ }
+
+ private void dropAllKnownTables(SQLiteDatabase db) {
+ db.execSQL(SQL_DELETE_KEYS_ENTRY);
+ db.execSQL(SQL_DELETE_USER_METADATA_ENTRY);
+ db.execSQL(SQL_DELETE_RECOVERY_SERVICE_METADATA_ENTRY);
+ db.execSQL(SQL_DELETE_ROOT_OF_TRUST_ENTRY);
}
private void upgradeDbForVersion3(SQLiteDatabase db) {
@@ -115,6 +156,16 @@
null);
}
+ private void upgradeDbForVersion4(SQLiteDatabase db) {
+ Log.d(TAG, "Updating recoverable keystore database to version 4");
+ // Add new table with two columns for cert path and cert serial number.
+ db.execSQL(SQL_CREATE_ROOT_OF_TRUST_ENTRY);
+ // adds column to store root of trust currently used by the recovery agent
+ addColumnToTable(db, RecoveryServiceMetadataEntry.TABLE_NAME,
+ RecoveryServiceMetadataEntry.COLUMN_NAME_ACTIVE_ROOT_OF_TRUST, "TEXT",
+ /*defaultStr=*/ null);
+ }
+
private static void addColumnToTable(
SQLiteDatabase db, String tableName, String column, String columnType,
String defaultStr) {
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 01f0d74..0eb906d 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -101,6 +101,7 @@
*/
public class MediaSessionService extends SystemService implements Monitor {
private static final String TAG = "MediaSessionService";
+ static final boolean USE_MEDIA2_APIS = false; // TODO: Change this to true when we're ready.
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
// Leave log for key event always.
private static final boolean DEBUG_KEY_EVENT = true;
@@ -508,6 +509,9 @@
}
private void buildMediaSessionService2List() {
+ if (!USE_MEDIA2_APIS) {
+ return;
+ }
if (DEBUG) {
Log.d(TAG, "buildMediaSessionService2List");
}
@@ -1531,6 +1535,9 @@
*/
@Override
public boolean createSession2(Bundle sessionToken) {
+ if (!USE_MEDIA2_APIS) {
+ return false;
+ }
final int uid = Binder.getCallingUid();
final SessionToken2 token = SessionToken2.fromBundle(sessionToken);
if (token == null || token.getUid() != uid) {
@@ -1570,6 +1577,9 @@
*/
@Override
public void destroySession2(Bundle sessionToken) {
+ if (!USE_MEDIA2_APIS) {
+ return;
+ }
final int uid = Binder.getCallingUid();
final SessionToken2 token = SessionToken2.fromBundle(sessionToken);
if (token == null || token.getUid() != uid) {
@@ -1586,6 +1596,9 @@
@Override
public List<Bundle> getSessionTokens(boolean activeSessionOnly,
boolean sessionServiceOnly, String packageName) throws RemoteException {
+ if (!USE_MEDIA2_APIS) {
+ return null;
+ }
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
@@ -1614,6 +1627,9 @@
@Override
public void addSessionTokensListener(ISessionTokensListener listener, int userId,
String packageName) throws RemoteException {
+ if (!USE_MEDIA2_APIS) {
+ return;
+ }
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
@@ -1637,6 +1653,9 @@
@Override
public void removeSessionTokensListener(ISessionTokensListener listener,
String packageName) throws RemoteException {
+ if (!USE_MEDIA2_APIS) {
+ return;
+ }
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 59cd561..210857e 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -5969,6 +5969,7 @@
}
private boolean isPackageSuspendedForUser(String pkg, int uid) {
+ final long identity = Binder.clearCallingIdentity();
int userId = UserHandle.getUserId(uid);
try {
return mPackageManager.isPackageSuspendedForUser(pkg, userId);
@@ -5977,6 +5978,8 @@
} catch (IllegalArgumentException ex) {
// Package not found.
return false;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index e315bc5..0774672 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -472,10 +472,17 @@
if (params.getJobId() == JOB_POST_BOOT_UPDATE) {
mAbortPostBootUpdate.set(true);
+
+ // Do not reschedule.
+ // TODO: We should reschedule if we didn't process all apps, yet.
+ return false;
} else {
mAbortIdleOptimization.set(true);
+
+ // Reschedule the run.
+ // TODO: Should this be dependent on the stop reason?
+ return true;
}
- return false;
}
private void notifyPinService(ArraySet<String> updatedPackages) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 5a63f29..775fdaa 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -92,6 +92,7 @@
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
+import static com.android.internal.util.ArrayUtils.appendElement;
import static com.android.internal.util.ArrayUtils.appendInt;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
@@ -778,8 +779,14 @@
return PackageManagerService.this.hasSystemFeature(feature, 0);
}
- final List<PackageParser.Package> getStaticOverlayPackagesLocked(
+ final List<PackageParser.Package> getStaticOverlayPackages(
Collection<PackageParser.Package> allPackages, String targetPackageName) {
+ if ("android".equals(targetPackageName)) {
+ // Static RROs targeting to "android", ie framework-res.apk, are already applied by
+ // native AssetManager.
+ return null;
+ }
+
List<PackageParser.Package> overlayPackages = null;
for (PackageParser.Package p : allPackages) {
if (targetPackageName.equals(p.mOverlayTarget) && p.mOverlayIsStatic) {
@@ -800,16 +807,8 @@
return overlayPackages;
}
- @GuardedBy("mInstallLock")
- final String[] getStaticOverlayPathsLocked(Collection<PackageParser.Package> allPackages,
- String targetPackageName, String targetPath) {
- if ("android".equals(targetPackageName)) {
- // Static RROs targeting to "android", ie framework-res.apk, are already applied by
- // native AssetManager.
- return null;
- }
- List<PackageParser.Package> overlayPackages =
- getStaticOverlayPackagesLocked(allPackages, targetPackageName);
+ final String[] getStaticOverlayPaths(List<PackageParser.Package> overlayPackages,
+ String targetPath) {
if (overlayPackages == null || overlayPackages.isEmpty()) {
return null;
}
@@ -829,9 +828,11 @@
//
// OverlayManagerService will update each of them with a correct gid from its
// target package app id.
- mInstaller.idmap(targetPath, overlayPackage.baseCodePath,
- UserHandle.getSharedAppGid(
- UserHandle.getUserGid(UserHandle.USER_SYSTEM)));
+ synchronized (mInstallLock) {
+ mInstaller.idmap(targetPath, overlayPackage.baseCodePath,
+ UserHandle.getSharedAppGid(
+ UserHandle.getUserGid(UserHandle.USER_SYSTEM)));
+ }
if (overlayPathList == null) {
overlayPathList = new ArrayList<String>();
}
@@ -845,10 +846,14 @@
}
String[] getStaticOverlayPaths(String targetPackageName, String targetPath) {
+ List<PackageParser.Package> overlayPackages;
synchronized (mPackages) {
- return getStaticOverlayPathsLocked(
- mPackages.values(), targetPackageName, targetPath);
+ overlayPackages = getStaticOverlayPackages(
+ mPackages.values(), targetPackageName);
}
+ // It is safe to keep overlayPackages without holding mPackages because static overlay
+ // packages can't be uninstalled or disabled.
+ return getStaticOverlayPaths(overlayPackages, targetPath);
}
@Override public final String[] getOverlayApks(String targetPackageName) {
@@ -883,7 +888,9 @@
// can't happen while running parallel parsing.
// Moreover holding mPackages on each parsing thread causes dead-lock.
return mOverlayPackages == null ? null :
- getStaticOverlayPathsLocked(mOverlayPackages, targetPackageName, targetPath);
+ getStaticOverlayPaths(
+ getStaticOverlayPackages(mOverlayPackages, targetPackageName),
+ targetPath);
}
}
@@ -13987,18 +13994,15 @@
return packageNames;
}
- // List of package names for whom the suspended state has changed.
- final List<String> changedPackages = new ArrayList<>(packageNames.length);
- // List of package names for whom the suspended state is not set as requested in this
- // method.
+ final List<String> changedPackagesList = new ArrayList<>(packageNames.length);
final List<String> unactionedPackages = new ArrayList<>(packageNames.length);
final long callingId = Binder.clearCallingIdentity();
try {
synchronized (mPackages) {
for (int i = 0; i < packageNames.length; i++) {
final String packageName = packageNames[i];
- if (packageName == callingPackage) {
- Slog.w(TAG, "Calling package: " + callingPackage + "trying to "
+ if (callingPackage.equals(packageName)) {
+ Slog.w(TAG, "Calling package: " + callingPackage + " trying to "
+ (suspended ? "" : "un") + "suspend itself. Ignoring");
unactionedPackages.add(packageName);
continue;
@@ -14018,17 +14022,18 @@
}
pkgSetting.setSuspended(suspended, callingPackage, appExtras,
launcherExtras, userId);
- changedPackages.add(packageName);
+ changedPackagesList.add(packageName);
}
}
}
} finally {
Binder.restoreCallingIdentity(callingId);
}
- // TODO (b/75036698): Also send each package a broadcast when suspended state changed
- if (!changedPackages.isEmpty()) {
- sendPackagesSuspendedForUser(changedPackages.toArray(
- new String[changedPackages.size()]), userId, suspended);
+ if (!changedPackagesList.isEmpty()) {
+ final String[] changedPackages = changedPackagesList.toArray(
+ new String[changedPackagesList.size()]);
+ sendPackagesSuspendedForUser(changedPackages, userId, suspended);
+ sendMyPackageSuspendedOrUnsuspended(changedPackages, suspended, appExtras, userId);
synchronized (mPackages) {
scheduleWritePackageRestrictionsLocked(userId);
}
@@ -14038,7 +14043,7 @@
}
@Override
- public PersistableBundle getPackageSuspendedAppExtras(String packageName, int userId) {
+ public PersistableBundle getSuspendedPackageAppExtras(String packageName, int userId) {
final int callingUid = Binder.getCallingUid();
if (getPackageUid(packageName, 0, userId) != callingUid) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS, null);
@@ -14049,7 +14054,10 @@
throw new IllegalArgumentException("Unknown target package: " + packageName);
}
final PackageUserState packageUserState = ps.readUserState(userId);
- return packageUserState.suspended ? packageUserState.suspendedAppExtras : null;
+ if (packageUserState.suspended) {
+ return packageUserState.suspendedAppExtras;
+ }
+ return null;
}
}
@@ -14065,12 +14073,49 @@
}
final PackageUserState packageUserState = ps.readUserState(userId);
if (packageUserState.suspended) {
- // TODO (b/75036698): Also send this package a broadcast with the new app extras
packageUserState.suspendedAppExtras = appExtras;
+ sendMyPackageSuspendedOrUnsuspended(new String[] {packageName}, true, appExtras,
+ userId);
}
}
}
+ private void sendMyPackageSuspendedOrUnsuspended(String[] affectedPackages, boolean suspended,
+ PersistableBundle appExtras, int userId) {
+ final String action;
+ final Bundle intentExtras = new Bundle();
+ if (suspended) {
+ action = Intent.ACTION_MY_PACKAGE_SUSPENDED;
+ if (appExtras != null) {
+ final Bundle bundledAppExtras = new Bundle(appExtras.deepCopy());
+ intentExtras.putBundle(Intent.EXTRA_SUSPENDED_PACKAGE_EXTRAS, bundledAppExtras);
+ }
+ } else {
+ action = Intent.ACTION_MY_PACKAGE_UNSUSPENDED;
+ }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ final IActivityManager am = ActivityManager.getService();
+ if (am == null) {
+ Slog.wtf(TAG, "IActivityManager null. Cannot send MY_PACKAGE_ "
+ + (suspended ? "" : "UN") + "SUSPENDED broadcasts");
+ return;
+ }
+ final int[] targetUserIds = new int[] {userId};
+ for (String packageName : affectedPackages) {
+ doSendBroadcast(am, action, null, intentExtras,
+ Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, packageName, null,
+ targetUserIds, false);
+ }
+ } catch (RemoteException ex) {
+ // Shouldn't happen as AMS is in the same process.
+ }
+ }
+ });
+ }
+
@Override
public boolean isPackageSuspendedForUser(String packageName, int userId) {
final int callingUid = Binder.getCallingUid();
@@ -18890,7 +18935,7 @@
return true;
}
- private static final class ClearStorageConnection implements ServiceConnection {
+ private final class ClearStorageConnection implements ServiceConnection {
IMediaContainerService mContainerService;
@Override
@@ -21611,37 +21656,35 @@
// the given package is involved with.
if (dumpState.onTitlePrinted()) pw.println();
- try (final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120)) {
- ipw.println();
- ipw.println("Frozen packages:");
- ipw.increaseIndent();
- if (mFrozenPackages.size() == 0) {
- ipw.println("(none)");
- } else {
- for (int i = 0; i < mFrozenPackages.size(); i++) {
- ipw.println(mFrozenPackages.valueAt(i));
- }
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
+ ipw.println();
+ ipw.println("Frozen packages:");
+ ipw.increaseIndent();
+ if (mFrozenPackages.size() == 0) {
+ ipw.println("(none)");
+ } else {
+ for (int i = 0; i < mFrozenPackages.size(); i++) {
+ ipw.println(mFrozenPackages.valueAt(i));
}
- ipw.decreaseIndent();
}
+ ipw.decreaseIndent();
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_VOLUMES) && packageName == null) {
if (dumpState.onTitlePrinted()) pw.println();
- try (final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120)) {
- ipw.println();
- ipw.println("Loaded volumes:");
- ipw.increaseIndent();
- if (mLoadedVolumes.size() == 0) {
- ipw.println("(none)");
- } else {
- for (int i = 0; i < mLoadedVolumes.size(); i++) {
- ipw.println(mLoadedVolumes.valueAt(i));
- }
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
+ ipw.println();
+ ipw.println("Loaded volumes:");
+ ipw.increaseIndent();
+ if (mLoadedVolumes.size() == 0) {
+ ipw.println("(none)");
+ } else {
+ for (int i = 0; i < mLoadedVolumes.size(); i++) {
+ ipw.println(mLoadedVolumes.valueAt(i));
}
- ipw.decreaseIndent();
}
+ ipw.decreaseIndent();
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS)
@@ -21770,63 +21813,61 @@
}
private void dumpDexoptStateLPr(PrintWriter pw, String packageName) {
- try (final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ")) {
- ipw.println();
- ipw.println("Dexopt state:");
- ipw.increaseIndent();
- Collection<PackageParser.Package> packages = null;
- if (packageName != null) {
- PackageParser.Package targetPackage = mPackages.get(packageName);
- if (targetPackage != null) {
- packages = Collections.singletonList(targetPackage);
- } else {
- ipw.println("Unable to find package: " + packageName);
- return;
- }
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ ipw.println();
+ ipw.println("Dexopt state:");
+ ipw.increaseIndent();
+ Collection<PackageParser.Package> packages = null;
+ if (packageName != null) {
+ PackageParser.Package targetPackage = mPackages.get(packageName);
+ if (targetPackage != null) {
+ packages = Collections.singletonList(targetPackage);
} else {
- packages = mPackages.values();
+ ipw.println("Unable to find package: " + packageName);
+ return;
}
+ } else {
+ packages = mPackages.values();
+ }
- for (PackageParser.Package pkg : packages) {
- ipw.println("[" + pkg.packageName + "]");
- ipw.increaseIndent();
- mPackageDexOptimizer.dumpDexoptState(ipw, pkg,
- mDexManager.getPackageUseInfoOrDefault(pkg.packageName));
- ipw.decreaseIndent();
- }
+ for (PackageParser.Package pkg : packages) {
+ ipw.println("[" + pkg.packageName + "]");
+ ipw.increaseIndent();
+ mPackageDexOptimizer.dumpDexoptState(ipw, pkg,
+ mDexManager.getPackageUseInfoOrDefault(pkg.packageName));
+ ipw.decreaseIndent();
}
}
private void dumpCompilerStatsLPr(PrintWriter pw, String packageName) {
- try (final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ")) {
- ipw.println();
- ipw.println("Compiler stats:");
- ipw.increaseIndent();
- Collection<PackageParser.Package> packages = null;
- if (packageName != null) {
- PackageParser.Package targetPackage = mPackages.get(packageName);
- if (targetPackage != null) {
- packages = Collections.singletonList(targetPackage);
- } else {
- ipw.println("Unable to find package: " + packageName);
- return;
- }
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ ipw.println();
+ ipw.println("Compiler stats:");
+ ipw.increaseIndent();
+ Collection<PackageParser.Package> packages = null;
+ if (packageName != null) {
+ PackageParser.Package targetPackage = mPackages.get(packageName);
+ if (targetPackage != null) {
+ packages = Collections.singletonList(targetPackage);
} else {
- packages = mPackages.values();
+ ipw.println("Unable to find package: " + packageName);
+ return;
}
+ } else {
+ packages = mPackages.values();
+ }
- for (PackageParser.Package pkg : packages) {
- ipw.println("[" + pkg.packageName + "]");
- ipw.increaseIndent();
+ for (PackageParser.Package pkg : packages) {
+ ipw.println("[" + pkg.packageName + "]");
+ ipw.increaseIndent();
- CompilerStats.PackageStats stats = getCompilerPackageStats(pkg.packageName);
- if (stats == null) {
- ipw.println("(No recorded stats)");
- } else {
- stats.dump(ipw);
- }
- ipw.decreaseIndent();
+ CompilerStats.PackageStats stats = getCompilerPackageStats(pkg.packageName);
+ if (stats == null) {
+ ipw.println("(No recorded stats)");
+ } else {
+ stats.dump(ipw);
}
+ ipw.decreaseIndent();
}
}
@@ -24053,6 +24094,33 @@
}
}
+ @Override
+ public void grantDefaultPermissionsToActiveLuiApp(String packageName, int userId) {
+ enforceSystemOrPhoneCaller("grantDefaultPermissionsToActiveLuiApp");
+ synchronized (mPackages) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mDefaultPermissionPolicy.grantDefaultPermissionsToActiveLuiApp(
+ packageName, userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
+ @Override
+ public void revokeDefaultPermissionsFromLuiApps(String[] packageNames, int userId) {
+ enforceSystemOrPhoneCaller("revokeDefaultPermissionsFromLuiApps");
+ synchronized (mPackages) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mDefaultPermissionPolicy.revokeDefaultPermissionsFromLuiApps(packageNames, userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
private static void enforceSystemOrPhoneCaller(String tag) {
int callingUid = Binder.getCallingUid();
if (callingUid != Process.PHONE_UID && callingUid != Process.SYSTEM_UID) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index fce8285..5fc5bac 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -25,7 +25,7 @@
*/
public class PackageManagerServiceCompilerMapping {
// Names for compilation reasons.
- static final String REASON_STRINGS[] = {
+ public static final String REASON_STRINGS[] = {
"first-boot", "boot", "install", "bg-dexopt", "ab-ota", "inactive", "shared"
};
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 41ed6f2..cdafe57 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -27,19 +27,18 @@
import android.content.pm.dex.ArtManager.ProfileType;
import android.content.pm.dex.ArtManagerInternal;
import android.content.pm.dex.DexMetadataHelper;
+import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
import android.content.pm.dex.PackageOptimizationInfo;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
-import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.system.Os;
import android.util.ArrayMap;
import android.util.Slog;
-
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
@@ -47,9 +46,8 @@
import com.android.server.LocalServices;
import com.android.server.pm.Installer;
import com.android.server.pm.Installer.InstallerException;
-
+import com.android.server.pm.PackageManagerServiceCompilerMapping;
import dalvik.system.DexFile;
-
import dalvik.system.VMRuntime;
import java.io.File;
import java.io.FileNotFoundException;
@@ -88,6 +86,10 @@
private final Handler mHandler;
+ static {
+ verifyTronLoggingConstants();
+ }
+
public ArtManagerService(IPackageManager pm, Installer installer, Object installLock) {
mPackageManager = pm;
mInstaller = installer;
@@ -423,6 +425,100 @@
return result;
}
+ // Constants used for logging compilation filter to TRON.
+ // DO NOT CHANGE existing values.
+ //
+ // NOTE: '-1' value is reserved for the case where we cannot produce a valid
+ // PackageOptimizationInfo because the ArtManagerInternal is not ready to be used by the
+ // ActivityMetricsLoggers.
+ private static final int TRON_COMPILATION_FILTER_ERROR = 0;
+ private static final int TRON_COMPILATION_FILTER_UNKNOWN = 1;
+ private static final int TRON_COMPILATION_FILTER_ASSUMED_VERIFIED = 2;
+ private static final int TRON_COMPILATION_FILTER_EXTRACT = 3;
+ private static final int TRON_COMPILATION_FILTER_VERIFY = 4;
+ private static final int TRON_COMPILATION_FILTER_QUICKEN = 5;
+ private static final int TRON_COMPILATION_FILTER_SPACE_PROFILE = 6;
+ private static final int TRON_COMPILATION_FILTER_SPACE = 7;
+ private static final int TRON_COMPILATION_FILTER_SPEED_PROFILE = 8;
+ private static final int TRON_COMPILATION_FILTER_SPEED = 9;
+ private static final int TRON_COMPILATION_FILTER_EVERYTHING_PROFILE = 10;
+ private static final int TRON_COMPILATION_FILTER_EVERYTHING = 11;
+ private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK = 12;
+ private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK = 13;
+ private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK = 14;
+
+ // Constants used for logging compilation reason to TRON.
+ // DO NOT CHANGE existing values.
+ //
+ // NOTE: '-1' value is reserved for the case where we cannot produce a valid
+ // PackageOptimizationInfo because the ArtManagerInternal is not ready to be used by the
+ // ActivityMetricsLoggers.
+ private static final int TRON_COMPILATION_REASON_ERROR = 0;
+ private static final int TRON_COMPILATION_REASON_UNKNOWN = 1;
+ private static final int TRON_COMPILATION_REASON_FIRST_BOOT = 2;
+ private static final int TRON_COMPILATION_REASON_BOOT = 3;
+ private static final int TRON_COMPILATION_REASON_INSTALL = 4;
+ private static final int TRON_COMPILATION_REASON_BG_DEXOPT = 5;
+ private static final int TRON_COMPILATION_REASON_AB_OTA = 6;
+ private static final int TRON_COMPILATION_REASON_INACTIVE = 7;
+ private static final int TRON_COMPILATION_REASON_SHARED = 8;
+
+ /**
+ * Convert the compilation reason to an int suitable to be logged to TRON.
+ */
+ private static int getCompilationReasonTronValue(String compilationReason) {
+ switch (compilationReason) {
+ case "unknown" : return TRON_COMPILATION_REASON_UNKNOWN;
+ case "error" : return TRON_COMPILATION_REASON_ERROR;
+ case "first-boot" : return TRON_COMPILATION_REASON_FIRST_BOOT;
+ case "boot" : return TRON_COMPILATION_REASON_BOOT;
+ case "install" : return TRON_COMPILATION_REASON_INSTALL;
+ case "bg-dexopt" : return TRON_COMPILATION_REASON_BG_DEXOPT;
+ case "ab-ota" : return TRON_COMPILATION_REASON_AB_OTA;
+ case "inactive" : return TRON_COMPILATION_REASON_INACTIVE;
+ case "shared" : return TRON_COMPILATION_REASON_SHARED;
+ default: return TRON_COMPILATION_REASON_UNKNOWN;
+ }
+ }
+
+ /**
+ * Convert the compilation filter to an int suitable to be logged to TRON.
+ */
+ private static int getCompilationFilterTronValue(String compilationFilter) {
+ switch (compilationFilter) {
+ case "error" : return TRON_COMPILATION_FILTER_ERROR;
+ case "unknown" : return TRON_COMPILATION_FILTER_UNKNOWN;
+ case "assume-verified" : return TRON_COMPILATION_FILTER_ASSUMED_VERIFIED;
+ case "extract" : return TRON_COMPILATION_FILTER_EXTRACT;
+ case "verify" : return TRON_COMPILATION_FILTER_VERIFY;
+ case "quicken" : return TRON_COMPILATION_FILTER_QUICKEN;
+ case "space-profile" : return TRON_COMPILATION_FILTER_SPACE_PROFILE;
+ case "space" : return TRON_COMPILATION_FILTER_SPACE;
+ case "speed-profile" : return TRON_COMPILATION_FILTER_SPEED_PROFILE;
+ case "speed" : return TRON_COMPILATION_FILTER_SPEED;
+ case "everything-profile" : return TRON_COMPILATION_FILTER_EVERYTHING_PROFILE;
+ case "everything" : return TRON_COMPILATION_FILTER_EVERYTHING;
+ case "run-from-apk" : return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK;
+ case "run-from-apk-fallback" :
+ return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK;
+ case "run-from-vdex-fallback" :
+ return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK;
+ default: return TRON_COMPILATION_FILTER_UNKNOWN;
+ }
+ }
+
+ private static void verifyTronLoggingConstants() {
+ for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) {
+ String reason = PackageManagerServiceCompilerMapping.REASON_STRINGS[i];
+ int value = getCompilationReasonTronValue(reason);
+ if (value == TRON_COMPILATION_REASON_ERROR
+ || value == TRON_COMPILATION_REASON_UNKNOWN) {
+ throw new IllegalArgumentException("Compilation reason not configured for TRON "
+ + "logging: " + reason);
+ }
+ }
+ }
+
private class ArtManagerInternalImpl extends ArtManagerInternal {
@Override
public PackageOptimizationInfo getPackageOptimizationInfo(
@@ -445,7 +541,11 @@
compilationReason = "error";
}
- return new PackageOptimizationInfo(compilationFilter, compilationReason);
+ int compilationFilterTronValue = getCompilationFilterTronValue(compilationFilter);
+ int compilationReasonTronValue = getCompilationReasonTronValue(compilationReason);
+
+ return new PackageOptimizationInfo(
+ compilationFilterTronValue, compilationReasonTronValue);
}
}
}
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 3116480..518d464 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -972,6 +972,7 @@
grantRuntimePermissions(imsServicePackage, MICROPHONE_PERMISSIONS, userId);
grantRuntimePermissions(imsServicePackage, LOCATION_PERMISSIONS, userId);
grantRuntimePermissions(imsServicePackage, CAMERA_PERMISSIONS, userId);
+ grantRuntimePermissions(imsServicePackage, CONTACTS_PERMISSIONS, userId);
}
}
}
@@ -1010,6 +1011,32 @@
}
}
+ public void grantDefaultPermissionsToActiveLuiApp(String packageName, int userId) {
+ Log.i(TAG, "Granting permissions to active LUI app for user:" + userId);
+ if (packageName == null) {
+ return;
+ }
+ PackageParser.Package luiAppPackage = getSystemPackage(packageName);
+ if (luiAppPackage != null
+ && doesPackageSupportRuntimePermissions(luiAppPackage)) {
+ grantRuntimePermissions(luiAppPackage, CAMERA_PERMISSIONS, true, userId);
+ }
+ }
+
+ public void revokeDefaultPermissionsFromLuiApps(String[] packageNames, int userId) {
+ Log.i(TAG, "Revoke permissions from LUI apps for user:" + userId);
+ if (packageNames == null) {
+ return;
+ }
+ for (String packageName : packageNames) {
+ PackageParser.Package luiAppPackage = getSystemPackage(packageName);
+ if (luiAppPackage != null
+ && doesPackageSupportRuntimePermissions(luiAppPackage)) {
+ revokeRuntimePermissions(luiAppPackage, CAMERA_PERMISSIONS, true, userId);
+ }
+ }
+ }
+
public void grantDefaultPermissionsToDefaultBrowser(String packageName, int userId) {
Log.i(TAG, "Granting permissions to default browser for user:" + userId);
if (packageName == null) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 4dc68ac..2e6e348 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3027,7 +3027,7 @@
// Show IME over the keyguard if the target allows it
boolean allowWhenLocked = (win.isInputMethodWindow() || imeTarget == this)
- && showImeOverKeyguard;;
+ && showImeOverKeyguard;
if (isKeyguardLocked() && isKeyguardOccluded()) {
// Show SHOW_WHEN_LOCKED windows if Keyguard is occluded.
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 062b154..81a8c55 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -213,7 +213,8 @@
// There are no longer any keyguard windows on secondary displays, so pass
// INVALID_DISPLAY. All that means is that showWhenLocked activities on
// secondary displays now get to show.
- ActivityManager.getService().setLockScreenShown(true, INVALID_DISPLAY);
+ ActivityManager.getService().setLockScreenShown(true /* keyguardShowing */,
+ false /* aodShowing */, INVALID_DISPLAY);
} catch (RemoteException e) {
// Local call.
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 0678d08..8af1101 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -23,7 +23,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Rect;
-import android.hardware.fingerprint.IFingerprintDialogReceiver;
+import android.hardware.biometrics.IBiometricDialogReceiver;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -547,7 +547,7 @@
}
@Override
- public void showFingerprintDialog(Bundle bundle, IFingerprintDialogReceiver receiver) {
+ public void showFingerprintDialog(Bundle bundle, IBiometricDialogReceiver receiver) {
if (mBar != null) {
try {
mBar.showFingerprintDialog(bundle, receiver);
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 8901b04..d123099c 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1428,7 +1428,7 @@
void clearWallpaperLocked(boolean defaultFailed, int which, int userId, IRemoteCallback reply) {
if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
- throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read");
+ throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to clear");
}
WallpaperData wallpaper = null;
diff --git a/services/core/java/com/android/server/wm/AnimatingAppWindowTokenRegistry.java b/services/core/java/com/android/server/wm/AnimatingAppWindowTokenRegistry.java
index ae343da..416469b 100644
--- a/services/core/java/com/android/server/wm/AnimatingAppWindowTokenRegistry.java
+++ b/services/core/java/com/android/server/wm/AnimatingAppWindowTokenRegistry.java
@@ -19,6 +19,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
+import java.io.PrintWriter;
import java.util.ArrayList;
/**
@@ -88,4 +89,13 @@
}
mTmpRunnableList.clear();
}
+
+ void dump(PrintWriter pw, String header, String prefix) {
+ if (!mAnimatingTokens.isEmpty() || !mFinishedTokens.isEmpty()) {
+ pw.print(prefix); pw.println(header);
+ prefix = prefix + " ";
+ pw.print(prefix); pw.print("mAnimatingTokens="); pw.println(mAnimatingTokens);
+ pw.print(prefix); pw.print("mFinishedTokens="); pw.println(mFinishedTokens);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 41ae48a..c6f156b 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -34,6 +34,8 @@
import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND;
import static android.view.WindowManager.TRANSIT_TASK_TO_BACK;
import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
+import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_UNSET;
import static android.view.WindowManager.TRANSIT_WALLPAPER_CLOSE;
import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_CLOSE;
@@ -114,6 +116,7 @@
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
+import com.android.internal.R;
import com.android.internal.util.DumpUtils.Dump;
import com.android.server.AttributeCache;
import com.android.server.wm.WindowManagerService.H;
@@ -1652,14 +1655,26 @@
+ " Callers=" + Debug.getCallers(3));
}
} else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS && enter) {
-
- a = loadAnimationRes("android", enter
- ? com.android.internal.R.anim.task_open_enter_cross_profile_apps
- : com.android.internal.R.anim.task_open_exit);
+ a = loadAnimationRes("android",
+ com.android.internal.R.anim.task_open_enter_cross_profile_apps);
Slog.v(TAG,
"applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS:"
+ " anim=" + a + " transit=" + appTransitionToString(transit)
- + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
+ + " isEntrance=true" + " Callers=" + Debug.getCallers(3));
+ } else if (transit == TRANSIT_TRANSLUCENT_ACTIVITY_OPEN && enter) {
+ a = loadAnimationRes("android",
+ com.android.internal.R.anim.activity_translucent_open_enter);
+ Slog.v(TAG,
+ "applyAnimation TRANSIT_TRANSLUCENT_ACTIVITY_OPEN:"
+ + " anim=" + a + " transit=" + appTransitionToString(transit)
+ + " isEntrance=true" + " Callers=" + Debug.getCallers(3));
+ } else if (transit == TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE && !enter) {
+ a = loadAnimationRes("android",
+ com.android.internal.R.anim.activity_translucent_close_exit);
+ Slog.v(TAG,
+ "applyAnimation TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE:"
+ + " anim=" + a + " transit=" + appTransitionToString(transit)
+ + " isEntrance=false" + " Callers=" + Debug.getCallers(3));
} else {
int animAttr = 0;
switch (transit) {
@@ -2001,6 +2016,12 @@
case TRANSIT_KEYGUARD_UNOCCLUDE: {
return "TRANSIT_KEYGUARD_UNOCCLUDE";
}
+ case TRANSIT_TRANSLUCENT_ACTIVITY_OPEN: {
+ return "TRANSIT_TRANSLUCENT_ACTIVITY_OPEN";
+ }
+ case TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE: {
+ return "TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE";
+ }
default: {
return "<UNKNOWN>";
}
@@ -2173,16 +2194,20 @@
|| transit == TRANSIT_KEYGUARD_UNOCCLUDE;
}
- private static boolean isTaskTransit(int transit) {
- return transit == TRANSIT_TASK_OPEN
+ static boolean isTaskTransit(int transit) {
+ return isTaskOpenTransit(transit)
|| transit == TRANSIT_TASK_CLOSE
- || transit == TRANSIT_TASK_OPEN_BEHIND
|| transit == TRANSIT_TASK_TO_BACK
- || transit == TRANSIT_TASK_TO_FRONT
|| transit == TRANSIT_TASK_IN_PLACE;
}
- private static boolean isActivityTransit(int transit) {
+ private static boolean isTaskOpenTransit(int transit) {
+ return transit == TRANSIT_TASK_OPEN
+ || transit == TRANSIT_TASK_OPEN_BEHIND
+ || transit == TRANSIT_TASK_TO_FRONT;
+ }
+
+ static boolean isActivityTransit(int transit) {
return transit == TRANSIT_ACTIVITY_OPEN
|| transit == TRANSIT_ACTIVITY_CLOSE
|| transit == TRANSIT_ACTIVITY_RELAUNCH;
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 85436da..56c9e51 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1660,6 +1660,10 @@
true /* topToBottom */);
}
+ SurfaceControl getAppAnimationLayer() {
+ return getAppAnimationLayer(needsZBoost());
+ }
+
@Override
public SurfaceControl getAnimationLeashParent() {
// All normal app transitions take place in an animation layer which is below the pinned
@@ -1855,7 +1859,7 @@
leash.setLayer(layer);
final DisplayContent dc = getDisplayContent();
- dc.assignStackOrdering(t);
+ dc.assignStackOrdering();
if (mAnimatingAppWindowTokenRegistry != null) {
mAnimatingAppWindowTokenRegistry.notifyStarting(this);
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index a7eac55..2ffdbfd 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3180,6 +3180,7 @@
* A control placed at the appropriate level for transitions to occur.
*/
SurfaceControl mAppAnimationLayer = null;
+ SurfaceControl mBoostedAppAnimationLayer = null;
/**
* Given that the split-screen divider does not have an AppWindowToken, it
@@ -3531,12 +3532,14 @@
}
void assignStackOrdering(SurfaceControl.Transaction t) {
+
final int HOME_STACK_STATE = 0;
final int NORMAL_STACK_STATE = 1;
final int ALWAYS_ON_TOP_STATE = 2;
int layer = 0;
int layerForAnimationLayer = 0;
+ int layerForBoostedAnimationLayer = 0;
for (int state = 0; state <= ALWAYS_ON_TOP_STATE; state++) {
for (int i = 0; i < mChildren.size(); i++) {
@@ -3558,16 +3561,22 @@
// highest animating stack and no higher.
layerForAnimationLayer = layer++;
}
+ if (state != ALWAYS_ON_TOP_STATE) {
+ layerForBoostedAnimationLayer = layer++;
+ }
}
}
if (mAppAnimationLayer != null) {
t.setLayer(mAppAnimationLayer, layerForAnimationLayer);
}
+ if (mBoostedAppAnimationLayer != null) {
+ t.setLayer(mBoostedAppAnimationLayer, layerForBoostedAnimationLayer);
+ }
}
@Override
- SurfaceControl getAppAnimationLayer() {
- return mAppAnimationLayer;
+ SurfaceControl getAppAnimationLayer(boolean boosted) {
+ return boosted ? mBoostedAppAnimationLayer : mAppAnimationLayer;
}
SurfaceControl getSplitScreenDividerAnchor() {
@@ -3581,16 +3590,22 @@
mAppAnimationLayer = makeChildSurface(null)
.setName("animationLayer")
.build();
+ mBoostedAppAnimationLayer = makeChildSurface(null)
+ .setName("boostedAnimationLayer")
+ .build();
mSplitScreenDividerAnchor = makeChildSurface(null)
.setName("splitScreenDividerAnchor")
.build();
getPendingTransaction()
.show(mAppAnimationLayer)
+ .show(mBoostedAppAnimationLayer)
.show(mSplitScreenDividerAnchor);
scheduleAnimation();
} else {
mAppAnimationLayer.destroy();
mAppAnimationLayer = null;
+ mBoostedAppAnimationLayer.destroy();
+ mBoostedAppAnimationLayer = null;
mSplitScreenDividerAnchor.destroy();
mSplitScreenDividerAnchor = null;
}
@@ -3872,7 +3887,7 @@
super.prepareSurfaces();
}
- void assignStackOrdering(SurfaceControl.Transaction t) {
- mTaskStackContainers.assignStackOrdering(t);
+ void assignStackOrdering() {
+ mTaskStackContainers.assignStackOrdering(getPendingTransaction());
}
}
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 3e7feda..379a1a1 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -134,11 +134,18 @@
private RemoteAnimationTarget[] createAnimations() {
final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
+ final RemoteAnimationAdapterWrapper wrapper = mPendingAnimations.get(i);
final RemoteAnimationTarget target =
mPendingAnimations.get(i).createRemoteAppAnimation();
if (target != null) {
targets.add(target);
} else {
+
+ // We can't really start an animation but we still need to make sure to finish the
+ // pending animation that was started by SurfaceAnimator
+ if (wrapper.mCapturedFinishCallback != null) {
+ wrapper.mCapturedFinishCallback.onAnimationFinished(wrapper);
+ }
mPendingAnimations.remove(i);
}
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 900e2df..62754ad 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -1387,6 +1387,7 @@
token.dump(pw, " ", dumpAll);
}
}
+ mAnimatingAppWindowTokenRegistry.dump(pw, "AnimatingApps:", prefix);
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 28fdaae..60e7c0d 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1125,12 +1125,15 @@
}
/**
+ * @param boosted If true, returns an animation layer that happens above all {@link TaskStack}s
+ * Otherwise, the layer will be positioned above all animating
+ * {@link TaskStack}s.
* @return The layer on which all app animations are happening.
*/
- SurfaceControl getAppAnimationLayer() {
+ SurfaceControl getAppAnimationLayer(boolean boosted) {
final WindowContainer parent = getParent();
if (parent != null) {
- return parent.getAppAnimationLayer();
+ return parent.getAppAnimationLayer(boosted);
}
return null;
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 3256762..b85f4a4 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -16,12 +16,13 @@
package com.android.server.wm;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.ActivityManagerInternal.APP_TRANSITION_SNAPSHOT;
import static android.app.ActivityManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
import static android.app.ActivityManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
+import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
@@ -42,6 +43,7 @@
import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_OPEN;
import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit;
+import static com.android.server.wm.AppTransition.isTaskTransit;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
@@ -61,16 +63,15 @@
import android.view.Display;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition;
-import android.view.SurfaceControl;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManager.TransitionType;
import android.view.animation.Animation;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.wm.WindowManagerService.H;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.function.Predicate;
/**
@@ -288,6 +289,7 @@
final boolean closingAppHasWallpaper = canBeWallpaperTarget(mService.mClosingApps)
&& hasWallpaperTarget;
+ transit = maybeUpdateTransitToTranslucentAnim(transit);
transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper,
closingAppHasWallpaper);
@@ -676,8 +678,9 @@
transit = TRANSIT_WALLPAPER_CLOSE;
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit away from wallpaper: "
+ AppTransition.appTransitionToString(transit));
- } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw() &&
- openingApps.contains(wallpaperTarget.mAppToken)) {
+ } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()
+ && openingApps.contains(wallpaperTarget.mAppToken)
+ && transit != TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE) {
// We are transitioning from an activity without
// a wallpaper to now showing the wallpaper
transit = TRANSIT_WALLPAPER_OPEN;
@@ -688,6 +691,50 @@
return transit;
}
+ /**
+ * There are cases where we open/close a new task/activity, but in reality only a translucent
+ * activity on top of existing activities is opening/closing. For that one, we have a different
+ * animation because non of the task/activity animations actually work well with translucent
+ * apps.
+ *
+ * @param transit The current transition type.
+ * @return The current transition type or
+ * {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE}/
+ * {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_OPEN} if appropriate for the
+ * situation.
+ */
+ @VisibleForTesting
+ int maybeUpdateTransitToTranslucentAnim(int transit) {
+ final boolean taskOrActivity = AppTransition.isTaskTransit(transit)
+ || AppTransition.isActivityTransit(transit);
+ boolean allOpeningVisible = true;
+ boolean allTranslucentOpeningApps = !mService.mOpeningApps.isEmpty();
+ for (int i = mService.mOpeningApps.size() - 1; i >= 0; i--) {
+ final AppWindowToken token = mService.mOpeningApps.valueAt(i);
+ if (!token.isVisible()) {
+ allOpeningVisible = false;
+ if (token.fillsParent()) {
+ allTranslucentOpeningApps = false;
+ }
+ }
+ }
+ boolean allTranslucentClosingApps = !mService.mClosingApps.isEmpty();
+ for (int i = mService.mClosingApps.size() - 1; i >= 0; i--) {
+ if (mService.mClosingApps.valueAt(i).fillsParent()) {
+ allTranslucentClosingApps = false;
+ break;
+ }
+ }
+
+ if (taskOrActivity && allTranslucentClosingApps && allOpeningVisible) {
+ return TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
+ }
+ if (taskOrActivity && allTranslucentOpeningApps && mService.mClosingApps.isEmpty()) {
+ return TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
+ }
+ return transit;
+ }
+
private boolean canBeWallpaperTarget(ArraySet<AppWindowToken> apps) {
for (int i = apps.size() - 1; i >= 0; i--) {
if (apps.valueAt(i).windowsCanBeWallpaperTarget()) {
diff --git a/services/core/jni/com_android_server_UsbAlsaJackDetector.cpp b/services/core/jni/com_android_server_UsbAlsaJackDetector.cpp
index e9d4482..ccb4f59 100644
--- a/services/core/jni/com_android_server_UsbAlsaJackDetector.cpp
+++ b/services/core/jni/com_android_server_UsbAlsaJackDetector.cpp
@@ -19,6 +19,7 @@
#include "jni.h"
#include <nativehelper/JNIHelp.h>
+#include "android-base/strings.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/Log.h"
@@ -33,24 +34,36 @@
#define DRIVER_NAME "/dev/usb_accessory"
-#define USB_IN_JACK_NAME "USB in Jack"
-#define USB_OUT_JACK_NAME "USB out Jack"
+#define USB_IN_JACK_SUFFIX "Input Jack"
+#define USB_OUT_JACK_SUFFIX "Output Jack"
namespace android
{
-static jboolean is_jack_connected(jint card, const char* control) {
+static struct mixer_ctl* find_mixer_with_suffix(struct mixer* card_mixer, const char* suffix) {
+ int id = 0;
+ struct mixer_ctl* ctl;
+ while ((ctl = mixer_get_ctl(card_mixer, id++)) != NULL) {
+ const char* name = mixer_ctl_get_name(ctl);
+ if (android::base::EndsWith(name, suffix)) {
+ return ctl;
+ }
+ }
+ return NULL;
+}
+
+static jboolean is_jack_connected(jint card, const char* suffix) {
struct mixer* card_mixer = mixer_open(card);
if (card_mixer == NULL) {
return true;
}
- struct mixer_ctl* ctl = mixer_get_ctl_by_name(card_mixer, control);
+ struct mixer_ctl* ctl = find_mixer_with_suffix(card_mixer, suffix);
if (!ctl) {
return true;
}
mixer_ctl_update(ctl);
int val = mixer_ctl_get_value(ctl, 0);
- ALOGI("JACK %s - value %d\n", control, val);
+ ALOGI("%s - value %d\n", mixer_ctl_get_name(ctl), val);
mixer_close(card_mixer);
return val != 0;
@@ -66,33 +79,31 @@
}
jboolean has_jack = false;
- if ((mixer_get_ctl_by_name(card_mixer, USB_IN_JACK_NAME) != NULL) ||
- (mixer_get_ctl_by_name(card_mixer, USB_OUT_JACK_NAME) != NULL)) {
+ if ((find_mixer_with_suffix(card_mixer, USB_IN_JACK_SUFFIX) != NULL) ||
+ (find_mixer_with_suffix(card_mixer, USB_OUT_JACK_SUFFIX) != NULL)) {
has_jack = true;
}
mixer_close(card_mixer);
return has_jack;
}
-
static jboolean android_server_UsbAlsaJackDetector_inputJackConnected(JNIEnv* /* env */,
jobject /* thiz */,
jint card)
{
- return is_jack_connected(card, USB_IN_JACK_NAME);
+ return is_jack_connected(card, USB_IN_JACK_SUFFIX);
}
-
static jboolean android_server_UsbAlsaJackDetector_outputJackConnected(JNIEnv* /* env */,
jobject /* thiz */,
jint card)
{
- return is_jack_connected(card, USB_OUT_JACK_NAME);
+ return is_jack_connected(card, USB_OUT_JACK_SUFFIX);
}
static void android_server_UsbAlsaJackDetector_jackDetect(JNIEnv* env,
- jobject thiz,
- jint card) {
+ jobject thiz,
+ jint card) {
jclass jdclass = env->GetObjectClass(thiz);
jmethodID method_jackDetectCallback = env->GetMethodID(jdclass, "jackDetectCallback", "()Z");
if (method_jackDetectCallback == NULL) {
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
index b452ea5..cda968a7 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
@@ -240,7 +240,7 @@
doReturn(displayShouldSleep).when(display).shouldSleep();
doReturn(displaySleeping).when(display).isSleeping();
- doReturn(keyguardShowing).when(keyguard).isKeyguardShowing(anyInt());
+ doReturn(keyguardShowing).when(keyguard).isKeyguardOrAodShowing(anyInt());
mSupervisor.mFocusedStack = isFocusedStack ? stack : null;
mSupervisor.applySleepTokensLocked(true);
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index 6fdb029..3c10b03 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -389,6 +389,14 @@
sentIntents.add(intent);
return 0;
}
+
+ @Override
+ void reportGlobalUsageEventLocked(int event) {
+ }
+
+ @Override
+ void reportCurWakefulnessUsageEvent() {
+ }
}
private static class TestHandler extends Handler {
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
index d922df3..fb25cf3 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
@@ -85,9 +85,6 @@
255
};
- private static final int[] MINIMUM_BRIGHTNESS_CURVE_LUX = { 2000, 4000 };
- private static final float[] MINIMUM_BRIGHTNESS_CURVE_NITS = { 1.0f, 50.0f, 90.0f };
-
private static final float[] DISPLAY_RANGE_NITS = { 2.685f, 478.5f };
private static final int[] BACKLIGHT_RANGE = { 1, 255 };
@@ -384,19 +381,6 @@
com.android.internal.R.array.config_autoBrightnessDisplayValuesNits))
.thenReturn(mockBrightnessLevelNits);
- int[] mockMinimumBrightnessCurveLux = new int[MINIMUM_BRIGHTNESS_CURVE_LUX.length];
- for (int i = 0; i < mockMinimumBrightnessCurveLux.length; i++) {
- mockMinimumBrightnessCurveLux[i] = (int) MINIMUM_BRIGHTNESS_CURVE_LUX[i];
- }
- when(mockResources.getIntArray(
- com.android.internal.R.array.config_autoBrightnessMinimumBrightnessCurveLux))
- .thenReturn(mockMinimumBrightnessCurveLux);
- TypedArray mockMinimumBrightnessCurveNits = createFloatTypedArray(
- MINIMUM_BRIGHTNESS_CURVE_NITS);
- when(mockResources.obtainTypedArray(
- com.android.internal.R.array.config_autoBrightnessMinimumBrightnessCurveNits))
- .thenReturn(mockMinimumBrightnessCurveNits);
-
TypedArray mockNitsRange = createFloatTypedArray(nitsRange);
when(mockResources.obtainTypedArray(
com.android.internal.R.array.config_screenBrightnessNits))
@@ -435,78 +419,4 @@
return mockArray;
}
- private float[] getNearMinimumNits(float epsilon) {
- float[] lux = new float[MINIMUM_BRIGHTNESS_CURVE_LUX.length + 1];
- for (int i = 0; i < MINIMUM_BRIGHTNESS_CURVE_LUX.length; i++) {
- lux[i+1] = MINIMUM_BRIGHTNESS_CURVE_LUX[i];
- }
- Spline minimumBrightnessCurve = Spline.createSpline(lux, MINIMUM_BRIGHTNESS_CURVE_NITS);
- float[] nits = new float[LUX_LEVELS.length];
- for (int i = 0; i < nits.length; i++) {
- nits[i] = minimumBrightnessCurve.interpolate(LUX_LEVELS[i]) + epsilon;
- }
- return nits;
- }
-
- @Test
- public void testCreateWithTooDarkBrightnessConfigurationThrowsException() {
- float[] nits = getNearMinimumNits(-0.1f);
- Resources res = createResources(LUX_LEVELS, nits, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
- Exception thrown = null;
- try {
- BrightnessMappingStrategy.create(res);
- } catch (IllegalArgumentException e) {
- thrown = e;
- }
- assertNotNull("Failed to throw IllegalArgumentException", thrown);
- }
-
- @Test
- public void testCreationWithBrightEnoughBrightnessConfigurationDoesNotThrowException() {
- float[] nits = getNearMinimumNits(0);
- Resources res = createResources(LUX_LEVELS, nits, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
- assertNotNull("Failed to create BrightnessMappingStrategy",
- BrightnessMappingStrategy.create(res));
- }
-
- @Test
- public void testSettingTooDarkBrightnessConfigurationThrowsException() {
- Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS,
- BACKLIGHT_RANGE);
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
- assertNotNull("Failed to create BrightnessMappingStrategy", strategy);
- float[] lux = new float[LUX_LEVELS.length];
- for (int i = 0; i < lux.length; i++) {
- lux[i] = LUX_LEVELS[i];
- }
- float[] nits = getNearMinimumNits(-0.1f);
- BrightnessConfiguration config = new BrightnessConfiguration.Builder()
- .setCurve(lux, nits)
- .build();
- Exception thrown = null;
- try {
- strategy.setBrightnessConfiguration(config);
- } catch (IllegalArgumentException e) {
- thrown = e;
- }
- assertNotNull("Failed to throw IllegalArgumentException", thrown);
- }
-
- @Test
- public void testSettingBrightEnouhgBrightnessConfigurationDoesNotThrowException() {
- Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS,
- BACKLIGHT_RANGE);
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
- assertNotNull("Failed to create BrightnessMappingStrategy", strategy);
- float[] lux = new float[LUX_LEVELS.length];
- for (int i = 0; i < lux.length; i++) {
- lux[i] = LUX_LEVELS[i];
- }
- float[] nits = getNearMinimumNits(0);
- BrightnessConfiguration config = new BrightnessConfiguration.Builder()
- .setCurve(lux, nits)
- .build();
- assertTrue("failed to set brightness configuration",
- strategy.setBrightnessConfiguration(config));
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
index 0ea2317..9ae45ea 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
@@ -74,6 +74,7 @@
public class KeySyncTaskTest {
private static final String KEY_ALGORITHM = "AES";
private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
+ private static final String TEST_ROOT_CERT_ALIAS = "trusted_root";
private static final String WRAPPING_KEY_ALIAS = "KeySyncTaskTest/WrappingKey";
private static final String DATABASE_FILE_NAME = "recoverablekeystore.db";
private static final int TEST_USER_ID = 1000;
@@ -111,6 +112,11 @@
new int[] {TYPE_LOCKSCREEN});
mRecoverableKeyStoreDb.setRecoverySecretTypes(TEST_USER_ID, TEST_RECOVERY_AGENT_UID2,
new int[] {TYPE_LOCKSCREEN});
+
+ mRecoverableKeyStoreDb.setActiveRootOfTrust(TEST_USER_ID, TEST_RECOVERY_AGENT_UID,
+ TEST_ROOT_CERT_ALIAS);
+ mRecoverableKeyStoreDb.setActiveRootOfTrust(TEST_USER_ID, TEST_RECOVERY_AGENT_UID2,
+ TEST_ROOT_CERT_ALIAS);
mRecoverySnapshotStorage = new RecoverySnapshotStorage();
mKeySyncTask = new KeySyncTask(
@@ -247,7 +253,7 @@
TEST_APP_KEY_ALIAS,
WrappedKey.fromSecretKey(mEncryptKey, applicationKey));
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
- TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
+ TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
mKeySyncTask.run();
@@ -263,7 +269,7 @@
mRecoverableKeyStoreDb.setPlatformKeyGenerationId(TEST_USER_ID, TEST_GENERATION_ID);
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
- TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
+ TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
mKeySyncTask.run();
@@ -273,7 +279,7 @@
@Test
public void run_sendsEncryptedKeysIfAvailableToSync_withRawPublicKey() throws Exception {
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
- TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
+ TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
mRecoverableKeyStoreDb.setServerParams(
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE);
@@ -320,7 +326,7 @@
@Test
public void run_sendsEncryptedKeysIfAvailableToSync_withCertPath() throws Exception {
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
- TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
+ TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
mRecoverableKeyStoreDb.setServerParams(
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE);
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
@@ -339,7 +345,7 @@
@Test
public void run_setsCorrectSnapshotVersion() throws Exception {
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
- TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
+ TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
@@ -358,7 +364,7 @@
@Test
public void run_recreatesMissingSnapshot() throws Exception {
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
- TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
+ TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
@@ -388,7 +394,7 @@
mPlatformKeyManager);
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
- TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
+ TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
SecretKey applicationKey =
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
@@ -414,7 +420,7 @@
mPlatformKeyManager);
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
- TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
+ TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
SecretKey applicationKey =
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
@@ -441,7 +447,7 @@
mPlatformKeyManager);
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
- TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
+ TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
SecretKey applicationKey =
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
@@ -457,9 +463,9 @@
@Test
public void run_sendsEncryptedKeysWithTwoRegisteredAgents() throws Exception {
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
- TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
+ TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
- TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, TestData.CERT_PATH_1);
+ TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID2)).thenReturn(true);
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
@@ -479,9 +485,9 @@
new int[] {1000});
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
- TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
+ TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
- TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, TestData.CERT_PATH_1);
+ TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID2)).thenReturn(true);
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
@@ -496,9 +502,9 @@
@Test
public void run_notifiesNonregisteredAgent() throws Exception {
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
- TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
+ TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
- TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, TestData.CERT_PATH_1);
+ TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID2)).thenReturn(false);
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index 8db2537..f5f5027 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -44,9 +44,10 @@
import android.security.keystore.AndroidKeyStoreSecretKey;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
-import android.security.keystore.recovery.KeyDerivationParams;
import android.security.keystore.recovery.KeyChainProtectionParams;
+import android.security.keystore.recovery.KeyDerivationParams;
import android.security.keystore.recovery.RecoveryCertPath;
+import android.security.keystore.recovery.TrustedRootCertificates;
import android.security.keystore.recovery.WrappedApplicationKey;
import android.support.test.filters.SmallTest;
import android.support.test.InstrumentationRegistry;
@@ -90,6 +91,8 @@
private static final String DATABASE_FILE_NAME = "recoverablekeystore.db";
private static final String ROOT_CERTIFICATE_ALIAS = "";
+ private static final String DEFAULT_ROOT_CERT_ALIAS =
+ TrustedRootCertificates.GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS;
private static final String TEST_SESSION_ID = "karlin";
private static final byte[] TEST_PUBLIC_KEY = new byte[] {
(byte) 0x30, (byte) 0x59, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x07, (byte) 0x2a,
@@ -143,7 +146,7 @@
private static final String KEY_ALGORITHM = "AES";
private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
private static final String WRAPPING_KEY_ALIAS = "RecoverableKeyStoreManagerTest/WrappingKey";
- private static final String TEST_ROOT_CERT_ALIAS = "";
+ private static final String TEST_DEFAULT_ROOT_CERT_ALIAS = "";
private static final KeyChainProtectionParams TEST_PROTECTION_PARAMS =
new KeyChainProtectionParams.Builder()
.setUserSecretType(TYPE_LOCKSCREEN)
@@ -299,10 +302,10 @@
TestData.getCertXmlWithSerial(certSerial));
assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isFalse();
- assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid)).isEqualTo(
- TestData.CERT_PATH_1);
- assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid)).isEqualTo(
- certSerial);
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
+ DEFAULT_ROOT_CERT_ALIAS)).isEqualTo(TestData.CERT_PATH_1);
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
+ DEFAULT_ROOT_CERT_ALIAS)).isEqualTo(certSerial);
assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isNull();
}
@@ -328,7 +331,8 @@
byte[] modifiedCertXml = TestData.getCertXml();
modifiedCertXml[modifiedCertXml.length - 50] ^= 1; // Flip a bit in the certificate
try {
- mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS, modifiedCertXml);
+ mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS,
+ modifiedCertXml);
fail("should have thrown");
} catch (ServiceSpecificException e) {
assertThat(e.getMessage()).contains("validate cert");
@@ -346,8 +350,8 @@
mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS,
TestData.getCertXmlWithSerial(certSerial + 1));
- assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid))
- .isEqualTo(certSerial + 1);
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
+ DEFAULT_ROOT_CERT_ALIAS)).isEqualTo(certSerial + 1);
assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue();
}
@@ -362,8 +366,8 @@
mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS,
TestData.getCertXmlWithSerial(certSerial - 1));
- assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid))
- .isEqualTo(certSerial);
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
+ DEFAULT_ROOT_CERT_ALIAS)).isEqualTo(certSerial);
assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isFalse();
}
@@ -391,8 +395,10 @@
mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS, TEST_PUBLIC_KEY);
assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue();
- assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid)).isNull();
- assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid)).isNull();
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
+ DEFAULT_ROOT_CERT_ALIAS)).isNull();
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
+ DEFAULT_ROOT_CERT_ALIAS)).isNull();
assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isNotNull();
}
@@ -406,8 +412,8 @@
ROOT_CERTIFICATE_ALIAS, TestData.getCertXml(), TestData.getSigXml());
assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isFalse();
- assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid)).isEqualTo(
- TestData.CERT_PATH_1);
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
+ DEFAULT_ROOT_CERT_ALIAS)).isEqualTo(TestData.CERT_PATH_1);
assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isNull();
}
@@ -480,7 +486,7 @@
public void startRecoverySessionWithCertPath_storesTheSessionInfo() throws Exception {
mRecoverableKeyStoreManager.startRecoverySessionWithCertPath(
TEST_SESSION_ID,
- TEST_ROOT_CERT_ALIAS,
+ TEST_DEFAULT_ROOT_CERT_ALIAS,
RecoveryCertPath.createRecoveryCertPath(TestData.CERT_PATH_1),
TEST_VAULT_PARAMS,
TEST_VAULT_CHALLENGE,
@@ -497,7 +503,7 @@
public void startRecoverySessionWithCertPath_checksPermissionFirst() throws Exception {
mRecoverableKeyStoreManager.startRecoverySessionWithCertPath(
TEST_SESSION_ID,
- TEST_ROOT_CERT_ALIAS,
+ TEST_DEFAULT_ROOT_CERT_ALIAS,
RecoveryCertPath.createRecoveryCertPath(TestData.CERT_PATH_1),
TEST_VAULT_PARAMS,
TEST_VAULT_CHALLENGE,
@@ -601,7 +607,7 @@
try {
mRecoverableKeyStoreManager.startRecoverySessionWithCertPath(
TEST_SESSION_ID,
- TEST_ROOT_CERT_ALIAS,
+ TEST_DEFAULT_ROOT_CERT_ALIAS,
RecoveryCertPath.createRecoveryCertPath(TestData.CERT_PATH_1),
TEST_VAULT_PARAMS,
TEST_VAULT_CHALLENGE,
@@ -620,7 +626,7 @@
try {
mRecoverableKeyStoreManager.startRecoverySessionWithCertPath(
TEST_SESSION_ID,
- TEST_ROOT_CERT_ALIAS,
+ TEST_DEFAULT_ROOT_CERT_ALIAS,
RecoveryCertPath.createRecoveryCertPath(TestData.CERT_PATH_1),
vaultParams,
TEST_VAULT_CHALLENGE,
@@ -638,7 +644,7 @@
try {
mRecoverableKeyStoreManager.startRecoverySessionWithCertPath(
TEST_SESSION_ID,
- TEST_ROOT_CERT_ALIAS,
+ TEST_DEFAULT_ROOT_CERT_ALIAS,
RecoveryCertPath.createRecoveryCertPath(emptyCertPath),
TEST_VAULT_PARAMS,
TEST_VAULT_CHALLENGE,
@@ -658,7 +664,7 @@
try {
mRecoverableKeyStoreManager.startRecoverySessionWithCertPath(
TEST_SESSION_ID,
- TEST_ROOT_CERT_ALIAS,
+ TEST_DEFAULT_ROOT_CERT_ALIAS,
RecoveryCertPath.createRecoveryCertPath(shortCertPath),
TEST_VAULT_PARAMS,
TEST_VAULT_CHALLENGE,
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java
index 37482a3..9b09dd1a 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java
@@ -34,6 +34,7 @@
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.KeysEntry;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RecoveryServiceMetadataEntry;
+import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RootOfTrustEntry;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.UserMetadataEntry;
@SmallTest
@@ -55,6 +56,7 @@
private static final String TEST_SECRET_TYPES = "test-secret-types";
private static final long TEST_COUNTER_ID = -3981205205038476415L;
private static final byte[] TEST_SERVER_PARAMS = "test-server-params".getBytes(UTF_8);
+ private static final String TEST_ROOT_ALIAS = "root_cert_alias";
private static final byte[] TEST_CERT_PATH = "test-cert-path".getBytes(UTF_8);
private static final long TEST_CERT_SERIAL = 1000L;
@@ -135,6 +137,32 @@
checkAllColumns();
}
+ @Test
+ public void onUpgrade_v2_to_v3_to_v4() throws Exception {
+ createV2Tables();
+
+ assertThat(isRootOfTrustTableAvailable()).isFalse(); // V2 doesn't have the table;
+
+ mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 2, /*newVersion=*/ 3);
+
+ assertThat(isRootOfTrustTableAvailable()).isFalse(); // V3 doesn't have the table;
+
+ mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 3,
+ RecoverableKeyStoreDbHelper.DATABASE_VERSION);
+ checkAllColumns();
+ }
+
+ private boolean isRootOfTrustTableAvailable() {
+ ContentValues values = new ContentValues();
+ values.put(RootOfTrustEntry.COLUMN_NAME_USER_ID, TEST_USER_ID);
+ values.put(RootOfTrustEntry.COLUMN_NAME_UID, TEST_UID);
+ values.put(RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS, TEST_ROOT_ALIAS);
+ values.put(RootOfTrustEntry.COLUMN_NAME_CERT_PATH, TEST_CERT_PATH);
+ values.put(RootOfTrustEntry.COLUMN_NAME_CERT_SERIAL, TEST_CERT_SERIAL);
+ return mDatabase.insert(RootOfTrustEntry.TABLE_NAME, /*nullColumnHack=*/ null, values)
+ > -1;
+ }
+
private void checkAllColumns() throws Exception {
// Check the table containing encrypted application keys
ContentValues values = new ContentValues();
@@ -165,6 +193,7 @@
TEST_SNAPSHOT_VERSION);
values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_SHOULD_CREATE_SNAPSHOT,
TEST_SHOULD_CREATE_SNAPSHOT);
+ values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_ACTIVE_ROOT_OF_TRUST, TEST_ROOT_ALIAS);
values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_PUBLIC_KEY, TEST_PUBLIC_KEY);
values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_SECRET_TYPES, TEST_SECRET_TYPES);
values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_COUNTER_ID, TEST_COUNTER_ID);
@@ -175,5 +204,8 @@
mDatabase.insert(RecoveryServiceMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null,
values))
.isGreaterThan(-1L);
+
+ // Check the table about recovery service and root of trust data introduced in V4
+ assertThat(isRootOfTrustTableAvailable()).isTrue();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
index 8b01d97..940745e 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
@@ -49,6 +49,9 @@
public class RecoverableKeyStoreDbTest {
private static final String DATABASE_FILE_NAME = "recoverablekeystore.db";
+ private static final String TEST_ROOT_CERT_ALIAS = "trusted_root";
+ private static final String TEST_ROOT_CERT_ALIAS2 = "another_trusted_root";
+
private RecoverableKeyStoreDb mRecoverableKeyStoreDb;
private File mDatabaseFile;
@@ -284,7 +287,8 @@
Map<String, Integer> statuses = mRecoverableKeyStoreDb.getStatusForAllKeys(uid);
assertThat(statuses).hasSize(3);
- assertThat(statuses).containsEntry(alias, RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS);
+ assertThat(statuses).containsEntry(alias,
+ RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS);
assertThat(statuses).containsEntry(alias2, status);
assertThat(statuses).containsEntry(alias3, status);
@@ -401,26 +405,53 @@
public void setRecoveryServiceCertPath_replaceOldValue() throws Exception {
int userId = 12;
int uid = 10009;
- mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TestData.CERT_PATH_1);
- mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TestData.CERT_PATH_2);
- assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid)).isEqualTo(
+ mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TEST_ROOT_CERT_ALIAS,
+ TestData.CERT_PATH_1);
+ mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TEST_ROOT_CERT_ALIAS,
TestData.CERT_PATH_2);
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
+ TEST_ROOT_CERT_ALIAS)).isEqualTo(TestData.CERT_PATH_2);
+ }
+
+ @Test
+ public void setRecoveryServiceCertPath_updateValuesForCorrectRootCert() throws Exception {
+ int userId = 12;
+ int uid = 10009;
+ mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TEST_ROOT_CERT_ALIAS,
+ TestData.CERT_PATH_1);
+ mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TEST_ROOT_CERT_ALIAS2,
+ TestData.CERT_PATH_1);
+
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
+ TEST_ROOT_CERT_ALIAS)).isEqualTo(TestData.CERT_PATH_1);
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
+ TEST_ROOT_CERT_ALIAS2)).isEqualTo(TestData.CERT_PATH_1);
+
+ mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TEST_ROOT_CERT_ALIAS2,
+ TestData.CERT_PATH_2);
+
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
+ TEST_ROOT_CERT_ALIAS)).isEqualTo(TestData.CERT_PATH_1);
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
+ TEST_ROOT_CERT_ALIAS2)).isEqualTo(TestData.CERT_PATH_2);
}
@Test
public void getRecoveryServiceCertPath_returnsNullIfNoValue() throws Exception {
int userId = 12;
int uid = 10009;
- assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid)).isNull();
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
+ TEST_ROOT_CERT_ALIAS)).isNull();
}
@Test
public void getRecoveryServiceCertPath_returnsInsertedValue() throws Exception {
int userId = 12;
int uid = 10009;
- mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TestData.CERT_PATH_1);
- assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid)).isEqualTo(
+ mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TEST_ROOT_CERT_ALIAS,
TestData.CERT_PATH_1);
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
+ TEST_ROOT_CERT_ALIAS)).isEqualTo(TestData.CERT_PATH_1);
}
@Test
@@ -428,25 +459,50 @@
int userId = 12;
int uid = 10009;
- mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, 1L);
- mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, 3L);
- assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid)).isEqualTo(3L);
+ mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, TEST_ROOT_CERT_ALIAS, 1L);
+ mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, TEST_ROOT_CERT_ALIAS, 3L);
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
+ TEST_ROOT_CERT_ALIAS)).isEqualTo(3L);
+ }
+
+ @Test
+ public void setRecoveryServiceCertSerial_updateValuesForCorrectRootCert() throws Exception {
+ int userId = 12;
+ int uid = 10009;
+ mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, TEST_ROOT_CERT_ALIAS, 1L);
+ mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, TEST_ROOT_CERT_ALIAS2, 1L);
+
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
+ TEST_ROOT_CERT_ALIAS)).isEqualTo(1L);
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
+ TEST_ROOT_CERT_ALIAS2)).isEqualTo(1L);
+
+ mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, TEST_ROOT_CERT_ALIAS2, 3L);
+
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
+ TEST_ROOT_CERT_ALIAS)).isEqualTo(1L);
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
+ TEST_ROOT_CERT_ALIAS2)).isEqualTo(3L);
}
@Test
public void getRecoveryServiceCertSerial_returnsNullIfNoValue() throws Exception {
int userId = 12;
int uid = 10009;
- assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid)).isNull();
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
+ TEST_ROOT_CERT_ALIAS)).isNull();
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
+ TEST_ROOT_CERT_ALIAS2)).isNull();
}
@Test
public void getRecoveryServiceCertSerial_returnsInsertedValue() throws Exception {
int userId = 12;
int uid = 10009;
- mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, 1234L);
- assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid)).isEqualTo(
- 1234L);
+ mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid,
+ TEST_ROOT_CERT_ALIAS, 1234L);
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
+ TEST_ROOT_CERT_ALIAS)).isEqualTo(1234L);
}
@Test
@@ -480,6 +536,24 @@
}
@Test
+ public void setActiveRootOfTrust_emptyDefaultValue() throws Exception {
+ int userId = 12;
+ int uid = 10009;
+ assertThat(mRecoverableKeyStoreDb.getActiveRootOfTrust(userId, uid)).isEqualTo(null);
+ }
+
+ @Test
+ public void setActiveRootOfTrust_updateValue() throws Exception {
+ int userId = 12;
+ int uid = 10009;
+ mRecoverableKeyStoreDb.setActiveRootOfTrust(userId, uid, "root");
+ assertThat(mRecoverableKeyStoreDb.getActiveRootOfTrust(userId, uid)).isEqualTo("root");
+
+ mRecoverableKeyStoreDb.setActiveRootOfTrust(userId, uid, "root2");
+ assertThat(mRecoverableKeyStoreDb.getActiveRootOfTrust(userId, uid)).isEqualTo("root2");
+ }
+
+ @Test
public void setRecoverySecretTypes_emptyDefaultValue() throws Exception {
int userId = 12;
int uid = 10009;
@@ -495,11 +569,9 @@
int[] types2 = new int[]{2};
mRecoverableKeyStoreDb.setRecoverySecretTypes(userId, uid, types1);
- assertThat(mRecoverableKeyStoreDb.getRecoverySecretTypes(userId, uid)).isEqualTo(
- types1);
+ assertThat(mRecoverableKeyStoreDb.getRecoverySecretTypes(userId, uid)).isEqualTo(types1);
mRecoverableKeyStoreDb.setRecoverySecretTypes(userId, uid, types2);
- assertThat(mRecoverableKeyStoreDb.getRecoverySecretTypes(userId, uid)).isEqualTo(
- types2);
+ assertThat(mRecoverableKeyStoreDb.getRecoverySecretTypes(userId, uid)).isEqualTo(types2);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
index d702318..ee0ad39 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
@@ -16,55 +16,129 @@
package com.android.server.pm;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import android.app.AppGlobals;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.os.BaseBundle;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.PersistableBundle;
+import android.os.RemoteException;
import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import com.android.servicestests.apps.suspendtestapp.SuspendTestReceiver;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
@RunWith(AndroidJUnit4.class)
-@MediumTest
+@LargeTest
public class SuspendPackagesTest {
private static final String TEST_APP_PACKAGE_NAME = SuspendTestReceiver.PACKAGE_NAME;
private static final String[] PACKAGES_TO_SUSPEND = new String[]{TEST_APP_PACKAGE_NAME};
+ public static final String INSTRUMENTATION_PACKAGE = "com.android.frameworks.servicestests";
+ public static final String ACTION_REPORT_MY_PACKAGE_SUSPENDED =
+ INSTRUMENTATION_PACKAGE + ".action.REPORT_MY_PACKAGE_SUSPENDED";
+ public static final String ACTION_REPORT_MY_PACKAGE_UNSUSPENDED =
+ INSTRUMENTATION_PACKAGE + ".action.REPORT_MY_PACKAGE_UNSUSPENDED";
+
private Context mContext;
private PackageManager mPackageManager;
private Handler mReceiverHandler;
private ComponentName mTestReceiverComponent;
+ private AppCommunicationReceiver mAppCommsReceiver;
+
+ private static final class AppCommunicationReceiver extends BroadcastReceiver {
+ private Context context;
+ private boolean registered;
+ private SynchronousQueue<Intent> intentQueue = new SynchronousQueue<>();
+
+ AppCommunicationReceiver(Context context) {
+ this.context = context;
+ }
+
+ void register(Handler handler) {
+ registered = true;
+ final IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(ACTION_REPORT_MY_PACKAGE_SUSPENDED);
+ intentFilter.addAction(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED);
+ context.registerReceiver(this, intentFilter, null, handler);
+ }
+
+ void unregister() {
+ if (registered) {
+ context.unregisterReceiver(this);
+ }
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ try {
+ intentQueue.offer(intent, 5, TimeUnit.SECONDS);
+ } catch (InterruptedException ie) {
+ throw new RuntimeException("Receiver thread interrupted", ie);
+ }
+ }
+
+ Intent receiveIntentFromApp() {
+ if (!registered) {
+ throw new IllegalStateException("Receiver not registered");
+ }
+ final Intent intent;
+ try {
+ intent = intentQueue.poll(5, TimeUnit.SECONDS);
+ } catch (InterruptedException ie) {
+ throw new RuntimeException("Interrupted while waiting for app broadcast", ie);
+ }
+ assertNotNull("No intent received from app within 5 seconds", intent);
+ return intent;
+ }
+ }
@Before
public void setUp() {
mContext = InstrumentationRegistry.getTargetContext();
mPackageManager = mContext.getPackageManager();
- mPackageManager.setPackagesSuspended(PACKAGES_TO_SUSPEND, false, null, null, null);
mReceiverHandler = new Handler(Looper.getMainLooper());
mTestReceiverComponent = new ComponentName(TEST_APP_PACKAGE_NAME,
SuspendTestReceiver.class.getCanonicalName());
+ IPackageManager ipm = AppGlobals.getPackageManager();
+ try {
+ // Otherwise implicit broadcasts will not be delivered.
+ ipm.setPackageStoppedState(TEST_APP_PACKAGE_NAME, false, mContext.getUserId());
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ unsuspendTestPackage();
+ mAppCommsReceiver = new AppCommunicationReceiver(mContext);
}
+ /**
+ * Care should be taken when used with {@link #mAppCommsReceiver} in the same test as both use
+ * the same handler.
+ */
private Bundle requestAppAction(String action) throws InterruptedException {
final AtomicReference<Bundle> result = new AtomicReference<>();
final CountDownLatch receiverLatch = new CountDownLatch(1);
@@ -98,6 +172,24 @@
assertTrue("setPackagesSuspended returned non-empty list", unchangedPackages.length == 0);
}
+ private void unsuspendTestPackage() {
+ final String[] unchangedPackages = mPackageManager.setPackagesSuspended(
+ PACKAGES_TO_SUSPEND, false, null, null, null);
+ assertTrue("setPackagesSuspended returned non-empty list", unchangedPackages.length == 0);
+ }
+
+
+ private static void assertSameExtras(String message, BaseBundle expected, BaseBundle received) {
+ if (expected != null) {
+ expected.get(""); // hack to unparcel the bundles.
+ }
+ if (received != null) {
+ received.get("");
+ }
+ assertTrue(message + ": [expected: " + expected + "; received: " + received + "]",
+ BaseBundle.kindofEquals(expected, received));
+ }
+
@Test
public void testIsPackageSuspended() {
suspendTestPackage(null, null);
@@ -109,19 +201,73 @@
public void testSuspendedStateFromApp() throws Exception {
Bundle resultFromApp = requestAppAction(SuspendTestReceiver.ACTION_GET_SUSPENDED_STATE);
assertFalse(resultFromApp.getBoolean(SuspendTestReceiver.EXTRA_SUSPENDED, true));
- assertNull(resultFromApp.getParcelable(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
+ assertNull(resultFromApp.getBundle(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
- final PersistableBundle appExtras = getExtras("appExtras", 20, "20", 0.2);
+ final PersistableBundle appExtras = getExtras("testSuspendedStateFromApp", 20, "20", 0.2);
suspendTestPackage(appExtras, null);
resultFromApp = requestAppAction(SuspendTestReceiver.ACTION_GET_SUSPENDED_STATE);
assertTrue("resultFromApp:suspended is false",
resultFromApp.getBoolean(SuspendTestReceiver.EXTRA_SUSPENDED));
- final PersistableBundle receivedAppExtras =
- resultFromApp.getParcelable(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS);
- receivedAppExtras.get(""); // hack to unparcel the bundles
- appExtras.get("");
- assertTrue("Received app extras " + receivedAppExtras + " different to the ones supplied",
- BaseBundle.kindofEquals(appExtras, receivedAppExtras));
+ final Bundle receivedAppExtras =
+ resultFromApp.getBundle(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS);
+ assertSameExtras("Received app extras different to the ones supplied",
+ appExtras, receivedAppExtras);
+ }
+
+ @Test
+ public void testMyPackageSuspendedUnsuspended() {
+ mAppCommsReceiver.register(mReceiverHandler);
+ final PersistableBundle appExtras = getExtras("testMyPackageSuspendBroadcasts", 1, "1", .1);
+ suspendTestPackage(appExtras, null);
+ Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
+ assertTrue("MY_PACKAGE_SUSPENDED delivery not reported",
+ ACTION_REPORT_MY_PACKAGE_SUSPENDED.equals(intentFromApp.getAction()));
+ assertSameExtras("Received app extras different to the ones supplied", appExtras,
+ intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
+ unsuspendTestPackage();
+ intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
+ assertTrue("MY_PACKAGE_UNSUSPENDED delivery not reported",
+ ACTION_REPORT_MY_PACKAGE_UNSUSPENDED.equals(intentFromApp.getAction()));
+ }
+
+ @Test
+ public void testUpdatingAppExtras() {
+ mAppCommsReceiver.register(mReceiverHandler);
+ final PersistableBundle extras1 = getExtras("testMyPackageSuspendedOnChangingExtras", 1,
+ "1", 0.1);
+ suspendTestPackage(extras1, null);
+ Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
+ assertTrue("MY_PACKAGE_SUSPENDED delivery not reported",
+ ACTION_REPORT_MY_PACKAGE_SUSPENDED.equals(intentFromApp.getAction()));
+ assertSameExtras("Received app extras different to the ones supplied", extras1,
+ intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
+ final PersistableBundle extras2 = getExtras("testMyPackageSuspendedOnChangingExtras", 2,
+ "2", 0.2);
+ mPackageManager.setSuspendedPackageAppExtras(TEST_APP_PACKAGE_NAME, extras2);
+ intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
+ assertTrue("MY_PACKAGE_SUSPENDED delivery not reported",
+ ACTION_REPORT_MY_PACKAGE_SUSPENDED.equals(intentFromApp.getAction()));
+ assertSameExtras("Received app extras different to the updated extras", extras2,
+ intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
+ }
+
+ @Test
+ public void testCannotSuspendSelf() {
+ final String[] unchangedPkgs = mPackageManager.setPackagesSuspended(
+ new String[]{mContext.getOpPackageName()}, true, null, null, null);
+ assertTrue(unchangedPkgs.length == 1);
+ assertEquals(mContext.getOpPackageName(), unchangedPkgs[0]);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mAppCommsReceiver.unregister();
+ Thread.sleep(250); // To prevent any race with the next registerReceiver
+ }
+
+ @FunctionalInterface
+ interface Condition {
+ boolean isTrue();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index 64501e4..553d658 100644
--- a/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -197,4 +197,16 @@
assertEquals(1, appsCaptor.getValue().length);
assertEquals(mMockLeash, appsCaptor.getValue()[0].leash);
}
+
+ @Test
+ public void testRemovedBeforeStarted() throws Exception {
+ final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
+ final AnimationAdapter adapter = mController.createAnimationAdapter(win.mAppToken,
+ new Point(50, 100), new Rect(50, 100, 150, 150));
+ adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
+ win.mAppToken.removeImmediately();
+ mController.goodToGo();
+ verifyZeroInteractions(mMockRunner);
+ verify(mFinishedCallback).onAnimationFinished(eq(adapter));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowSurfacePlacerTest.java b/services/tests/servicestests/src/com/android/server/wm/WindowSurfacePlacerTest.java
new file mode 100644
index 0000000..e173b7d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowSurfacePlacerTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.wm;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
+import static android.view.WindowManager.TRANSIT_TASK_OPEN;
+import static junit.framework.Assert.assertEquals;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.WindowManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class WindowSurfacePlacerTest extends WindowTestsBase {
+
+ private WindowSurfacePlacer mWindowSurfacePlacer;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ mWindowSurfacePlacer = new WindowSurfacePlacer(sWm);
+ }
+
+ @Test
+ public void testTranslucentOpen() throws Exception {
+ synchronized (sWm.mWindowMap) {
+ final AppWindowToken behind = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final AppWindowToken translucentOpening = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ translucentOpening.setFillsParent(false);
+ translucentOpening.setHidden(true);
+ sWm.mOpeningApps.add(behind);
+ sWm.mOpeningApps.add(translucentOpening);
+ assertEquals(WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN,
+ mWindowSurfacePlacer.maybeUpdateTransitToTranslucentAnim(TRANSIT_TASK_OPEN));
+ }
+ }
+
+ @Test
+ public void testTranslucentClose() throws Exception {
+ synchronized (sWm.mWindowMap) {
+ final AppWindowToken behind = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final AppWindowToken translucentClosing = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ translucentClosing.setFillsParent(false);
+ sWm.mClosingApps.add(translucentClosing);
+ assertEquals(WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE,
+ mWindowSurfacePlacer.maybeUpdateTransitToTranslucentAnim(TRANSIT_TASK_CLOSE));
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 6fa2740..d2eee68 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -173,6 +173,8 @@
mDisplayContent.removeImmediately();
sWm.mInputMethodTarget = null;
+ sWm.mClosingApps.clear();
+ sWm.mOpeningApps.clear();
}
// Wait until everything is really cleaned up.
diff --git a/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk b/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk
index 40a34b9..afdde72 100644
--- a/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk
+++ b/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk
@@ -17,14 +17,18 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_SRC_FILES += ../../src/com/android/server/pm/SuspendPackagesTest.java
LOCAL_PACKAGE_NAME := SuspendTestApp
LOCAL_DEX_PREOPT := false
LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_PRIVATE_PLATFORM_APIS := true
+
include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/services/tests/servicestests/test-apps/SuspendTestApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/SuspendTestApp/AndroidManifest.xml
index 70a1fd0..ce6a27a 100644
--- a/services/tests/servicestests/test-apps/SuspendTestApp/AndroidManifest.xml
+++ b/services/tests/servicestests/test-apps/SuspendTestApp/AndroidManifest.xml
@@ -21,7 +21,12 @@
<activity android:name=".SuspendTestActivity"
android:exported="true" />
<receiver android:name=".SuspendTestReceiver"
- android:exported="true" />
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MY_PACKAGE_SUSPENDED" />
+ <action android:name="android.intent.action.MY_PACKAGE_UNSUSPENDED" />
+ </intent-filter>
+ </receiver>
</application>
</manifest>
\ No newline at end of file
diff --git a/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestReceiver.java b/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestReceiver.java
index 6f353a0..90a9f01 100644
--- a/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestReceiver.java
+++ b/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestReceiver.java
@@ -16,12 +16,15 @@
package com.android.servicestests.apps.suspendtestapp;
+import static com.android.server.pm.SuspendPackagesTest.ACTION_REPORT_MY_PACKAGE_SUSPENDED;
+import static com.android.server.pm.SuspendPackagesTest.ACTION_REPORT_MY_PACKAGE_UNSUSPENDED;
+import static com.android.server.pm.SuspendPackagesTest.INSTRUMENTATION_PACKAGE;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
-import android.os.PersistableBundle;
import android.util.Log;
public class SuspendTestReceiver extends BroadcastReceiver {
@@ -34,21 +37,33 @@
public static final String EXTRA_SUSPENDED_APP_EXTRAS =
PACKAGE_NAME + ".extra.SUSPENDED_APP_EXTRAS";
- private PackageManager mPm;
-
@Override
public void onReceive(Context context, Intent intent) {
- mPm = context.getPackageManager();
- Log.d(TAG, "Received request action " + intent.getAction());
+ final PackageManager packageManager = context.getPackageManager();
+ Log.d(TAG, "Received action " + intent.getAction());
+ final Bundle appExtras;
switch (intent.getAction()) {
case ACTION_GET_SUSPENDED_STATE:
final Bundle result = new Bundle();
- final boolean suspended = mPm.isPackageSuspended();
- final PersistableBundle appExtras = mPm.getSuspendedPackageAppExtras();
+ final boolean suspended = packageManager.isPackageSuspended();
+ appExtras = packageManager.getSuspendedPackageAppExtras();
result.putBoolean(EXTRA_SUSPENDED, suspended);
- result.putParcelable(EXTRA_SUSPENDED_APP_EXTRAS, appExtras);
+ result.putBundle(EXTRA_SUSPENDED_APP_EXTRAS, appExtras);
setResult(0, null, result);
break;
+ case Intent.ACTION_MY_PACKAGE_SUSPENDED:
+ appExtras = intent.getBundleExtra(Intent.EXTRA_SUSPENDED_PACKAGE_EXTRAS);
+ final Intent reportSuspendIntent = new Intent(ACTION_REPORT_MY_PACKAGE_SUSPENDED)
+ .putExtra(EXTRA_SUSPENDED_APP_EXTRAS, appExtras)
+ .setPackage(INSTRUMENTATION_PACKAGE);
+ context.sendBroadcast(reportSuspendIntent);
+ break;
+ case Intent.ACTION_MY_PACKAGE_UNSUSPENDED:
+ final Intent reportUnsuspendIntent =
+ new Intent(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED)
+ .setPackage(INSTRUMENTATION_PACKAGE);
+ context.sendBroadcast(reportUnsuspendIntent);
+ break;
default:
Log.e(TAG, "Unknown action: " + intent.getAction());
}
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index 00826e0..b070e03 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -16,6 +16,7 @@
package com.android.server.usage;
import android.app.usage.ConfigurationStats;
+import android.app.usage.EventStats;
import android.app.usage.TimeSparseArray;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStats;
@@ -23,10 +24,18 @@
import android.util.ArrayMap;
import android.util.ArraySet;
+import java.util.List;
+
class IntervalStats {
public long beginTime;
public long endTime;
public long lastTimeSaved;
+ public long lastInteractiveTime;
+ public long lastNonInteractiveTime;
+ public long interactiveDuration;
+ public int interactiveCount;
+ public long nonInteractiveDuration;
+ public int nonInteractiveCount;
public final ArrayMap<String, UsageStats> packageStats = new ArrayMap<>();
public final ArrayMap<Configuration, ConfigurationStats> configurations = new ArrayMap<>();
public Configuration activeConfiguration;
@@ -171,6 +180,60 @@
usageStats.mAppLaunchCount += 1;
}
+ private void commitInteractiveTime(long timeStamp) {
+ if (lastInteractiveTime != 0) {
+ interactiveDuration += timeStamp - lastInteractiveTime;
+ lastInteractiveTime = 0;
+ }
+ if (lastNonInteractiveTime != 0) {
+ nonInteractiveDuration += timeStamp - lastNonInteractiveTime;
+ lastNonInteractiveTime = 0;
+ }
+ }
+
+ void commitTime(long timeStamp) {
+ commitInteractiveTime(timeStamp);
+ }
+
+ void updateScreenInteractive(long timeStamp) {
+ if (lastInteractiveTime != 0) {
+ // Already interactive, just keep running.
+ return;
+ }
+ commitInteractiveTime(timeStamp);
+ lastInteractiveTime = timeStamp;
+ interactiveCount++;
+ }
+
+ void updateScreenNonInteractive(long timeStamp) {
+ if (lastNonInteractiveTime != 0) {
+ // Already non-interactive, just keep running.
+ return;
+ }
+ commitInteractiveTime(timeStamp);
+ lastNonInteractiveTime = timeStamp;
+ nonInteractiveCount++;
+ }
+
+ private void addOneEventStats(List<EventStats> out, int event, int count, long duration) {
+ if (count != 0 || duration != 0) {
+ EventStats ev = new EventStats();
+ ev.mEventType = event;
+ ev.mCount = count;
+ ev.mTotalTime = duration;
+ ev.mBeginTimeStamp = beginTime;
+ ev.mEndTimeStamp = endTime;
+ out.add(ev);
+ }
+ }
+
+ void addEventStatsTo(List<EventStats> out) {
+ addOneEventStats(out, UsageEvents.Event.SCREEN_INTERACTIVE, interactiveCount,
+ interactiveDuration);
+ addOneEventStats(out, UsageEvents.Event.SCREEN_NON_INTERACTIVE, nonInteractiveCount,
+ nonInteractiveDuration);
+ }
+
private String getCachedStringRef(String str) {
final int index = mStringCache.indexOf(str);
if (index < 0) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index b8317b4..2258b24 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -25,6 +25,7 @@
import android.app.admin.DevicePolicyManagerInternal;
import android.app.usage.AppStandbyInfo;
import android.app.usage.ConfigurationStats;
+import android.app.usage.EventStats;
import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManager;
@@ -486,6 +487,23 @@
/**
* Called by the Binder stub.
*/
+ List<EventStats> queryEventStats(int userId, int bucketType, long beginTime,
+ long endTime) {
+ synchronized (mLock) {
+ final long timeNow = checkAndGetTimeLocked();
+ if (!validRange(timeNow, beginTime, endTime)) {
+ return null;
+ }
+
+ final UserUsageStatsService service =
+ getUserDataAndInitializeIfNeededLocked(userId, timeNow);
+ return service.queryEventStats(bucketType, beginTime, endTime);
+ }
+ }
+
+ /**
+ * Called by the Binder stub.
+ */
UsageEvents queryEvents(int userId, long beginTime, long endTime,
boolean shouldObfuscateInstantApps) {
synchronized (mLock) {
@@ -713,6 +731,28 @@
}
@Override
+ public ParceledListSlice<EventStats> queryEventStats(int bucketType,
+ long beginTime, long endTime, String callingPackage) throws RemoteException {
+ if (!hasPermission(callingPackage)) {
+ return null;
+ }
+
+ final int userId = UserHandle.getCallingUserId();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ final List<EventStats> results =
+ UsageStatsService.this.queryEventStats(userId, bucketType,
+ beginTime, endTime);
+ if (results != null) {
+ return new ParceledListSlice<>(results);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return null;
+ }
+
+ @Override
public UsageEvents queryEvents(long beginTime, long endTime, String callingPackage) {
if (!hasPermission(callingPackage)) {
return null;
diff --git a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
index bcfc421..2287b27 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
@@ -27,6 +27,7 @@
import android.app.usage.UsageStats;
import android.content.res.Configuration;
import android.util.ArrayMap;
+import android.util.Pair;
import java.io.IOException;
import java.net.ProtocolException;
@@ -37,6 +38,9 @@
final class UsageStatsXmlV1 {
private static final String TAG = "UsageStatsXmlV1";
+ private static final String INTERACTIVE_TAG = "interactive";
+ private static final String NON_INTERACTIVE_TAG = "non-interactive";
+
private static final String PACKAGES_TAG = "packages";
private static final String PACKAGE_TAG = "package";
@@ -99,6 +103,14 @@
}
}
+ private static Pair<Integer, Long> loadCountAndTime(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ int count = XmlUtils.readIntAttribute(parser, COUNT_ATTR, 0);
+ long time = XmlUtils.readLongAttribute(parser, TIME_ATTR, 0);
+ XmlUtils.skipCurrentTag(parser);
+ return new Pair<>(count, time);
+ }
+
private static void loadChooserCounts(
XmlPullParser parser, UsageStats usageStats, String action)
throws XmlPullParserException, IOException {
@@ -202,6 +214,14 @@
xml.endTag(null, PACKAGE_TAG);
}
+ private static void writeCountAndTime(XmlSerializer xml, String tag, int count, long time)
+ throws IOException {
+ xml.startTag(null, tag);
+ XmlUtils.writeIntAttribute(xml, COUNT_ATTR, count);
+ XmlUtils.writeLongAttribute(xml, TIME_ATTR, time);
+ xml.endTag(null, tag);
+ }
+
private static void writeChooserCounts(XmlSerializer xml, final UsageStats usageStats)
throws IOException {
if (usageStats == null || usageStats.mChooserCounts == null ||
@@ -320,6 +340,18 @@
final String tag = parser.getName();
switch (tag) {
+ case INTERACTIVE_TAG: {
+ Pair<Integer, Long> result = loadCountAndTime(parser);
+ statsOut.interactiveCount = result.first;
+ statsOut.interactiveDuration = result.second;
+ } break;
+
+ case NON_INTERACTIVE_TAG: {
+ Pair<Integer, Long> result = loadCountAndTime(parser);
+ statsOut.nonInteractiveCount = result.first;
+ statsOut.nonInteractiveDuration = result.second;
+ } break;
+
case PACKAGE_TAG:
loadUsageStats(parser, statsOut);
break;
@@ -346,6 +378,11 @@
public static void write(XmlSerializer xml, IntervalStats stats) throws IOException {
XmlUtils.writeLongAttribute(xml, END_TIME_ATTR, stats.endTime - stats.beginTime);
+ writeCountAndTime(xml, INTERACTIVE_TAG, stats.interactiveCount, stats.interactiveDuration);
+
+ writeCountAndTime(xml, NON_INTERACTIVE_TAG, stats.nonInteractiveCount,
+ stats.nonInteractiveDuration);
+
xml.startTag(null, PACKAGES_TAG);
final int statsCount = stats.packageStats.size();
for (int i = 0; i < statsCount; i++) {
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index afc3d59..6ad374b 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -17,6 +17,7 @@
package com.android.server.usage;
import android.app.usage.ConfigurationStats;
+import android.app.usage.EventStats;
import android.app.usage.TimeSparseArray;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStats;
@@ -191,21 +192,31 @@
}
for (IntervalStats stats : mCurrentStats) {
- if (event.mEventType == UsageEvents.Event.CONFIGURATION_CHANGE) {
- stats.updateConfigurationStats(newFullConfig, event.mTimeStamp);
- } else if (event.mEventType == UsageEvents.Event.CHOOSER_ACTION) {
- stats.updateChooserCounts(event.mPackage, event.mContentType, event.mAction);
- String[] annotations = event.mContentAnnotations;
- if (annotations != null) {
- for (String annotation : annotations) {
- stats.updateChooserCounts(event.mPackage, annotation, event.mAction);
+ switch (event.mEventType) {
+ case UsageEvents.Event.CONFIGURATION_CHANGE: {
+ stats.updateConfigurationStats(newFullConfig, event.mTimeStamp);
+ } break;
+ case UsageEvents.Event.CHOOSER_ACTION: {
+ stats.updateChooserCounts(event.mPackage, event.mContentType, event.mAction);
+ String[] annotations = event.mContentAnnotations;
+ if (annotations != null) {
+ for (String annotation : annotations) {
+ stats.updateChooserCounts(event.mPackage, annotation, event.mAction);
+ }
}
- }
- } else {
- stats.update(event.mPackage, event.mTimeStamp, event.mEventType);
- if (incrementAppLaunch) {
- stats.incrementAppLaunchCount(event.mPackage);
- }
+ } break;
+ case UsageEvents.Event.SCREEN_INTERACTIVE: {
+ stats.updateScreenInteractive(event.mTimeStamp);
+ } break;
+ case UsageEvents.Event.SCREEN_NON_INTERACTIVE: {
+ stats.updateScreenNonInteractive(event.mTimeStamp);
+ } break;
+ default: {
+ stats.update(event.mPackage, event.mTimeStamp, event.mEventType);
+ if (incrementAppLaunch) {
+ stats.incrementAppLaunchCount(event.mPackage);
+ }
+ } break;
}
}
@@ -246,6 +257,15 @@
}
};
+ private static final StatCombiner<EventStats> sEventStatsCombiner =
+ new StatCombiner<EventStats>() {
+ @Override
+ public void combine(IntervalStats stats, boolean mutable,
+ List<EventStats> accResult) {
+ stats.addEventStatsTo(accResult);
+ }
+ };
+
/**
* Generic query method that selects the appropriate IntervalStats for the specified time range
* and bucket, then calls the {@link com.android.server.usage.UsageStatsDatabase.StatCombiner}
@@ -325,6 +345,10 @@
return queryStats(bucketType, beginTime, endTime, sConfigStatsCombiner);
}
+ List<EventStats> queryEventStats(int bucketType, long beginTime, long endTime) {
+ return queryStats(bucketType, beginTime, endTime, sEventStatsCombiner);
+ }
+
UsageEvents queryEvents(final long beginTime, final long endTime,
boolean obfuscateInstantApps) {
final ArraySet<String> names = new ArraySet<>();
@@ -448,6 +472,7 @@
}
stat.updateConfigurationStats(null, mDailyExpiryDate.getTimeInMillis() - 1);
+ stat.commitTime(mDailyExpiryDate.getTimeInMillis() - 1);
}
persistActiveStats();
@@ -640,6 +665,18 @@
}
}
+ void printEventAggregation(IndentingPrintWriter pw, String label, int count, long duration,
+ boolean prettyDates) {
+ if (count != 0 || duration != 0) {
+ pw.print(label);
+ pw.print(": ");
+ pw.print(count);
+ pw.print("x for ");
+ pw.print(formatElapsedTime(duration, prettyDates));
+ pw.println();
+ }
+ }
+
void printIntervalStats(IndentingPrintWriter pw, IntervalStats stats,
boolean prettyDates, boolean skipEvents, String pkg) {
if (prettyDates) {
@@ -713,6 +750,13 @@
pw.println();
}
pw.decreaseIndent();
+ pw.println("event aggregations");
+ pw.increaseIndent();
+ printEventAggregation(pw, "screen-interactive", stats.interactiveCount,
+ stats.interactiveDuration, prettyDates);
+ printEventAggregation(pw, "screen-non-interactive", stats.nonInteractiveCount,
+ stats.nonInteractiveDuration, prettyDates);
+ pw.decreaseIndent();
}
// The last 24 hours of events is already printed in the non checkin dump
@@ -781,6 +825,10 @@
return "SLICE_PINNED";
case UsageEvents.Event.SLICE_PINNED_PRIV:
return "SLICE_PINNED_PRIV";
+ case UsageEvents.Event.SCREEN_INTERACTIVE:
+ return "SCREEN_INTERACTIVE";
+ case UsageEvents.Event.SCREEN_NON_INTERACTIVE:
+ return "SCREEN_NON_INTERACTIVE";
default:
return "UNKNOWN";
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 8b8310f..4683161 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -397,6 +397,15 @@
public static final String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
/**
+ * Where there is no preloaded voicemail number on a SIM card, specifies the carrier's default
+ * voicemail number for roaming network.
+ * When empty string, no default voicemail number is specified for roaming network.
+ * @hide
+ */
+ public static final String KEY_DEFAULT_VM_NUMBER_ROAMING_STRING =
+ "default_vm_number_roaming_string";
+
+ /**
* Flag that specifies to use the user's own phone number as the voicemail number when there is
* no pre-loaded voicemail number on the SIM card.
* <p>
@@ -1931,6 +1940,7 @@
sDefaults.putBoolean(KEY_NOTIFY_HANDOVER_VIDEO_FROM_LTE_TO_WIFI_BOOL, false);
sDefaults.putBoolean(KEY_SUPPORT_DOWNGRADE_VT_TO_AUDIO_BOOL, true);
sDefaults.putString(KEY_DEFAULT_VM_NUMBER_STRING, "");
+ sDefaults.putString(KEY_DEFAULT_VM_NUMBER_ROAMING_STRING, "");
sDefaults.putBoolean(KEY_CONFIG_TELEPHONY_USE_OWN_NUMBER_FOR_VOICEMAIL_BOOL, false);
sDefaults.putBoolean(KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS, true);
sDefaults.putBoolean(KEY_VILTE_DATA_IS_METERED_BOOL, true);
diff --git a/telephony/java/android/telephony/LocationAccessPolicy.java b/telephony/java/android/telephony/LocationAccessPolicy.java
index 6480aab..6db8e82 100644
--- a/telephony/java/android/telephony/LocationAccessPolicy.java
+++ b/telephony/java/android/telephony/LocationAccessPolicy.java
@@ -40,17 +40,19 @@
*/
public final class LocationAccessPolicy {
private static final String LOG_TAG = LocationAccessPolicy.class.getSimpleName();
+
/**
* API to determine if the caller has permissions to get cell location.
*
* @param pkgName Package name of the application requesting access
* @param uid The uid of the package
* @param pid The pid of the package
+ * @param throwOnDeniedPermission Whether to throw if the location permission is denied.
* @return boolean true or false if permissions is granted
*/
public static boolean canAccessCellLocation(@NonNull Context context, @NonNull String pkgName,
- int uid, int pid) throws SecurityException {
- Trace.beginSection("TelephonyLocationCheck");
+ int uid, int pid, boolean throwOnDeniedPermission) throws SecurityException {
+ Trace.beginSection("TelephonyLohcationCheck");
try {
// Always allow the phone process to access location. This avoid breaking legacy code
// that rely on public-facing APIs to access cell location, and it doesn't create a
@@ -65,9 +67,11 @@
// where a legacy app the user is not using tracks their location.
// Granting ACCESS_FINE_LOCATION to an app automatically grants it
// ACCESS_COARSE_LOCATION.
-
- if (context.checkPermission(Manifest.permission.ACCESS_COARSE_LOCATION, pid, uid) ==
- PackageManager.PERMISSION_DENIED) {
+ if (throwOnDeniedPermission) {
+ context.enforcePermission(Manifest.permission.ACCESS_COARSE_LOCATION,
+ pid, uid, "canAccessCellLocation");
+ } else if (context.checkPermission(Manifest.permission.ACCESS_COARSE_LOCATION,
+ pid, uid) == PackageManager.PERMISSION_DENIED) {
return false;
}
final int opCode = AppOpsManager.permissionToOpCode(
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 77413d9c..936505c 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -335,7 +335,7 @@
return this.mCountryIso;
}
- /** @return whether the subscription is an embedded one. */
+ /** @return whether the subscription is an eUICC one. */
public boolean isEmbedded() {
return this.mIsEmbedded;
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 472a6fb..7664b94 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1925,26 +1925,28 @@
*
* @param info The subscription to check.
* @return whether the app is authorized to manage this subscription per its metadata.
- * @throws UnsupportedOperationException if this subscription is not embedded.
+ * @throws IllegalArgumentException if this subscription is not embedded.
*/
public boolean canManageSubscription(SubscriptionInfo info) {
return canManageSubscription(info, mContext.getPackageName());
}
/**
- * Checks whether the given app is authorized to manage the given subscription according to its
- * metadata. Only supported for embedded subscriptions (if {@code SubscriptionInfo#isEmbedded}
+ * Checks whether the given app is authorized to manage the given subscription. An app can only
+ * be authorized if it is included in the {@link android.telephony.UiccAccessRule} of the
+ * {@link android.telephony.SubscriptionInfo} with the access status.
+ * Only supported for embedded subscriptions (if {@link SubscriptionInfo#isEmbedded}
* returns true).
*
* @param info The subscription to check.
* @param packageName Package name of the app to check.
- * @return whether the app is authorized to manage this subscription per its metadata.
- * @throws UnsupportedOperationException if this subscription is not embedded.
+ * @return whether the app is authorized to manage this subscription per its access rules.
+ * @throws IllegalArgumentException if this subscription is not embedded.
* @hide
*/
public boolean canManageSubscription(SubscriptionInfo info, String packageName) {
if (!info.isEmbedded()) {
- throw new UnsupportedOperationException("Not an embedded subscription");
+ throw new IllegalArgumentException("Not an embedded subscription");
}
if (info.getAccessRules() == null) {
return false;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a12a7a0..da5bd84 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -6349,34 +6349,39 @@
*
* @param enable Whether to enable mobile data.
*
- * @deprecated use {@link #setUserMobileDataEnabled(boolean)} instead.
*/
- @Deprecated
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void setDataEnabled(boolean enable) {
- setUserMobileDataEnabled(enable);
+ setDataEnabled(getSubId(SubscriptionManager.getDefaultDataSubscriptionId()), enable);
}
/**
* @hide
- * @deprecated use {@link #setUserMobileDataEnabled(boolean)} instead.
+ * @deprecated use {@link #setDataEnabled(boolean)} instead.
*/
@SystemApi
@Deprecated
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void setDataEnabled(int subId, boolean enable) {
- setUserMobileDataEnabled(subId, enable);
+ try {
+ Log.d(TAG, "setDataEnabled: enabled=" + enable);
+ ITelephony telephony = getITelephony();
+ if (telephony != null)
+ telephony.setUserDataEnabled(subId, enable);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#setUserDataEnabled", e);
+ }
}
/**
- * @deprecated use {@link #isUserMobileDataEnabled()} instead.
+ * @deprecated use {@link #isDataEnabled()} instead.
* @hide
*/
@SystemApi
@Deprecated
public boolean getDataEnabled() {
- return isUserMobileDataEnabled();
+ return isDataEnabled();
}
/**
@@ -6396,22 +6401,28 @@
* {@link ConnectivityManager#getRestrictBackgroundStatus}.
*
* @return true if mobile data is enabled.
- *
- * @deprecated use {@link #isUserMobileDataEnabled()} instead.
*/
- @Deprecated
public boolean isDataEnabled() {
- return isUserMobileDataEnabled();
+ return getDataEnabled(getSubId(SubscriptionManager.getDefaultDataSubscriptionId()));
}
/**
- * @deprecated use {@link #isUserMobileDataEnabled()} instead.
+ * @deprecated use {@link #isDataEnabled()} instead.
* @hide
*/
@Deprecated
@SystemApi
public boolean getDataEnabled(int subId) {
- return isUserMobileDataEnabled(subId);
+ boolean retVal = false;
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null)
+ retVal = telephony.isUserDataEnabled(subId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#isUserDataEnabled", e);
+ } catch (NullPointerException e) {
+ }
+ return retVal;
}
/** @hide */
@@ -7684,56 +7695,12 @@
}
/**
- * Turns mobile data on or off.
- * If the {@link TelephonyManager} object has been created with
- * {@link #createForSubscriptionId}, this API applies to the given subId.
- * Otherwise, it applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
- *
- * <p>Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
- * app has carrier privileges (see {@link #hasCarrierPrivileges}.
- *
- * @param enable Whether to enable mobile data.
- */
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public void setUserMobileDataEnabled(boolean enable) {
- setUserMobileDataEnabled(
- getSubId(SubscriptionManager.getDefaultDataSubscriptionId()), enable);
- }
-
- /**
- * Returns whether mobile data is enabled or not per user setting. There are other factors
- * that could disable mobile data, but they are not considered here.
- *
- * If this object has been created with {@link #createForSubscriptionId}, applies to the given
- * subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
- *
- * <p>Requires one of the following permissions:
- * {@link android.Manifest.permission#ACCESS_NETWORK_STATE ACCESS_NETWORK_STATE},
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}, or that the
- * calling app has carrier privileges (see {@link #hasCarrierPrivileges}.
- *
- * <p>Note that this does not take into account any data restrictions that may be present on the
- * calling app. Such restrictions may be inspected with
- * {@link ConnectivityManager#getRestrictBackgroundStatus}.
- *
- * @return true if mobile data is enabled.
- */
- @RequiresPermission(anyOf = {
- android.Manifest.permission.ACCESS_NETWORK_STATE,
- android.Manifest.permission.MODIFY_PHONE_STATE
- })
- public boolean isUserMobileDataEnabled() {
- return isUserMobileDataEnabled(
- getSubId(SubscriptionManager.getDefaultDataSubscriptionId()));
- }
-
- /**
* @hide
- * Unlike isUserMobileDataEnabled, this API also evaluates carrierDataEnabled,
- * policyDataEnabled etc to give a final decision.
+ * It's similar to isDataEnabled, but unlike isDataEnabled, this API also evaluates
+ * carrierDataEnabled, policyDataEnabled etc to give a final decision of whether mobile data is
+ * capable of using.
*/
- public boolean isMobileDataEnabled() {
+ public boolean isDataCapable() {
boolean retVal = false;
try {
int subId = getSubId(SubscriptionManager.getDefaultDataSubscriptionId());
@@ -7748,35 +7715,6 @@
}
/**
- * Utility class of {@link #isUserMobileDataEnabled()};
- */
- private boolean isUserMobileDataEnabled(int subId) {
- boolean retVal = false;
- try {
- ITelephony telephony = getITelephony();
- if (telephony != null)
- retVal = telephony.isUserDataEnabled(subId);
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#isUserDataEnabled", e);
- } catch (NullPointerException e) {
- }
- return retVal;
- }
-
- /** Utility method of {@link #setUserMobileDataEnabled(boolean)} */
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- private void setUserMobileDataEnabled(int subId, boolean enable) {
- try {
- Log.d(TAG, "setUserMobileDataEnabled: enabled=" + enable);
- ITelephony telephony = getITelephony();
- if (telephony != null)
- telephony.setUserDataEnabled(subId, enable);
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#setUserDataEnabled", e);
- }
- }
-
- /**
* In this mode, modem will not send specified indications when screen is off.
* @hide
*/
diff --git a/telephony/java/android/telephony/euicc/DownloadableSubscription.java b/telephony/java/android/telephony/euicc/DownloadableSubscription.java
index 88db22b..edf3b08 100644
--- a/telephony/java/android/telephony/euicc/DownloadableSubscription.java
+++ b/telephony/java/android/telephony/euicc/DownloadableSubscription.java
@@ -17,6 +17,7 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.app.PendingIntent;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.UiccAccessRule;
@@ -26,7 +27,14 @@
import com.android.internal.util.Preconditions;
-/** Information about a subscription which is available for download. */
+/**
+ * Information about a subscription which is downloadable to an eUICC using
+ * {@link EuiccManager#downloadSubscription(DownloadableSubscription, boolean, PendingIntent).
+ *
+ * <p>For example, a DownloadableSubscription can be created through an activation code parsed from
+ * a QR code. A server address can be parsed from the activation code to download more information
+ * about the profile, such as carrier name, access rules, etc.
+ */
public final class DownloadableSubscription implements Parcelable {
public static final Creator<DownloadableSubscription> CREATOR =
@@ -136,7 +144,15 @@
/**
* Create a DownloadableSubscription for the given activation code.
*
- * @param encodedActivationCode the activation code to use. Must not be null.
+ * <p>This fills the encodedActivationCode field. Other fields like confirmationCode,
+ * carrierName and accessRules may be filled in the implementation of
+ * {@code android.service.euicc.EuiccService} if exists.
+ *
+ * @param encodedActivationCode the activation code to use. An activation code can be parsed
+ * from a user scanned QR code. The format of activation code is defined in SGP.22. For
+ * example, "1$SMDP.GSMA.COM$04386-AGYFT-A74Y8-3F815$1.3.6.1.4.1.31746". For detail, see
+ * {@code com.android.euicc.data.ActivationCode}. Must not be null.
+ *
* @return the {@link DownloadableSubscription} which may be passed to
* {@link EuiccManager#downloadSubscription}.
*/
@@ -157,6 +173,9 @@
/**
* Returns the confirmation code.
+ *
+ * <p>As an example, the confirmation code can be input by the user through a carrier app or the
+ * UI component of the eUICC local profile assistant (LPA) application.
*/
@Nullable
public String getConfirmationCode() {
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index dff1c6f..b732d4d 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -142,11 +142,9 @@
"android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DETAILED_CODE";
/**
- * Key for an extra set on {@link #getDownloadableSubscriptionMetadata} PendingIntent result
+ * Key for an extra set on {@code #getDownloadableSubscriptionMetadata} PendingIntent result
* callbacks providing the downloadable subscription metadata.
- * @hide
*/
- @SystemApi
public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION =
"android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION";
diff --git a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
index 8b81b0d..bcad554 100644
--- a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
+++ b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
@@ -26,6 +26,7 @@
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -49,10 +50,11 @@
/**
* Handle preinstalled carrier apps which should be disabled until a matching SIM is inserted.
*
- * Evaluates the list of applications in config_disabledUntilUsedPreinstalledCarrierApps. We
- * want to disable each such application which is present on the system image until the user
- * inserts a SIM which causes that application to gain carrier privilege (indicating a "match"),
- * without interfering with the user if they opt to enable/disable the app explicitly.
+ * Evaluates the list of applications in
+ * {@link SystemConfig#getDisabledUntilUsedPreinstalledCarrierApps()}. We want to disable each
+ * such application which is present on the system image until the user inserts a SIM which
+ * causes that application to gain carrier privilege (indicating a "match"), without interfering
+ * with the user if they opt to enable/disable the app explicitly.
*
* So, for each such app, we either disable until used IFF the app is not carrier privileged AND
* in the default state (e.g. not explicitly DISABLED/DISABLED_BY_USER/ENABLED), or we enable if
@@ -76,8 +78,8 @@
Slog.d(TAG, "disableCarrierAppsUntilPrivileged");
}
SystemConfig config = SystemConfig.getInstance();
- String[] systemCarrierAppsDisabledUntilUsed = Resources.getSystem().getStringArray(
- com.android.internal.R.array.config_disabledUntilUsedPreinstalledCarrierApps);
+ ArraySet<String> systemCarrierAppsDisabledUntilUsed =
+ config.getDisabledUntilUsedPreinstalledCarrierApps();
ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed =
config.getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
disableCarrierAppsUntilPrivileged(callingPackage, packageManager, telephonyManager,
@@ -102,8 +104,10 @@
Slog.d(TAG, "disableCarrierAppsUntilPrivileged");
}
SystemConfig config = SystemConfig.getInstance();
- String[] systemCarrierAppsDisabledUntilUsed = Resources.getSystem().getStringArray(
- com.android.internal.R.array.config_disabledUntilUsedPreinstalledCarrierApps);
+ ArraySet<String> systemCarrierAppsDisabledUntilUsed =
+ config.getDisabledUntilUsedPreinstalledCarrierApps();
+
+
ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed =
config.getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
disableCarrierAppsUntilPrivileged(callingPackage, packageManager,
@@ -116,7 +120,7 @@
public static void disableCarrierAppsUntilPrivileged(String callingPackage,
IPackageManager packageManager, @Nullable TelephonyManager telephonyManager,
ContentResolver contentResolver, int userId,
- String[] systemCarrierAppsDisabledUntilUsed,
+ ArraySet<String> systemCarrierAppsDisabledUntilUsed,
ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed) {
List<ApplicationInfo> candidates = getDefaultCarrierAppCandidatesHelper(packageManager,
userId, systemCarrierAppsDisabledUntilUsed);
@@ -286,8 +290,8 @@
*/
public static List<ApplicationInfo> getDefaultCarrierAppCandidates(
IPackageManager packageManager, int userId) {
- String[] systemCarrierAppsDisabledUntilUsed = Resources.getSystem().getStringArray(
- com.android.internal.R.array.config_disabledUntilUsedPreinstalledCarrierApps);
+ ArraySet<String> systemCarrierAppsDisabledUntilUsed =
+ SystemConfig.getInstance().getDisabledUntilUsedPreinstalledCarrierApps();
return getDefaultCarrierAppCandidatesHelper(packageManager, userId,
systemCarrierAppsDisabledUntilUsed);
}
@@ -295,14 +299,19 @@
private static List<ApplicationInfo> getDefaultCarrierAppCandidatesHelper(
IPackageManager packageManager,
int userId,
- String[] systemCarrierAppsDisabledUntilUsed) {
- if (systemCarrierAppsDisabledUntilUsed == null
- || systemCarrierAppsDisabledUntilUsed.length == 0) {
+ ArraySet<String> systemCarrierAppsDisabledUntilUsed) {
+ if (systemCarrierAppsDisabledUntilUsed == null) {
return null;
}
- List<ApplicationInfo> apps = new ArrayList<>(systemCarrierAppsDisabledUntilUsed.length);
- for (int i = 0; i < systemCarrierAppsDisabledUntilUsed.length; i++) {
- String packageName = systemCarrierAppsDisabledUntilUsed[i];
+
+ int size = systemCarrierAppsDisabledUntilUsed.size();
+ if (size == 0) {
+ return null;
+ }
+
+ List<ApplicationInfo> apps = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ String packageName = systemCarrierAppsDisabledUntilUsed.valueAt(i);
ApplicationInfo ai =
getApplicationInfoIfSystemApp(packageManager, userId, packageName);
if (ai != null) {
diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/java/android/net/NetworkCapabilitiesTest.java
index c866371..941c94d 100644
--- a/tests/net/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/java/android/net/NetworkCapabilitiesTest.java
@@ -315,28 +315,26 @@
@Test
public void testEqualsNetCapabilities() {
- int CAPABILITY = NET_CAPABILITY_MMS; // An arbitrary not mutable capability.
-
NetworkCapabilities nc1 = new NetworkCapabilities();
NetworkCapabilities nc2 = new NetworkCapabilities();
assertTrue(nc1.equalsNetCapabilities(nc2));
assertEquals(nc1, nc2);
- nc1.addCapability(CAPABILITY);
+ nc1.addCapability(NET_CAPABILITY_MMS);
assertFalse(nc1.equalsNetCapabilities(nc2));
assertNotEquals(nc1, nc2);
- nc2.addCapability(CAPABILITY);
+ nc2.addCapability(NET_CAPABILITY_MMS);
assertTrue(nc1.equalsNetCapabilities(nc2));
assertEquals(nc1, nc2);
- nc1.addUnwantedCapability(CAPABILITY);
+ nc1.addUnwantedCapability(NET_CAPABILITY_INTERNET);
assertFalse(nc1.equalsNetCapabilities(nc2));
- nc2.addUnwantedCapability(CAPABILITY);
+ nc2.addUnwantedCapability(NET_CAPABILITY_INTERNET);
assertTrue(nc1.equalsNetCapabilities(nc2));
- nc1.removeCapability(CAPABILITY);
+ nc1.removeCapability(NET_CAPABILITY_INTERNET);
assertFalse(nc1.equalsNetCapabilities(nc2));
- nc2.removeCapability(CAPABILITY);
+ nc2.removeCapability(NET_CAPABILITY_INTERNET);
assertTrue(nc1.equalsNetCapabilities(nc2));
}
diff --git a/tools/stringslint/stringslint_sha.sh b/tools/stringslint/stringslint_sha.sh
index c79ba04..bd80bb4 100755
--- a/tools/stringslint/stringslint_sha.sh
+++ b/tools/stringslint/stringslint_sha.sh
@@ -1,4 +1,5 @@
#!/bin/bash
+LOCAL_DIR="$( dirname ${BASH_SOURCE} )"
git show --name-only --pretty=format: $1 | grep values/strings.xml | while read file; do
- python $ANDROID_BUILD_TOP/frameworks/base/tools/stringslint/stringslint.py <(git show $1:$file) <(git show $1^:$file)
+ python $LOCAL_DIR/stringslint.py <(git show $1:$file) <(git show $1^:$file)
done
diff --git a/wifi/java/android/net/wifi/rtt/RangingResult.java b/wifi/java/android/net/wifi/rtt/RangingResult.java
index 7fe85be..758a8d5 100644
--- a/wifi/java/android/net/wifi/rtt/RangingResult.java
+++ b/wifi/java/android/net/wifi/rtt/RangingResult.java
@@ -22,7 +22,6 @@
import android.annotation.SystemApi;
import android.net.MacAddress;
import android.net.wifi.aware.PeerHandle;
-import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
@@ -79,19 +78,24 @@
private final int mDistanceMm;
private final int mDistanceStdDevMm;
private final int mRssi;
+ private final int mNumAttemptedMeasurements;
+ private final int mNumSuccessfulMeasurements;
private final byte[] mLci;
private final byte[] mLcr;
private final long mTimestamp;
/** @hide */
public RangingResult(@RangeResultStatus int status, @NonNull MacAddress mac, int distanceMm,
- int distanceStdDevMm, int rssi, byte[] lci, byte[] lcr, long timestamp) {
+ int distanceStdDevMm, int rssi, int numAttemptedMeasurements,
+ int numSuccessfulMeasurements, byte[] lci, byte[] lcr, long timestamp) {
mStatus = status;
mMac = mac;
mPeerHandle = null;
mDistanceMm = distanceMm;
mDistanceStdDevMm = distanceStdDevMm;
mRssi = rssi;
+ mNumAttemptedMeasurements = numAttemptedMeasurements;
+ mNumSuccessfulMeasurements = numSuccessfulMeasurements;
mLci = lci == null ? EMPTY_BYTE_ARRAY : lci;
mLcr = lcr == null ? EMPTY_BYTE_ARRAY : lcr;
mTimestamp = timestamp;
@@ -99,13 +103,16 @@
/** @hide */
public RangingResult(@RangeResultStatus int status, PeerHandle peerHandle, int distanceMm,
- int distanceStdDevMm, int rssi, byte[] lci, byte[] lcr, long timestamp) {
+ int distanceStdDevMm, int rssi, int numAttemptedMeasurements,
+ int numSuccessfulMeasurements, byte[] lci, byte[] lcr, long timestamp) {
mStatus = status;
mMac = null;
mPeerHandle = peerHandle;
mDistanceMm = distanceMm;
mDistanceStdDevMm = distanceStdDevMm;
mRssi = rssi;
+ mNumAttemptedMeasurements = numAttemptedMeasurements;
+ mNumSuccessfulMeasurements = numSuccessfulMeasurements;
mLci = lci == null ? EMPTY_BYTE_ARRAY : lci;
mLcr = lcr == null ? EMPTY_BYTE_ARRAY : lcr;
mTimestamp = timestamp;
@@ -163,7 +170,9 @@
/**
* @return The standard deviation of the measured distance (in mm) to the device specified by
* {@link #getMacAddress()} or {@link #getPeerHandle()}. The standard deviation is calculated
- * over the measurements executed in a single RTT burst.
+ * over the measurements executed in a single RTT burst. The number of measurements is returned
+ * by {@link #getNumSuccessfulMeasurements()} - 0 successful measurements indicate that the
+ * standard deviation is not valid (a valid standard deviation requires at least 2 data points).
* <p>
* Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an
* exception.
@@ -191,6 +200,46 @@
}
/**
+ * @return The number of attempted measurements used in the RTT exchange resulting in this set
+ * of results. The number of successful measurements is returned by
+ * {@link #getNumSuccessfulMeasurements()} which at most, if there are no errors, will be 1 less
+ * that the number of attempted measurements.
+ * <p>
+ * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an
+ * exception.
+ */
+ public int getNumAttemptedMeasurements() {
+ if (mStatus != STATUS_SUCCESS) {
+ throw new IllegalStateException(
+ "getNumAttemptedMeasurements(): invoked on an invalid result: getStatus()="
+ + mStatus);
+ }
+ return mNumAttemptedMeasurements;
+ }
+
+ /**
+ * @return The number of successful measurements used to calculate the distance and standard
+ * deviation. If the number of successful measurements if 1 then then standard deviation,
+ * returned by {@link #getDistanceStdDevMm()}, is not valid (a 0 is returned for the standard
+ * deviation).
+ * <p>
+ * The total number of measurement attempts is returned by
+ * {@link #getNumAttemptedMeasurements()}. The number of successful measurements will be at
+ * most 1 less then the number of attempted measurements.
+ * <p>
+ * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an
+ * exception.
+ */
+ public int getNumSuccessfulMeasurements() {
+ if (mStatus != STATUS_SUCCESS) {
+ throw new IllegalStateException(
+ "getNumSuccessfulMeasurements(): invoked on an invalid result: getStatus()="
+ + mStatus);
+ }
+ return mNumSuccessfulMeasurements;
+ }
+
+ /**
* @return The Location Configuration Information (LCI) as self-reported by the peer. The format
* is specified in the IEEE 802.11-2016 specifications, section 9.4.2.22.10.
* <p>
@@ -269,6 +318,8 @@
dest.writeInt(mDistanceMm);
dest.writeInt(mDistanceStdDevMm);
dest.writeInt(mRssi);
+ dest.writeInt(mNumAttemptedMeasurements);
+ dest.writeInt(mNumSuccessfulMeasurements);
dest.writeByteArray(mLci);
dest.writeByteArray(mLcr);
dest.writeLong(mTimestamp);
@@ -296,15 +347,17 @@
int distanceMm = in.readInt();
int distanceStdDevMm = in.readInt();
int rssi = in.readInt();
+ int numAttemptedMeasurements = in.readInt();
+ int numSuccessfulMeasurements = in.readInt();
byte[] lci = in.createByteArray();
byte[] lcr = in.createByteArray();
long timestamp = in.readLong();
if (peerHandlePresent) {
return new RangingResult(status, peerHandle, distanceMm, distanceStdDevMm, rssi,
- lci, lcr, timestamp);
+ numAttemptedMeasurements, numSuccessfulMeasurements, lci, lcr, timestamp);
} else {
return new RangingResult(status, mac, distanceMm, distanceStdDevMm, rssi,
- lci, lcr, timestamp);
+ numAttemptedMeasurements, numSuccessfulMeasurements, lci, lcr, timestamp);
}
}
};
@@ -316,7 +369,9 @@
mMac).append(", peerHandle=").append(
mPeerHandle == null ? "<null>" : mPeerHandle.peerId).append(", distanceMm=").append(
mDistanceMm).append(", distanceStdDevMm=").append(mDistanceStdDevMm).append(
- ", rssi=").append(mRssi).append(", lci=").append(mLci).append(", lcr=").append(
+ ", rssi=").append(mRssi).append(", numAttemptedMeasurements=").append(
+ mNumAttemptedMeasurements).append(", numSuccessfulMeasurements=").append(
+ mNumSuccessfulMeasurements).append(", lci=").append(mLci).append(", lcr=").append(
mLcr).append(", timestamp=").append(mTimestamp).append("]").toString();
}
@@ -335,6 +390,8 @@
return mStatus == lhs.mStatus && Objects.equals(mMac, lhs.mMac) && Objects.equals(
mPeerHandle, lhs.mPeerHandle) && mDistanceMm == lhs.mDistanceMm
&& mDistanceStdDevMm == lhs.mDistanceStdDevMm && mRssi == lhs.mRssi
+ && mNumAttemptedMeasurements == lhs.mNumAttemptedMeasurements
+ && mNumSuccessfulMeasurements == lhs.mNumSuccessfulMeasurements
&& Arrays.equals(mLci, lhs.mLci) && Arrays.equals(mLcr, lhs.mLcr)
&& mTimestamp == lhs.mTimestamp;
}
@@ -342,6 +399,6 @@
@Override
public int hashCode() {
return Objects.hash(mStatus, mMac, mPeerHandle, mDistanceMm, mDistanceStdDevMm, mRssi,
- mLci, mLcr, mTimestamp);
+ mNumAttemptedMeasurements, mNumSuccessfulMeasurements, mLci, mLcr, mTimestamp);
}
}
diff --git a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
index 1e4cea1..ddddde9 100644
--- a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
@@ -78,7 +78,7 @@
List<RangingResult> results = new ArrayList<>();
results.add(
new RangingResult(RangingResult.STATUS_SUCCESS, MacAddress.BROADCAST_ADDRESS, 15, 5,
- 10, null, null, 666));
+ 10, 8, 5, null, null, 666));
RangingResultCallback callbackMock = mock(RangingResultCallback.class);
ArgumentCaptor<IRttCallback> callbackCaptor = ArgumentCaptor.forClass(IRttCallback.class);
@@ -232,13 +232,15 @@
int distanceCm = 105;
int distanceStdDevCm = 10;
int rssi = 5;
+ int numAttemptedMeasurements = 8;
+ int numSuccessfulMeasurements = 3;
long timestamp = System.currentTimeMillis();
byte[] lci = { 0x5, 0x6, 0x7 };
byte[] lcr = { 0x1, 0x2, 0x3, 0xA, 0xB, 0xC };
// RangingResults constructed with a MAC address
RangingResult result = new RangingResult(status, mac, distanceCm, distanceStdDevCm, rssi,
- lci, lcr, timestamp);
+ numAttemptedMeasurements, numSuccessfulMeasurements, lci, lcr, timestamp);
Parcel parcelW = Parcel.obtain();
result.writeToParcel(parcelW, 0);
@@ -254,7 +256,7 @@
// RangingResults constructed with a PeerHandle
result = new RangingResult(status, peerHandle, distanceCm, distanceStdDevCm, rssi,
- null, null, timestamp);
+ numAttemptedMeasurements, numSuccessfulMeasurements, null, null, timestamp);
parcelW = Parcel.obtain();
result.writeToParcel(parcelW, 0);
@@ -280,14 +282,16 @@
int distanceCm = 105;
int distanceStdDevCm = 10;
int rssi = 5;
+ int numAttemptedMeasurements = 10;
+ int numSuccessfulMeasurements = 3;
long timestamp = System.currentTimeMillis();
byte[] lci = { };
byte[] lcr = { };
- RangingResult rr1 = new RangingResult(status, mac, distanceCm, distanceStdDevCm, rssi, lci,
- lcr, timestamp);
- RangingResult rr2 = new RangingResult(status, mac, distanceCm, distanceStdDevCm, rssi, null,
- null, timestamp);
+ RangingResult rr1 = new RangingResult(status, mac, distanceCm, distanceStdDevCm, rssi,
+ numAttemptedMeasurements, numSuccessfulMeasurements, lci, lcr, timestamp);
+ RangingResult rr2 = new RangingResult(status, mac, distanceCm, distanceStdDevCm, rssi,
+ numAttemptedMeasurements, numSuccessfulMeasurements, null, null, timestamp);
assertEquals(rr1, rr2);
}