diff options
190 files changed, 6228 insertions, 3456 deletions
diff --git a/Android.bp b/Android.bp index fb018a5645c2..32bd40861839 100644 --- a/Android.bp +++ b/Android.bp @@ -691,7 +691,6 @@ java_defaults { "frameworks/av/media/libaudioclient/aidl", "frameworks/native/aidl/gui", "system/core/storaged/binder", - "system/netd/server/binder", "system/vold/binder", "system/bt/binder", "system/security/keystore/binder", diff --git a/api/current.txt b/api/current.txt index b8a37d492303..6ecb914a5723 100644 --- a/api/current.txt +++ b/api/current.txt @@ -78,6 +78,7 @@ package android { field public static final java.lang.String FOREGROUND_SERVICE = "android.permission.FOREGROUND_SERVICE"; field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS"; field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED"; + field public static final java.lang.String GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY = "android.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY"; field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE"; field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS"; field public static final java.lang.String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH"; @@ -90,6 +91,7 @@ package android { field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE"; field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS"; field public static final java.lang.String MANAGE_OWN_CALLS = "android.permission.MANAGE_OWN_CALLS"; + field public static final java.lang.String CALL_COMPANION_APP = "android.permission.CALL_COMPANION_APP"; field public static final java.lang.String MASTER_CLEAR = "android.permission.MASTER_CLEAR"; field public static final java.lang.String MEDIA_CONTENT_CONTROL = "android.permission.MEDIA_CONTENT_CONTROL"; field public static final java.lang.String MODIFY_AUDIO_SETTINGS = "android.permission.MODIFY_AUDIO_SETTINGS"; @@ -5948,6 +5950,15 @@ package android.app { field public static final int STYLE_SPINNER = 0; // 0x0 } + public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable { + ctor public RecoverableSecurityException(java.lang.Throwable, java.lang.CharSequence, android.app.RemoteAction); + method public int describeContents(); + method public android.app.RemoteAction getUserAction(); + method public java.lang.CharSequence getUserMessage(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.app.RecoverableSecurityException> CREATOR; + } + public final class RemoteAction implements android.os.Parcelable { ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent); method public android.app.RemoteAction clone(); @@ -5973,6 +5984,7 @@ package android.app { method public java.util.Set<java.lang.String> getAllowedDataTypes(); method public java.lang.CharSequence[] getChoices(); method public static java.util.Map<java.lang.String, android.net.Uri> getDataResultsFromIntent(android.content.Intent, java.lang.String); + method public int getEditChoicesBeforeSending(); method public android.os.Bundle getExtras(); method public java.lang.CharSequence getLabel(); method public java.lang.String getResultKey(); @@ -5982,6 +5994,9 @@ package android.app { method public static void setResultsSource(android.content.Intent, int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.app.RemoteInput> CREATOR; + field public static final int EDIT_CHOICES_BEFORE_SENDING_AUTO = 0; // 0x0 + field public static final int EDIT_CHOICES_BEFORE_SENDING_DISABLED = 1; // 0x1 + field public static final int EDIT_CHOICES_BEFORE_SENDING_ENABLED = 2; // 0x2 field public static final java.lang.String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData"; field public static final java.lang.String RESULTS_CLIP_LABEL = "android.remoteinput.results"; field public static final int SOURCE_CHOICE = 1; // 0x1 @@ -5996,6 +6011,7 @@ package android.app { method public android.app.RemoteInput.Builder setAllowDataType(java.lang.String, boolean); method public android.app.RemoteInput.Builder setAllowFreeFormInput(boolean); method public android.app.RemoteInput.Builder setChoices(java.lang.CharSequence[]); + method public android.app.RemoteInput.Builder setEditChoicesBeforeSending(int); method public android.app.RemoteInput.Builder setLabel(java.lang.CharSequence); } @@ -6433,6 +6449,13 @@ package android.app.admin { field public static final android.os.Parcelable.Creator<android.app.admin.ConnectEvent> CREATOR; } + public class DelegatedAdminReceiver extends android.content.BroadcastReceiver { + ctor public DelegatedAdminReceiver(); + method public java.lang.String onChoosePrivateKeyAlias(android.content.Context, android.content.Intent, int, android.net.Uri, java.lang.String); + method public void onNetworkLogsAvailable(android.content.Context, android.content.Intent, long, int); + method public void onReceive(android.content.Context, android.content.Intent); + } + public final class DeviceAdminInfo implements android.os.Parcelable { ctor public DeviceAdminInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public int describeContents(); @@ -6495,11 +6518,13 @@ package android.app.admin { method public void onUserStarted(android.content.Context, android.content.Intent, android.os.UserHandle); method public void onUserStopped(android.content.Context, android.content.Intent, android.os.UserHandle); method public void onUserSwitched(android.content.Context, android.content.Intent, android.os.UserHandle); + field public static final java.lang.String ACTION_CHOOSE_PRIVATE_KEY_ALIAS = "android.app.action.CHOOSE_PRIVATE_KEY_ALIAS"; field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLED = "android.app.action.DEVICE_ADMIN_DISABLED"; field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLE_REQUESTED = "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED"; field public static final java.lang.String ACTION_DEVICE_ADMIN_ENABLED = "android.app.action.DEVICE_ADMIN_ENABLED"; field public static final java.lang.String ACTION_LOCK_TASK_ENTERING = "android.app.action.LOCK_TASK_ENTERING"; field public static final java.lang.String ACTION_LOCK_TASK_EXITING = "android.app.action.LOCK_TASK_EXITING"; + field public static final java.lang.String ACTION_NETWORK_LOGS_AVAILABLE = "android.app.action.NETWORK_LOGS_AVAILABLE"; field public static final java.lang.String ACTION_PASSWORD_CHANGED = "android.app.action.ACTION_PASSWORD_CHANGED"; field public static final java.lang.String ACTION_PASSWORD_EXPIRING = "android.app.action.ACTION_PASSWORD_EXPIRING"; field public static final java.lang.String ACTION_PASSWORD_FAILED = "android.app.action.ACTION_PASSWORD_FAILED"; @@ -6573,6 +6598,7 @@ package android.app.admin { method public java.lang.CharSequence getOrganizationName(android.content.ComponentName); method public java.util.List<android.telephony.data.ApnSetting> getOverrideApns(android.content.ComponentName); method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName); + method public int getPasswordComplexity(); method public long getPasswordExpiration(android.content.ComponentName); method public long getPasswordExpirationTimeout(android.content.ComponentName); method public int getPasswordHistoryLength(android.content.ComponentName); @@ -6744,10 +6770,13 @@ package android.app.admin { field public static final java.lang.String DELEGATION_APP_RESTRICTIONS = "delegation-app-restrictions"; field public static final java.lang.String DELEGATION_BLOCK_UNINSTALL = "delegation-block-uninstall"; field public static final java.lang.String DELEGATION_CERT_INSTALL = "delegation-cert-install"; + field public static final java.lang.String DELEGATION_CERT_SELECTION = "delegation-cert-selection"; field public static final java.lang.String DELEGATION_ENABLE_SYSTEM_APP = "delegation-enable-system-app"; field public static final java.lang.String DELEGATION_INSTALL_EXISTING_PACKAGE = "delegation-install-existing-package"; field public static final java.lang.String DELEGATION_KEEP_UNINSTALLED_PACKAGES = "delegation-keep-uninstalled-packages"; + field public static final java.lang.String DELEGATION_NETWORK_LOGGING = "delegation-network-logging"; field public static final java.lang.String DELEGATION_PACKAGE_ACCESS = "delegation-package-access"; + field public static final java.lang.String DELEGATION_PACKAGE_INSTALLATION = "delegation-package-installation"; field public static final java.lang.String DELEGATION_PERMISSION_GRANT = "delegation-permission-grant"; field public static final int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2 field public static final int ENCRYPTION_STATUS_ACTIVE = 3; // 0x3 @@ -6826,6 +6855,10 @@ package android.app.admin { field public static final int LOCK_TASK_FEATURE_SYSTEM_INFO = 1; // 0x1 field public static final int MAKE_USER_EPHEMERAL = 2; // 0x2 field public static final java.lang.String MIME_TYPE_PROVISIONING_NFC = "application/com.android.managedprovisioning"; + field public static final int PASSWORD_COMPLEXITY_HIGH = 327680; // 0x50000 + field public static final int PASSWORD_COMPLEXITY_LOW = 65536; // 0x10000 + field public static final int PASSWORD_COMPLEXITY_MEDIUM = 196608; // 0x30000 + field public static final int PASSWORD_COMPLEXITY_NONE = 0; // 0x0 field public static final int PASSWORD_QUALITY_ALPHABETIC = 262144; // 0x40000 field public static final int PASSWORD_QUALITY_ALPHANUMERIC = 327680; // 0x50000 field public static final int PASSWORD_QUALITY_BIOMETRIC_WEAK = 32768; // 0x8000 @@ -7614,13 +7647,16 @@ package android.app.usage { method public java.lang.String getPackageName(); method public java.lang.String getShortcutId(); method public long getTimeStamp(); + field public static final int ACTIVITY_PAUSED = 2; // 0x2 + field public static final int ACTIVITY_RESUMED = 1; // 0x1 + field public static final int ACTIVITY_STOPPED = 23; // 0x17 field public static final int CONFIGURATION_CHANGE = 5; // 0x5 field public static final int FOREGROUND_SERVICE_START = 19; // 0x13 field public static final int FOREGROUND_SERVICE_STOP = 20; // 0x14 field public static final int KEYGUARD_HIDDEN = 18; // 0x12 field public static final int KEYGUARD_SHOWN = 17; // 0x11 - field public static final int MOVE_TO_BACKGROUND = 2; // 0x2 - field public static final int MOVE_TO_FOREGROUND = 1; // 0x1 + field public static final deprecated int MOVE_TO_BACKGROUND = 2; // 0x2 + field public static final deprecated 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 @@ -7637,9 +7673,11 @@ package android.app.usage { method public long getLastTimeForegroundServiceUsed(); method public long getLastTimeStamp(); method public long getLastTimeUsed(); + method public long getLastTimeVisible(); method public java.lang.String getPackageName(); method public long getTotalTimeForegroundServiceUsed(); method public long getTotalTimeInForeground(); + method public long getTotalTimeVisible(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.app.usage.UsageStats> CREATOR; } @@ -11235,6 +11273,7 @@ package android.content.pm { method public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getAllSessions(); method public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getMySessions(); method public android.content.pm.PackageInstaller.SessionInfo getSessionInfo(int); + method public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getStagedSessions(); method public android.content.pm.PackageInstaller.Session openSession(int) throws java.io.IOException; method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback); method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback, android.os.Handler); @@ -11273,6 +11312,7 @@ package android.content.pm { method public java.lang.String[] getNames() throws java.io.IOException; method public int getParentSessionId(); method public boolean isMultiPackage(); + method public boolean isStaged(); method public java.io.InputStream openRead(java.lang.String) throws java.io.IOException; method public java.io.OutputStream openWrite(java.lang.String, long, long) throws java.io.IOException; method public void removeChildSessionId(int); @@ -11311,6 +11351,7 @@ package android.content.pm { method public boolean isActive(); method public boolean isMultiPackage(); method public boolean isSealed(); + method public boolean isStaged(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionInfo> CREATOR; field public static final int INVALID_ID = -1; // 0xffffffff @@ -11329,6 +11370,7 @@ package android.content.pm { method public void setOriginatingUri(android.net.Uri); method public void setReferrerUri(android.net.Uri); method public void setSize(long); + method public void setStaged(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionParams> CREATOR; field public static final int MODE_FULL_INSTALL = 1; // 0x1 @@ -15724,6 +15766,7 @@ package android.graphics.text { public static class MeasuredText.Builder { ctor public MeasuredText.Builder(char[]); + ctor public MeasuredText.Builder(android.graphics.text.MeasuredText); method public android.graphics.text.MeasuredText.Builder appendReplacementRun(android.graphics.Paint, int, float); method public android.graphics.text.MeasuredText.Builder appendStyleRun(android.graphics.Paint, int, boolean); method public android.graphics.text.MeasuredText build(); @@ -23060,6 +23103,7 @@ package android.media { method public deprecated boolean isBluetoothA2dpOn(); method public boolean isBluetoothScoAvailableOffCall(); method public boolean isBluetoothScoOn(); + method public static boolean isHapticPlaybackSupported(); method public boolean isMicrophoneMute(); method public boolean isMusicActive(); method public static boolean isOffloadedPlaybackSupported(android.media.AudioFormat); @@ -23956,6 +24000,7 @@ package android.media { method public void releaseOutputBuffer(int, boolean); method public void releaseOutputBuffer(int, long); method public void reset(); + method public void setAudioPresentation(android.media.AudioPresentation); method public void setCallback(android.media.MediaCodec.Callback, android.os.Handler); method public void setCallback(android.media.MediaCodec.Callback); method public void setInputSurface(android.view.Surface); @@ -24946,6 +24991,7 @@ package android.media { field public static final int MUXER_OUTPUT_3GPP = 2; // 0x2 field public static final int MUXER_OUTPUT_HEIF = 3; // 0x3 field public static final int MUXER_OUTPUT_MPEG_4 = 0; // 0x0 + field public static final int MUXER_OUTPUT_OGG = 4; // 0x4 field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1 } @@ -25401,6 +25447,7 @@ package android.media { field public static final int AMR_WB = 2; // 0x2 field public static final int DEFAULT = 0; // 0x0 field public static final int HE_AAC = 4; // 0x4 + field public static final int OPUS = 7; // 0x7 field public static final int VORBIS = 6; // 0x6 } @@ -25451,6 +25498,7 @@ package android.media { field public static final int DEFAULT = 0; // 0x0 field public static final int MPEG_2_TS = 8; // 0x8 field public static final int MPEG_4 = 2; // 0x2 + field public static final int OGG = 11; // 0xb field public static final deprecated int RAW_AMR = 3; // 0x3 field public static final int THREE_GPP = 1; // 0x1 field public static final int WEBM = 9; // 0x9 @@ -35929,9 +35977,11 @@ package android.provider { } public final class CalendarContract { + method public static boolean startViewCalendarEventInManagedProfile(android.content.Context, long, long, long, boolean, int); field public static final java.lang.String ACCOUNT_TYPE_LOCAL = "LOCAL"; field public static final java.lang.String ACTION_EVENT_REMINDER = "android.intent.action.EVENT_REMINDER"; field public static final java.lang.String ACTION_HANDLE_CUSTOM_EVENT = "android.provider.calendar.action.HANDLE_CUSTOM_EVENT"; + field public static final java.lang.String ACTION_VIEW_WORK_CALENDAR_EVENT = "android.provider.calendar.action.VIEW_WORK_CALENDAR_EVENT"; field public static final java.lang.String AUTHORITY = "com.android.calendar"; field public static final java.lang.String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter"; field public static final android.net.Uri CONTENT_URI; @@ -35939,6 +35989,7 @@ package android.provider { field public static final java.lang.String EXTRA_EVENT_ALL_DAY = "allDay"; field public static final java.lang.String EXTRA_EVENT_BEGIN_TIME = "beginTime"; field public static final java.lang.String EXTRA_EVENT_END_TIME = "endTime"; + field public static final java.lang.String EXTRA_EVENT_ID = "id"; } public static final class CalendarContract.Attendees implements android.provider.BaseColumns android.provider.CalendarContract.AttendeesColumns android.provider.CalendarContract.EventsColumns { @@ -38469,10 +38520,13 @@ package android.provider { } public static final class Telephony.CarrierId implements android.provider.BaseColumns { + method public static android.net.Uri getPreciseCarrierIdUriForSubscriptionId(int); method public static android.net.Uri getUriForSubscriptionId(int); field public static final java.lang.String CARRIER_ID = "carrier_id"; field public static final java.lang.String CARRIER_NAME = "carrier_name"; field public static final android.net.Uri CONTENT_URI; + field public static final java.lang.String PRECISE_CARRIER_ID = "precise_carrier_id"; + field public static final java.lang.String PRECISE_CARRIER_ID_NAME = "precise_carrier_id_name"; } public static final class Telephony.Carriers implements android.provider.BaseColumns { @@ -40618,13 +40672,16 @@ package android.service.carrier { public class CarrierIdentifier implements android.os.Parcelable { ctor public CarrierIdentifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String); + ctor public CarrierIdentifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, int, int); ctor public CarrierIdentifier(byte[], java.lang.String, java.lang.String); method public int describeContents(); + method public int getCarrierId(); method public java.lang.String getGid1(); method public java.lang.String getGid2(); method public java.lang.String getImsi(); method public java.lang.String getMcc(); method public java.lang.String getMnc(); + method public int getPreciseCarrierId(); method public java.lang.String getSpn(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.service.carrier.CarrierIdentifier> CREATOR; @@ -43116,12 +43173,14 @@ package android.telecom { field public static final java.lang.String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT"; field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE"; field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE"; + field public static final java.lang.String EXTRA_IS_ENABLED = "android.telecom.extra.IS_ENABLED"; field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS"; field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE"; field public static final java.lang.String METADATA_INCLUDE_EXTERNAL_CALLS = "android.telecom.INCLUDE_EXTERNAL_CALLS"; field public static final java.lang.String METADATA_INCLUDE_SELF_MANAGED_CALLS = "android.telecom.INCLUDE_SELF_MANAGED_CALLS"; field public static final java.lang.String METADATA_IN_CALL_SERVICE_RINGING = "android.telecom.IN_CALL_SERVICE_RINGING"; field public static final java.lang.String METADATA_IN_CALL_SERVICE_UI = "android.telecom.IN_CALL_SERVICE_UI"; + field public static final java.lang.String METADATA_IN_CALL_SERVICE_CAR_MODE_UI = "android.telecom.IN_CALL_SERVICE_CAR_MODE_UI"; field public static final int PRESENTATION_ALLOWED = 1; // 0x1 field public static final int PRESENTATION_PAYPHONE = 4; // 0x4 field public static final int PRESENTATION_RESTRICTED = 2; // 0x2 @@ -43309,6 +43368,7 @@ package android.telephony { field public static final java.lang.String KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY = "call_forwarding_blocks_while_roaming_string_array"; field public static final java.lang.String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL = "carrier_allow_turnoff_ims_bool"; field public static final java.lang.String KEY_CARRIER_CALL_SCREENING_APP_STRING = "call_screening_app"; + field public static final java.lang.String KEY_CARRIER_CONFIG_VERSION_STRING = "carrier_config_version_string"; field public static final java.lang.String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS = "carrier_data_call_permanent_failure_strings"; field public static final java.lang.String KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT = "carrier_default_wfc_ims_mode_int"; field public static final java.lang.String KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT = "carrier_default_wfc_ims_roaming_mode_int"; @@ -44106,12 +44166,14 @@ package android.telephony { method public static int getSlotIndex(int); method public int[] getSubscriptionIds(int); method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int); + method public java.util.List<android.telephony.SubscriptionInfo> getSubscriptionsInGroup(int); method public boolean isActiveSubscriptionId(int); method public boolean isNetworkRoaming(int); method public static boolean isUsableSubscriptionId(int); method public static boolean isValidSubscriptionId(int); method public void removeOnOpportunisticSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener); method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener); + method public boolean removeSubscriptionsFromGroup(int[]); method public java.lang.String setSubscriptionGroup(int[]); method public void setSubscriptionOverrideCongested(int, boolean, long); method public void setSubscriptionOverrideUnmetered(int, boolean, long); @@ -44176,6 +44238,7 @@ package android.telephony { method public java.util.List<android.telephony.CellInfo> getAllCellInfo(); method public int getCallState(); method public android.os.PersistableBundle getCarrierConfig(); + method public int getCarrierIdFromSimMccMnc(); method public deprecated android.telephony.CellLocation getCellLocation(); method public java.util.Map<java.lang.Integer, java.util.List<android.telephony.emergency.EmergencyNumber>> getCurrentEmergencyNumberList(); method public java.util.Map<java.lang.Integer, java.util.List<android.telephony.emergency.EmergencyNumber>> getCurrentEmergencyNumberList(int); @@ -44213,6 +44276,8 @@ package android.telephony { method public java.lang.String getSimCountryIso(); method public java.lang.String getSimOperator(); method public java.lang.String getSimOperatorName(); + method public int getSimPreciseCarrierId(); + method public java.lang.CharSequence getSimPreciseCarrierIdName(); method public java.lang.String getSimSerialNumber(); method public int getSimState(); method public int getSimState(int); @@ -44269,6 +44334,7 @@ package android.telephony { field public static final java.lang.String ACTION_SHOW_VOICEMAIL_NOTIFICATION = "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION"; field public static final java.lang.String ACTION_SMS_APP_SERVICE = "android.telephony.action.SMS_APP_SERVICE"; field public static final java.lang.String ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED"; + field public static final java.lang.String ACTION_SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED"; field public static final int APPTYPE_CSIM = 4; // 0x4 field public static final int APPTYPE_ISIM = 5; // 0x5 field public static final int APPTYPE_RUIM = 3; // 0x3 @@ -44301,6 +44367,8 @@ package android.telephony { field public static final java.lang.String EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT = "android.telephony.extra.LAUNCH_VOICEMAIL_SETTINGS_INTENT"; field public static final java.lang.String EXTRA_NOTIFICATION_COUNT = "android.telephony.extra.NOTIFICATION_COUNT"; field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telephony.extra.PHONE_ACCOUNT_HANDLE"; + field public static final java.lang.String EXTRA_PRECISE_CARRIER_ID = "android.telephony.extra.PRECISE_CARRIER_ID"; + field public static final java.lang.String EXTRA_PRECISE_CARRIER_NAME = "android.telephony.extra.PRECISE_CARRIER_NAME"; field public static final java.lang.String EXTRA_STATE = "state"; field public static final java.lang.String EXTRA_STATE_IDLE; field public static final java.lang.String EXTRA_STATE_OFFHOOK; @@ -45263,6 +45331,7 @@ package android.text { public static class PrecomputedText.Params.Builder { ctor public PrecomputedText.Params.Builder(android.text.TextPaint); + ctor public PrecomputedText.Params.Builder(android.text.PrecomputedText.Params); method public android.text.PrecomputedText.Params build(); method public android.text.PrecomputedText.Params.Builder setBreakStrategy(int); method public android.text.PrecomputedText.Params.Builder setHyphenationFrequency(int); diff --git a/api/system-current.txt b/api/system-current.txt index 6db4ec75632d..feecdf8356ab 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4,7 +4,6 @@ package android { field public static final java.lang.String ACCESS_AMBIENT_LIGHT_STATS = "android.permission.ACCESS_AMBIENT_LIGHT_STATS"; field public static final java.lang.String ACCESS_BROADCAST_RADIO = "android.permission.ACCESS_BROADCAST_RADIO"; field public static final java.lang.String ACCESS_CACHE_FILESYSTEM = "android.permission.ACCESS_CACHE_FILESYSTEM"; - field public static final java.lang.String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES"; field public static final java.lang.String ACCESS_DRM_CERTIFICATES = "android.permission.ACCESS_DRM_CERTIFICATES"; field public static final deprecated java.lang.String ACCESS_FM_RADIO = "android.permission.ACCESS_FM_RADIO"; field public static final java.lang.String ACCESS_INSTANT_APPS = "android.permission.ACCESS_INSTANT_APPS"; @@ -14,14 +13,11 @@ package android { field public static final java.lang.String ACCESS_NOTIFICATIONS = "android.permission.ACCESS_NOTIFICATIONS"; field public static final java.lang.String ACCESS_SHORTCUTS = "android.permission.ACCESS_SHORTCUTS"; field public static final java.lang.String ACCESS_SURFACE_FLINGER = "android.permission.ACCESS_SURFACE_FLINGER"; - field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER"; field public static final java.lang.String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING"; field public static final java.lang.String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE"; field public static final java.lang.String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK"; field public static final java.lang.String AMBIENT_WALLPAPER = "android.permission.AMBIENT_WALLPAPER"; field public static final java.lang.String BACKUP = "android.permission.BACKUP"; - field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS"; - field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET"; field public static final java.lang.String BIND_AUGMENTED_AUTOFILL_SERVICE = "android.permission.BIND_AUGMENTED_AUTOFILL_SERVICE"; field public static final deprecated java.lang.String BIND_CONNECTION_SERVICE = "android.permission.BIND_CONNECTION_SERVICE"; field public static final java.lang.String BIND_CONTENT_CAPTURE_SERVICE = "android.permission.BIND_CONTENT_CAPTURE_SERVICE"; @@ -32,7 +28,6 @@ package android { field public static final java.lang.String BIND_NETWORK_RECOMMENDATION_SERVICE = "android.permission.BIND_NETWORK_RECOMMENDATION_SERVICE"; field public static final java.lang.String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE"; field public static final java.lang.String BIND_PRINT_RECOMMENDATION_SERVICE = "android.permission.BIND_PRINT_RECOMMENDATION_SERVICE"; - field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS"; field public static final java.lang.String BIND_RESOLVER_RANKER_SERVICE = "android.permission.BIND_RESOLVER_RANKER_SERVICE"; field public static final java.lang.String BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE = "android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE"; field public static final java.lang.String BIND_SETTINGS_SUGGESTIONS_SERVICE = "android.permission.BIND_SETTINGS_SUGGESTIONS_SERVICE"; @@ -42,18 +37,13 @@ package android { field public static final java.lang.String BIND_TEXTCLASSIFIER_SERVICE = "android.permission.BIND_TEXTCLASSIFIER_SERVICE"; field public static final java.lang.String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT"; field public static final java.lang.String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE"; - field public static final java.lang.String BLUETOOTH_PRIVILEGED = "android.permission.BLUETOOTH_PRIVILEGED"; field public static final java.lang.String BRICK = "android.permission.BRICK"; field public static final java.lang.String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE"; field public static final deprecated java.lang.String BROADCAST_NETWORK_PRIVILEGED = "android.permission.BROADCAST_NETWORK_PRIVILEGED"; - field public static final java.lang.String CALL_PRIVILEGED = "android.permission.CALL_PRIVILEGED"; field public static final java.lang.String CAMERA_DISABLE_TRANSMIT_LED = "android.permission.CAMERA_DISABLE_TRANSMIT_LED"; field public static final java.lang.String CAPTURE_AUDIO_HOTWORD = "android.permission.CAPTURE_AUDIO_HOTWORD"; - field public static final java.lang.String CAPTURE_AUDIO_OUTPUT = "android.permission.CAPTURE_AUDIO_OUTPUT"; field public static final java.lang.String CAPTURE_TV_INPUT = "android.permission.CAPTURE_TV_INPUT"; field public static final java.lang.String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE"; - field public static final java.lang.String CHANGE_COMPONENT_ENABLED_STATE = "android.permission.CHANGE_COMPONENT_ENABLED_STATE"; - field public static final java.lang.String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION"; field public static final java.lang.String CHANGE_DEVICE_IDLE_TEMP_WHITELIST = "android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"; field public static final java.lang.String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA"; field public static final java.lang.String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS"; @@ -63,22 +53,15 @@ package android { field public static final java.lang.String CONTROL_DISPLAY_SATURATION = "android.permission.CONTROL_DISPLAY_SATURATION"; field public static final java.lang.String CONTROL_INCALL_EXPERIENCE = "android.permission.CONTROL_INCALL_EXPERIENCE"; field public static final java.lang.String CONTROL_KEYGUARD_SECURE_NOTIFICATIONS = "android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS"; - field public static final java.lang.String CONTROL_LOCATION_UPDATES = "android.permission.CONTROL_LOCATION_UPDATES"; field public static final java.lang.String CONTROL_VPN = "android.permission.CONTROL_VPN"; field public static final java.lang.String CRYPT_KEEPER = "android.permission.CRYPT_KEEPER"; - field public static final java.lang.String DELETE_CACHE_FILES = "android.permission.DELETE_CACHE_FILES"; - field public static final java.lang.String DELETE_PACKAGES = "android.permission.DELETE_PACKAGES"; field public static final java.lang.String DEVICE_POWER = "android.permission.DEVICE_POWER"; - field public static final java.lang.String DIAGNOSTIC = "android.permission.DIAGNOSTIC"; field public static final java.lang.String DISPATCH_PROVISIONING_MESSAGE = "android.permission.DISPATCH_PROVISIONING_MESSAGE"; - field public static final java.lang.String DUMP = "android.permission.DUMP"; field public static final java.lang.String FORCE_BACK = "android.permission.FORCE_BACK"; field public static final java.lang.String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES"; - field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED"; field public static final java.lang.String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS"; field public static final java.lang.String GET_PROCESS_STATE_AND_OOM_SCORE = "android.permission.GET_PROCESS_STATE_AND_OOM_SCORE"; field public static final java.lang.String GET_TOP_ACTIVITY_INFO = "android.permission.GET_TOP_ACTIVITY_INFO"; - field public static final java.lang.String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH"; field public static final java.lang.String GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS = "android.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS"; field public static final java.lang.String GRANT_RUNTIME_PERMISSIONS = "android.permission.GRANT_RUNTIME_PERMISSIONS"; field public static final java.lang.String HARDWARE_TEST = "android.permission.HARDWARE_TEST"; @@ -86,8 +69,6 @@ package android { field public static final java.lang.String HIDE_NON_SYSTEM_OVERLAY_WINDOWS = "android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"; field public static final java.lang.String INJECT_EVENTS = "android.permission.INJECT_EVENTS"; field public static final java.lang.String INSTALL_GRANT_RUNTIME_PERMISSIONS = "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS"; - field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER"; - field public static final java.lang.String INSTALL_PACKAGES = "android.permission.INSTALL_PACKAGES"; field public static final java.lang.String INSTALL_PACKAGE_UPDATES = "android.permission.INSTALL_PACKAGE_UPDATES"; field public static final java.lang.String INSTALL_SELF_UPDATES = "android.permission.INSTALL_SELF_UPDATES"; field public static final java.lang.String INTENT_FILTER_VERIFICATION_AGENT = "android.permission.INTENT_FILTER_VERIFICATION_AGENT"; @@ -98,7 +79,6 @@ package android { field public static final java.lang.String INVOKE_CARRIER_SETUP = "android.permission.INVOKE_CARRIER_SETUP"; field public static final java.lang.String KILL_UID = "android.permission.KILL_UID"; field public static final java.lang.String LOCAL_MAC_ADDRESS = "android.permission.LOCAL_MAC_ADDRESS"; - field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE"; field public static final java.lang.String LOCK_DEVICE = "android.permission.LOCK_DEVICE"; field public static final java.lang.String LOOP_RADIO = "android.permission.LOOP_RADIO"; field public static final java.lang.String MANAGE_ACCESSIBILITY = "android.permission.MANAGE_ACCESSIBILITY"; @@ -118,18 +98,13 @@ package android { field public static final java.lang.String MANAGE_USB = "android.permission.MANAGE_USB"; field public static final java.lang.String MANAGE_USERS = "android.permission.MANAGE_USERS"; field public static final java.lang.String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE"; - field public static final java.lang.String MASTER_CLEAR = "android.permission.MASTER_CLEAR"; - field public static final java.lang.String MEDIA_CONTENT_CONTROL = "android.permission.MEDIA_CONTENT_CONTROL"; field public static final java.lang.String MODIFY_APPWIDGET_BIND_PERMISSIONS = "android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"; field public static final java.lang.String MODIFY_AUDIO_ROUTING = "android.permission.MODIFY_AUDIO_ROUTING"; field public static final java.lang.String MODIFY_CELL_BROADCASTS = "android.permission.MODIFY_CELL_BROADCASTS"; field public static final java.lang.String MODIFY_DAY_NIGHT_MODE = "android.permission.MODIFY_DAY_NIGHT_MODE"; field public static final deprecated java.lang.String MODIFY_NETWORK_ACCOUNTING = "android.permission.MODIFY_NETWORK_ACCOUNTING"; field public static final java.lang.String MODIFY_PARENTAL_CONTROLS = "android.permission.MODIFY_PARENTAL_CONTROLS"; - field public static final java.lang.String MODIFY_PHONE_STATE = "android.permission.MODIFY_PHONE_STATE"; field public static final java.lang.String MODIFY_QUIET_MODE = "android.permission.MODIFY_QUIET_MODE"; - field public static final java.lang.String MOUNT_FORMAT_FILESYSTEMS = "android.permission.MOUNT_FORMAT_FILESYSTEMS"; - field public static final java.lang.String MOUNT_UNMOUNT_FILESYSTEMS = "android.permission.MOUNT_UNMOUNT_FILESYSTEMS"; field public static final java.lang.String MOVE_PACKAGE = "android.permission.MOVE_PACKAGE"; field public static final java.lang.String NETWORK_MANAGED_PROVISIONING = "android.permission.NETWORK_MANAGED_PROVISIONING"; field public static final java.lang.String NETWORK_SETUP_WIZARD = "android.permission.NETWORK_SETUP_WIZARD"; @@ -138,7 +113,6 @@ package android { field public static final java.lang.String OBSERVE_APP_USAGE = "android.permission.OBSERVE_APP_USAGE"; field public static final java.lang.String OBSERVE_ROLE_HOLDERS = "android.permission.OBSERVE_ROLE_HOLDERS"; field public static final java.lang.String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG"; - field public static final java.lang.String PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS"; field public static final java.lang.String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT"; field public static final java.lang.String PEERS_MAC_ADDRESS = "android.permission.PEERS_MAC_ADDRESS"; field public static final java.lang.String PERFORM_CDMA_PROVISIONING = "android.permission.PERFORM_CDMA_PROVISIONING"; @@ -151,7 +125,6 @@ package android { field public static final java.lang.String READ_CONTENT_RATING_SYSTEMS = "android.permission.READ_CONTENT_RATING_SYSTEMS"; field public static final java.lang.String READ_DREAM_STATE = "android.permission.READ_DREAM_STATE"; field public static final java.lang.String READ_INSTALL_SESSIONS = "android.permission.READ_INSTALL_SESSIONS"; - field public static final java.lang.String READ_LOGS = "android.permission.READ_LOGS"; field public static final java.lang.String READ_NETWORK_USAGE_HISTORY = "android.permission.READ_NETWORK_USAGE_HISTORY"; field public static final java.lang.String READ_OEM_UNLOCK_STATE = "android.permission.READ_OEM_UNLOCK_STATE"; field public static final java.lang.String READ_PRINT_SERVICES = "android.permission.READ_PRINT_SERVICES"; @@ -163,7 +136,6 @@ package android { field public static final java.lang.String READ_WALLPAPER_INTERNAL = "android.permission.READ_WALLPAPER_INTERNAL"; field public static final java.lang.String READ_WIFI_CREDENTIAL = "android.permission.READ_WIFI_CREDENTIAL"; field public static final java.lang.String REAL_GET_TASKS = "android.permission.REAL_GET_TASKS"; - field public static final java.lang.String REBOOT = "android.permission.REBOOT"; field public static final java.lang.String RECEIVE_DATA_ACTIVITY_CHANGE = "android.permission.RECEIVE_DATA_ACTIVITY_CHANGE"; field public static final java.lang.String RECEIVE_DEVICE_CUSTOMIZATION_READY = "android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY"; field public static final java.lang.String RECEIVE_EMERGENCY_BROADCAST = "android.permission.RECEIVE_EMERGENCY_BROADCAST"; @@ -181,27 +153,19 @@ package android { field public static final java.lang.String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS"; field public static final java.lang.String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS"; field public static final java.lang.String SEND_DEVICE_CUSTOMIZATION_READY = "android.permission.SEND_DEVICE_CUSTOMIZATION_READY"; - field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE"; field public static final java.lang.String SEND_SHOW_SUSPENDED_APP_DETAILS = "android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS"; field public static final java.lang.String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION"; field public static final java.lang.String SERIAL_PORT = "android.permission.SERIAL_PORT"; field public static final java.lang.String SET_ACTIVITY_WATCHER = "android.permission.SET_ACTIVITY_WATCHER"; - field public static final java.lang.String SET_ALWAYS_FINISH = "android.permission.SET_ALWAYS_FINISH"; - field public static final java.lang.String SET_ANIMATION_SCALE = "android.permission.SET_ANIMATION_SCALE"; - field public static final java.lang.String SET_DEBUG_APP = "android.permission.SET_DEBUG_APP"; field public static final java.lang.String SET_HARMFUL_APP_WARNINGS = "android.permission.SET_HARMFUL_APP_WARNINGS"; field public static final java.lang.String SET_MEDIA_KEY_LISTENER = "android.permission.SET_MEDIA_KEY_LISTENER"; field public static final java.lang.String SET_ORIENTATION = "android.permission.SET_ORIENTATION"; field public static final java.lang.String SET_POINTER_SPEED = "android.permission.SET_POINTER_SPEED"; - field public static final java.lang.String SET_PROCESS_LIMIT = "android.permission.SET_PROCESS_LIMIT"; field public static final java.lang.String SET_SCREEN_COMPATIBILITY = "android.permission.SET_SCREEN_COMPATIBILITY"; - field public static final java.lang.String SET_TIME = "android.permission.SET_TIME"; field public static final java.lang.String SET_VOLUME_KEY_LONG_PRESS_LISTENER = "android.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER"; field public static final java.lang.String SET_WALLPAPER_COMPONENT = "android.permission.SET_WALLPAPER_COMPONENT"; field public static final java.lang.String SHOW_KEYGUARD_MESSAGE = "android.permission.SHOW_KEYGUARD_MESSAGE"; field public static final java.lang.String SHUTDOWN = "android.permission.SHUTDOWN"; - field public static final java.lang.String SIGNAL_PERSISTENT_PROCESSES = "android.permission.SIGNAL_PERSISTENT_PROCESSES"; - field public static final java.lang.String STATUS_BAR = "android.permission.STATUS_BAR"; field public static final java.lang.String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES"; field public static final java.lang.String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"; field public static final java.lang.String SUSPEND_APPS = "android.permission.SUSPEND_APPS"; @@ -210,18 +174,14 @@ package android { field public static final java.lang.String TV_VIRTUAL_REMOTE_CONTROLLER = "android.permission.TV_VIRTUAL_REMOTE_CONTROLLER"; field public static final java.lang.String UNLIMITED_SHORTCUTS_API_CALLS = "android.permission.UNLIMITED_SHORTCUTS_API_CALLS"; field public static final java.lang.String UPDATE_APP_OPS_STATS = "android.permission.UPDATE_APP_OPS_STATS"; - field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS"; field public static final java.lang.String UPDATE_LOCK = "android.permission.UPDATE_LOCK"; field public static final java.lang.String UPDATE_TIME_ZONE_RULES = "android.permission.UPDATE_TIME_ZONE_RULES"; field public static final java.lang.String USER_ACTIVITY = "android.permission.USER_ACTIVITY"; field public static final java.lang.String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK"; - field public static final java.lang.String WRITE_APN_SETTINGS = "android.permission.WRITE_APN_SETTINGS"; field public static final java.lang.String WRITE_DREAM_STATE = "android.permission.WRITE_DREAM_STATE"; field public static final java.lang.String WRITE_EMBEDDED_SUBSCRIPTIONS = "android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"; - field public static final java.lang.String WRITE_GSERVICES = "android.permission.WRITE_GSERVICES"; field public static final java.lang.String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE"; field public static final java.lang.String WRITE_OBB = "android.permission.WRITE_OBB"; - field public static final java.lang.String WRITE_SECURE_SETTINGS = "android.permission.WRITE_SECURE_SETTINGS"; } public static final class Manifest.permission_group { @@ -582,10 +542,6 @@ package android.app { package android.app.admin { - public class DeviceAdminReceiver extends android.content.BroadcastReceiver { - method public deprecated void onReadyForUserInitialization(android.content.Context, android.content.Intent); - } - public class DevicePolicyManager { method public java.lang.String getDeviceOwner(); method public android.content.ComponentName getDeviceOwnerComponentOnAnyUser(); @@ -634,10 +590,7 @@ package android.app.admin { } public final class SystemUpdatePolicy implements android.os.Parcelable { - method public int describeContents(); method public android.app.admin.SystemUpdatePolicy.InstallationOption getInstallationOptionAt(long); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.app.admin.SystemUpdatePolicy> CREATOR; field public static final int TYPE_PAUSE = 4; // 0x4 } @@ -946,6 +899,7 @@ package android.app.usage { } public static final class UsageEvents.Event { + method public int getInstanceId(); method public java.lang.String getNotificationChannelId(); field public static final int NOTIFICATION_INTERRUPTION = 12; // 0xc field public static final int NOTIFICATION_SEEN = 10; // 0xa @@ -1054,7 +1008,7 @@ package android.content { method public void setDetectNotResponding(long); } - public abstract class ContentResolver { + public abstract class ContentResolver implements android.content.ContentInterface { method public android.graphics.drawable.Drawable getTypeDrawable(java.lang.String); } @@ -3251,7 +3205,6 @@ package android.media.tv { method public void addBlockedRating(android.media.tv.TvContentRating); method public boolean captureFrame(java.lang.String, android.view.Surface, android.media.tv.TvStreamConfig); method public java.util.List<android.media.tv.TvStreamConfig> getAvailableTvStreamConfigList(java.lang.String); - method public java.util.List<android.media.tv.TvContentRating> getBlockedRatings(); method public java.util.List<android.media.tv.TvInputHardwareInfo> getHardwareList(); method public java.util.List<android.media.tv.TvContentRatingSystemInfo> getTvContentRatingSystemList(); method public boolean isSingleSessionActive(); @@ -3497,11 +3450,9 @@ package android.net { } public class TrafficStats { - method public static void clearThreadStatsUid(); method public static void setThreadStatsTagApp(); method public static void setThreadStatsTagBackup(); method public static void setThreadStatsTagRestore(); - method public static void setThreadStatsUid(int); } public class VpnService extends android.app.Service { @@ -3523,14 +3474,6 @@ package android.net { } -package android.net.http { - - public class X509TrustManagerExtensions { - method public boolean isSameTrustConfiguration(java.lang.String, java.lang.String); - } - -} - package android.net.wifi { public deprecated class RttManager { @@ -3754,7 +3697,6 @@ package android.net.wifi { method public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks(); method public android.net.wifi.WifiConfiguration getWifiApConfiguration(); method public int getWifiApState(); - method public boolean isDeviceToApRttSupported(); method public boolean isDeviceToDeviceRttSupported(); method public boolean isPortableHotspotSupported(); method public boolean isWifiApEnabled(); @@ -5205,28 +5147,6 @@ package android.service.notification { field public static final java.lang.String KEY_USER_SENTIMENT = "key_user_sentiment"; } - public final class Condition implements android.os.Parcelable { - ctor public Condition(android.net.Uri, java.lang.String, java.lang.String, java.lang.String, int, int, int); - method public android.service.notification.Condition copy(); - method public static boolean isValidId(android.net.Uri, java.lang.String); - method public static android.net.Uri.Builder newId(android.content.Context); - method public static java.lang.String relevanceToString(int); - method public static java.lang.String stateToString(int); - field public static final int FLAG_RELEVANT_ALWAYS = 2; // 0x2 - field public static final int FLAG_RELEVANT_NOW = 1; // 0x1 - field public static final java.lang.String SCHEME = "condition"; - field public static final int STATE_ERROR = 3; // 0x3 - field public static final int STATE_UNKNOWN = 2; // 0x2 - field public final int flags; - field public final int icon; - field public final java.lang.String line1; - field public final java.lang.String line2; - } - - public abstract class ConditionProviderService extends android.app.Service { - method public void onRequestConditions(int); - } - public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService { ctor public NotificationAssistantService(); method public final void adjustNotification(android.service.notification.Adjustment); @@ -5709,7 +5629,6 @@ package android.telecom { method public void clearPhoneAccounts(); method public android.telecom.TelecomAnalytics dumpAnalytics(); method public void enablePhoneAccount(android.telecom.PhoneAccountHandle, boolean); - method public boolean endCall(); method public java.util.List<android.telecom.PhoneAccountHandle> getAllPhoneAccountHandles(); method public java.util.List<android.telecom.PhoneAccount> getAllPhoneAccounts(); method public int getAllPhoneAccountsCount(); @@ -5721,7 +5640,6 @@ package android.telecom { method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsSupportingScheme(java.lang.String); method public boolean isInEmergencyCall(); method public boolean isRinging(); - method public boolean isTtySupported(); method public boolean setDefaultDialer(java.lang.String); field public static final java.lang.String EXTRA_CALL_BACK_INTENT = "android.telecom.extra.CALL_BACK_INTENT"; field public static final java.lang.String EXTRA_CLEAR_MISSED_CALLS_INTENT = "android.telecom.extra.CLEAR_MISSED_CALLS_INTENT"; @@ -5746,7 +5664,6 @@ package android.telephony { method public void overrideConfig(int, android.os.PersistableBundle); method public void updateConfigForPhoneId(int, java.lang.String); field public static final java.lang.String KEY_CARRIER_SETUP_APP_STRING = "carrier_setup_app_string"; - field public static final java.lang.String KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING = "config_plans_package_override_string"; } public class MbmsDownloadSession implements java.lang.AutoCloseable { @@ -5861,7 +5778,6 @@ package android.telephony { public final class SmsManager { method public void sendMultipartTextMessageWithoutPersisting(java.lang.String, java.lang.String, java.util.List<java.lang.String>, java.util.List<android.app.PendingIntent>, java.util.List<android.app.PendingIntent>); - method public void sendTextMessageWithoutPersisting(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent); field public static final int RESULT_CANCELLED = 23; // 0x17 field public static final int RESULT_ENCODING_ERROR = 18; // 0x12 field public static final int RESULT_ERROR_FDN_CHECK_FAILURE = 6; // 0x6 @@ -5888,15 +5804,9 @@ package android.telephony { public class SubscriptionManager { method public java.util.List<android.telephony.SubscriptionInfo> getAvailableSubscriptionInfoList(); - method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int); method public void requestEmbeddedSubscriptionInfoListRefresh(); method public void setDefaultDataSubId(int); method public void setDefaultSmsSubId(int); - method public void setSubscriptionOverrideCongested(int, boolean, long); - method public void setSubscriptionOverrideUnmetered(int, boolean, long); - method public void setSubscriptionPlans(int, java.util.List<android.telephony.SubscriptionPlan>); - field public static final java.lang.String ACTION_MANAGE_SUBSCRIPTION_PLANS = "android.telephony.action.MANAGE_SUBSCRIPTION_PLANS"; - field public static final java.lang.String ACTION_REFRESH_SUBSCRIPTION_PLANS = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS"; field public static final android.net.Uri ADVANCED_CALLING_ENABLED_CONTENT_URI; field public static final android.net.Uri VT_ENABLED_CONTENT_URI; field public static final android.net.Uri WFC_ENABLED_CONTENT_URI; @@ -5905,37 +5815,10 @@ package android.telephony { field public static final android.net.Uri WFC_ROAMING_MODE_CONTENT_URI; } - public final class SubscriptionPlan implements android.os.Parcelable { - method public java.util.Iterator<android.util.Range<java.time.ZonedDateTime>> cycleIterator(); - method public int describeContents(); - method public int getDataLimitBehavior(); - method public long getDataLimitBytes(); - method public long getDataUsageBytes(); - method public long getDataUsageTime(); - method public java.lang.CharSequence getSummary(); - method public java.lang.CharSequence getTitle(); - method public void writeToParcel(android.os.Parcel, int); - field public static final long BYTES_UNKNOWN = -1L; // 0xffffffffffffffffL - field public static final long BYTES_UNLIMITED = 9223372036854775807L; // 0x7fffffffffffffffL - field public static final android.os.Parcelable.Creator<android.telephony.SubscriptionPlan> CREATOR; - field public static final int LIMIT_BEHAVIOR_BILLED = 1; // 0x1 - field public static final int LIMIT_BEHAVIOR_DISABLED = 0; // 0x0 - field public static final int LIMIT_BEHAVIOR_THROTTLED = 2; // 0x2 - field public static final int LIMIT_BEHAVIOR_UNKNOWN = -1; // 0xffffffff - field public static final long TIME_UNKNOWN = -1L; // 0xffffffffffffffffL - } - public static class SubscriptionPlan.Builder { - method public android.telephony.SubscriptionPlan build(); - method public static android.telephony.SubscriptionPlan.Builder createNonrecurring(java.time.ZonedDateTime, java.time.ZonedDateTime); - method public static android.telephony.SubscriptionPlan.Builder createRecurring(java.time.ZonedDateTime, java.time.Period); method public static deprecated android.telephony.SubscriptionPlan.Builder createRecurringDaily(java.time.ZonedDateTime); method public static deprecated android.telephony.SubscriptionPlan.Builder createRecurringMonthly(java.time.ZonedDateTime); method public static deprecated android.telephony.SubscriptionPlan.Builder createRecurringWeekly(java.time.ZonedDateTime); - method public android.telephony.SubscriptionPlan.Builder setDataLimit(long, int); - method public android.telephony.SubscriptionPlan.Builder setDataUsage(long, long); - method public android.telephony.SubscriptionPlan.Builder setSummary(java.lang.CharSequence); - method public android.telephony.SubscriptionPlan.Builder setTitle(java.lang.CharSequence); } public final class TelephonyHistogram implements android.os.Parcelable { diff --git a/api/test-current.txt b/api/test-current.txt index 4717969902b9..8d8999e6a30b 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -5,7 +5,6 @@ package android { field public static final java.lang.String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING"; field public static final java.lang.String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE"; field public static final java.lang.String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE"; - field public static final java.lang.String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION"; field public static final java.lang.String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS"; field public static final java.lang.String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES"; field public static final java.lang.String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS"; @@ -1710,11 +1709,6 @@ package android.view { method public static int getLongPressTooltipHideTimeout(); } - public final class ViewTreeObserver { - method public void registerFrameCommitCallback(java.lang.Runnable); - method public boolean unregisterFrameCommitCallback(java.lang.Runnable); - } - public abstract interface WindowManager implements android.view.ViewManager { method public default void setShouldShowIme(int, boolean); method public default void setShouldShowSystemDecors(int, boolean); diff --git a/cmds/incident_helper/tests/KernelWakesParser_test.cpp b/cmds/incident_helper/tests/KernelWakesParser_test.cpp index f92d81361eab..573ca4f632e0 100644 --- a/cmds/incident_helper/tests/KernelWakesParser_test.cpp +++ b/cmds/incident_helper/tests/KernelWakesParser_test.cpp @@ -84,9 +84,9 @@ TEST_F(KernelWakesParserTest, Normal) { record1->set_event_count(8); record1->set_wakeup_count(0); record1->set_expire_count(0); - record1->set_active_since(0l); - record1->set_total_time(0l); - record1->set_max_time(0l); + record1->set_active_since(0L); + record1->set_total_time(0L); + record1->set_max_time(0L); record1->set_last_change(131348LL); record1->set_prevent_suspend_time(0LL); @@ -96,9 +96,9 @@ TEST_F(KernelWakesParserTest, Normal) { record2->set_event_count(143); record2->set_wakeup_count(0); record2->set_expire_count(0); - record2->set_active_since(0l); - record2->set_total_time(123l); - record2->set_max_time(3l); + record2->set_active_since(0L); + record2->set_total_time(123L); + record2->set_max_time(3L); record2->set_last_change(2067286206LL); record2->set_prevent_suspend_time(0LL); diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index af3da0cbf5ee..f928501b7c1a 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -196,8 +196,26 @@ public abstract class ActivityManagerInternal { public abstract void updateOomAdj(); public abstract void updateCpuStats(); - public abstract void updateUsageStats( + + /** + * Update battery stats on activity usage. + * @param activity + * @param uid + * @param userId + * @param started + */ + public abstract void updateBatteryStats( ComponentName activity, int uid, int userId, boolean resumed); + + /** + * Update UsageStats of the activity. + * @param activity + * @param userId + * @param event + * @param appToken ActivityRecord's appToken. + */ + public abstract void updateActivityUsageStats( + ComponentName activity, int userId, int event, IBinder appToken); public abstract void updateForegroundTimeIfOnBattery( String packageName, int uid, long cpuTimeDiff); public abstract void sendForegroundProfileChanged(int userId); diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java index 6fdf7c8b4fac..4d8c8563ad7c 100644 --- a/core/java/android/app/ActivityTaskManager.java +++ b/core/java/android/app/ActivityTaskManager.java @@ -303,9 +303,7 @@ public class ActivityTaskManager { * @param stackId Id of stack to move the top activity to pinned stack. * @param bounds Bounds to use for pinned stack. * @return True if the top activity of stack was successfully moved to the pinned stack. - * @hide */ - @TestApi @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) { try { @@ -318,9 +316,7 @@ public class ActivityTaskManager { /** * Start to enter lock task mode for given task by system(UI). * @param taskId Id of task to lock. - * @hide */ - @TestApi @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void startSystemLockTaskMode(int taskId) { try { @@ -332,9 +328,7 @@ public class ActivityTaskManager { /** * Stop lock task mode by system(UI). - * @hide */ - @TestApi @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void stopSystemLockTaskMode() { try { @@ -349,9 +343,7 @@ public class ActivityTaskManager { * @param taskId Id of the task to move. * @param stackId Id of the stack for task moving. * @param toTop Whether the given task should shown to top of stack. - * @hide */ - @TestApi @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void moveTaskToStack(int taskId, int stackId, boolean toTop) { try { @@ -366,9 +358,7 @@ public class ActivityTaskManager { * @param stackId Id of the stack to resize. * @param bounds Bounds to resize the stack to or {@code null} for fullscreen. * @param animate Whether we should play an animation for resizing stack. - * @hide */ - @TestApi @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void resizeStack(int stackId, Rect bounds, boolean animate) { try { @@ -383,9 +373,7 @@ public class ActivityTaskManager { * Resize task to given bounds. * @param taskId Id of task to resize. * @param bounds Bounds to resize task. - * @hide */ - @TestApi @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void resizeTask(int taskId, Rect bounds) { try { @@ -399,9 +387,7 @@ public class ActivityTaskManager { * Resize docked stack & its task to given stack & task bounds. * @param stackBounds Bounds to resize stack. * @param taskBounds Bounds to resize task. - * @hide */ - @TestApi @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void resizeDockedStack(Rect stackBounds, Rect taskBounds) { try { @@ -413,9 +399,7 @@ public class ActivityTaskManager { /** * List all activity stacks information. - * @hide */ - @TestApi @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public String listAllStacks() { final List<ActivityManager.StackInfo> stacks; @@ -438,7 +422,6 @@ public class ActivityTaskManager { * Clears launch params for the given package. * @param packageNames the names of the packages of which the launch params are to be cleared */ - @TestApi @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void clearLaunchParamsForPackages(List<String> packageNames) { try { diff --git a/core/java/android/app/RecoverableSecurityException.java b/core/java/android/app/RecoverableSecurityException.java index 6747004e8186..7cc3dab5866c 100644 --- a/core/java/android/app/RecoverableSecurityException.java +++ b/core/java/android/app/RecoverableSecurityException.java @@ -16,15 +16,13 @@ package android.app; -import android.content.ContentProvider; -import android.content.ContentResolver; +import android.annotation.NonNull; import android.content.Context; -import android.graphics.drawable.Icon; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; -import com.android.internal.util.Preconditions; +import java.util.Objects; /** * Specialization of {@link SecurityException} that contains additional @@ -35,18 +33,11 @@ import com.android.internal.util.Preconditions; * authentication credentials, or granting access. * <p> * If the receiving app is actively involved with the user, it should present - * the contained recovery details to help the user make forward progress. The - * {@link #showAsDialog(Activity)} and - * {@link #showAsNotification(Context, String)} methods are provided as a - * convenience, but receiving apps are encouraged to use - * {@link #getUserMessage()} and {@link #getUserAction()} to integrate in a more - * natural way if relevant. + * the contained recovery details to help the user make forward progress. * <p class="note"> * Note: legacy code that receives this exception may treat it as a general * {@link SecurityException}, and thus there is no guarantee that the messages * contained will be shown to the end user. - * - * @hide */ public final class RecoverableSecurityException extends SecurityException implements Parcelable { private static final String TAG = "RecoverableSecurityException"; @@ -78,53 +69,28 @@ public final class RecoverableSecurityException extends SecurityException implem * apps that observe {@link Activity#RESULT_OK} may choose to * immediately retry their operation. */ - public RecoverableSecurityException(Throwable cause, CharSequence userMessage, - RemoteAction userAction) { + public RecoverableSecurityException(@NonNull Throwable cause, @NonNull CharSequence userMessage, + @NonNull RemoteAction userAction) { super(cause.getMessage()); - mUserMessage = Preconditions.checkNotNull(userMessage); - mUserAction = Preconditions.checkNotNull(userAction); - } - - /** {@hide} */ - @Deprecated - public RecoverableSecurityException(Throwable cause, CharSequence userMessage, - CharSequence userActionTitle, PendingIntent userAction) { - this(cause, userMessage, - new RemoteAction( - Icon.createWithResource("android", - com.android.internal.R.drawable.ic_restart), - userActionTitle, userActionTitle, userAction)); + mUserMessage = Objects.requireNonNull(userMessage); + mUserAction = Objects.requireNonNull(userAction); } /** * Return short message describing the issue for end user audiences, which * may be shown in a notification or dialog. */ - public CharSequence getUserMessage() { + public @NonNull CharSequence getUserMessage() { return mUserMessage; } /** * Return primary action that will initiate the recovery. */ - public RemoteAction getUserAction() { + public @NonNull RemoteAction getUserAction() { return mUserAction; } - /** @removed */ - @Deprecated - public void showAsNotification(Context context) { - final NotificationManager nm = context.getSystemService(NotificationManager.class); - - // Create a channel per-sender, since we don't want one poorly behaved - // remote app to cause all of our notifications to be blocked - final String channelId = TAG + "_" + mUserAction.getActionIntent().getCreatorUid(); - nm.createNotificationChannel(new NotificationChannel(channelId, TAG, - NotificationManager.IMPORTANCE_DEFAULT)); - - showAsNotification(context, channelId); - } - /** * Convenience method that will show a very simple notification populated * with the details from this exception. @@ -142,6 +108,7 @@ public final class RecoverableSecurityException extends SecurityException implem * @param channelId the {@link NotificationChannel} to use, which must have * been already created using * {@link NotificationManager#createNotificationChannel}. + * @hide */ public void showAsNotification(Context context, String channelId) { final NotificationManager nm = context.getSystemService(NotificationManager.class); @@ -167,6 +134,8 @@ public final class RecoverableSecurityException extends SecurityException implem * <p> * This method will only display the most recent exception from any single * remote UID; dialogs from older exceptions will always be replaced. + * + * @hide */ public void showAsDialog(Activity activity) { final LocalDialog dialog = new LocalDialog(); diff --git a/core/java/android/app/RemoteInput.java b/core/java/android/app/RemoteInput.java index 85fe99d95969..ebbf317ad05d 100644 --- a/core/java/android/app/RemoteInput.java +++ b/core/java/android/app/RemoteInput.java @@ -93,6 +93,22 @@ public final class RemoteInput implements Parcelable { /** The user selected one of the choices from {@link #getChoices}. */ public static final int SOURCE_CHOICE = 1; + /** @hide */ + @IntDef(prefix = {"EDIT_CHOICES_BEFORE_SENDING_"}, + value = {EDIT_CHOICES_BEFORE_SENDING_AUTO, EDIT_CHOICES_BEFORE_SENDING_DISABLED, + EDIT_CHOICES_BEFORE_SENDING_ENABLED}) + @Retention(RetentionPolicy.SOURCE) + public @interface EditChoicesBeforeSending {} + + /** The platform will determine whether choices will be edited before being sent to the app. */ + public static final int EDIT_CHOICES_BEFORE_SENDING_AUTO = 0; + + /** Tapping on a choice should send the input immediately, without letting the user edit it. */ + public static final int EDIT_CHOICES_BEFORE_SENDING_DISABLED = 1; + + /** Tapping on a choice should let the user edit the input before it is sent to the app. */ + public static final int EDIT_CHOICES_BEFORE_SENDING_ENABLED = 2; + // Flags bitwise-ored to mFlags private static final int FLAG_ALLOW_FREE_FORM_INPUT = 0x1; @@ -103,17 +119,25 @@ public final class RemoteInput implements Parcelable { private final CharSequence mLabel; private final CharSequence[] mChoices; private final int mFlags; + @EditChoicesBeforeSending private final int mEditChoicesBeforeSending; private final Bundle mExtras; private final ArraySet<String> mAllowedDataTypes; private RemoteInput(String resultKey, CharSequence label, CharSequence[] choices, - int flags, Bundle extras, ArraySet<String> allowedDataTypes) { + int flags, int editChoicesBeforeSending, Bundle extras, + ArraySet<String> allowedDataTypes) { this.mResultKey = resultKey; this.mLabel = label; this.mChoices = choices; this.mFlags = flags; + this.mEditChoicesBeforeSending = editChoicesBeforeSending; this.mExtras = extras; this.mAllowedDataTypes = allowedDataTypes; + if (getEditChoicesBeforeSending() == EDIT_CHOICES_BEFORE_SENDING_ENABLED + && !getAllowFreeFormInput()) { + throw new IllegalArgumentException( + "setEditChoicesBeforeSending requires setAllowFreeFormInput"); + } } /** @@ -169,6 +193,15 @@ public final class RemoteInput implements Parcelable { } /** + * Gets whether tapping on a choice should let the user edit the input before it is sent to the + * app. + */ + @EditChoicesBeforeSending + public int getEditChoicesBeforeSending() { + return mEditChoicesBeforeSending; + } + + /** * Get additional metadata carried around with this remote input. */ public Bundle getExtras() { @@ -185,6 +218,8 @@ public final class RemoteInput implements Parcelable { private CharSequence mLabel; private CharSequence[] mChoices; private int mFlags = DEFAULT_FLAGS; + @EditChoicesBeforeSending + private int mEditChoicesBeforeSending = EDIT_CHOICES_BEFORE_SENDING_AUTO; /** * Create a builder object for {@link RemoteInput} objects. @@ -269,7 +304,20 @@ public final class RemoteInput implements Parcelable { */ @NonNull public Builder setAllowFreeFormInput(boolean allowFreeFormTextInput) { - setFlag(mFlags, allowFreeFormTextInput); + setFlag(FLAG_ALLOW_FREE_FORM_INPUT, allowFreeFormTextInput); + return this; + } + + /** + * Specifies whether tapping on a choice should let the user edit the input before it is + * sent to the app. The default is {@link #EDIT_CHOICES_BEFORE_SENDING_AUTO}. + * + * It cannot be used if {@link #setAllowFreeFormInput} has been set to false. + */ + @NonNull + public Builder setEditChoicesBeforeSending( + @EditChoicesBeforeSending int editChoicesBeforeSending) { + mEditChoicesBeforeSending = editChoicesBeforeSending; return this; } @@ -312,8 +360,8 @@ public final class RemoteInput implements Parcelable { */ @NonNull public RemoteInput build() { - return new RemoteInput( - mResultKey, mLabel, mChoices, mFlags, mExtras, mAllowedDataTypes); + return new RemoteInput(mResultKey, mLabel, mChoices, mFlags, mEditChoicesBeforeSending, + mExtras, mAllowedDataTypes); } } @@ -322,6 +370,7 @@ public final class RemoteInput implements Parcelable { mLabel = in.readCharSequence(); mChoices = in.readCharSequenceArray(); mFlags = in.readInt(); + mEditChoicesBeforeSending = in.readInt(); mExtras = in.readBundle(); mAllowedDataTypes = (ArraySet<String>) in.readArraySet(null); } @@ -507,6 +556,7 @@ public final class RemoteInput implements Parcelable { out.writeCharSequence(mLabel); out.writeCharSequenceArray(mChoices); out.writeInt(mFlags); + out.writeInt(mEditChoicesBeforeSending); out.writeBundle(mExtras); out.writeArraySet(mAllowedDataTypes); } diff --git a/core/java/android/app/admin/DelegatedAdminReceiver.java b/core/java/android/app/admin/DelegatedAdminReceiver.java new file mode 100644 index 000000000000..dc8dfdff2e00 --- /dev/null +++ b/core/java/android/app/admin/DelegatedAdminReceiver.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.admin; + +import static android.app.admin.DeviceAdminReceiver.ACTION_CHOOSE_PRIVATE_KEY_ALIAS; +import static android.app.admin.DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE; +import static android.app.admin.DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_ALIAS; +import static android.app.admin.DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_SENDER_UID; +import static android.app.admin.DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_URI; +import static android.app.admin.DeviceAdminReceiver.EXTRA_NETWORK_LOGS_COUNT; +import static android.app.admin.DeviceAdminReceiver.EXTRA_NETWORK_LOGS_TOKEN; + +import android.app.Service; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.security.KeyChain; +import android.util.Log; + +/** + * Base class for delegated apps to handle callbacks related to their delegated capabilities. + * + * <p>Delegated apps are apps that receive additional capabilities from the profile owner or + * device owner apps. Some of these capabilities involve the framework calling into the apps. + * To receive these callbacks, delegated apps should subclass this class and override the + * appropriate methods here. The subclassed receiver needs to be published in the app's + * manifest, with appropriate intent filters to mark which callbacks the receiver is interested + * in. An app can have multiple receivers as long as they listen for disjoint set of callbacks. + * For the manifest definitions, it must be protected by the + * {@link android.Manifest.permission#BIND_DEVICE_ADMIN} permission to ensure only + * the system can trigger these callbacks. + * + * <p>The callback methods happen on the main thread of the process. Thus long running + * operations must be done on another thread. Note that because a receiver + * is done once returning from its receive function, such long-running operations + * should probably be done in a {@link Service}. + * + * @see DevicePolicyManager#setDelegatedScopes + * @see DeviceAdminReceiver + */ +public class DelegatedAdminReceiver extends BroadcastReceiver { + private static final String TAG = "DelegatedAdminReceiver"; + + /** + * Allows this receiver to select the alias for a private key and certificate pair for + * authentication. If this method returns null, the default {@link android.app.Activity} will + * be shown that lets the user pick a private key and certificate pair. + * + * <p> This callback is only applicable if the delegated app has + * {@link DevicePolicyManager#DELEGATION_CERT_SELECTION} capability. Additionally, it must + * declare an intent fitler for {@link #ACTION_CHOOSE_PRIVATE_KEY_ALIAS} in the receiver's + * manifest in order to receive this callback. + * + * @param context The running context as per {@link #onReceive}. + * @param intent The received intent as per {@link #onReceive}. + * @param uid The uid asking for the private key and certificate pair. + * @param uri The URI to authenticate, may be null. + * @param alias The alias preselected by the client, or null. + * @return The private key alias to return and grant access to. + * @see KeyChain#choosePrivateKeyAlias + */ + public String onChoosePrivateKeyAlias(Context context, Intent intent, int uid, Uri uri, + String alias) { + return null; + } + + /** + * Called each time a new batch of network logs can be retrieved. This callback method will only + * ever be called when network logging is enabled. The logs can only be retrieved while network + * logging is enabled. + * + * <p>If a secondary user or profile is created, this callback won't be received until all users + * become affiliated again (even if network logging is enabled). It will also no longer be + * possible to retrieve the network logs batch with the most recent {@code batchToken} provided + * by this callback. See {@link DevicePolicyManager#setAffiliationIds}. + * + * <p> This callback is only applicable if the delegated app has + * {@link DevicePolicyManager#DELEGATION_NETWORK_LOGGING} capability. Additionally, it must + * declare an intent fitler for {@link #ACTION_NETWORK_LOGS_AVAILABLE} in the receiver's + * manifest in order to receive this callback. + * + * @param context The running context as per {@link #onReceive}. + * @param intent The received intent as per {@link #onReceive}. + * @param batchToken The token representing the current batch of network logs. + * @param networkLogsCount The total count of events in the current batch of network logs. + * @see DevicePolicyManager#retrieveNetworkLogs + */ + public void onNetworkLogsAvailable(Context context, Intent intent, long batchToken, + int networkLogsCount) { + } + + /** + * Intercept delegated device administrator broadcasts. Implementations should not override + * this method; implement the convenience callbacks for each action instead. + */ + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + + if (ACTION_CHOOSE_PRIVATE_KEY_ALIAS.equals(action)) { + int uid = intent.getIntExtra(EXTRA_CHOOSE_PRIVATE_KEY_SENDER_UID, -1); + Uri uri = intent.getParcelableExtra(EXTRA_CHOOSE_PRIVATE_KEY_URI); + String alias = intent.getStringExtra(EXTRA_CHOOSE_PRIVATE_KEY_ALIAS); + String chosenAlias = onChoosePrivateKeyAlias(context, intent, uid, uri, alias); + setResultData(chosenAlias); + } else if (ACTION_NETWORK_LOGS_AVAILABLE.equals(action)) { + long batchToken = intent.getLongExtra(EXTRA_NETWORK_LOGS_TOKEN, -1); + int networkLogsCount = intent.getIntExtra(EXTRA_NETWORK_LOGS_COUNT, 0); + onNetworkLogsAvailable(context, intent, batchToken, networkLogsCount); + } else { + Log.w(TAG, "Unhandled broadcast: " + action); + } + } +} diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java index 1c9477d08cb3..5a7124e1fdc6 100644 --- a/core/java/android/app/admin/DeviceAdminReceiver.java +++ b/core/java/android/app/admin/DeviceAdminReceiver.java @@ -23,7 +23,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.SystemApi; import android.app.Service; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -297,7 +296,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { /** * Broadcast action: notify that a new batch of network logs is ready to be collected. * @see DeviceAdminReceiver#onNetworkLogsAvailable - * @hide + * @see DelegatedAdminReceiver#onNetworkLogsAvailable */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) @BroadcastBehavior(explicitOnly = true) @@ -426,7 +425,11 @@ public class DeviceAdminReceiver extends BroadcastReceiver { */ public static final int BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE = 1; - /** @hide */ + /** + * Broadcast action: notify that some app is attempting to choose a KeyChain key. + * @see DeviceAdminReceiver#onChoosePrivateKeyAlias + * @see DelegatedAdminReceiver#onChoosePrivateKeyAlias + */ public static final String ACTION_CHOOSE_PRIVATE_KEY_ALIAS = "android.app.action.CHOOSE_PRIVATE_KEY_ALIAS"; @@ -755,7 +758,6 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @deprecated Do not use */ @Deprecated - @SystemApi public void onReadyForUserInitialization(Context context, Intent intent) { } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 81eac5a413a6..670f8db7c588 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -16,6 +16,7 @@ package android.app.admin; +import android.Manifest.permission; import android.annotation.CallbackExecutor; import android.annotation.ColorInt; import android.annotation.IntDef; @@ -66,6 +67,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.UserManager.UserOperationException; import android.os.UserManager.UserOperationResult; +import android.provider.CalendarContract; import android.provider.ContactsContract.Directory; import android.provider.Settings; import android.security.AttestedKeyPair; @@ -1381,6 +1383,73 @@ public class DevicePolicyManager { = "android.app.action.SET_NEW_PASSWORD"; /** + * Constant for {@link #getPasswordComplexity()}: no password. + * + * <p>Note that these complexity constants are ordered so that higher values are more complex. + */ + public static final int PASSWORD_COMPLEXITY_NONE = 0; + + /** + * Constant for {@link #getPasswordComplexity()}: password satisfies one of the following: + * <ul> + * <li>pattern + * <li>PIN with repeating (4444) or ordered (1234, 4321, 2468) sequences + * </ul> + * + * <p>Note that these complexity constants are ordered so that higher values are more complex. + * + * @see #PASSWORD_QUALITY_SOMETHING + * @see #PASSWORD_QUALITY_NUMERIC + */ + public static final int PASSWORD_COMPLEXITY_LOW = 0x10000; + + /** + * Constant for {@link #getPasswordComplexity()}: password satisfies one of the following: + * <ul> + * <li>PIN with <b>no</b> repeating (4444) or ordered (1234, 4321, 2468) sequences, length at + * least 4 + * <li>alphabetic, length at least 4 + * <li>alphanumeric, length at least 4 + * </ul> + * + * <p>Note that these complexity constants are ordered so that higher values are more complex. + * + * @see #PASSWORD_QUALITY_NUMERIC_COMPLEX + * @see #PASSWORD_QUALITY_ALPHABETIC + * @see #PASSWORD_QUALITY_ALPHANUMERIC + */ + public static final int PASSWORD_COMPLEXITY_MEDIUM = 0x30000; + + /** + * Constant for {@link #getPasswordComplexity()}: password satisfies one of the following: + * <ul> + * <li>PIN with <b>no</b> repeating (4444) or ordered (1234, 4321, 2468) sequences, length at + * least 4 + * <li>alphabetic, length at least 6 + * <li>alphanumeric, length at least 6 + * </ul> + * + * <p>Note that these complexity constants are ordered so that higher values are more complex. + * + * @see #PASSWORD_QUALITY_NUMERIC_COMPLEX + * @see #PASSWORD_QUALITY_ALPHABETIC + * @see #PASSWORD_QUALITY_ALPHANUMERIC + */ + public static final int PASSWORD_COMPLEXITY_HIGH = 0x50000; + + /** + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"PASSWORD_COMPLEXITY_"}, value = { + PASSWORD_COMPLEXITY_NONE, + PASSWORD_COMPLEXITY_LOW, + PASSWORD_COMPLEXITY_MEDIUM, + PASSWORD_COMPLEXITY_HIGH, + }) + public @interface PasswordComplexity {} + + /** * Activity action: have the user enter a new password for the parent profile. * If the intent is launched from within a managed profile, this will trigger * entering a new password for the parent of the profile. In all other cases @@ -1546,12 +1615,46 @@ public class DevicePolicyManager { /** * Delegation of management of uninstalled packages. This scope grants access to the - * {@code #setKeepUninstalledPackages} and {@code #getKeepUninstalledPackages} APIs. + * {@link #setKeepUninstalledPackages} and {@link #getKeepUninstalledPackages} APIs. */ public static final String DELEGATION_KEEP_UNINSTALLED_PACKAGES = "delegation-keep-uninstalled-packages"; /** + * Grants access to {@link #setNetworkLoggingEnabled}, {@link #isNetworkLoggingEnabled} and + * {@link #retrieveNetworkLogs}. Once granted the delegated app will start receiving + * DelegatedAdminReceiver.onNetworkLogsAvailable() callback, and Device owner will no longer + * receive the DeviceAdminReceiver.onNetworkLogsAvailable() callback. + * There can be at most one app that has this delegation. + * If another app already had delegated network logging access, + * it will lose the delegation when a new app is delegated. + * + * <p> Can only be granted by Device Owner. + */ + public static final String DELEGATION_NETWORK_LOGGING = "delegation-network-logging"; + + /** + * Grants access to selection of KeyChain certificates on behalf of requesting apps. + * Once granted the app will start receiving + * DelegatedAdminReceiver.onChoosePrivateKeyAlias. The caller (PO/DO) will + * no longer receive {@link DeviceAdminReceiver#onChoosePrivateKeyAlias()}. + * There can be at most one app that has this delegation. + * If another app already had delegated certificate selection access, + * it will lose the delegation when a new app is delegated. + * + * <p> Can be granted by Device Owner or Profile Owner. + */ + public static final String DELEGATION_CERT_SELECTION = "delegation-cert-selection"; + + + /** + * Delegation of silent APK installation via {@link android.content.pm.PackageInstaller} APIs. + * + * <p> Can only be delegated by Device Owner. + */ + public static final String DELEGATION_PACKAGE_INSTALLATION = "delegation-package-installation"; + + /** * No management for current user in-effect. This is the default. * @hide */ @@ -3071,6 +3174,33 @@ public class DevicePolicyManager { } /** + * Returns how complex the current user's screen lock is. + * + * <p>Note that when called from a profile which uses an unified challenge with its parent, the + * screen lock complexity of the parent will be returned. However, this API does not support + * explicitly querying the parent profile screen lock complexity via {@link + * #getParentProfileInstance}. + * + * @throws IllegalStateException if the user is not unlocked. + * @throws SecurityException if the calling application does not have the permission + * {@link permission#GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY} + */ + @PasswordComplexity + @RequiresPermission(android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY) + public int getPasswordComplexity() { + throwIfParentInstance("getPasswordComplexity"); + if (mService == null) { + return PASSWORD_COMPLEXITY_NONE; + } + + try { + return mService.getPasswordComplexity(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * When called by a profile owner of a managed profile returns true if the profile uses unified * challenge with its parent user. * @@ -9238,7 +9368,8 @@ public class DevicePolicyManager { } /** - * Called by a device owner to control the network logging feature. + * Called by a device owner or delegated app with {@link #DELEGATION_NETWORK_LOGGING} to + * control the network logging feature. * * <p> Network logs contain DNS lookup and connect() library call events. The following library * functions are recorded while network logging is active: @@ -9275,16 +9406,17 @@ public class DevicePolicyManager { * all users to become affiliated. Therefore it's recommended that affiliation ids are set for * new users as soon as possible after provisioning via {@link #setAffiliationIds}. * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if called by a delegated app. * @param enabled whether network logging should be enabled or not. * @throws SecurityException if {@code admin} is not a device owner. * @see #setAffiliationIds * @see #retrieveNetworkLogs */ - public void setNetworkLoggingEnabled(@NonNull ComponentName admin, boolean enabled) { + public void setNetworkLoggingEnabled(@Nullable ComponentName admin, boolean enabled) { throwIfParentInstance("setNetworkLoggingEnabled"); try { - mService.setNetworkLoggingEnabled(admin, enabled); + mService.setNetworkLoggingEnabled(admin, mContext.getPackageName(), enabled); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } @@ -9294,7 +9426,8 @@ public class DevicePolicyManager { * Return whether network logging is enabled by a device owner. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Can only - * be {@code null} if the caller has MANAGE_USERS permission. + * be {@code null} if the caller is a delegated app with {@link #DELEGATION_NETWORK_LOGGING} + * or has MANAGE_USERS permission. * @return {@code true} if network logging is enabled by device owner, {@code false} otherwise. * @throws SecurityException if {@code admin} is not a device owner and caller has * no MANAGE_USERS permission @@ -9302,14 +9435,15 @@ public class DevicePolicyManager { public boolean isNetworkLoggingEnabled(@Nullable ComponentName admin) { throwIfParentInstance("isNetworkLoggingEnabled"); try { - return mService.isNetworkLoggingEnabled(admin); + return mService.isNetworkLoggingEnabled(admin, mContext.getPackageName()); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } } /** - * Called by device owner to retrieve the most recent batch of network logging events. + * Called by device owner or delegated app with {@link #DELEGATION_NETWORK_LOGGING} to retrieve + * the most recent batch of network logging events. * A device owner has to provide a batchToken provided as part of * {@link DeviceAdminReceiver#onNetworkLogsAvailable} callback. If the token doesn't match the * token of the most recent available batch of logs, {@code null} will be returned. @@ -9328,7 +9462,8 @@ public class DevicePolicyManager { * by {@link DeviceAdminReceiver#onNetworkLogsAvailable}. See * {@link DevicePolicyManager#setAffiliationIds}. * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if called by a delegated app. * @param batchToken A token of the batch to retrieve * @return A new batch of network logs which is a list of {@link NetworkEvent}. Returns * {@code null} if the batch represented by batchToken is no longer available or if @@ -9338,11 +9473,11 @@ public class DevicePolicyManager { * @see #setAffiliationIds * @see DeviceAdminReceiver#onNetworkLogsAvailable */ - public @Nullable List<NetworkEvent> retrieveNetworkLogs(@NonNull ComponentName admin, + public @Nullable List<NetworkEvent> retrieveNetworkLogs(@Nullable ComponentName admin, long batchToken) { throwIfParentInstance("retrieveNetworkLogs"); try { - return mService.retrieveNetworkLogs(admin, batchToken); + return mService.retrieveNetworkLogs(admin, mContext.getPackageName(), batchToken); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } @@ -10308,4 +10443,33 @@ public class DevicePolicyManager { } return false; } + + /** + * Starts an activity to view calendar events in the managed profile. + * + * @param eventId the id of the event to be viewed. + * @param start the start time of the event. + * @param end the end time of the event. + * @param allDay if the event is an all-day event. + * @param flags flags to be set for the intent + * @return {@code true} if the activity is started successfully. {@code false} otherwise. + * + * @see CalendarContract#startViewCalendarEventInManagedProfile(Context, String, long, long, + * long, boolean, int) + * + * @hide + */ + public boolean startViewCalendarEventInManagedProfile(long eventId, long start, long end, + boolean allDay, int flags) { + throwIfParentInstance("startViewCalendarEventInManagedProfile"); + if (mService != null) { + try { + return mService.startViewCalendarEventInManagedProfile(mContext.getPackageName(), + eventId, start, end, allDay, flags); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return false; + } } diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 1ff414619be1..568becfcdd1a 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -82,6 +82,7 @@ interface IDevicePolicyManager { boolean isActivePasswordSufficient(int userHandle, boolean parent); boolean isProfileActivePasswordSufficientForParent(int userHandle); + int getPasswordComplexity(); boolean isUsingUnifiedPassword(in ComponentName admin); int getCurrentFailedPasswordAttempts(int userHandle, boolean parent); int getProfileWithMinimumFailedPasswordsForWipe(int userHandle, boolean parent); @@ -366,9 +367,9 @@ interface IDevicePolicyManager { void setBackupServiceEnabled(in ComponentName admin, boolean enabled); boolean isBackupServiceEnabled(in ComponentName admin); - void setNetworkLoggingEnabled(in ComponentName admin, boolean enabled); - boolean isNetworkLoggingEnabled(in ComponentName admin); - List<NetworkEvent> retrieveNetworkLogs(in ComponentName admin, long batchToken); + void setNetworkLoggingEnabled(in ComponentName admin, in String packageName, boolean enabled); + boolean isNetworkLoggingEnabled(in ComponentName admin, in String packageName); + List<NetworkEvent> retrieveNetworkLogs(in ComponentName admin, in String packageName, long batchToken); boolean bindDeviceAdminServiceAsUser(in ComponentName admin, IApplicationThread caller, IBinder token, in Intent service, @@ -431,4 +432,6 @@ interface IDevicePolicyManager { boolean isManagedKiosk(); boolean isUnattendedManagedKiosk(); + + boolean startViewCalendarEventInManagedProfile(String packageName, long eventId, long start, long end, boolean allDay, int flags); } diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java index 5fee853275fb..8b41755f6dec 100644 --- a/core/java/android/app/admin/PasswordMetrics.java +++ b/core/java/android/app/admin/PasswordMetrics.java @@ -16,8 +16,14 @@ package android.app.admin; +import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH; +import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW; +import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM; +import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE; + import android.annotation.IntDef; import android.annotation.NonNull; +import android.app.admin.DevicePolicyManager.PasswordComplexity; import android.os.Parcel; import android.os.Parcelable; @@ -35,6 +41,8 @@ public class PasswordMetrics implements Parcelable { // consider it a complex PIN/password. public static final int MAX_ALLOWED_SEQUENCE = 3; + // TODO(b/120536847): refactor isActivePasswordSufficient logic so that the actual password + // quality is not overwritten public int quality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; public int length = 0; public int letters = 0; @@ -46,6 +54,10 @@ public class PasswordMetrics implements Parcelable { public PasswordMetrics() {} + public PasswordMetrics(int quality) { + this.quality = quality; + } + public PasswordMetrics(int quality, int length) { this.quality = quality; this.length = length; @@ -173,6 +185,15 @@ public class PasswordMetrics implements Parcelable { && this.nonLetter == o.nonLetter; } + private boolean satisfiesBucket(PasswordMetrics... bucket) { + for (PasswordMetrics metrics : bucket) { + if (this.quality == metrics.quality) { + return this.length >= metrics.length; + } + } + return false; + } + /* * Returns the maximum length of a sequential characters. A sequence is defined as * monotonically increasing characters with a constant interval or the same character repeated. @@ -254,4 +275,99 @@ public class PasswordMetrics implements Parcelable { return 0; } } + + /** Determines the {@link PasswordComplexity} of this {@link PasswordMetrics}. */ + @PasswordComplexity + public int determineComplexity() { + for (PasswordComplexityBucket bucket : PasswordComplexityBucket.BUCKETS) { + if (satisfiesBucket(bucket.getMetrics())) { + return bucket.mComplexityLevel; + } + } + return PASSWORD_COMPLEXITY_NONE; + } + + /** + * Requirements in terms of {@link PasswordMetrics} for each {@link PasswordComplexity}. + */ + public static class PasswordComplexityBucket { + /** + * Definition of {@link DevicePolicyManager#PASSWORD_COMPLEXITY_HIGH} in terms of + * {@link PasswordMetrics}. + */ + private static final PasswordComplexityBucket HIGH = + new PasswordComplexityBucket( + PASSWORD_COMPLEXITY_HIGH, + new PasswordMetrics( + DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, /* length= */ 6), + new PasswordMetrics( + DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC, /* length= */ 6), + new PasswordMetrics( + DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX, /* length= */ + 8)); + + /** + * Definition of {@link DevicePolicyManager#PASSWORD_COMPLEXITY_MEDIUM} in terms of + * {@link PasswordMetrics}. + */ + private static final PasswordComplexityBucket MEDIUM = + new PasswordComplexityBucket( + PASSWORD_COMPLEXITY_MEDIUM, + new PasswordMetrics( + DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, /* length= */ 4), + new PasswordMetrics( + DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC, /* length= */ 4), + new PasswordMetrics( + DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX, /* length= */ + 4)); + + /** + * Definition of {@link DevicePolicyManager#PASSWORD_COMPLEXITY_LOW} in terms of + * {@link PasswordMetrics}. + */ + private static final PasswordComplexityBucket LOW = + new PasswordComplexityBucket( + PASSWORD_COMPLEXITY_LOW, + new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC), + new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC), + new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX), + new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC), + new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)); + + /** + * A special bucket to represent {@link DevicePolicyManager#PASSWORD_COMPLEXITY_NONE}. + */ + private static final PasswordComplexityBucket NONE = + new PasswordComplexityBucket(PASSWORD_COMPLEXITY_NONE, new PasswordMetrics()); + + /** Array containing all buckets from high to low. */ + private static final PasswordComplexityBucket[] BUCKETS = + new PasswordComplexityBucket[] {HIGH, MEDIUM, LOW}; + + @PasswordComplexity + private final int mComplexityLevel; + private final PasswordMetrics[] mMetrics; + + private PasswordComplexityBucket(@PasswordComplexity int complexityLevel, + PasswordMetrics... metrics) { + this.mComplexityLevel = complexityLevel; + this.mMetrics = metrics; + } + + /** Returns the {@link PasswordMetrics} that meet the min requirements of this bucket. */ + public PasswordMetrics[] getMetrics() { + return mMetrics; + } + + /** Returns the bucket that {@code complexityLevel} represents. */ + public static PasswordComplexityBucket complexityLevelToBucket( + @PasswordComplexity int complexityLevel) { + for (PasswordComplexityBucket bucket : BUCKETS) { + if (bucket.mComplexityLevel == complexityLevel) { + return bucket; + } + } + return NONE; + } + } } diff --git a/core/java/android/app/admin/SystemUpdatePolicy.java b/core/java/android/app/admin/SystemUpdatePolicy.java index bcd5f6c7497f..dd7284540fef 100644 --- a/core/java/android/app/admin/SystemUpdatePolicy.java +++ b/core/java/android/app/admin/SystemUpdatePolicy.java @@ -689,13 +689,11 @@ public final class SystemUpdatePolicy implements Parcelable { mFreezePeriods.stream().map(n -> n.toString()).collect(Collectors.joining(","))); } - @SystemApi @Override public int describeContents() { return 0; } - @SystemApi @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mPolicyType); @@ -712,7 +710,6 @@ public final class SystemUpdatePolicy implements Parcelable { } } - @SystemApi public static final Parcelable.Creator<SystemUpdatePolicy> CREATOR = new Parcelable.Creator<SystemUpdatePolicy>() { diff --git a/core/java/android/app/usage/EventList.java b/core/java/android/app/usage/EventList.java index aaae57e526a0..a79ad2fc8607 100644 --- a/core/java/android/app/usage/EventList.java +++ b/core/java/android/app/usage/EventList.java @@ -103,4 +103,21 @@ public class EventList { } return result; } + + /** + * Remove events of certain type on or after a timestamp. + * @param type The type of event to remove. + * @param timeStamp the timeStamp on or after which to remove the event. + */ + public void removeOnOrAfter(int type, long timeStamp) { + for (int i = mEvents.size() - 1; i >= 0; i--) { + UsageEvents.Event event = mEvents.get(i); + if (event.mTimeStamp < timeStamp) { + break; + } + if (event.mEventType == type) { + mEvents.remove(i); + } + } + } } diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java index 3a5975aea628..a06213d77a68 100644 --- a/core/java/android/app/usage/UsageEvents.java +++ b/core/java/android/app/usage/UsageEvents.java @@ -50,13 +50,27 @@ public final class UsageEvents implements Parcelable { public static final int NONE = 0; /** + * @deprecated by {@link #ACTIVITY_RESUMED} + */ + @Deprecated + public static final int MOVE_TO_FOREGROUND = 1; + + /** * An event type denoting that an {@link android.app.Activity} moved to the foreground. * This event has a package name and class name associated with it and can be retrieved * using {@link #getPackageName()} and {@link #getClassName()}. * If a package has multiple activities, this event is reported for each activity that moves * to foreground. + * This event is corresponding to {@link android.app.Activity#onResume()} of the + * activity's lifecycle. */ - public static final int MOVE_TO_FOREGROUND = 1; + public static final int ACTIVITY_RESUMED = MOVE_TO_FOREGROUND; + + /** + * @deprecated by {@link #ACTIVITY_PAUSED} + */ + @Deprecated + public static final int MOVE_TO_BACKGROUND = 2; /** * An event type denoting that an {@link android.app.Activity} moved to the background. @@ -64,19 +78,21 @@ public final class UsageEvents implements Parcelable { * using {@link #getPackageName()} and {@link #getClassName()}. * If a package has multiple activities, this event is reported for each activity that moves * to background. + * This event is corresponding to {@link android.app.Activity#onPause()} of the activity's + * lifecycle. */ - public static final int MOVE_TO_BACKGROUND = 2; + public static final int ACTIVITY_PAUSED = MOVE_TO_BACKGROUND; /** * An event type denoting that a component was in the foreground when the stats - * rolled-over. This is effectively treated as a {@link #MOVE_TO_BACKGROUND}. + * rolled-over. This is effectively treated as a {@link #ACTIVITY_PAUSED}. * {@hide} */ public static final int END_OF_DAY = 3; /** * An event type denoting that a component was in the foreground the previous day. - * This is effectively treated as a {@link #MOVE_TO_FOREGROUND}. + * This is effectively treated as a {@link #ACTIVITY_RESUMED}. * {@hide} */ public static final int CONTINUE_PREVIOUS_DAY = 4; @@ -207,10 +223,31 @@ public final class UsageEvents implements Parcelable { public static final int ROLLOVER_FOREGROUND_SERVICE = 22; /** + * An activity becomes invisible on the UI, corresponding to + * {@link android.app.Activity#onStop()} of the activity's lifecycle. + */ + public static final int ACTIVITY_STOPPED = 23; + + /** + * An activity object is destroyed, corresponding to + * {@link android.app.Activity#onDestroy()} of the activity's lifecycle. + * {@hide} + */ + public static final int ACTIVITY_DESTROYED = 24; + + /** + * The event type demoting that a flush of UsageStatsDatabase to file system. Before the + * flush all usage stats need to be updated to latest timestamp to make sure the most + * up to date stats are persisted. + * @hide + */ + public static final int FLUSH_TO_DISK = 25; + + /** * Keep in sync with the greatest event type value. * @hide */ - public static final int MAX_EVENT_TYPE = 22; + public static final int MAX_EVENT_TYPE = 25; /** @hide */ public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0; @@ -240,6 +277,12 @@ public final class UsageEvents implements Parcelable { @UnsupportedAppUsage public String mClass; + + /** + * {@hide} + */ + public int mInstanceId; + /** * {@hide} */ @@ -311,9 +354,16 @@ public final class UsageEvents implements Parcelable { } /** @hide */ + public Event(int type, long timeStamp) { + mEventType = type; + mTimeStamp = timeStamp; + } + + /** @hide */ public Event(Event orig) { mPackage = orig.mPackage; mClass = orig.mClass; + mInstanceId = orig.mInstanceId; mTimeStamp = orig.mTimeStamp; mEventType = orig.mEventType; mConfiguration = orig.mConfiguration; @@ -342,6 +392,16 @@ public final class UsageEvents implements Parcelable { } /** + * An activity can be instantiated multiple times, this is the unique activity instance ID. + * For non-activity class, instance ID is always zero. + * @hide + */ + @SystemApi + public int getInstanceId() { + return mInstanceId; + } + + /** * The time at which this event occurred, measured in milliseconds since the epoch. * <p/> * See {@link System#currentTimeMillis()}. @@ -352,12 +412,14 @@ public final class UsageEvents implements Parcelable { /** * The event type. - * - * @see #MOVE_TO_BACKGROUND - * @see #MOVE_TO_FOREGROUND + * @see #ACTIVITY_PAUSED + * @see #ACTIVITY_RESUMED * @see #CONFIGURATION_CHANGE * @see #USER_INTERACTION * @see #STANDBY_BUCKET_CHANGED + * @see #FOREGROUND_SERVICE_START + * @see #FOREGROUND_SERVICE_STOP + * @see #ACTIVITY_STOPPED */ public int getEventType() { return mEventType; @@ -576,6 +638,7 @@ public final class UsageEvents implements Parcelable { } p.writeInt(packageIndex); p.writeInt(classIndex); + p.writeInt(event.mInstanceId); p.writeInt(event.mEventType); p.writeLong(event.mTimeStamp); @@ -618,6 +681,7 @@ public final class UsageEvents implements Parcelable { } else { eventOut.mClass = null; } + eventOut.mInstanceId = p.readInt(); eventOut.mEventType = p.readInt(); eventOut.mTimeStamp = p.readLong(); diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java index 73426e495037..8fb7f4cb4d99 100644 --- a/core/java/android/app/usage/UsageStats.java +++ b/core/java/android/app/usage/UsageStats.java @@ -16,13 +16,15 @@ package android.app.usage; -import static android.app.usage.UsageEvents.Event.CONTINUE_PREVIOUS_DAY; +import static android.app.usage.UsageEvents.Event.ACTIVITY_DESTROYED; +import static android.app.usage.UsageEvents.Event.ACTIVITY_PAUSED; +import static android.app.usage.UsageEvents.Event.ACTIVITY_RESUMED; +import static android.app.usage.UsageEvents.Event.ACTIVITY_STOPPED; import static android.app.usage.UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE; import static android.app.usage.UsageEvents.Event.END_OF_DAY; +import static android.app.usage.UsageEvents.Event.FLUSH_TO_DISK; import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_START; import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_STOP; -import static android.app.usage.UsageEvents.Event.MOVE_TO_BACKGROUND; -import static android.app.usage.UsageEvents.Event.MOVE_TO_FOREGROUND; import static android.app.usage.UsageEvents.Event.ROLLOVER_FOREGROUND_SERVICE; import android.annotation.SystemApi; @@ -31,6 +33,7 @@ import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.util.ArrayMap; +import android.util.SparseIntArray; /** * Contains usage statistics for an app package for a specific @@ -57,13 +60,20 @@ public final class UsageStats implements Parcelable { public long mEndTimeStamp; /** - * Last time used by the user with an explicit action (notification, activity launch) + * Last time an activity is at foreground (have focus), this is corresponding to + * {@link android.app.usage.UsageEvents.Event#ACTIVITY_RESUMED} event. * {@hide} */ @UnsupportedAppUsage public long mLastTimeUsed; /** + * Last time an activity is visible. + * @hide + */ + public long mLastTimeVisible; + + /** * Total time this package's activity is in foreground. * {@hide} */ @@ -71,6 +81,12 @@ public final class UsageStats implements Parcelable { public long mTotalTimeInForeground; /** + * Total time this package's activity is visible. + * {@hide} + */ + public long mTotalTimeVisible; + + /** * Last time foreground service is started. * {@hide} */ @@ -93,31 +109,32 @@ public final class UsageStats implements Parcelable { */ public int mAppLaunchCount; - /** Last activity MOVE_TO_FOREGROUND or MOVE_TO_BACKGROUND event. + /** Last activity ACTIVITY_RESUMED or ACTIVITY_PAUSED event. * {@hide} - * @deprecated use {@link #mLastForegroundActivityEventMap} instead. + * @deprecated use {@link #mActivities} instead. */ @UnsupportedAppUsage @Deprecated public int mLastEvent; /** - * If an activity is in foreground, it has one entry in this map. - * When activity moves to background, it is removed from this map. - * Key is activity class name. - * Value is last time this activity MOVE_TO_FOREGROUND or MOVE_TO_BACKGROUND event. + * If an activity is visible(onStart(), onPause() states) or in foreground (onResume() state), + * it has one entry in this map. When an activity becomes invisible (onStop() or onDestroy()), + * it is removed from this map. + * Key is instanceId of the activity (ActivityRecode appToken hashCode).. + * Value is this activity's last event, one of ACTIVITY_RESUMED or + * ACTIVITY_PAUSED. * {@hide} */ - public ArrayMap<String, Integer> mLastForegroundActivityEventMap = new ArrayMap<>(); - + public SparseIntArray mActivities = new SparseIntArray(); /** * If a foreground service is started, it has one entry in this map. - * When a foreground service is stopped, it is removed from this map. + * When a foreground service is stopped, it is removed from this set. * Key is foreground service class name. - * Value is last foreground service FOREGROUND_SERVICE_START ot FOREGROUND_SERVICE_STOP event. + * Value is the foreground service's last event, it is FOREGROUND_SERVICE_START. * {@hide} */ - public ArrayMap<String, Integer> mLastForegroundServiceEventMap = new ArrayMap<>(); + public ArrayMap<String, Integer> mForegroundServices = new ArrayMap<>(); /** * {@hide} @@ -135,14 +152,16 @@ public final class UsageStats implements Parcelable { mBeginTimeStamp = stats.mBeginTimeStamp; mEndTimeStamp = stats.mEndTimeStamp; mLastTimeUsed = stats.mLastTimeUsed; + mLastTimeVisible = stats.mLastTimeVisible; mLastTimeForegroundServiceUsed = stats.mLastTimeForegroundServiceUsed; mTotalTimeInForeground = stats.mTotalTimeInForeground; + mTotalTimeVisible = stats.mTotalTimeVisible; mTotalTimeForegroundServiceUsed = stats.mTotalTimeForegroundServiceUsed; mLaunchCount = stats.mLaunchCount; mAppLaunchCount = stats.mAppLaunchCount; mLastEvent = stats.mLastEvent; - mLastForegroundActivityEventMap = stats.mLastForegroundActivityEventMap; - mLastForegroundServiceEventMap = stats.mLastForegroundServiceEventMap; + mActivities = stats.mActivities; + mForegroundServices = stats.mForegroundServices; mChooserCounts = stats.mChooserCounts; } @@ -191,6 +210,14 @@ public final class UsageStats implements Parcelable { } /** + * Get the last time this package's activity is visible in the UI, measured in milliseconds + * since the epoch. + */ + public long getLastTimeVisible() { + return mLastTimeVisible; + } + + /** * Get the total time this package spent in the foreground, measured in milliseconds. */ public long getTotalTimeInForeground() { @@ -198,6 +225,13 @@ public final class UsageStats implements Parcelable { } /** + * Get the total time this package's activity is visible in the UI, measured in milliseconds. + */ + public long getTotalTimeVisible() { + return mTotalTimeVisible; + } + + /** * Get the last time this package's foreground service was used, measured in milliseconds since * the epoch. * <p/> @@ -224,6 +258,20 @@ public final class UsageStats implements Parcelable { return mAppLaunchCount; } + private void mergeEventMap(SparseIntArray left, SparseIntArray right) { + final int size = right.size(); + for (int i = 0; i < size; i++) { + final int instanceId = right.keyAt(i); + final int event = right.valueAt(i); + final int index = left.indexOfKey(instanceId); + if (index >= 0) { + left.put(instanceId, Math.max(left.valueAt(index), event)); + } else { + left.put(instanceId, event); + } + } + } + private void mergeEventMap(ArrayMap<String, Integer> left, ArrayMap<String, Integer> right) { final int size = right.size(); for (int i = 0; i < size; i++) { @@ -255,15 +303,17 @@ public final class UsageStats implements Parcelable { if (right.mBeginTimeStamp > mBeginTimeStamp) { // Even though incoming UsageStat begins after this one, its last time used fields // may somehow be empty or chronologically preceding the older UsageStat. - mergeEventMap(mLastForegroundActivityEventMap, right.mLastForegroundActivityEventMap); - mergeEventMap(mLastForegroundServiceEventMap, right.mLastForegroundServiceEventMap); + mergeEventMap(mActivities, right.mActivities); + mergeEventMap(mForegroundServices, right.mForegroundServices); mLastTimeUsed = Math.max(mLastTimeUsed, right.mLastTimeUsed); + mLastTimeVisible = Math.max(mLastTimeVisible, right.mLastTimeVisible); mLastTimeForegroundServiceUsed = Math.max(mLastTimeForegroundServiceUsed, right.mLastTimeForegroundServiceUsed); } mBeginTimeStamp = Math.min(mBeginTimeStamp, right.mBeginTimeStamp); mEndTimeStamp = Math.max(mEndTimeStamp, right.mEndTimeStamp); mTotalTimeInForeground += right.mTotalTimeInForeground; + mTotalTimeVisible += right.mTotalTimeVisible; mTotalTimeForegroundServiceUsed += right.mTotalTimeForegroundServiceUsed; mLaunchCount += right.mLaunchCount; mAppLaunchCount += right.mAppLaunchCount; @@ -290,36 +340,76 @@ public final class UsageStats implements Parcelable { } /** - * Tell if an event indicate activity is in foreground or not. - * @param event the activity event. - * @return true if activity is in foreground, false otherwise. - * @hide + * Tell if any activity is in foreground. + * @return */ - private boolean isActivityInForeground(int event) { - return event == MOVE_TO_FOREGROUND - || event == CONTINUE_PREVIOUS_DAY; + private boolean hasForegroundActivity() { + final int size = mActivities.size(); + for (int i = 0; i < size; i++) { + if (mActivities.valueAt(i) == ACTIVITY_RESUMED) { + return true; + } + } + return false; } /** - * Tell if an event indicate foreground sevice is started or not. - * @param event the foreground service event. - * @return true if foreground service is started, false if stopped. - * @hide + * Tell if any activity is visible. + * @return */ - private boolean isForegroundServiceStarted(int event) { - return event == FOREGROUND_SERVICE_START - || event == CONTINUING_FOREGROUND_SERVICE; + private boolean hasVisibleActivity() { + final int size = mActivities.size(); + for (int i = 0; i < size; i++) { + final int type = mActivities.valueAt(i); + if (type == ACTIVITY_RESUMED + || type == ACTIVITY_PAUSED) { + return true; + } + } + return false; } /** - * If any activity in foreground or any foreground service is started, the app is considered in - * use. - * @return true if in use, false otherwise. - * @hide + * Tell if any foreground service is started. + * @return + */ + private boolean anyForegroundServiceStarted() { + return !mForegroundServices.isEmpty(); + } + + /** + * Increment total time in foreground and update last time in foreground. + * @param timeStamp current timestamp. + */ + private void incrementTimeUsed(long timeStamp) { + if (timeStamp > mLastTimeUsed) { + mTotalTimeInForeground += timeStamp - mLastTimeUsed; + mLastTimeUsed = timeStamp; + } + } + + /** + * Increment total time visible and update last time visible. + * @param timeStamp current timestmap. */ - private boolean isAppInUse() { - return !mLastForegroundActivityEventMap.isEmpty() - || !mLastForegroundServiceEventMap.isEmpty(); + private void incrementTimeVisible(long timeStamp) { + if (timeStamp > mLastTimeVisible) { + mTotalTimeVisible += timeStamp - mLastTimeVisible; + mLastTimeVisible = timeStamp; + } + } + + /** + * Increment total time foreground service is used and update last time foreground service is + * used. + * @param timeStamp current timestamp. + */ + private void incrementServiceTimeUsed(long timeStamp) { + if (timeStamp > mLastTimeForegroundServiceUsed) { + mTotalTimeForegroundServiceUsed += + timeStamp - mLastTimeForegroundServiceUsed; + mLastTimeForegroundServiceUsed = timeStamp; + } } /** @@ -327,33 +417,63 @@ public final class UsageStats implements Parcelable { * @param className className of the activity. * @param timeStamp timeStamp of the event. * @param eventType type of the event. + * @param instanceId hashCode of the ActivityRecord's appToken. * @hide */ - private void updateForegroundActivity(String className, long timeStamp, int eventType) { - if (eventType != MOVE_TO_BACKGROUND - && eventType != MOVE_TO_FOREGROUND - && eventType != END_OF_DAY) { + private void updateActivity(String className, long timeStamp, int eventType, int instanceId) { + if (eventType != ACTIVITY_RESUMED + && eventType != ACTIVITY_PAUSED + && eventType != ACTIVITY_STOPPED + && eventType != ACTIVITY_DESTROYED) { return; } - final Integer lastEvent = mLastForegroundActivityEventMap.get(className); - if (lastEvent != null) { - if (isActivityInForeground(lastEvent)) { - if (timeStamp > mLastTimeUsed) { - mTotalTimeInForeground += timeStamp - mLastTimeUsed; + // update usage. + final int index = mActivities.indexOfKey(instanceId); + if (index >= 0) { + final int lastEvent = mActivities.valueAt(index); + switch (lastEvent) { + case ACTIVITY_RESUMED: + incrementTimeUsed(timeStamp); + incrementTimeVisible(timeStamp); + break; + case ACTIVITY_PAUSED: + incrementTimeVisible(timeStamp); + break; + default: + break; + } + } + + // update current event. + switch(eventType) { + case ACTIVITY_RESUMED: + if (!hasVisibleActivity()) { + // this is the first visible activity. + mLastTimeUsed = timeStamp; + mLastTimeVisible = timeStamp; + } else if (!hasForegroundActivity()) { + // this is the first foreground activity. mLastTimeUsed = timeStamp; } - } - if (eventType == MOVE_TO_BACKGROUND) { - mLastForegroundActivityEventMap.remove(className); - } else { - mLastForegroundActivityEventMap.put(className, eventType); - } - } else if (eventType == MOVE_TO_FOREGROUND) { - if (!isAppInUse()) { - mLastTimeUsed = timeStamp; - } - mLastForegroundActivityEventMap.put(className, eventType); + mActivities.put(instanceId, eventType); + break; + case ACTIVITY_PAUSED: + if (!hasVisibleActivity()) { + // this is the first visible activity. + mLastTimeVisible = timeStamp; + } + mActivities.put(instanceId, eventType); + break; + case ACTIVITY_STOPPED: + mActivities.put(instanceId, eventType); + break; + case ACTIVITY_DESTROYED: + // remove activity from the map. + mActivities.delete(instanceId); + break; + default: + break; } } @@ -366,80 +486,97 @@ public final class UsageStats implements Parcelable { */ private void updateForegroundService(String className, long timeStamp, int eventType) { if (eventType != FOREGROUND_SERVICE_STOP - && eventType != FOREGROUND_SERVICE_START - && eventType != ROLLOVER_FOREGROUND_SERVICE) { + && eventType != FOREGROUND_SERVICE_START) { return; } - final Integer lastEvent = mLastForegroundServiceEventMap.get(className); + final Integer lastEvent = mForegroundServices.get(className); + // update usage. if (lastEvent != null) { - if (isForegroundServiceStarted(lastEvent)) { - if (timeStamp > mLastTimeForegroundServiceUsed) { - mTotalTimeForegroundServiceUsed += - timeStamp - mLastTimeForegroundServiceUsed; + switch (lastEvent) { + case FOREGROUND_SERVICE_START: + case CONTINUING_FOREGROUND_SERVICE: + incrementServiceTimeUsed(timeStamp); + break; + default: + break; + } + } + + // update current event. + switch (eventType) { + case FOREGROUND_SERVICE_START: + if (!anyForegroundServiceStarted()) { mLastTimeForegroundServiceUsed = timeStamp; } - } - if (eventType == FOREGROUND_SERVICE_STOP) { - mLastForegroundServiceEventMap.remove(className); - } else { - mLastForegroundServiceEventMap.put(className, eventType); - } - } else if (eventType == FOREGROUND_SERVICE_START) { - if (!isAppInUse()) { - mLastTimeForegroundServiceUsed = timeStamp; - } - mLastForegroundServiceEventMap.put(className, eventType); + mForegroundServices.put(className, eventType); + break; + case FOREGROUND_SERVICE_STOP: + mForegroundServices.remove(className); + break; + default: + break; } } /** * Update the UsageStats by a activity or foreground service event. - * @param className class name of a activity or foreground service, could be null to mark - * END_OF_DAY or rollover. + * @param className class name of a activity or foreground service, could be null to if this + * is sent to all activities/services in this package. * @param timeStamp Epoch timestamp in milliseconds. * @param eventType event type as in {@link UsageEvents.Event} + * @param instanceId if className is an activity, the hashCode of ActivityRecord's appToken. + * if className is not an activity, instanceId is not used. * @hide */ - public void update(String className, long timeStamp, int eventType) { + public void update(String className, long timeStamp, int eventType, int instanceId) { switch(eventType) { - case MOVE_TO_BACKGROUND: - case MOVE_TO_FOREGROUND: - updateForegroundActivity(className, timeStamp, eventType); + case ACTIVITY_RESUMED: + case ACTIVITY_PAUSED: + case ACTIVITY_STOPPED: + case ACTIVITY_DESTROYED: + updateActivity(className, timeStamp, eventType, instanceId); break; case END_OF_DAY: - // END_OF_DAY means updating all activities. - final int size = mLastForegroundActivityEventMap.size(); - for (int i = 0; i < size; i++) { - final String name = mLastForegroundActivityEventMap.keyAt(i); - updateForegroundActivity(name, timeStamp, eventType); + // END_OF_DAY updates all activities. + if (hasForegroundActivity()) { + incrementTimeUsed(timeStamp); + } + if (hasVisibleActivity()) { + incrementTimeVisible(timeStamp); } break; - case CONTINUE_PREVIOUS_DAY: - mLastTimeUsed = timeStamp; - mLastForegroundActivityEventMap.put(className, eventType); - break; - case FOREGROUND_SERVICE_STOP: case FOREGROUND_SERVICE_START: + case FOREGROUND_SERVICE_STOP: updateForegroundService(className, timeStamp, eventType); break; case ROLLOVER_FOREGROUND_SERVICE: - // ROLLOVER_FOREGROUND_SERVICE means updating all foreground services. - final int size2 = mLastForegroundServiceEventMap.size(); - for (int i = 0; i < size2; i++) { - final String name = mLastForegroundServiceEventMap.keyAt(i); - updateForegroundService(name, timeStamp, eventType); + // ROLLOVER_FOREGROUND_SERVICE updates all foreground services. + if (anyForegroundServiceStarted()) { + incrementServiceTimeUsed(timeStamp); } break; case CONTINUING_FOREGROUND_SERVICE: mLastTimeForegroundServiceUsed = timeStamp; - mLastForegroundServiceEventMap.put(className, eventType); + mForegroundServices.put(className, eventType); + break; + case FLUSH_TO_DISK: + // update usage of all active activities/services. + if (hasForegroundActivity()) { + incrementTimeUsed(timeStamp); + } + if (hasVisibleActivity()) { + incrementTimeVisible(timeStamp); + } + if (anyForegroundServiceStarted()) { + incrementServiceTimeUsed(timeStamp); + } break; default: break; } mEndTimeStamp = timeStamp; - if (eventType == MOVE_TO_FOREGROUND) { + if (eventType == ACTIVITY_RESUMED) { mLaunchCount += 1; } } @@ -455,8 +592,10 @@ public final class UsageStats implements Parcelable { dest.writeLong(mBeginTimeStamp); dest.writeLong(mEndTimeStamp); dest.writeLong(mLastTimeUsed); + dest.writeLong(mLastTimeVisible); dest.writeLong(mLastTimeForegroundServiceUsed); dest.writeLong(mTotalTimeInForeground); + dest.writeLong(mTotalTimeVisible); dest.writeLong(mTotalTimeForegroundServiceUsed); dest.writeInt(mLaunchCount); dest.writeInt(mAppLaunchCount); @@ -477,21 +616,26 @@ public final class UsageStats implements Parcelable { } dest.writeBundle(allCounts); - final Bundle foregroundActivityEventBundle = new Bundle(); - final int foregroundEventSize = mLastForegroundActivityEventMap.size(); - for (int i = 0; i < foregroundEventSize; i++) { - foregroundActivityEventBundle.putInt(mLastForegroundActivityEventMap.keyAt(i), - mLastForegroundActivityEventMap.valueAt(i)); + writeSparseIntArray(dest, mActivities); + dest.writeBundle(eventMapToBundle(mForegroundServices)); + } + + private void writeSparseIntArray(Parcel dest, SparseIntArray arr) { + final int size = arr.size(); + dest.writeInt(size); + for (int i = 0; i < size; i++) { + dest.writeInt(arr.keyAt(i)); + dest.writeInt(arr.valueAt(i)); } - dest.writeBundle(foregroundActivityEventBundle); + } - final Bundle foregroundServiceEventBundle = new Bundle(); - final int foregroundServiceEventSize = mLastForegroundServiceEventMap.size(); - for (int i = 0; i < foregroundServiceEventSize; i++) { - foregroundServiceEventBundle.putInt(mLastForegroundServiceEventMap.keyAt(i), - mLastForegroundServiceEventMap.valueAt(i)); + private Bundle eventMapToBundle(ArrayMap<String, Integer> eventMap) { + final Bundle bundle = new Bundle(); + final int size = eventMap.size(); + for (int i = 0; i < size; i++) { + bundle.putInt(eventMap.keyAt(i), eventMap.valueAt(i)); } - dest.writeBundle(foregroundServiceEventBundle); + return bundle; } public static final Creator<UsageStats> CREATOR = new Creator<UsageStats>() { @@ -502,8 +646,10 @@ public final class UsageStats implements Parcelable { stats.mBeginTimeStamp = in.readLong(); stats.mEndTimeStamp = in.readLong(); stats.mLastTimeUsed = in.readLong(); + stats.mLastTimeVisible = in.readLong(); stats.mLastTimeForegroundServiceUsed = in.readLong(); stats.mTotalTimeInForeground = in.readLong(); + stats.mTotalTimeVisible = in.readLong(); stats.mTotalTimeForegroundServiceUsed = in.readLong(); stats.mLaunchCount = in.readInt(); stats.mAppLaunchCount = in.readInt(); @@ -527,12 +673,21 @@ public final class UsageStats implements Parcelable { } } } - readBundleToEventMap(stats.mLastForegroundActivityEventMap, in.readBundle()); - readBundleToEventMap(stats.mLastForegroundServiceEventMap, in.readBundle()); + readSparseIntArray(in, stats.mActivities); + readBundleToEventMap(in.readBundle(), stats.mForegroundServices); return stats; } - private void readBundleToEventMap(ArrayMap<String, Integer> eventMap, Bundle bundle) { + private void readSparseIntArray(Parcel in, SparseIntArray arr) { + final int size = in.readInt(); + for (int i = 0; i < size; i++) { + final int key = in.readInt(); + final int value = in.readInt(); + arr.put(key, value); + } + } + + private void readBundleToEventMap(Bundle bundle, ArrayMap<String, Integer> eventMap) { if (bundle != null) { for (String className : bundle.keySet()) { final int event = bundle.getInt(className); diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java index 1a656ab39373..2edad350e18e 100644 --- a/core/java/android/app/usage/UsageStatsManagerInternal.java +++ b/core/java/android/app/usage/UsageStatsManagerInternal.java @@ -37,9 +37,12 @@ public abstract class UsageStatsManagerInternal { * @param component The component for which this event occurred. * @param userId The user id to which the component belongs to. * @param eventType The event that occurred. Valid values can be found at - * {@link UsageEvents} + * {@link UsageEvents} + * @param instanceId For activity, hashCode of ActivityRecord's appToken. + * For non-activity, it is not used. */ - public abstract void reportEvent(ComponentName component, @UserIdInt int userId, int eventType); + public abstract void reportEvent(ComponentName component, @UserIdInt int userId, int eventType, + int instanceId); /** * Reports an event to the UsageStatsManager. diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl index ecc8cd678af1..a251c0036a78 100644 --- a/core/java/android/content/pm/IPackageInstaller.aidl +++ b/core/java/android/content/pm/IPackageInstaller.aidl @@ -42,6 +42,8 @@ interface IPackageInstaller { ParceledListSlice getAllSessions(int userId); ParceledListSlice getMySessions(String installerPackageName, int userId); + ParceledListSlice getStagedSessions(); + void registerCallback(IPackageInstallerCallback callback, int userId); void unregisterCallback(IPackageInstallerCallback callback); diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl index cef21f607e5f..04e15c7957bd 100644 --- a/core/java/android/content/pm/IPackageInstallerSession.aidl +++ b/core/java/android/content/pm/IPackageInstallerSession.aidl @@ -38,9 +38,12 @@ interface IPackageInstallerSession { void commit(in IntentSender statusReceiver, boolean forTransferred); void transfer(in String packageName); void abandon(); + boolean isMultiPackage(); int[] getChildSessionIds(); void addChildSessionId(in int sessionId); void removeChildSessionId(in int sessionId); int getParentSessionId(); + + boolean isStaged(); } diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 07672d979cf5..96c30f156105 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -463,6 +463,18 @@ public class PackageInstaller { } /** + * Return list of all staged install sessions. + */ + public @NonNull List<SessionInfo> getStagedSessions() { + try { + // TODO: limit this to the mUserId? + return mInstaller.getStagedSessions().getList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Uninstall the given package, removing it completely from the device. This * method is available to: * <ul> @@ -779,6 +791,11 @@ public class PackageInstaller { * individual session IDs can be added with {@link #addChildSessionId(int)} * and commit of the multi-package session will result in all child sessions * being committed atomically. + * <p> + * If a package requires to be installed only at reboot, the session should + * be marked as a staged session by calling {@link SessionParams#setStaged()} + * with {@code true}. This can also apply to a multi-package session, in + * which case all the packages in the session will be applied at reboot. */ public static class Session implements Closeable { /** {@hide} */ @@ -1105,6 +1122,17 @@ public class PackageInstaller { } /** + * @return {@code true} if this session will be staged and applied at next reboot. + */ + public boolean isStaged() { + try { + return mSession.isStaged(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * @return the session ID of the multi-package session that this belongs to or * {@link SessionInfo#INVALID_ID} if it does not belong to a multi-package session. */ @@ -1227,6 +1255,8 @@ public class PackageInstaller { public String installerPackageName; /** {@hide} */ public boolean isMultiPackage; + /** {@hide} */ + public boolean isStaged; /** * Construct parameters for a new package install session. @@ -1257,6 +1287,7 @@ public class PackageInstaller { grantedRuntimePermissions = source.readStringArray(); installerPackageName = source.readString(); isMultiPackage = source.readBoolean(); + isStaged = source.readBoolean(); } /** @@ -1471,6 +1502,17 @@ public class PackageInstaller { this.isMultiPackage = true; } + /** + * Set this session to be staged to be installed at reboot. + * + * Staged sessions are scheduled to be installed at next reboot. Staged sessions can also be + * multi-package. In that case, if any of the children sessions fail to install at reboot, + * all the other children sessions are aborted as well. + */ + public void setStaged() { + this.isStaged = true; + } + /** {@hide} */ public void dump(IndentingPrintWriter pw) { pw.printPair("mode", mode); @@ -1488,6 +1530,7 @@ public class PackageInstaller { pw.printPair("grantedRuntimePermissions", grantedRuntimePermissions); pw.printPair("installerPackageName", installerPackageName); pw.printPair("isMultiPackage", isMultiPackage); + pw.printPair("isStaged", isStaged); pw.println(); } @@ -1514,6 +1557,7 @@ public class PackageInstaller { dest.writeStringArray(grantedRuntimePermissions); dest.writeString(installerPackageName); dest.writeBoolean(isMultiPackage); + dest.writeBoolean(isStaged); } public static final Parcelable.Creator<SessionParams> @@ -1593,6 +1637,8 @@ public class PackageInstaller { /** {@hide} */ public boolean isMultiPackage; /** {@hide} */ + public boolean isStaged; + /** {@hide} */ public int parentSessionId = INVALID_ID; /** {@hide} */ public int[] childSessionIds = NO_SESSIONS; @@ -1625,6 +1671,7 @@ public class PackageInstaller { grantedRuntimePermissions = source.readStringArray(); installFlags = source.readInt(); isMultiPackage = source.readBoolean(); + isStaged = source.readBoolean(); parentSessionId = source.readInt(); childSessionIds = source.createIntArray(); if (childSessionIds == null) { @@ -1892,6 +1939,13 @@ public class PackageInstaller { } /** + * Returns true if this session is a staged session which will be applied at next reboot. + */ + public boolean isStaged() { + return isStaged; + } + + /** * Returns the parent multi-package session ID if this session belongs to one, * {@link #INVALID_ID} otherwise. */ @@ -1935,6 +1989,7 @@ public class PackageInstaller { dest.writeStringArray(grantedRuntimePermissions); dest.writeInt(installFlags); dest.writeBoolean(isMultiPackage); + dest.writeBoolean(isStaged); dest.writeInt(parentSessionId); dest.writeIntArray(childSessionIds); } diff --git a/core/java/android/database/sqlite/SQLiteDebug.java b/core/java/android/database/sqlite/SQLiteDebug.java index f220205b5f26..4fc7f5d257a9 100644 --- a/core/java/android/database/sqlite/SQLiteDebug.java +++ b/core/java/android/database/sqlite/SQLiteDebug.java @@ -143,7 +143,6 @@ public final class SQLiteDebug { /** * contains statistics about a database */ - @TestApi public static class DbStats { /** name of the database */ public String dbName; @@ -175,7 +174,6 @@ public final class SQLiteDebug { * return all pager and database stats for the current process. * @return {@link PagerStats} */ - @TestApi public static PagerStats getDatabaseInfo() { PagerStats stats = new PagerStats(); nativeGetPagerStats(stats); diff --git a/core/java/android/hardware/biometrics/BiometricFaceConstants.java b/core/java/android/hardware/biometrics/BiometricFaceConstants.java index 1d9330d4dfed..9d37d9939127 100644 --- a/core/java/android/hardware/biometrics/BiometricFaceConstants.java +++ b/core/java/android/hardware/biometrics/BiometricFaceConstants.java @@ -28,6 +28,21 @@ import android.hardware.face.FaceManager; */ public interface BiometricFaceConstants { // + // Accessibility constants + // + /** + * Require the user to look at the device during enrollment and + * authentication. Note this is to accommodate people who have limited + * vision. + */ + public static final int FEATURE_REQUIRE_ATTENTION = 1; + /** + * Require a diverse set of poses during enrollment. Note this is to + * accommodate people with limited mobility. + */ + public static final int FEATURE_REQUIRE_REQUIRE_DIVERSITY = 2; + + // // Error messages from face authentication hardware during initialization, enrollment, // authentication or removal. Must agree with the list in HAL h file // diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index 9d61f028bc91..1af9cdebf6bc 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -16,6 +16,7 @@ package android.hardware.display; +import android.annotation.Nullable; import android.hardware.SensorManager; import android.os.Handler; import android.os.PowerManager; @@ -195,6 +196,44 @@ public abstract class DisplayManagerInternal { public abstract void onOverlayChanged(); /** + * Get the attributes available for display color sampling. + * @param displayId id of the display to collect the sample from. + * + * @return The attributes the display supports, or null if sampling is not supported. + */ + @Nullable + public abstract DisplayedContentSamplingAttributes getDisplayedContentSamplingAttributes( + int displayId); + + /** + * Enable or disable the collection of color samples. + * + * @param displayId id of the display to collect the sample from. + * @param componentMask a bitmask of the color channels to collect samples for, or zero for all + * available. + * @param maxFrames maintain a ringbuffer of the last maxFrames. + * @param enable True to enable, False to disable. + * + * @return True if sampling was enabled, false if failure. + */ + public abstract boolean setDisplayedContentSamplingEnabled( + int displayId, boolean enable, int componentMask, int maxFrames); + + /** + * Accesses the color histogram statistics of displayed frames on devices that support sampling. + * + * @param displayId id of the display to collect the sample from + * @param maxFrames limit the statistics to the last maxFrames number of frames. + * @param timestamp discard statistics that were collected prior to timestamp, where timestamp + * is given as CLOCK_MONOTONIC. + * @return The statistics representing a histogram of the color distribution of the frames + * displayed on-screen, or null if sampling is not supported. + */ + @Nullable + public abstract DisplayedContentSample getDisplayedContentSample( + int displayId, long maxFrames, long timestamp); + + /** * Describes the requested power state of the display. * * This object is intended to describe the general characteristics of the diff --git a/core/java/android/hardware/display/DisplayedContentSample.java b/core/java/android/hardware/display/DisplayedContentSample.java new file mode 100644 index 000000000000..0610377c648a --- /dev/null +++ b/core/java/android/hardware/display/DisplayedContentSample.java @@ -0,0 +1,94 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.display; + +/** + * @hide + */ +public final class DisplayedContentSample { + private long mNumFrames; + private long[] mSamplesComponent0; + private long[] mSamplesComponent1; + private long[] mSamplesComponent2; + private long[] mSamplesComponent3; + + /** + * Construct an object representing a color histogram of pixels that were displayed on screen. + * + * @param numFrames The number of frames represented by this sample. + * @param mSamplesComponent0 is a histogram counting how many times a pixel of a given value + * was displayed onscreen for FORMAT_COMPONENT_0. The buckets of the histogram are evenly + * weighted, the number of buckets is device specific. + * eg, for RGBA_8888, if sampleComponent0 is {10, 6, 4, 1} this means that 10 red pixels were + * displayed onscreen in range 0x00->0x3F, 6 red pixels were displayed onscreen in range + * 0x40->0x7F, etc. + * @param mSamplesComponent1 is the same sample definition as sampleComponent0, but for the + * second component of format. + * @param mSamplesComponent2 is the same sample definition as sampleComponent0, but for the + * third component of format. + * @param mSamplesComponent3 is the same sample definition as sampleComponent0, but for the + * fourth component of format. + */ + public DisplayedContentSample(long numFrames, + long[] sampleComponent0, + long[] sampleComponent1, + long[] sampleComponent2, + long[] sampleComponent3) { + mNumFrames = numFrames; + mSamplesComponent0 = sampleComponent0; + mSamplesComponent1 = sampleComponent1; + mSamplesComponent2 = sampleComponent2; + mSamplesComponent3 = sampleComponent3; + } + + public enum ColorComponent { + CHANNEL0, + CHANNEL1, + CHANNEL2, + CHANNEL3, + } + + /** + * Returns a color histogram according to component channel. + * + * @param component the component to return, according to the PixelFormat ordering + * (eg, for RGBA, CHANNEL0 is R, CHANNEL1 is G, etc). + * + * @return an evenly weighted histogram counting how many times a pixel was + * displayed onscreen that fell into the corresponding bucket, with the first entry + * corresponding to the normalized 0.0 value, and the last corresponding to the 1.0 + * value for that PixelFormat component. + */ + public long[] getSampleComponent(ColorComponent component) { + switch (component) { + case CHANNEL0: return mSamplesComponent0; + case CHANNEL1: return mSamplesComponent1; + case CHANNEL2: return mSamplesComponent2; + case CHANNEL3: return mSamplesComponent3; + default: throw new ArrayIndexOutOfBoundsException(); + } + } + + /** + * Return the number of frames this sample was collected over. + * + * @return the number of frames that this sample was collected over. + */ + public long getNumFrames() { + return mNumFrames; + } +} diff --git a/core/java/android/hardware/display/DisplayedContentSamplingAttributes.java b/core/java/android/hardware/display/DisplayedContentSamplingAttributes.java new file mode 100644 index 000000000000..aad68d9bcf09 --- /dev/null +++ b/core/java/android/hardware/display/DisplayedContentSamplingAttributes.java @@ -0,0 +1,67 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.display; + +/** + * @hide + */ +public final class DisplayedContentSamplingAttributes { + private int mPixelFormat; + private int mDataspace; + private int mComponentMask; + + /* Creates the attributes reported by the display hardware about what capabilities + * are present. + * + * NOTE: the format and ds constants must match the values from graphics/common/x.x/types.hal + * @param format the format that the display hardware samples in. + * @param ds the dataspace in use when sampling. + * @param componentMask a mask of which of the format components are supported. + */ + public DisplayedContentSamplingAttributes(int format, int ds, int componentMask) { + mPixelFormat = format; + mDataspace = ds; + mComponentMask = componentMask; + } + + /* Returns the pixel format that the display hardware uses when sampling. + * + * NOTE: the returned constant matches the values from graphics/common/x.x/types.hal + * @return the format that the samples were collected in. + */ + public int getPixelFormat() { + return mPixelFormat; + } + + /* Returns the dataspace that the display hardware uses when sampling. + * + * NOTE: the returned constant matches the values from graphics/common/x.x/types.hal + * @return the dataspace that the samples were collected in. + */ + public int getDataspace() { + return mDataspace; + } + + /* Returns a mask of which components can be collected by the sampling engine. + * + * @return a mask of the components which are supported by the engine. The lowest + * bit corresponds to the lowest component (ie, 0x1 corresponds to A for RGBA). + */ + public int getComponentMask() { + return mComponentMask; + } +} diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java index 322863a6577d..bac23b3c00f9 100644 --- a/core/java/android/hardware/face/FaceManager.java +++ b/core/java/android/hardware/face/FaceManager.java @@ -207,11 +207,8 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan * @hide */ @RequiresPermission(MANAGE_BIOMETRIC) - public void enroll(byte[] token, CancellationSignal cancel, int flags, - int userId, EnrollmentCallback callback) { - if (userId == UserHandle.USER_CURRENT) { - userId = getCurrentUserId(); - } + public void enroll(byte[] token, CancellationSignal cancel, + EnrollmentCallback callback, int[] disabledFeatures) { if (callback == null) { throw new IllegalArgumentException("Must supply an enrollment callback"); } @@ -228,8 +225,8 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan if (mService != null) { try { mEnrollmentCallback = callback; - mService.enroll(mToken, token, userId, mServiceReceiver, flags, - mContext.getOpPackageName()); + mService.enroll(mToken, token, mServiceReceiver, + mContext.getOpPackageName(), disabledFeatures); } catch (RemoteException e) { Log.w(TAG, "Remote exception in enroll: ", e); if (callback != null) { @@ -284,10 +281,10 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan * @hide */ @RequiresPermission(MANAGE_BIOMETRIC) - public void setRequireAttention(boolean requireAttention, byte[] token) { + public void setFeature(int feature, boolean enabled, byte[] token) { if (mService != null) { try { - mService.setRequireAttention(requireAttention, token); + mService.setFeature(feature, enabled, token); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -298,11 +295,11 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan * @hide */ @RequiresPermission(MANAGE_BIOMETRIC) - public boolean getRequireAttention(byte[] token) { + public boolean getFeature(int feature) { boolean result = true; if (mService != null) { try { - mService.getRequireAttention(token); + result = mService.getFeature(feature); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl index a15dcec3b276..a1c88f81e3e7 100644 --- a/core/java/android/hardware/face/IFaceService.aidl +++ b/core/java/android/hardware/face/IFaceService.aidl @@ -50,8 +50,8 @@ interface IFaceService { int callingUid, int callingPid, int callingUserId, boolean fromClient); // Start face enrollment - void enroll(IBinder token, in byte [] cryptoToken, int userId, IFaceServiceReceiver receiver, - int flags, String opPackageName); + void enroll(IBinder token, in byte [] cryptoToken, IFaceServiceReceiver receiver, + String opPackageName, in int [] disabledFeatures); // Cancel enrollment in progress void cancelEnrollment(IBinder token); @@ -98,9 +98,9 @@ interface IFaceService { // Enumerate all faces void enumerate(IBinder token, int userId, IFaceServiceReceiver receiver); - int setRequireAttention(boolean requireAttention, in byte [] token); + int setFeature(int feature, boolean enabled, in byte [] token); - boolean getRequireAttention(in byte [] token); + boolean getFeature(int feature); void userActivity(); } diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index 0c44a566b48a..8a5f43de6883 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -931,7 +931,7 @@ public final class NetworkCapabilities implements Parcelable { * Returns a transport-specific information container. The application may cast this * container to a concrete sub-class based on its knowledge of the network request. The * application should be able to deal with a {@code null} return value or an invalid case, - * e.g. use {@code instanceof} operation to verify expected type. + * e.g. use {@code instanceof} operator to verify expected type. * * @return A concrete implementation of the {@link TransportInfo} class or null if not * available for the network. diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 22dd4fc362ba..bbf8f97c8865 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -274,7 +274,6 @@ public class TrafficStats { * Changes only take effect during subsequent calls to * {@link #tagSocket(Socket)}. */ - @SystemApi @SuppressLint("Doclava125") public static void setThreadStatsUid(int uid) { NetworkManagementSocketTagger.setThreadSocketStatsUid(uid); @@ -313,7 +312,6 @@ public class TrafficStats { * * @see #setThreadStatsUid(int) */ - @SystemApi @SuppressLint("Doclava125") public static void clearThreadStatsUid() { NetworkManagementSocketTagger.setThreadSocketStatsUid(-1); diff --git a/core/java/android/net/http/X509TrustManagerExtensions.java b/core/java/android/net/http/X509TrustManagerExtensions.java index f9b6dfce32ff..280dad0284b6 100644 --- a/core/java/android/net/http/X509TrustManagerExtensions.java +++ b/core/java/android/net/http/X509TrustManagerExtensions.java @@ -16,7 +16,6 @@ package android.net.http; -import android.annotation.SystemApi; import android.security.net.config.UserCertificateSource; import com.android.org.conscrypt.TrustManagerImpl; @@ -133,7 +132,6 @@ public class X509TrustManagerExtensions { * Returns {@code true} if the TrustManager uses the same trust configuration for the provided * hostnames. */ - @SystemApi public boolean isSameTrustConfiguration(String hostname1, String hostname2) { if (mIsSameTrustConfiguration == null) { return true; diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java index 228fe7a3dae5..3de3494e7ea7 100644 --- a/core/java/android/os/HwBinder.java +++ b/core/java/android/os/HwBinder.java @@ -32,10 +32,7 @@ public abstract class HwBinder implements IHwBinder { /** * Create and initialize a HwBinder object and the native objects * used to allow this to participate in hwbinder transactions. - * - * @hide */ - @SystemApi public HwBinder() { native_setup(); @@ -44,7 +41,6 @@ public abstract class HwBinder implements IHwBinder { mNativeContext); } - /** @hide */ @Override public final native void transact( int code, HwParcel request, HwParcel reply, int flags) @@ -57,10 +53,7 @@ public abstract class HwBinder implements IHwBinder { * @param request parceled transaction * @param reply object to parcel reply into * @param flags transaction flags to be chosen by wire protocol - * - * @hide */ - @SystemApi public abstract void onTransact( int code, HwParcel request, HwParcel reply, int flags) throws RemoteException; @@ -69,9 +62,7 @@ public abstract class HwBinder implements IHwBinder { * Registers this service with the hwservicemanager. * * @param serviceName instance name of the service - * @hide */ - @SystemApi public native final void registerService(String serviceName) throws RemoteException; @@ -81,9 +72,7 @@ public abstract class HwBinder implements IHwBinder { * @param iface fully-qualified interface name for example foo.bar@1.3::IBaz * @param serviceName the instance name of the service for example default. * @throws NoSuchElementException when the service is unavailable - * @hide */ - @SystemApi public static final IHwBinder getService( String iface, String serviceName) @@ -96,9 +85,7 @@ public abstract class HwBinder implements IHwBinder { * @param serviceName the instance name of the service for example default. * @param retry whether to wait for the service to start if it's not already started * @throws NoSuchElementException when the service is unavailable - * @hide */ - @SystemApi public static native final IHwBinder getService( String iface, String serviceName, @@ -112,9 +99,7 @@ public abstract class HwBinder implements IHwBinder { * @param maxThreads total number of threads to create (includes this thread if * callerWillJoin is true) * @param callerWillJoin whether joinRpcThreadpool will be called in advance - * @hide */ - @SystemApi public static native final void configureRpcThreadpool( long maxThreads, boolean callerWillJoin); @@ -124,10 +109,7 @@ public abstract class HwBinder implements IHwBinder { * a threadpool with callerWillJoin true and then registering * the provided service if this thread doesn't need to do * anything else. - * - * @hide */ - @SystemApi public static native final void joinRpcThreadpool(); // Returns address of the "freeFunction". @@ -155,10 +137,7 @@ public abstract class HwBinder implements IHwBinder { * - tries to enable atracing (if enabled) * - tries to enable coverage dumps (if running in VTS) * - tries to enable record and replay (if running in VTS) - * - * @hide */ - @SystemApi public static void enableInstrumentation() { native_report_sysprop_change(); } diff --git a/core/java/android/os/IHwBinder.java b/core/java/android/os/IHwBinder.java index fbdf27e38d67..249eb3aa3456 100644 --- a/core/java/android/os/IHwBinder.java +++ b/core/java/android/os/IHwBinder.java @@ -28,10 +28,7 @@ public interface IHwBinder { * @param request parceled transaction * @param reply object to parcel reply into * @param flags transaction flags to be chosen by wire protocol - * - * @hide */ - @SystemApi public void transact( int code, HwParcel request, HwParcel reply, int flags) throws RemoteException; @@ -40,23 +37,19 @@ public interface IHwBinder { * Return as IHwInterface instance only if this implements descriptor. * * @param descriptor for example foo.bar@1.0::IBaz - * @hide */ - @SystemApi public IHwInterface queryLocalInterface(String descriptor); /** * Interface for receiving a callback when the process hosting a service * has gone away. */ - @SystemApi public interface DeathRecipient { /** * Callback for a registered process dying. * * @param cookie cookie this death recipient was registered with. */ - @SystemApi public void serviceDied(long cookie); } @@ -67,13 +60,11 @@ public interface IHwBinder { * @param recipient callback object to be called on object death. * @param cookie value to be given to callback on object death. */ - @SystemApi public boolean linkToDeath(DeathRecipient recipient, long cookie); /** * Unregisters the death recipient from this binder. * * @param recipient callback to no longer recieve death notifications on this binder. */ - @SystemApi public boolean unlinkToDeath(DeathRecipient recipient); } diff --git a/core/java/android/os/IHwInterface.java b/core/java/android/os/IHwInterface.java index 1d9e2b0197c7..f9edd5bf8883 100644 --- a/core/java/android/os/IHwInterface.java +++ b/core/java/android/os/IHwInterface.java @@ -23,6 +23,5 @@ public interface IHwInterface { /** * @return the binder object that corresponds to this interface. */ - @SystemApi public IHwBinder asBinder(); } diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index c9c42058bad0..be8cf0e9137a 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -18,7 +18,6 @@ package android.os; import android.net.InterfaceConfiguration; -import android.net.INetd; import android.net.INetworkManagementEventObserver; import android.net.ITetheringStatsProvider; import android.net.Network; @@ -47,11 +46,6 @@ interface INetworkManagementService void unregisterObserver(INetworkManagementEventObserver obs); /** - * Retrieve an INetd to talk to netd. - */ - INetd getNetdService(); - - /** * Returns a list of currently known network interfaces */ String[] listInterfaces(); diff --git a/core/java/android/os/SystemUpdateManager.java b/core/java/android/os/SystemUpdateManager.java index ce3e225975f0..9146731f8f9f 100644 --- a/core/java/android/os/SystemUpdateManager.java +++ b/core/java/android/os/SystemUpdateManager.java @@ -34,62 +34,51 @@ public class SystemUpdateManager { private static final String TAG = "SystemUpdateManager"; /** The status key of the system update info, expecting an int value. */ - @SystemApi public static final String KEY_STATUS = "status"; /** The title of the current update, expecting a String value. */ - @SystemApi public static final String KEY_TITLE = "title"; /** Whether it is a security update, expecting a boolean value. */ - @SystemApi public static final String KEY_IS_SECURITY_UPDATE = "is_security_update"; /** The build fingerprint after installing the current update, expecting a String value. */ - @SystemApi public static final String KEY_TARGET_BUILD_FINGERPRINT = "target_build_fingerprint"; /** The security patch level after installing the current update, expecting a String value. */ - @SystemApi public static final String KEY_TARGET_SECURITY_PATCH_LEVEL = "target_security_patch_level"; /** * The KEY_STATUS value that indicates there's no update status info available. */ - @SystemApi public static final int STATUS_UNKNOWN = 0; /** * The KEY_STATUS value that indicates there's no pending update. */ - @SystemApi public static final int STATUS_IDLE = 1; /** * The KEY_STATUS value that indicates an update is available for download, but pending user * approval to start. */ - @SystemApi public static final int STATUS_WAITING_DOWNLOAD = 2; /** * The KEY_STATUS value that indicates an update is in progress (i.e. downloading or installing * has started). */ - @SystemApi public static final int STATUS_IN_PROGRESS = 3; /** * The KEY_STATUS value that indicates an update is available for install. */ - @SystemApi public static final int STATUS_WAITING_INSTALL = 4; /** * The KEY_STATUS value that indicates an update will be installed after a reboot. This applies * to both of A/B and non-A/B OTAs. */ - @SystemApi public static final int STATUS_WAITING_REBOOT = 5; private final ISystemUpdateManager mService; @@ -110,7 +99,6 @@ public class SystemUpdateManager { * * @throws SecurityException if the caller is not allowed to read the info. */ - @SystemApi @RequiresPermission(anyOf = { android.Manifest.permission.READ_SYSTEM_UPDATE_INFO, android.Manifest.permission.RECOVERY, @@ -137,7 +125,6 @@ public class SystemUpdateManager { * @throws IllegalArgumentException if @link #KEY_STATUS} does not exist. * @throws SecurityException if the caller is not allowed to update the info. */ - @SystemApi @RequiresPermission(android.Manifest.permission.RECOVERY) public void updateSystemUpdateInfo(PersistableBundle infoBundle) { if (infoBundle == null || !infoBundle.containsKey(KEY_STATUS)) { diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java index 24c9c9177360..8f2826c16b63 100644 --- a/core/java/android/os/UpdateEngine.java +++ b/core/java/android/os/UpdateEngine.java @@ -54,7 +54,6 @@ public class UpdateEngine { * Error code from the update engine. Values must agree with the ones in * system/update_engine/common/error_code.h. */ - @SystemApi public static final class ErrorCodeConstants { public static final int SUCCESS = 0; public static final int ERROR = 1; @@ -74,7 +73,6 @@ public class UpdateEngine { * Update status code from the update engine. Values must agree with the * ones in system/update_engine/client_library/include/update_engine/update_status.h. */ - @SystemApi public static final class UpdateStatusConstants { public static final int IDLE = 0; public static final int CHECKING_FOR_UPDATE = 1; @@ -95,7 +93,6 @@ public class UpdateEngine { /** * Creates a new instance. */ - @SystemApi public UpdateEngine() { mUpdateEngine = IUpdateEngine.Stub.asInterface( ServiceManager.getService(UPDATE_ENGINE_SERVICE)); @@ -106,7 +103,6 @@ public class UpdateEngine { * status change, and when the update completes. A handler can be supplied * to control which thread runs the callback, or null. */ - @SystemApi public boolean bind(final UpdateEngineCallback callback, final Handler handler) { synchronized (mUpdateEngineCallbackLock) { mUpdateEngineCallback = new IUpdateEngineCallback.Stub() { @@ -150,7 +146,6 @@ public class UpdateEngine { /** * Equivalent to {@code bind(callback, null)}. */ - @SystemApi public boolean bind(final UpdateEngineCallback callback) { return bind(callback, null); } @@ -183,7 +178,6 @@ public class UpdateEngine { * }; * </pre> */ - @SystemApi public void applyPayload(String url, long offset, long size, String[] headerKeyValuePairs) { try { mUpdateEngine.applyPayload(url, offset, size, headerKeyValuePairs); @@ -201,7 +195,6 @@ public class UpdateEngine { * <p>See {@link #suspend} for a way to temporarily stop an in-progress * update with the ability to resume it later. */ - @SystemApi public void cancel() { try { mUpdateEngine.cancel(); @@ -214,7 +207,6 @@ public class UpdateEngine { * Suspends an in-progress update. This can be undone by calling * {@link #resume}. */ - @SystemApi public void suspend() { try { mUpdateEngine.suspend(); @@ -226,7 +218,6 @@ public class UpdateEngine { /** * Resumes a suspended update. */ - @SystemApi public void resume() { try { mUpdateEngine.resume(); @@ -244,7 +235,6 @@ public class UpdateEngine { * {@code UPDATED_NEED_REBOOT}, so your callback can remove any outstanding * notification that rebooting into the new system is possible. */ - @SystemApi public void resetStatus() { try { mUpdateEngine.resetStatus(); @@ -256,7 +246,6 @@ public class UpdateEngine { /** * Unbinds the last bound callback function. */ - @SystemApi public boolean unbind() { synchronized (mUpdateEngineCallbackLock) { if (mUpdateEngineCallback == null) { @@ -281,7 +270,6 @@ public class UpdateEngine { * @param payloadMetadataFilename the location of the metadata without the * {@code file://} prefix. */ - @SystemApi public boolean verifyPayloadMetadata(String payloadMetadataFilename) { try { return mUpdateEngine.verifyPayloadApplicable(payloadMetadataFilename); diff --git a/core/java/android/os/UpdateEngineCallback.java b/core/java/android/os/UpdateEngineCallback.java index afff60abb22b..f07294e222e2 100644 --- a/core/java/android/os/UpdateEngineCallback.java +++ b/core/java/android/os/UpdateEngineCallback.java @@ -37,7 +37,6 @@ public abstract class UpdateEngineCallback { * be one of the values from {@link UpdateEngine.UpdateStatusConstants}, * and {@code percent} will be valid [TODO: in which cases?]. */ - @SystemApi public abstract void onStatusUpdate(int status, float percent); /** @@ -45,6 +44,5 @@ public abstract class UpdateEngineCallback { * unsuccessfully. The value of {@code errorCode} will be one of the * values from {@link UpdateEngine.ErrorCodeConstants}. */ - @SystemApi public abstract void onPayloadApplicationComplete(int errorCode); } diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java index 865b8f8482bd..c167ea18f0c5 100644 --- a/core/java/android/provider/CalendarContract.java +++ b/core/java/android/provider/CalendarContract.java @@ -16,6 +16,7 @@ package android.provider; +import android.annotation.NonNull; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.UnsupportedAppUsage; @@ -41,6 +42,8 @@ import android.text.format.DateUtils; import android.text.format.Time; import android.util.Log; +import com.android.internal.util.Preconditions; + /** * <p> * The contract between the calendar provider and applications. Contains @@ -129,6 +132,13 @@ public final class CalendarContract { "android.provider.calendar.action.HANDLE_CUSTOM_EVENT"; /** + * Action used to help apps show calendar events in the managed profile. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_VIEW_WORK_CALENDAR_EVENT = + "android.provider.calendar.action.VIEW_WORK_CALENDAR_EVENT"; + + /** * Intent Extras key: {@link EventsColumns#CUSTOM_APP_URI} for the event in * the {@link #ACTION_HANDLE_CUSTOM_EVENT} intent */ @@ -153,6 +163,11 @@ public final class CalendarContract { public static final String EXTRA_EVENT_ALL_DAY = "allDay"; /** + * Intent Extras key: The id of an event. + */ + public static final String EXTRA_EVENT_ID = "id"; + + /** * This authority is used for writing to or querying from the calendar * provider. Note: This is set at first run and cannot be changed without * breaking apps that access the provider. @@ -195,6 +210,43 @@ public final class CalendarContract { private CalendarContract() {} /** + * Starts an activity to view calendar events in the managed profile. + * + * When this API is called, the system will attempt to start an activity + * in the managed profile with an intent targeting the same caller package. + * The intent will have its action set to + * {@link CalendarContract#ACTION_VIEW_WORK_CALENDAR_EVENT} and contain extras + * corresponding to the API's arguments. A calendar app intending to support + * cross profile events viewing should handle this intent, parse the arguments + * and show the appropriate UI. + * + * @param context the context. + * @param eventId the id of the event to be viewed. Will be put into {@link #EXTRA_EVENT_ID} + * field of the intent. + * @param start the start time of the event. Will be put into {@link #EXTRA_EVENT_BEGIN_TIME} + * field of the intent. + * @param end the end time of the event. Will be put into {@link #EXTRA_EVENT_END_TIME} field + * of the intent. + * @param allDay if the event is an all-day event. Will be put into + * {@link #EXTRA_EVENT_ALL_DAY} field of the intent. + * @param flags flags to be set on the intent via {@link Intent#setFlags} + * @return {@code true} if the activity is started successfully. {@code false} otherwise. + * + * @see #EXTRA_EVENT_ID + * @see #EXTRA_EVENT_BEGIN_TIME + * @see #EXTRA_EVENT_END_TIME + * @see #EXTRA_EVENT_ALL_DAY + */ + public static boolean startViewCalendarEventInManagedProfile(@NonNull Context context, + long eventId, long start, long end, boolean allDay, int flags) { + Preconditions.checkNotNull(context, "Context is null"); + final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( + Context.DEVICE_POLICY_SERVICE); + return dpm.startViewCalendarEventInManagedProfile(eventId, start, + end, allDay, flags); + } + + /** * Generic columns for use by sync adapters. The specific functions of these * columns are private to the sync adapter. Other clients of the API should * not attempt to either read or write this column. These columns are @@ -695,7 +747,7 @@ public final class CalendarContract { public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/calendars"); /** - * The content:// style URL for querying Calendars table in the work profile. Appending a + * The content:// style URL for querying Calendars table in the managed profile. Appending a * calendar id using {@link ContentUris#withAppendedId(Uri, long)} will * specify a single calendar. * @@ -715,9 +767,9 @@ public final class CalendarContract { * projection of the query to this uri that are not contained in the above list. * * <p>This uri will return an empty cursor if the calling user is not a parent profile - * of a work profile, or cross profile calendar is disabled in Settings, or this uri is - * queried from a package that is not whitelisted by profile owner of the work profile via - * {@link DevicePolicyManager#addCrossProfileCalendarPackage(ComponentName, String)}. + * of a managed profile, or cross profile calendar is disabled in Settings, or this uri is + * queried from a package that is not whitelisted by profile owner of the managed profile + * via {@link DevicePolicyManager#addCrossProfileCalendarPackage(ComponentName, String)}. * * @see DevicePolicyManager#getCrossProfileCalendarPackages(ComponentName) * @see Settings.Secure#CROSS_PROFILE_CALENDAR_ENABLED @@ -1673,7 +1725,7 @@ public final class CalendarContract { Uri.parse("content://" + AUTHORITY + "/events"); /** - * The content:// style URL for querying Events table in the work profile. Appending an + * The content:// style URL for querying Events table in the managed profile. Appending an * event id using {@link ContentUris#withAppendedId(Uri, long)} will * specify a single event. * @@ -1706,9 +1758,9 @@ public final class CalendarContract { * projection of the query to this uri that are not contained in the above list. * * <p>This uri will return an empty cursor if the calling user is not a parent profile - * of a work profile, or cross profile calendar is disabled in Settings, or this uri is - * queried from a package that is not whitelisted by profile owner of the work profile via - * {@link DevicePolicyManager#addCrossProfileCalendarPackage(ComponentName, String)}. + * of a managed profile, or cross profile calendar is disabled in Settings, or this uri is + * queried from a package that is not whitelisted by profile owner of the managed profile + * via {@link DevicePolicyManager#addCrossProfileCalendarPackage(ComponentName, String)}. * * @see DevicePolicyManager#getCrossProfileCalendarPackages(ComponentName) * @see Settings.Secure#CROSS_PROFILE_CALENDAR_ENABLED @@ -1896,7 +1948,7 @@ public final class CalendarContract { Uri.parse("content://" + AUTHORITY + "/instances/searchbyday"); /** - * The content:// style URL for querying an instance range in the work profile. + * The content:// style URL for querying an instance range in the managed profile. * It supports similar semantics as {@link #CONTENT_URI}. * * <p>The following columns plus the columns that are whitelisted by @@ -1916,9 +1968,9 @@ public final class CalendarContract { * projection of the query to this uri that are not contained in the above list. * * <p>This uri will return an empty cursor if the calling user is not a parent profile - * of a work profile, or cross profile calendar for the work profile is disabled in + * of a managed profile, or cross profile calendar for the managed profile is disabled in * Settings, or this uri is queried from a package that is not whitelisted by - * profile owner of the work profile via + * profile owner of the managed profile via * {@link DevicePolicyManager#addCrossProfileCalendarPackage(ComponentName, String)}. * * @see DevicePolicyManager#getCrossProfileCalendarPackages(ComponentName) @@ -1929,7 +1981,7 @@ public final class CalendarContract { /** * The content:// style URL for querying an instance range by Julian - * Day in the work profile. It supports similar semantics as {@link #CONTENT_BY_DAY_URI} + * Day in the managed profile. It supports similar semantics as {@link #CONTENT_BY_DAY_URI} * and performs similar checks as {@link #ENTERPRISE_CONTENT_URI}. */ public static final Uri ENTERPRISE_CONTENT_BY_DAY_URI = @@ -1937,7 +1989,7 @@ public final class CalendarContract { /** * The content:// style URL for querying an instance range with a search - * term in the work profile. It supports similar semantics as {@link #CONTENT_SEARCH_URI} + * term in the managed profile. It supports similar semantics as {@link #CONTENT_SEARCH_URI} * and performs similar checks as {@link #ENTERPRISE_CONTENT_URI}. */ public static final Uri ENTERPRISE_CONTENT_SEARCH_URI = @@ -1945,7 +1997,7 @@ public final class CalendarContract { /** * The content:// style URL for querying an instance range with a search - * term in the work profile. It supports similar semantics as + * term in the managed profile. It supports similar semantics as * {@link #CONTENT_SEARCH_BY_DAY_URI} and performs similar checks as * {@link #ENTERPRISE_CONTENT_URI}. */ diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 9380695f39c4..93a59502ebea 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -13933,13 +13933,6 @@ public final class Settings { /** * Store a name/value pair into the database. * <p> - * The method takes an optional tag to associate with the setting which can be used to clear - * only settings made by your package and associated with this tag by passing the tag to - * {@link #resetToDefaults(ContentResolver, String)}. The value of this setting can be - * overridden by future calls to this or other put methods, and the tag provided in those - * calls, which may be null, will override the tag provided in this call. Any call to a put - * method which does not accept a tag will effectively set the tag to null. - * </p><p> * Also the method takes an argument whether to make the value the default for this setting. * If the system already specified a default value, then the one passed in here will * <strong>not</strong> be set as the default. @@ -13948,46 +13941,47 @@ public final class Settings { * @param resolver to access the database with. * @param name to store. * @param value to associate with the name. - * @param tag to associated with the setting. * @param makeDefault whether to make the value the default one. * @return true if the value was set, false on database errors. * - * @see #resetToDefaults(ContentResolver, String) + * @see #resetToDefaults(ContentResolver, int, String) * * @hide */ // TODO(b/117663715): require a new write permission restricted to a single source @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) - static boolean putString(@NonNull ContentResolver resolver, - @NonNull String name, @Nullable String value, @Nullable String tag, - boolean makeDefault) { - return sNameValueCache.putStringForUser(resolver, name, value, tag, makeDefault, + static boolean putString(@NonNull ContentResolver resolver, @NonNull String name, + @Nullable String value, boolean makeDefault) { + return sNameValueCache.putStringForUser(resolver, name, value, null, makeDefault, resolver.getUserId()); } /** - * Reset the settings to their defaults. This would reset <strong>only</strong> settings set - * by the caller's package. Passing in the optional tag will reset only settings changed by - * your package and associated with this tag. + * Reset the values to their defaults. + * <p> + * The method accepts an optional prefix parameter. If provided, only pairs with a name that + * starts with the exact prefix will be reset. Otherwise all will be reset. * * @param resolver Handle to the content resolver. - * @param tag Optional tag which should be associated with the settings to reset. + * @param resetMode The reset mode to use. + * @param prefix Optionally, to limit which which pairs are reset. * - * @see #putString(ContentResolver, String, String, String, boolean) + * @see #putString(ContentResolver, String, String, boolean) * * @hide */ // TODO(b/117663715): require a new write permission restricted to a single source @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) - static void resetToDefaults(@NonNull ContentResolver resolver, - @Nullable String tag) { + static void resetToDefaults(@NonNull ContentResolver resolver, @ResetMode int resetMode, + @Nullable String prefix) { try { Bundle arg = new Bundle(); arg.putInt(CALL_METHOD_USER_KEY, resolver.getUserId()); - if (tag != null) { - arg.putString(CALL_METHOD_TAG_KEY, tag); + arg.putInt(Settings.CALL_METHOD_RESET_MODE_KEY, resetMode); + if (prefix != null) { + arg.putString(Settings.CALL_METHOD_PREFIX_KEY, prefix); } - arg.putInt(CALL_METHOD_RESET_MODE_KEY, RESET_MODE_PACKAGE_DEFAULTS); + arg.putInt(CALL_METHOD_RESET_MODE_KEY, resetMode); IContentProvider cp = sProviderHolder.getProvider(resolver); cp.call(resolver.getPackageName(), sProviderHolder.mUri.getAuthority(), CALL_METHOD_RESET_CONFIG, null, arg); diff --git a/core/java/android/service/carrier/CarrierIdentifier.java b/core/java/android/service/carrier/CarrierIdentifier.java index e930f401ecd5..568ca0f6b56e 100644 --- a/core/java/android/service/carrier/CarrierIdentifier.java +++ b/core/java/android/service/carrier/CarrierIdentifier.java @@ -71,10 +71,8 @@ public class CarrierIdentifier implements Parcelable { * @param gid2 group id level 2 * @param carrierid carrier unique identifier {@link TelephonyManager#getSimCarrierId()}, used * to uniquely identify the carrier and look up the carrier configurations. - * @param preciseCarrierId precise carrier identifier {@link TelephonyManager#getSimPreciseCarrierId()} - * @hide - * - * TODO: expose this to public API + * @param preciseCarrierId precise carrier identifier + * {@link TelephonyManager#getSimPreciseCarrierId()} */ public CarrierIdentifier(String mcc, String mnc, @Nullable String spn, @Nullable String imsi, @Nullable String gid1, @Nullable String gid2, @@ -155,16 +153,16 @@ public class CarrierIdentifier implements Parcelable { } /** - * Get the carrier id {@link TelephonyManager#getSimCarrierId() } - * @hide + * Returns the carrier id. + * @see TelephonyManager#getSimCarrierId() */ public int getCarrierId() { return mCarrierId; } /** - * Get the precise carrier id {@link TelephonyManager#getSimPreciseCarrierId()} - * @hide + * Returns the precise carrier id. + * @see TelephonyManager#getSimPreciseCarrierId() */ public int getPreciseCarrierId() { return mPreciseCarrierId; diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java index 5a7a83f19b0c..af7e93e0ed74 100644 --- a/core/java/android/service/notification/Condition.java +++ b/core/java/android/service/notification/Condition.java @@ -17,7 +17,6 @@ package android.service.notification; import android.annotation.IntDef; -import android.annotation.SystemApi; import android.content.Context; import android.net.Uri; import android.os.Parcel; @@ -35,7 +34,6 @@ import java.util.Objects; */ public final class Condition implements Parcelable { - @SystemApi public static final String SCHEME = "condition"; /** @hide */ @@ -59,14 +57,10 @@ public final class Condition implements Parcelable { */ public static final int STATE_TRUE = 1; - @SystemApi public static final int STATE_UNKNOWN = 2; - @SystemApi public static final int STATE_ERROR = 3; - @SystemApi public static final int FLAG_RELEVANT_NOW = 1 << 0; - @SystemApi public static final int FLAG_RELEVANT_ALWAYS = 1 << 1; /** @@ -81,9 +75,7 @@ public final class Condition implements Parcelable { */ public final String summary; - @SystemApi public final String line1; - @SystemApi public final String line2; /** @@ -94,9 +86,7 @@ public final class Condition implements Parcelable { @State public final int state; - @SystemApi public final int flags; - @SystemApi public final int icon; /** @@ -108,7 +98,6 @@ public final class Condition implements Parcelable { this(id, summary, "", "", -1, state, FLAG_RELEVANT_ALWAYS); } - @SystemApi public Condition(Uri id, String summary, String line1, String line2, int icon, int state, int flags) { if (id == null) throw new IllegalArgumentException("id is required"); @@ -177,7 +166,6 @@ public final class Condition implements Parcelable { proto.end(token); } - @SystemApi public static String stateToString(int state) { if (state == STATE_FALSE) return "STATE_FALSE"; if (state == STATE_TRUE) return "STATE_TRUE"; @@ -186,7 +174,6 @@ public final class Condition implements Parcelable { throw new IllegalArgumentException("state is invalid: " + state); } - @SystemApi public static String relevanceToString(int flags) { final boolean now = (flags & FLAG_RELEVANT_NOW) != 0; final boolean always = (flags & FLAG_RELEVANT_ALWAYS) != 0; @@ -219,7 +206,6 @@ public final class Condition implements Parcelable { return 0; } - @SystemApi public Condition copy() { final Parcel parcel = Parcel.obtain(); try { @@ -231,14 +217,12 @@ public final class Condition implements Parcelable { } } - @SystemApi public static Uri.Builder newId(Context context) { return new Uri.Builder() .scheme(Condition.SCHEME) .authority(context.getPackageName()); } - @SystemApi public static boolean isValidId(Uri id, String pkg) { return id != null && SCHEME.equals(id.getScheme()) && pkg.equals(id.getAuthority()); } diff --git a/core/java/android/service/notification/ConditionProviderService.java b/core/java/android/service/notification/ConditionProviderService.java index 6fc689ab07cf..5203c8f4bb27 100644 --- a/core/java/android/service/notification/ConditionProviderService.java +++ b/core/java/android/service/notification/ConditionProviderService.java @@ -17,7 +17,6 @@ package android.service.notification; import android.annotation.SdkConstant; -import android.annotation.SystemApi; import android.annotation.TestApi; import android.app.ActivityManager; import android.app.INotificationManager; @@ -107,7 +106,6 @@ public abstract class ConditionProviderService extends Service { */ abstract public void onConnected(); - @SystemApi public void onRequestConditions(int relevance) {} /** diff --git a/core/java/android/service/textclassifier/TextClassifierService.java b/core/java/android/service/textclassifier/TextClassifierService.java index d7359f1aa5dd..3b813c7df82b 100644 --- a/core/java/android/service/textclassifier/TextClassifierService.java +++ b/core/java/android/service/textclassifier/TextClassifierService.java @@ -81,7 +81,6 @@ public abstract class TextClassifierService extends Service { * {@link android.Manifest.permission#BIND_TEXTCLASSIFIER_SERVICE} permission so * that other applications can not abuse it. */ - @SystemApi public static final String SERVICE_INTERFACE = "android.service.textclassifier.TextClassifierService"; @@ -407,9 +406,7 @@ public abstract class TextClassifierService extends Service { * Callbacks for TextClassifierService results. * * @param <T> the type of the result - * @hide */ - @SystemApi public interface Callback<T> { /** * Returns the result. diff --git a/core/java/android/text/MeasuredParagraph.java b/core/java/android/text/MeasuredParagraph.java index f9370a8aa6af..7e41878b3d4e 100644 --- a/core/java/android/text/MeasuredParagraph.java +++ b/core/java/android/text/MeasuredParagraph.java @@ -377,6 +377,9 @@ public class MeasuredParagraph { * @param start the inclusive start offset of the target region in the text * @param end the exclusive end offset of the target region in the text * @param textDir the text direction + * @param computeHyphenation true if need to compute hyphenation, otherwise false + * @param computeLayout true if need to compute full layout, otherwise false. + * @param hint pass if you already have measured paragraph. * @param recycle pass existing MeasuredParagraph if you want to recycle it. * * @return measured text @@ -389,12 +392,18 @@ public class MeasuredParagraph { @NonNull TextDirectionHeuristic textDir, boolean computeHyphenation, boolean computeLayout, + @Nullable MeasuredParagraph hint, @Nullable MeasuredParagraph recycle) { final MeasuredParagraph mt = recycle == null ? obtain() : recycle; mt.resetAndAnalyzeBidi(text, start, end, textDir); - final MeasuredText.Builder builder = new MeasuredText.Builder(mt.mCopiedBuffer); - builder.setComputeHyphenation(computeHyphenation); - builder.setComputeLayout(computeLayout); + final MeasuredText.Builder builder; + if (hint == null) { + builder = new MeasuredText.Builder(mt.mCopiedBuffer) + .setComputeHyphenation(computeHyphenation) + .setComputeLayout(computeLayout); + } else { + builder = new MeasuredText.Builder(hint.mMeasuredText); + } if (mt.mTextLength == 0) { // Need to build empty native measured text for StaticLayout. // TODO: Stop creating empty measured text for empty lines. diff --git a/core/java/android/text/PrecomputedText.java b/core/java/android/text/PrecomputedText.java index b7ea0122cb06..08741d6a7d88 100644 --- a/core/java/android/text/PrecomputedText.java +++ b/core/java/android/text/PrecomputedText.java @@ -17,6 +17,7 @@ package android.text; import android.annotation.FloatRange; +import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; @@ -25,6 +26,8 @@ import android.text.style.MetricAffectingSpan; import com.android.internal.util.Preconditions; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Objects; @@ -119,6 +122,16 @@ public class PrecomputedText implements Spannable { } /** + * Builder constructor from existing params. + */ + public Builder(@NonNull Params params) { + mPaint = params.mPaint; + mTextDir = params.mTextDir; + mBreakStrategy = params.mBreakStrategy; + mHyphenationFrequency = params.mHyphenationFrequency; + } + + /** * Set the line break strategy. * * The default value is {@link Layout#BREAK_STRATEGY_HIGH_QUALITY}. @@ -220,13 +233,41 @@ public class PrecomputedText implements Spannable { } /** @hide */ - public boolean isSameTextMetricsInternal(@NonNull TextPaint paint, + @IntDef(value = { UNUSABLE, NEED_RECOMPUTE, USABLE }) + @Retention(RetentionPolicy.SOURCE) + public @interface CheckResultUsableResult {} + + /** + * Constant for returning value of checkResultUsable indicating that given parameter is not + * compatible. + * @hide + */ + public static final int UNUSABLE = 0; + + /** + * Constant for returning value of checkResultUsable indicating that given parameter is not + * compatible but partially usable for creating new PrecomputedText. + * @hide + */ + public static final int NEED_RECOMPUTE = 1; + + /** + * Constant for returning value of checkResultUsable indicating that given parameter is + * compatible. + * @hide + */ + public static final int USABLE = 2; + + /** @hide */ + public @CheckResultUsableResult int checkResultUsable(@NonNull TextPaint paint, @NonNull TextDirectionHeuristic textDir, @Layout.BreakStrategy int strategy, @Layout.HyphenationFrequency int frequency) { - return mTextDir == textDir - && mBreakStrategy == strategy - && mHyphenationFrequency == frequency - && mPaint.equalsForTextMeasurement(paint); + if (mBreakStrategy == strategy && mHyphenationFrequency == frequency + && mPaint.equalsForTextMeasurement(paint)) { + return mTextDir == textDir ? USABLE : NEED_RECOMPUTE; + } else { + return UNUSABLE; + } } /** @@ -243,8 +284,8 @@ public class PrecomputedText implements Spannable { return false; } Params param = (Params) o; - return isSameTextMetricsInternal(param.mPaint, param.mTextDir, param.mBreakStrategy, - param.mHyphenationFrequency); + return checkResultUsable(param.mPaint, param.mTextDir, param.mBreakStrategy, + param.mHyphenationFrequency) == Params.USABLE; } @Override @@ -321,11 +362,55 @@ public class PrecomputedText implements Spannable { * @return A {@link PrecomputedText} */ public static PrecomputedText create(@NonNull CharSequence text, @NonNull Params params) { - ParagraphInfo[] paraInfo = createMeasuredParagraphs( - text, params, 0, text.length(), true /* computeLayout */); + ParagraphInfo[] paraInfo = null; + if (text instanceof PrecomputedText) { + final PrecomputedText hintPct = (PrecomputedText) text; + final PrecomputedText.Params hintParams = hintPct.getParams(); + final @Params.CheckResultUsableResult int checkResult = + hintParams.checkResultUsable(params.mPaint, params.mTextDir, + params.mBreakStrategy, params.mHyphenationFrequency); + switch (checkResult) { + case Params.USABLE: + return hintPct; + case Params.NEED_RECOMPUTE: + // To be able to use PrecomputedText for new params, at least break strategy and + // hyphenation frequency must be the same. + if (params.getBreakStrategy() == hintParams.getBreakStrategy() + && params.getHyphenationFrequency() + == hintParams.getHyphenationFrequency()) { + paraInfo = createMeasuredParagraphsFromPrecomputedText( + hintPct, params, true /* compute layout */); + } + break; + case Params.UNUSABLE: + // Unable to use anything in PrecomputedText. Create PrecomputedText as the + // normal text input. + } + + } + if (paraInfo == null) { + paraInfo = createMeasuredParagraphs( + text, params, 0, text.length(), true /* computeLayout */); + } return new PrecomputedText(text, 0, text.length(), params, paraInfo); } + private static ParagraphInfo[] createMeasuredParagraphsFromPrecomputedText( + @NonNull PrecomputedText pct, @NonNull Params params, boolean computeLayout) { + final boolean needHyphenation = params.getBreakStrategy() != Layout.BREAK_STRATEGY_SIMPLE + && params.getHyphenationFrequency() != Layout.HYPHENATION_FREQUENCY_NONE; + ArrayList<ParagraphInfo> result = new ArrayList<>(); + for (int i = 0; i < pct.getParagraphCount(); ++i) { + final int paraStart = pct.getParagraphStart(i); + final int paraEnd = pct.getParagraphEnd(i); + result.add(new ParagraphInfo(paraEnd, MeasuredParagraph.buildForStaticLayout( + params.getTextPaint(), pct, paraStart, paraEnd, params.getTextDirection(), + needHyphenation, computeLayout, pct.getMeasuredParagraph(i), + null /* no recycle */))); + } + return result.toArray(new ParagraphInfo[result.size()]); + } + /** @hide */ public static ParagraphInfo[] createMeasuredParagraphs( @NonNull CharSequence text, @NonNull Params params, @@ -350,7 +435,8 @@ public class PrecomputedText implements Spannable { result.add(new ParagraphInfo(paraEnd, MeasuredParagraph.buildForStaticLayout( params.getTextPaint(), text, paraStart, paraEnd, params.getTextDirection(), - needHyphenation, computeLayout, null /* no recycle */))); + needHyphenation, computeLayout, null /* no hint */, + null /* no recycle */))); } return result.toArray(new ParagraphInfo[result.size()]); } @@ -434,12 +520,15 @@ public class PrecomputedText implements Spannable { * Returns true if the given TextPaint gives the same result of text layout for this text. * @hide */ - public boolean canUseMeasuredResult(@IntRange(from = 0) int start, @IntRange(from = 0) int end, - @NonNull TextDirectionHeuristic textDir, @NonNull TextPaint paint, - @Layout.BreakStrategy int strategy, @Layout.HyphenationFrequency int frequency) { - return mStart == start - && mEnd == end - && mParams.isSameTextMetricsInternal(paint, textDir, strategy, frequency); + public @Params.CheckResultUsableResult int checkResultUsable(@IntRange(from = 0) int start, + @IntRange(from = 0) int end, @NonNull TextDirectionHeuristic textDir, + @NonNull TextPaint paint, @Layout.BreakStrategy int strategy, + @Layout.HyphenationFrequency int frequency) { + if (mStart != start || mEnd != end) { + return Params.UNUSABLE; + } else { + return mParams.checkResultUsable(paint, textDir, strategy, frequency); + } } /** @hide */ diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index 8cb18b255589..3d0c6622d8af 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -650,10 +650,26 @@ public class StaticLayout extends Layout { final Spanned spanned = (source instanceof Spanned) ? (Spanned) source : null; if (source instanceof PrecomputedText) { PrecomputedText precomputed = (PrecomputedText) source; - if (precomputed.canUseMeasuredResult(bufStart, bufEnd, textDir, paint, - b.mBreakStrategy, b.mHyphenationFrequency)) { - // Some parameters are different from the ones when measured text is created. - paragraphInfo = precomputed.getParagraphInfo(); + final @PrecomputedText.Params.CheckResultUsableResult int checkResult = + precomputed.checkResultUsable(bufStart, bufEnd, textDir, paint, + b.mBreakStrategy, b.mHyphenationFrequency); + switch (checkResult) { + case PrecomputedText.Params.UNUSABLE: + break; + case PrecomputedText.Params.NEED_RECOMPUTE: + final PrecomputedText.Params newParams = + new PrecomputedText.Params.Builder(paint) + .setBreakStrategy(b.mBreakStrategy) + .setHyphenationFrequency(b.mHyphenationFrequency) + .setTextDirection(textDir) + .build(); + precomputed = PrecomputedText.create(precomputed, newParams); + paragraphInfo = precomputed.getParagraphInfo(); + break; + case PrecomputedText.Params.USABLE: + // Some parameters are different from the ones when measured text is created. + paragraphInfo = precomputed.getParagraphInfo(); + break; } } diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index ab010855b896..a006e5de283e 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -36,6 +36,8 @@ import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; +import android.hardware.display.DisplayedContentSample; +import android.hardware.display.DisplayedContentSamplingAttributes; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; @@ -129,6 +131,12 @@ public class SurfaceControl implements Parcelable { int width, int height); private static native SurfaceControl.PhysicalDisplayInfo[] nativeGetDisplayConfigs( IBinder displayToken); + private static native DisplayedContentSamplingAttributes + nativeGetDisplayedContentSamplingAttributes(IBinder displayToken); + private static native boolean nativeSetDisplayedContentSamplingEnabled(IBinder displayToken, + boolean enable, int componentMask, int maxFrames); + private static native DisplayedContentSample nativeGetDisplayedContentSample( + IBinder displayToken, long numFrames, long timestamp); private static native int nativeGetActiveConfig(IBinder displayToken); private static native boolean nativeSetActiveConfig(IBinder displayToken, int id); private static native int[] nativeGetDisplayColorModes(IBinder displayToken); @@ -1164,6 +1172,45 @@ public class SurfaceControl implements Parcelable { return nativeGetActiveConfig(displayToken); } + /** + * @hide + */ + public static DisplayedContentSamplingAttributes getDisplayedContentSamplingAttributes( + IBinder displayToken) { + if (displayToken == null) { + throw new IllegalArgumentException("displayToken must not be null"); + } + return nativeGetDisplayedContentSamplingAttributes(displayToken); + } + + /** + * @hide + */ + public static boolean setDisplayedContentSamplingEnabled( + IBinder displayToken, boolean enable, int componentMask, int maxFrames) { + if (displayToken == null) { + throw new IllegalArgumentException("displayToken must not be null"); + } + final int maxColorComponents = 4; + if ((componentMask >> maxColorComponents) != 0) { + throw new IllegalArgumentException("invalid componentMask when enabling sampling"); + } + return nativeSetDisplayedContentSamplingEnabled( + displayToken, enable, componentMask, maxFrames); + } + + /** + * @hide + */ + public static DisplayedContentSample getDisplayedContentSample( + IBinder displayToken, long maxFrames, long timestamp) { + if (displayToken == null) { + throw new IllegalArgumentException("displayToken must not be null"); + } + return nativeGetDisplayedContentSample(displayToken, maxFrames, timestamp); + } + + public static boolean setActiveConfig(IBinder displayToken, int id) { if (displayToken == null) { throw new IllegalArgumentException("displayToken must not be null"); diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java index f7c9a0bf0f4b..763ce4f45b01 100644 --- a/core/java/android/view/ViewTreeObserver.java +++ b/core/java/android/view/ViewTreeObserver.java @@ -18,7 +18,6 @@ package android.view; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Rect; @@ -749,7 +748,6 @@ public final class ViewTreeObserver { * * @param callback The callback to invoke when the frame is committed. */ - @TestApi public void registerFrameCommitCallback(@NonNull Runnable callback) { checkIsAlive(); if (mOnFrameCommitListeners == null) { @@ -772,7 +770,6 @@ public final class ViewTreeObserver { * not be invoked. If false is returned then the callback was either never added * or may already be pending execution and was unable to be removed */ - @TestApi public boolean unregisterFrameCommitCallback(@NonNull Runnable callback) { checkIsAlive(); if (mOnFrameCommitListeners == null) { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 2a4223201af1..90da81276ba3 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -6028,14 +6028,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mTextDir == null) { mTextDir = getTextDirectionHeuristic(); } - if (!precomputed.getParams().isSameTextMetricsInternal( - getPaint(), mTextDir, mBreakStrategy, mHyphenationFrequency)) { - throw new IllegalArgumentException( + final @PrecomputedText.Params.CheckResultUsableResult int checkResult = + precomputed.getParams().checkResultUsable(getPaint(), mTextDir, mBreakStrategy, + mHyphenationFrequency); + switch (checkResult) { + case PrecomputedText.Params.UNUSABLE: + throw new IllegalArgumentException( "PrecomputedText's Parameters don't match the parameters of this TextView." + "Consider using setTextMetricsParams(precomputedText.getParams()) " + "to override the settings of this TextView: " + "PrecomputedText: " + precomputed.getParams() + "TextView: " + getTextMetricsParams()); + case PrecomputedText.Params.NEED_RECOMPUTE: + precomputed = PrecomputedText.create(precomputed, getTextMetricsParams()); + break; + case PrecomputedText.Params.USABLE: + // pass through } } else if (type == BufferType.SPANNABLE || mMovement != null) { text = mSpannableFactory.newSpannable(text); @@ -10209,7 +10217,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } // ContentCapture - if (isImportantForContentCapture() && isTextEditable()) { + if (isLaidOut() && isImportantForContentCapture() && isTextEditable()) { final ContentCaptureManager cm = mContext.getSystemService(ContentCaptureManager.class); if (cm != null && cm.isContentCaptureEnabled()) { // TODO(b/111276913): pass flags when edited by user / add CTS test diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index b00e6fdd5e9a..2e674a5892c6 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -25,6 +25,7 @@ import android.content.pm.PackageManager; import android.os.Build; import android.os.Environment; import android.os.Process; +import android.os.SystemProperties; import android.os.storage.StorageManager; import android.permission.PermissionManager.SplitPermissionInfo; import android.text.TextUtils; @@ -68,6 +69,9 @@ public class SystemConfig { private static final int ALLOW_HIDDENAPI_WHITELISTING = 0x40; private static final int ALLOW_ALL = ~0; + // property for runtime configuration differentiation + private static final String SKU_PROPERTY = "ro.boot.product.hardware.sku"; + // Group-ids that are given to all packages as read from etc/permissions/*.xml. int[] mGlobalGids; @@ -344,6 +348,17 @@ public class SystemConfig { readPermissions(Environment.buildPath( Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag); + String skuProperty = SystemProperties.get(SKU_PROPERTY, ""); + if (!skuProperty.isEmpty()) { + String skuDir = "sku_" + skuProperty; + + readPermissions(Environment.buildPath( + Environment.getOdmDirectory(), "etc", "sysconfig", skuDir), odmPermissionFlag); + readPermissions(Environment.buildPath( + Environment.getOdmDirectory(), "etc", "permissions", skuDir), + odmPermissionFlag); + } + // Allow OEM to customize features and OEM permissions int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS; readPermissions(Environment.buildPath( @@ -380,6 +395,10 @@ public class SystemConfig { // Iterate over the files in the directory and scan .xml files File platformFile = null; for (File f : libraryDir.listFiles()) { + if (!f.isFile()) { + continue; + } + // We'll read platform.xml last if (f.getPath().endsWith("etc/permissions/platform.xml")) { platformFile = f; diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 31bb1d57d702..8962e1d8c727 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -132,7 +132,6 @@ cc_library_shared { "android/graphics/GIFMovie.cpp", "android/graphics/GraphicBuffer.cpp", "android/graphics/Graphics.cpp", - "android/graphics/HarfBuzzNGFaceSkia.cpp", "android/graphics/ImageDecoder.cpp", "android/graphics/Interpolator.cpp", "android/graphics/MaskFilter.cpp", diff --git a/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp b/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp deleted file mode 100644 index cfe742d0134d..000000000000 --- a/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2012 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#define LOG_TAG "TextLayoutCache" - -#include "HarfBuzzNGFaceSkia.h" - -#include <stdlib.h> - -#include <log/log.h> - -#include <SkPaint.h> -#include <SkPath.h> -#include <SkPoint.h> -#include <SkRect.h> -#include <SkTypeface.h> - -#include <hb.h> - -namespace android { - -static const bool kDebugGlyphs = false; - -// Our implementation of the callbacks which Harfbuzz requires by using Skia -// calls. See the Harfbuzz source for references about what these callbacks do. - -struct HarfBuzzFontData { - explicit HarfBuzzFontData(SkPaint* paint) : m_paint(paint) { } - SkPaint* m_paint; -}; - -static void SkiaGetGlyphWidthAndExtents(SkPaint* paint, hb_codepoint_t codepoint, hb_position_t* width, hb_glyph_extents_t* extents) -{ - ALOG_ASSERT(codepoint <= 0xFFFF); - paint->setTextEncoding(kGlyphID_SkTextEncoding); - - SkScalar skWidth; - SkRect skBounds; - uint16_t glyph = codepoint; - - paint->getTextWidths(&glyph, sizeof(glyph), &skWidth, &skBounds); - if (kDebugGlyphs) { - ALOGD("returned glyph for %i: width = %f", codepoint, skWidth); - } - if (width) - *width = SkScalarToHBFixed(skWidth); - if (extents) { - // Invert y-axis because Skia is y-grows-down but we set up harfbuzz to be y-grows-up. - extents->x_bearing = SkScalarToHBFixed(skBounds.fLeft); - extents->y_bearing = SkScalarToHBFixed(-skBounds.fTop); - extents->width = SkScalarToHBFixed(skBounds.width()); - extents->height = SkScalarToHBFixed(-skBounds.height()); - } -} - -static hb_bool_t harfbuzzGetGlyph(hb_font_t* hbFont, void* fontData, hb_codepoint_t unicode, hb_codepoint_t variationSelector, hb_codepoint_t* glyph, void* userData) -{ - HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData); - SkPaint* paint = hbFontData->m_paint; - paint->setTextEncoding(kUTF32_SkTextEncoding); - - if (unicode > 0x10ffff) { - unicode = 0xfffd; - } - SkUnichar unichar = unicode; - - uint16_t glyph16; - paint->textToGlyphs(&unichar, sizeof(unichar), &glyph16); - *glyph = glyph16; - return !!*glyph; -} - -static hb_position_t harfbuzzGetGlyphHorizontalAdvance(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, void* userData) -{ - HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData); - hb_position_t advance = 0; - - SkiaGetGlyphWidthAndExtents(hbFontData->m_paint, glyph, &advance, 0); - return advance; -} - -static hb_bool_t harfbuzzGetGlyphHorizontalOrigin(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, hb_position_t* x, hb_position_t* y, void* userData) -{ - // Just return true, following the way that Harfbuzz-FreeType - // implementation does. - return true; -} - -static hb_bool_t harfbuzzGetGlyphExtents(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, hb_glyph_extents_t* extents, void* userData) -{ - HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData); - - SkiaGetGlyphWidthAndExtents(hbFontData->m_paint, glyph, 0, extents); - return true; -} - -static hb_font_funcs_t* harfbuzzSkiaGetFontFuncs() -{ - static hb_font_funcs_t* harfbuzzSkiaFontFuncs = 0; - - // We don't set callback functions which we can't support. - // Harfbuzz will use the fallback implementation if they aren't set. - if (!harfbuzzSkiaFontFuncs) { - harfbuzzSkiaFontFuncs = hb_font_funcs_create(); - hb_font_funcs_set_glyph_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyph, 0, 0); - hb_font_funcs_set_glyph_h_advance_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyphHorizontalAdvance, 0, 0); - hb_font_funcs_set_glyph_h_origin_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyphHorizontalOrigin, 0, 0); - hb_font_funcs_set_glyph_extents_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyphExtents, 0, 0); - hb_font_funcs_make_immutable(harfbuzzSkiaFontFuncs); - } - return harfbuzzSkiaFontFuncs; -} - -hb_blob_t* harfbuzzSkiaReferenceTable(hb_face_t* face, hb_tag_t tag, void* userData) -{ - SkTypeface* typeface = reinterpret_cast<SkTypeface*>(userData); - - const size_t tableSize = typeface->getTableSize(tag); - if (!tableSize) - return 0; - - char* buffer = reinterpret_cast<char*>(malloc(tableSize)); - if (!buffer) - return 0; - size_t actualSize = typeface->getTableData(tag, 0, tableSize, buffer); - if (tableSize != actualSize) { - free(buffer); - return 0; - } - - return hb_blob_create(const_cast<char*>(buffer), tableSize, - HB_MEMORY_MODE_WRITABLE, buffer, free); -} - -static void destroyHarfBuzzFontData(void* data) { - delete (HarfBuzzFontData*)data; -} - -hb_font_t* createFont(hb_face_t* face, SkPaint* paint, float sizeX, float sizeY) { - hb_font_t* font = hb_font_create(face); - - // Note: this needs to be reworked when we do subpixels - int x_ppem = floor(sizeX + 0.5); - int y_ppem = floor(sizeY + 0.5); - hb_font_set_ppem(font, x_ppem, y_ppem); - hb_font_set_scale(font, HBFloatToFixed(sizeX), HBFloatToFixed(sizeY)); - - HarfBuzzFontData* data = new HarfBuzzFontData(paint); - hb_font_set_funcs(font, harfbuzzSkiaGetFontFuncs(), data, destroyHarfBuzzFontData); - - return font; -} - -} // namespace android diff --git a/core/jni/android/graphics/text/MeasuredText.cpp b/core/jni/android/graphics/text/MeasuredText.cpp index 0bfadb407a93..d7d96fbf3956 100644 --- a/core/jni/android/graphics/text/MeasuredText.cpp +++ b/core/jni/android/graphics/text/MeasuredText.cpp @@ -84,14 +84,14 @@ static void nAddReplacementRun(JNIEnv* /* unused */, jclass /* unused */, jlong // Regular JNI static jlong nBuildMeasuredText(JNIEnv* env, jclass /* unused */, jlong builderPtr, - jcharArray javaText, jboolean computeHyphenation, - jboolean computeLayout) { + jlong hintPtr, jcharArray javaText, jboolean computeHyphenation, + jboolean computeLayout) { ScopedCharArrayRO text(env, javaText); const minikin::U16StringPiece textBuffer(text.get(), text.size()); // Pass the ownership to Java. - return toJLong(toBuilder(builderPtr)->build(textBuffer, computeHyphenation, - computeLayout).release()); + return toJLong(toBuilder(builderPtr)->build(textBuffer, computeHyphenation, computeLayout, + toMeasuredParagraph(hintPtr)).release()); } // Regular JNI @@ -147,7 +147,7 @@ static const JNINativeMethod gMTBuilderMethods[] = { {"nInitBuilder", "()J", (void*) nInitBuilder}, {"nAddStyleRun", "(JJIIZ)V", (void*) nAddStyleRun}, {"nAddReplacementRun", "(JJIIF)V", (void*) nAddReplacementRun}, - {"nBuildMeasuredText", "(J[CZZ)J", (void*) nBuildMeasuredText}, + {"nBuildMeasuredText", "(JJ[CZZ)J", (void*) nBuildMeasuredText}, {"nFreeBuilder", "(J)V", (void*) nFreeBuilder}, }; diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index adab8e2bae39..283eb035c6f7 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -2061,6 +2061,12 @@ android_media_AudioSystem_setA11yServicesUids(JNIEnv *env, jobject thiz, jintArr return (jint)nativeToJavaStatus(status); } +static jboolean +android_media_AudioSystem_isHapticPlaybackSupported(JNIEnv *env, jobject thiz) +{ + return AudioSystem::isHapticPlaybackSupported(); +} + // ---------------------------------------------------------------------------- static const JNINativeMethod gMethods[] = { @@ -2123,6 +2129,7 @@ static const JNINativeMethod gMethods[] = { {"setSurroundFormatEnabled", "(IZ)I", (void *)android_media_AudioSystem_setSurroundFormatEnabled}, {"setAssistantUid", "(I)I", (void *)android_media_AudioSystem_setAssistantUid}, {"setA11yServicesUids", "([I)I", (void *)android_media_AudioSystem_setA11yServicesUids}, + {"isHapticPlaybackSupported", "()Z", (void *)android_media_AudioSystem_isHapticPlaybackSupported}, }; static const JNINativeMethod gEventHandlerMethods[] = { diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index ea6e0178bd9c..c745c160e143 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -37,6 +37,7 @@ #include <stdio.h> #include <system/graphics.h> #include <ui/DisplayInfo.h> +#include <ui/DisplayedFrameStats.h> #include <ui/FrameStats.h> #include <ui/GraphicTypes.h> #include <ui/HdrCapabilities.h> @@ -97,6 +98,16 @@ static struct { jmethodID builder; } gGraphicBufferClassInfo; +static struct { + jclass clazz; + jmethodID ctor; +} gDisplayedContentSampleClassInfo; + +static struct { + jclass clazz; + jmethodID ctor; +} gDisplayedContentSamplingAttributesClassInfo; + // ---------------------------------------------------------------------------- static jlong nativeCreateTransaction(JNIEnv* env, jclass clazz) { @@ -398,6 +409,73 @@ static jobject nativeGetBuiltInDisplay(JNIEnv* env, jclass clazz, jint id) { return javaObjectForIBinder(env, token); } +static jobject nativeGetDisplayedContentSamplingAttributes(JNIEnv* env, jclass clazz, + jobject tokenObj) { + sp<IBinder> token(ibinderForJavaObject(env, tokenObj)); + + ui::PixelFormat format; + ui::Dataspace dataspace; + uint8_t componentMask; + status_t err = SurfaceComposerClient::getDisplayedContentSamplingAttributes( + token, &format, &dataspace, &componentMask); + if (err != OK) { + return nullptr; + } + return env->NewObject(gDisplayedContentSamplingAttributesClassInfo.clazz, + gDisplayedContentSamplingAttributesClassInfo.ctor, + format, dataspace, componentMask); +} + +static jboolean nativeSetDisplayedContentSamplingEnabled(JNIEnv* env, jclass clazz, + jobject tokenObj, jboolean enable, jint componentMask, jint maxFrames) { + sp<IBinder> token(ibinderForJavaObject(env, tokenObj)); + return SurfaceComposerClient::setDisplayContentSamplingEnabled( + token, enable, componentMask, maxFrames); +} + +static jobject nativeGetDisplayedContentSample(JNIEnv* env, jclass clazz, jobject tokenObj, + jlong maxFrames, jlong timestamp) { + sp<IBinder> token(ibinderForJavaObject(env, tokenObj)); + + DisplayedFrameStats stats; + status_t err = SurfaceComposerClient::getDisplayedContentSample( + token, maxFrames, timestamp, &stats); + if (err != OK) { + return nullptr; + } + + jlongArray histogramComponent0 = env->NewLongArray(stats.component_0_sample.size()); + jlongArray histogramComponent1 = env->NewLongArray(stats.component_1_sample.size()); + jlongArray histogramComponent2 = env->NewLongArray(stats.component_2_sample.size()); + jlongArray histogramComponent3 = env->NewLongArray(stats.component_3_sample.size()); + if ((histogramComponent0 == nullptr) || + (histogramComponent1 == nullptr) || + (histogramComponent2 == nullptr) || + (histogramComponent3 == nullptr)) { + return JNI_FALSE; + } + + env->SetLongArrayRegion(histogramComponent0, 0, + stats.component_0_sample.size(), + reinterpret_cast<jlong*>(stats.component_0_sample.data())); + env->SetLongArrayRegion(histogramComponent1, 0, + stats.component_1_sample.size(), + reinterpret_cast<jlong*>(stats.component_1_sample.data())); + env->SetLongArrayRegion(histogramComponent2, 0, + stats.component_2_sample.size(), + reinterpret_cast<jlong*>(stats.component_2_sample.data())); + env->SetLongArrayRegion(histogramComponent3, 0, + stats.component_3_sample.size(), + reinterpret_cast<jlong*>(stats.component_3_sample.data())); + return env->NewObject(gDisplayedContentSampleClassInfo.clazz, + gDisplayedContentSampleClassInfo.ctor, + stats.numFrames, + histogramComponent0, + histogramComponent1, + histogramComponent2, + histogramComponent3); +} + static jobject nativeCreateDisplay(JNIEnv* env, jclass clazz, jstring nameObj, jboolean secure) { ScopedUtfChars name(env, nameObj); @@ -955,6 +1033,14 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeCaptureLayers }, {"nativeSetInputWindowInfo", "(JJLandroid/view/InputWindowHandle;)V", (void*)nativeSetInputWindowInfo }, + {"nativeGetDisplayedContentSamplingAttributes", + "(Landroid/os/IBinder;)Landroid/hardware/display/DisplayedContentSamplingAttributes;", + (void*)nativeGetDisplayedContentSamplingAttributes }, + {"nativeSetDisplayedContentSamplingEnabled", "(Landroid/os/IBinder;ZII)Z", + (void*)nativeSetDisplayedContentSamplingEnabled }, + {"nativeGetDisplayedContentSample", + "(Landroid/os/IBinder;JJ)Landroid/hardware/display/DisplayedContentSample;", + (void*)nativeGetDisplayedContentSample }, }; int register_android_view_SurfaceControl(JNIEnv* env) @@ -1009,6 +1095,18 @@ int register_android_view_SurfaceControl(JNIEnv* env) gGraphicBufferClassInfo.builder = GetStaticMethodIDOrDie(env, graphicsBufferClazz, "createFromExisting", "(IIIIJ)Landroid/graphics/GraphicBuffer;"); + jclass displayedContentSampleClazz = FindClassOrDie(env, + "android/hardware/display/DisplayedContentSample"); + gDisplayedContentSampleClassInfo.clazz = MakeGlobalRefOrDie(env, displayedContentSampleClazz); + gDisplayedContentSampleClassInfo.ctor = GetMethodIDOrDie(env, + displayedContentSampleClazz, "<init>", "(J[J[J[J[J)V"); + + jclass displayedContentSamplingAttributesClazz = FindClassOrDie(env, + "android/hardware/display/DisplayedContentSamplingAttributes"); + gDisplayedContentSamplingAttributesClassInfo.clazz = MakeGlobalRefOrDie(env, + displayedContentSamplingAttributesClazz); + gDisplayedContentSamplingAttributesClassInfo.ctor = GetMethodIDOrDie(env, + displayedContentSamplingAttributesClazz, "<init>", "(III)V"); return err; } diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto index fd64c651528e..514f306953a5 100644 --- a/core/proto/android/app/settings_enums.proto +++ b/core/proto/android/app/settings_enums.proto @@ -76,5 +76,11 @@ enum PageId { // OPEN: Settings > Developer options > Disable > Info dialog DIALOG_DISABLE_DEVELOPMENT_OPTIONS = 1591; + + // OPEN: WifiDppConfiguratorActivity (android.settings.WIFI_DPP_CONFIGURATOR_XXX action intents) + SETTINGS_WIFI_DPP_CONFIGURATOR = 1595; + + // OPEN: WifiDppEnrolleeActivity (android.settings.WIFI_DPP_ENROLLEE_XXX action intents) + SETTINGS_WIFI_DPP_ENROLLEE = 1596; } diff --git a/core/proto/android/server/usagestatsservice.proto b/core/proto/android/server/usagestatsservice.proto index 3d60a86d86c9..528c1a4134f1 100644 --- a/core/proto/android/server/usagestatsservice.proto +++ b/core/proto/android/server/usagestatsservice.proto @@ -54,6 +54,9 @@ message IntervalStatsProto { // Time attributes stored as an offset of the IntervalStats's beginTime. optional int64 last_time_service_used_ms = 8; optional int64 total_time_service_used_ms = 9; + // Time attributes stored as an offset of the IntervalStats's beginTime. + optional int64 last_time_visible_ms = 10; + optional int64 total_time_visible_ms = 11; } // Stores the relevant information an IntervalStats will have about a Configuration @@ -82,6 +85,9 @@ message IntervalStatsProto { optional string notification_channel = 12; // notification_channel_index contains the index + 1 of the channel name in the string pool optional int32 notification_channel_index = 13; + // If class field is an Activity, instance_id is a unique id of the + // Activity object. + optional int32 instance_id = 14; } // The following fields contain supplemental data used to build IntervalStats, such as a string diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 9c55c752e552..77efbecc57ce 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1120,6 +1120,18 @@ android:description="@string/permdesc_manageOwnCalls" android:protectionLevel="normal" /> + <!--Allows an app which implements the + {@link InCallService} API to be eligible to be enabled as a calling companion app. This + means that the Telecom framework will bind to the app's InCallService implementation when + there are calls active. The app can use the InCallService API to view information about + calls on the system and control these calls. + <p>Protection level: normal + --> + <permission android:name="android.permission.CALL_COMPANION_APP" + android:label="@string/permlab_callCompanionApp" + android:description="@string/permdesc_callCompanionApp" + android:protectionLevel="normal" /> + <!-- Allows a calling app to continue a call which was started in another app. An example is a video calling app that wants to continue a voice call on the user's mobile network.<p> When the handover of a call from one app to another takes place, there are two devices @@ -1368,7 +1380,7 @@ <!-- ================================== --> <eat-comment /> - <!-- @SystemApi Allows an application (Phone) to send a request to other applications + <!-- Allows an application (Phone) to send a request to other applications to handle the respond-via-message action during incoming calls. <p>Not for use by third-party applications. --> <permission android:name="android.permission.SEND_RESPOND_VIA_MESSAGE" @@ -1452,7 +1464,7 @@ android:description="@string/permdesc_accessLocationExtraCommands" android:protectionLevel="normal" /> - <!-- @SystemApi Allows an application to install a location provider into the Location Manager. + <!-- Allows an application to install a location provider into the Location Manager. <p>Not for use by third-party applications. --> <permission android:name="android.permission.INSTALL_LOCATION_PROVIDER" android:protectionLevel="signature|privileged" /> @@ -1463,7 +1475,7 @@ <permission android:name="android.permission.HDMI_CEC" android:protectionLevel="signature|privileged|vendorPrivileged" /> - <!-- @SystemApi Allows an application to use location features in hardware, + <!-- Allows an application to use location features in hardware, such as the geofencing api. <p>Not for use by third-party applications. --> <permission android:name="android.permission.LOCATION_HARDWARE" @@ -1658,7 +1670,7 @@ android:label="@string/permlab_bluetoothAdmin" android:protectionLevel="normal" /> - <!-- @SystemApi Allows applications to pair bluetooth devices without user interaction, and to + <!-- Allows applications to pair bluetooth devices without user interaction, and to allow or disallow phonebook access or message access. This is not available to third party applications. --> <permission android:name="android.permission.BLUETOOTH_PRIVILEGED" @@ -1749,7 +1761,7 @@ android:usageInfoRequired="true" /> <uses-permission android:name="android.permission.GET_ACCOUNTS"/> - <!-- @SystemApi Allows applications to call into AccountAuthenticators. + <!-- Allows applications to call into AccountAuthenticators. <p>Not for use by third-party applications. --> <permission android:name="android.permission.ACCOUNT_MANAGER" android:protectionLevel="signature" /> @@ -1928,7 +1940,7 @@ <!-- =========================================== --> <eat-comment /> - <!-- @SystemApi Allows modification of the telephony state - power on, mmi, etc. + <!-- Allows modification of the telephony state - power on, mmi, etc. Does not include placing calls. <p>Not for use by third-party applications. --> <permission android:name="android.permission.MODIFY_PHONE_STATE" @@ -2093,10 +2105,9 @@ <!-- @hide Allows an application to cache content. <p>Not for use by third-party applications. - <p>Protection level: signature --> <permission android:name="android.permission.CACHE_CONTENT" - android:protectionLevel="signature" /> + android:protectionLevel="signature|documenter" /> <!-- @SystemApi @hide Allows an application to aggressively allocate disk space. @@ -2127,6 +2138,15 @@ android:label="@string/permlab_disableKeyguard" android:protectionLevel="normal" /> + <!-- Allows an application to get the screen lock complexity and prompt users to update the + screen lock to a certain complexity level. + <p>Protection level: normal + --> + <permission android:name="android.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY" + android:label="@string/permlab_getAndRequestScreenLockComplexity" + android:description="@string/permdesc_getAndRequestScreenLockComplexity" + android:protectionLevel="normal" /> + <!-- ================================== --> <!-- Permissions to access other installed applications --> <!-- ================================== --> @@ -2371,7 +2391,7 @@ <!-- ============================================ --> <eat-comment /> - <!-- @SystemApi Allows applications to set the system time. + <!-- Allows applications to set the system time. <p>Not for use by third-party applications. --> <permission android:name="android.permission.SET_TIME" android:protectionLevel="signature|privileged" /> @@ -2461,7 +2481,7 @@ <permission android:name="android.permission.SET_SCREEN_COMPATIBILITY" android:protectionLevel="signature" /> - <!-- @SystemApi @TestApi Allows an application to modify the current configuration, such + <!-- Allows an application to modify the current configuration, such as locale. --> <permission android:name="android.permission.CHANGE_CONFIGURATION" android:protectionLevel="signature|privileged|development" /> @@ -2483,7 +2503,7 @@ android:description="@string/permdesc_writeSettings" android:protectionLevel="signature|preinstalled|appop|pre23" /> - <!-- @SystemApi Allows an application to modify the Google service map. + <!-- Allows an application to modify the Google service map. <p>Not for use by third-party applications. --> <permission android:name="android.permission.WRITE_GSERVICES" android:protectionLevel="signature|privileged" /> @@ -2499,7 +2519,7 @@ <permission android:name="android.permission.RETRIEVE_WINDOW_CONTENT" android:protectionLevel="signature|privileged" /> - <!-- @SystemApi Modify the global animation scaling factor. + <!-- Modify the global animation scaling factor. <p>Not for use by third-party applications. --> <permission android:name="android.permission.SET_ANIMATION_SCALE" android:protectionLevel="signature|privileged|development" /> @@ -2554,12 +2574,12 @@ android:description="@string/permdesc_broadcastSticky" android:protectionLevel="normal" /> - <!-- @SystemApi Allows mounting and unmounting file systems for removable storage. + <!-- Allows mounting and unmounting file systems for removable storage. <p>Not for use by third-party applications.--> <permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" android:protectionLevel="signature|privileged" /> - <!-- @SystemApi Allows formatting file systems for removable storage. + <!-- Allows formatting file systems for removable storage. <p>Not for use by third-party applications. --> <permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS" android:protectionLevel="signature|privileged" /> @@ -2593,7 +2613,7 @@ <permission android:name="android.permission.ASEC_RENAME" android:protectionLevel="signature" /> - <!-- @SystemApi Allows applications to write the apn settings and read sensitive fields of + <!-- Allows applications to write the apn settings and read sensitive fields of an existing apn settings like user and password. <p>Not for use by third-party applications. --> <permission android:name="android.permission.WRITE_APN_SETTINGS" @@ -2694,40 +2714,40 @@ <!-- ========================================= --> <eat-comment /> - <!-- @SystemApi Allows an application to read or write the secure system settings. + <!-- Allows an application to read or write the secure system settings. <p>Not for use by third-party applications. --> <permission android:name="android.permission.WRITE_SECURE_SETTINGS" android:protectionLevel="signature|privileged|development" /> - <!-- @SystemApi Allows an application to retrieve state dump information from system services. + <!-- Allows an application to retrieve state dump information from system services. <p>Not for use by third-party applications. --> <permission android:name="android.permission.DUMP" android:protectionLevel="signature|privileged|development" /> - <!-- @SystemApi Allows an application to read the low-level system log files. + <!-- Allows an application to read the low-level system log files. <p>Not for use by third-party applications, because Log entries can contain the user's private information. --> <permission android:name="android.permission.READ_LOGS" android:protectionLevel="signature|privileged|development" /> - <!-- @SystemApi Configure an application for debugging. + <!-- Configure an application for debugging. <p>Not for use by third-party applications. --> <permission android:name="android.permission.SET_DEBUG_APP" android:protectionLevel="signature|privileged|development" /> - <!-- @SystemApi Allows an application to set the maximum number of (not needed) + <!-- Allows an application to set the maximum number of (not needed) application processes that can be running. <p>Not for use by third-party applications. --> <permission android:name="android.permission.SET_PROCESS_LIMIT" android:protectionLevel="signature|privileged|development" /> - <!-- @SystemApi Allows an application to control whether activities are immediately + <!-- Allows an application to control whether activities are immediately finished when put in the background. <p>Not for use by third-party applications. --> <permission android:name="android.permission.SET_ALWAYS_FINISH" android:protectionLevel="signature|privileged|development" /> - <!-- @SystemApi Allow an application to request that a signal be sent to all persistent processes. + <!-- Allow an application to request that a signal be sent to all persistent processes. <p>Not for use by third-party applications. --> <permission android:name="android.permission.SIGNAL_PERSISTENT_PROCESSES" android:protectionLevel="signature|privileged|development" /> @@ -2737,7 +2757,7 @@ <!-- ==================================== --> <eat-comment /> - <!-- @SystemApi Allows access to the list of accounts in the Accounts Service. --> + <!-- Allows access to the list of accounts in the Accounts Service. --> <permission android:name="android.permission.GET_ACCOUNTS_PRIVILEGED" android:protectionLevel="signature|privileged" /> @@ -2746,12 +2766,12 @@ <permission android:name="android.permission.GET_PASSWORD" android:protectionLevel="signature" /> - <!-- @SystemApi Allows applications to RW to diagnostic resources. + <!-- Allows applications to RW to diagnostic resources. <p>Not for use by third-party applications. --> <permission android:name="android.permission.DIAGNOSTIC" android:protectionLevel="signature" /> - <!-- @SystemApi Allows an application to open, close, or disable the status bar + <!-- Allows an application to open, close, or disable the status bar and its icons. <p>Not for use by third-party applications. --> <permission android:name="android.permission.STATUS_BAR" @@ -2776,7 +2796,7 @@ <permission android:name="android.permission.FORCE_BACK" android:protectionLevel="signature" /> - <!-- @SystemApi Allows an application to update device statistics. + <!-- Allows an application to update device statistics. <p>Not for use by third-party applications. --> <permission android:name="android.permission.UPDATE_DEVICE_STATS" android:protectionLevel="signature|privileged" /> @@ -3223,7 +3243,7 @@ android:description="@string/permdesc_requestDeletePackages" android:protectionLevel="normal" /> - <!-- @SystemApi Allows an application to install packages. + <!-- Allows an application to install packages. <p>Not for use by third-party applications. --> <permission android:name="android.permission.INSTALL_PACKAGES" android:protectionLevel="signature|privileged" /> @@ -3296,7 +3316,7 @@ <permission android:name="android.permission.FORCE_PERSISTABLE_URI_PERMISSIONS" android:protectionLevel="signature" /> - <!-- @SystemApi Old permission for deleting an app's cache files, no longer used, + <!-- Old permission for deleting an app's cache files, no longer used, but signals for us to quietly ignore calls instead of throwing an exception. --> <permission android:name="android.permission.DELETE_CACHE_FILES" android:protectionLevel="signature|privileged" /> @@ -3306,7 +3326,7 @@ <permission android:name="android.permission.INTERNAL_DELETE_CACHE_FILES" android:protectionLevel="signature" /> - <!-- @SystemApi Allows an application to delete packages. + <!-- Allows an application to delete packages. <p>Not for use by third-party applications. <p>Starting in {@link android.os.Build.VERSION_CODES#N}, user confirmation is requested when the application deleting the package is not the same application that installed the @@ -3319,7 +3339,7 @@ <permission android:name="android.permission.MOVE_PACKAGE" android:protectionLevel="signature|privileged" /> - <!-- @SystemApi Allows an application to change whether an application component (other than its own) is + <!-- Allows an application to change whether an application component (other than its own) is enabled or not. <p>Not for use by third-party applications. --> <permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" @@ -3447,7 +3467,7 @@ android:protectionLevel="signature|privileged" /> <uses-permission android:name="android.permission.CONTROL_VPN" /> - <!-- @SystemApi Allows an application to capture audio output. + <!-- Allows an application to capture audio output. <p>Not for use by third-party applications.</p> --> <permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT" android:protectionLevel="signature|privileged" /> @@ -3485,7 +3505,7 @@ <permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT" android:protectionLevel="signature|privileged" /> - <!-- @SystemApi Allows an application to know what content is playing and control its playback. + <!-- Allows an application to know what content is playing and control its playback. <p>Not for use by third-party applications due to privacy of media consumption</p> --> <permission android:name="android.permission.MEDIA_CONTENT_CONTROL" android:protectionLevel="signature|privileged" /> @@ -3512,7 +3532,7 @@ <permission android:name="android.permission.BRICK" android:protectionLevel="signature" /> - <!-- @SystemApi Required to be able to reboot the device. + <!-- Required to be able to reboot the device. <p>Not for use by third-party applications. --> <permission android:name="android.permission.REBOOT" android:protectionLevel="signature|privileged" /> @@ -3573,11 +3593,11 @@ <permission android:name="android.permission.BROADCAST_NETWORK_PRIVILEGED" android:protectionLevel="signature|privileged" /> - <!-- @SystemApi Not for use by third-party applications. --> + <!-- Not for use by third-party applications. --> <permission android:name="android.permission.MASTER_CLEAR" android:protectionLevel="signature|privileged" /> - <!-- @SystemApi Allows an application to call any phone number, including emergency + <!-- Allows an application to call any phone number, including emergency numbers, without going through the Dialer user interface for the user to confirm the call being placed. <p>Not for use by third-party applications. --> @@ -3592,19 +3612,19 @@ <permission android:name="android.permission.PERFORM_SIM_ACTIVATION" android:protectionLevel="signature|privileged" /> - <!-- @SystemApi Allows enabling/disabling location update notifications from + <!-- Allows enabling/disabling location update notifications from the radio. <p>Not for use by third-party applications. --> <permission android:name="android.permission.CONTROL_LOCATION_UPDATES" android:protectionLevel="signature|privileged" /> - <!-- @SystemApi Allows read/write access to the "properties" table in the checkin + <!-- Allows read/write access to the "properties" table in the checkin database, to change values that get uploaded. <p>Not for use by third-party applications. --> <permission android:name="android.permission.ACCESS_CHECKIN_PROPERTIES" android:protectionLevel="signature|privileged" /> - <!-- @SystemApi Allows an application to collect component usage + <!-- Allows an application to collect component usage statistics <p>Declaring the permission implies intention to use the API and the user of the device can grant permission through the Settings application. --> @@ -3637,7 +3657,7 @@ android:description="@string/permdesc_requestIgnoreBatteryOptimizations" android:protectionLevel="normal" /> - <!-- @SystemApi Allows an application to collect battery statistics --> + <!-- Allows an application to collect battery statistics --> <permission android:name="android.permission.BATTERY_STATS" android:protectionLevel="signature|privileged|development" /> @@ -3666,12 +3686,12 @@ <permission android:name="android.permission.CONFIRM_FULL_BACKUP" android:protectionLevel="signature" /> - <!-- @SystemApi Must be required by a {@link android.widget.RemoteViewsService}, + <!-- Must be required by a {@link android.widget.RemoteViewsService}, to ensure that only the system can bind to it. --> <permission android:name="android.permission.BIND_REMOTEVIEWS" android:protectionLevel="signature|privileged" /> - <!-- @SystemApi Allows an application to tell the AppWidget service which application + <!-- Allows an application to tell the AppWidget service which application can access AppWidget's data. The normal user flow is that a user picks an AppWidget to go into a particular host, thereby giving that host application access to the private data from the AppWidget app. @@ -3702,7 +3722,7 @@ <permission android:name="android.permission.CHANGE_BACKGROUND_DATA_SETTING" android:protectionLevel="signature" /> - <!-- @SystemApi This permission can be used on content providers to allow the global + <!-- This permission can be used on content providers to allow the global search system to access their data. Typically it used when the provider has some permissions protecting it (which global search would not be expected to hold), and added as a read-only permission diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 101f92b2097c..1c0ccde4fb70 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -222,6 +222,11 @@ so that applications can still use their own mechanisms. --> <bool name="config_enableAutoPowerModes">false</bool> + <!-- Whether (if true) this is a kind of device that can be moved around (eg. phone/laptop), + or (if false) something for which movement is either not measurable or should not count + toward power states (eg. tv/soundbar). --> + <bool name="config_autoPowerModeUseMotionSensor">true</bool> + <!-- The threshold angle for any motion detection in auto-power save modes. In hundreths of a degree. --> <integer name="config_autoPowerModeThresholdAngle">200</integer> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index a33f6b2fbf9c..cab01f9c027f 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1215,6 +1215,15 @@ <string name="permdesc_manageOwnCalls">Allows the app to route its calls through the system in order to improve the calling experience.</string> + <!-- Title of an application permission. When granted the app is allowed to be enabled as + a companion app. [CHAR LIMIT=NONE]--> + <string name="permlab_callCompanionApp">see and control calls through the system.</string> + <!-- Description of an application permission. When granted the app is allowed to be enabled as + a companion app. [CHAR LIMIT=NONE]--> + <string name="permdesc_callCompanionApp">Allows the app to see and control ongoing calls on the + device. This includes information such as call numbers for calls and the state of the + calls.</string> + <!-- Title of an application permission. When granted the user is giving access to a third party app to continue a call which originated in another app. For example, the user could be in a voice call over their carrier's mobile network, and a third party video @@ -1397,6 +1406,16 @@ 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_getAndRequestScreenLockComplexity">get and request screen lock complexity</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_getAndRequestScreenLockComplexity">Allows the app to learn the screen + lock complexity level (high, medium, low or none), which indicates the possible range of + length and type of the screen lock. The app can also suggest to users that they update the + screen lock to a certain level but users can freely ignore and navigate away. Note that the + screen lock is not stored in plaintext so the app does not know the exact password. + </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> @@ -3323,6 +3342,15 @@ <!-- Notification action name for opening the wifi picker, showing the user all the nearby networks. --> <string name="wifi_available_action_all_networks">All networks</string> + <!-- Notification title for a connection to a app suggested wireless network.--> + <string name="wifi_suggestion_title">Connected to Wi\u2011Fi network proposed by <xliff:g id="name" example="App123">%s</xliff:g></string> + <!-- Notification content for a connection to a app suggested wireless network.--> + <string name="wifi_suggestion_content">Do you want to let <xliff:g id="name" example="App123">%s</xliff:g> propose networks for you?</string> + <!-- Notification action for allowing app specified in the notification body.--> + <string name="wifi_suggestion_action_allow_app">Yes</string> + <!-- Notification action for disallowing app specified in the notification body.--> + <string name="wifi_suggestion_action_disallow_app">No</string> + <!--Notification title for Wi-Fi Wake onboarding. This is displayed the first time a user disables Wi-Fi with the feature enabled. --> <string name="wifi_wakeup_onboarding_title">Wi\u2011Fi will turn on automatically</string> <!--Notification subtext for Wi-Fi Wake onboarding.--> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index b24cdba5ec47..199fbc09d38f 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -265,6 +265,7 @@ <java-symbol type="integer" name="config_autoPowerModeAnyMotionSensor" /> <java-symbol type="bool" name="config_autoPowerModePreferWristTilt" /> <java-symbol type="bool" name="config_autoPowerModePrefetchLocation" /> + <java-symbol type="bool" name="config_autoPowerModeUseMotionSensor" /> <java-symbol type="bool" name="config_enable_emergency_call_while_sim_locked" /> <java-symbol type="bool" name="config_enable_puk_unlock_screen" /> <java-symbol type="bool" name="config_disableLockscreenByDefault" /> @@ -1988,6 +1989,10 @@ <java-symbol type="string" name="wifi_available_content_failed_to_connect" /> <java-symbol type="string" name="wifi_available_action_connect" /> <java-symbol type="string" name="wifi_available_action_all_networks" /> + <java-symbol type="string" name="wifi_suggestion_title" /> + <java-symbol type="string" name="wifi_suggestion_content" /> + <java-symbol type="string" name="wifi_suggestion_action_allow_app" /> + <java-symbol type="string" name="wifi_suggestion_action_disallow_app" /> <java-symbol type="string" name="wifi_wakeup_onboarding_title" /> <java-symbol type="string" name="wifi_wakeup_onboarding_subtext" /> <java-symbol type="string" name="wifi_wakeup_onboarding_action_disable" /> diff --git a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java index d289f1f5defc..9b5b725a3bed 100644 --- a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java +++ b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java @@ -16,9 +16,16 @@ package android.app.admin; +import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH; +import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW; +import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM; +import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE; +import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import android.app.admin.PasswordMetrics.PasswordComplexityBucket; import android.os.Parcel; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -164,4 +171,126 @@ public class PasswordMetricsTest { } + + @Test + public void testConstructQuality() { + PasswordMetrics expected = new PasswordMetrics(); + expected.quality = DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; + + PasswordMetrics actual = new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_COMPLEX); + + assertEquals(expected, actual); + } + + @Test + public void testDetermineComplexity_none() { + assertEquals(PASSWORD_COMPLEXITY_NONE, + PasswordMetrics.computeForPassword("").determineComplexity()); + } + + @Test + public void testDetermineComplexity_lowSomething() { + assertEquals(PASSWORD_COMPLEXITY_LOW, + new PasswordMetrics(PASSWORD_QUALITY_SOMETHING).determineComplexity()); + } + + @Test + public void testDetermineComplexity_lowNumeric() { + assertEquals(PASSWORD_COMPLEXITY_LOW, + PasswordMetrics.computeForPassword("1234").determineComplexity()); + } + + @Test + public void testDetermineComplexity_lowNumericComplex() { + assertEquals(PASSWORD_COMPLEXITY_LOW, + PasswordMetrics.computeForPassword("124").determineComplexity()); + } + + @Test + public void testDetermineComplexity_lowAlphabetic() { + assertEquals(PASSWORD_COMPLEXITY_LOW, + PasswordMetrics.computeForPassword("a!").determineComplexity()); + } + + @Test + public void testDetermineComplexity_lowAlphanumeric() { + assertEquals(PASSWORD_COMPLEXITY_LOW, + PasswordMetrics.computeForPassword("a!1").determineComplexity()); + } + + @Test + public void testDetermineComplexity_mediumNumericComplex() { + assertEquals(PASSWORD_COMPLEXITY_MEDIUM, + PasswordMetrics.computeForPassword("1238").determineComplexity()); + } + + @Test + public void testDetermineComplexity_mediumAlphabetic() { + assertEquals(PASSWORD_COMPLEXITY_MEDIUM, + PasswordMetrics.computeForPassword("ab!c").determineComplexity()); + } + + @Test + public void testDetermineComplexity_mediumAlphanumeric() { + assertEquals(PASSWORD_COMPLEXITY_MEDIUM, + PasswordMetrics.computeForPassword("ab!1").determineComplexity()); + } + + @Test + public void testDetermineComplexity_highNumericComplex() { + assertEquals(PASSWORD_COMPLEXITY_HIGH, + PasswordMetrics.computeForPassword("12389647!").determineComplexity()); + } + + @Test + public void testDetermineComplexity_highAlphabetic() { + assertEquals(PASSWORD_COMPLEXITY_HIGH, + PasswordMetrics.computeForPassword("alphabetic!").determineComplexity()); + } + + @Test + public void testDetermineComplexity_highAlphanumeric() { + assertEquals(PASSWORD_COMPLEXITY_HIGH, + PasswordMetrics.computeForPassword("alphanumeric123!").determineComplexity()); + } + + @Test + public void testComplexityLevelToBucket_none() { + PasswordMetrics[] bucket = PasswordComplexityBucket.complexityLevelToBucket( + PASSWORD_COMPLEXITY_NONE).getMetrics(); + + for (PasswordMetrics metrics : bucket) { + assertEquals(PASSWORD_COMPLEXITY_NONE, metrics.determineComplexity()); + } + } + + @Test + public void testComplexityLevelToBucket_low() { + PasswordMetrics[] bucket = PasswordComplexityBucket.complexityLevelToBucket( + PASSWORD_COMPLEXITY_LOW).getMetrics(); + + for (PasswordMetrics metrics : bucket) { + assertEquals(PASSWORD_COMPLEXITY_LOW, metrics.determineComplexity()); + } + } + + @Test + public void testComplexityLevelToBucket_medium() { + PasswordMetrics[] bucket = PasswordComplexityBucket.complexityLevelToBucket( + PASSWORD_COMPLEXITY_MEDIUM).getMetrics(); + + for (PasswordMetrics metrics : bucket) { + assertEquals(PASSWORD_COMPLEXITY_MEDIUM, metrics.determineComplexity()); + } + } + + @Test + public void testComplexityLevelToBucket_high() { + PasswordMetrics[] bucket = PasswordComplexityBucket.complexityLevelToBucket( + PASSWORD_COMPLEXITY_HIGH).getMetrics(); + + for (PasswordMetrics metrics : bucket) { + assertEquals(PASSWORD_COMPLEXITY_HIGH, metrics.determineComplexity()); + } + } } diff --git a/core/tests/coretests/src/android/app/usage/UsageStatsTest.java b/core/tests/coretests/src/android/app/usage/UsageStatsTest.java index 1f047f9e6d10..28aaf1e05644 100644 --- a/core/tests/coretests/src/android/app/usage/UsageStatsTest.java +++ b/core/tests/coretests/src/android/app/usage/UsageStatsTest.java @@ -16,18 +16,22 @@ package android.app.usage; -import static android.app.usage.UsageEvents.Event.CONTINUE_PREVIOUS_DAY; +import static android.app.usage.UsageEvents.Event.ACTIVITY_DESTROYED; +import static android.app.usage.UsageEvents.Event.ACTIVITY_PAUSED; +import static android.app.usage.UsageEvents.Event.ACTIVITY_RESUMED; +import static android.app.usage.UsageEvents.Event.ACTIVITY_STOPPED; import static android.app.usage.UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE; import static android.app.usage.UsageEvents.Event.END_OF_DAY; +import static android.app.usage.UsageEvents.Event.FLUSH_TO_DISK; import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_START; import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_STOP; -import static android.app.usage.UsageEvents.Event.MOVE_TO_BACKGROUND; -import static android.app.usage.UsageEvents.Event.MOVE_TO_FOREGROUND; import static android.app.usage.UsageEvents.Event.ROLLOVER_FOREGROUND_SERVICE; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import android.app.usage.UsageEvents.Event; import android.os.Parcel; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -120,10 +124,10 @@ public class UsageStatsTest { left.mBeginTimeStamp = 100000; left.mTotalTimeInForeground = 10; - left.mLastForegroundActivityEventMap.put("com.test.activity1", MOVE_TO_FOREGROUND); - left.mLastForegroundActivityEventMap.put("com.test.activity2", MOVE_TO_FOREGROUND); - left.mLastForegroundServiceEventMap.put("com.test.service1", FOREGROUND_SERVICE_START); - left.mLastForegroundServiceEventMap.put("com.test.service2", FOREGROUND_SERVICE_START); + left.mActivities.put(1, Event.ACTIVITY_RESUMED); + left.mActivities.put(2, Event.ACTIVITY_RESUMED); + left.mForegroundServices.put("com.test.service1", FOREGROUND_SERVICE_START); + left.mForegroundServices.put("com.test.service2", FOREGROUND_SERVICE_START); Parcel p = Parcel.obtain(); left.writeToParcel(p, 0); @@ -133,131 +137,182 @@ public class UsageStatsTest { } @Test - public void testForegroundActivity() { + public void testActivity() { left.mPackageName = "com.test"; left.mBeginTimeStamp = 100000; - left.update("com.test.activity1", 200000, MOVE_TO_FOREGROUND); + left.update("com.test.activity1", 200000, Event.ACTIVITY_RESUMED, 1); assertEquals(left.mLastTimeUsed, 200000); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), - new Integer(MOVE_TO_FOREGROUND)); + assertEquals(left.mLastTimeVisible, 200000); + assertEquals(left.mActivities.get(1), Event.ACTIVITY_RESUMED); assertEquals(left.mLaunchCount, 1); + assertEquals(left.mTotalTimeInForeground, 0); + assertEquals(left.mTotalTimeVisible, 0); - left.update("com.test.activity1", 350000, MOVE_TO_BACKGROUND); + left.update("com.test.activity1", 350000, ACTIVITY_PAUSED, 1); assertEquals(left.mLastTimeUsed, 350000); - assertFalse(left.mLastForegroundActivityEventMap.containsKey("com.test.activity1")); + assertEquals(left.mLastTimeVisible, 350000); + assertEquals(left.mActivities.get(1), ACTIVITY_PAUSED); assertEquals(left.mTotalTimeInForeground, 350000 - 200000); + assertEquals(left.mTotalTimeVisible, 350000 - 200000); + + left.update("com.test.activity1", 400000, ACTIVITY_STOPPED, 1); + assertEquals(left.mLastTimeUsed, 350000); + assertEquals(left.mLastTimeVisible, 400000); + assertEquals(left.mActivities.get(1), ACTIVITY_STOPPED); + assertEquals(left.mTotalTimeInForeground, 350000 - 200000); + assertEquals(left.mTotalTimeVisible, 400000 - 200000); + + left.update("com.test.activity1", 500000, ACTIVITY_DESTROYED, 1); + assertEquals(left.mLastTimeUsed, 350000); + assertEquals(left.mLastTimeVisible, 400000); + assertTrue(left.mActivities.indexOfKey(1) < 0); + assertEquals(left.mTotalTimeInForeground, 350000 - 200000); + assertEquals(left.mTotalTimeVisible, 400000 - 200000); } @Test - public void testEvent_CONTINUE_PREVIOUS_DAY() { + public void testEvent_END_OF_DAY() { left.mPackageName = "com.test"; left.mBeginTimeStamp = 100000; - left.update("com.test.activity1", 100000, CONTINUE_PREVIOUS_DAY); + left.update("com.test.activity1", 100000, Event.ACTIVITY_RESUMED, 1); assertEquals(left.mLastTimeUsed, 100000); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), - new Integer(CONTINUE_PREVIOUS_DAY)); - assertEquals(left.mLaunchCount, 0); + assertEquals(left.mLastTimeVisible, 100000); + assertEquals(left.mActivities.get(1), Event.ACTIVITY_RESUMED); + assertEquals(left.mLaunchCount, 1); - left.update("com.test.activity1", 350000, MOVE_TO_BACKGROUND); + left.update(null, 350000, END_OF_DAY, 0); assertEquals(left.mLastTimeUsed, 350000); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), null); + assertEquals(left.mLastTimeVisible, 350000); + assertEquals(left.mActivities.get(1), Event.ACTIVITY_RESUMED); assertEquals(left.mTotalTimeInForeground, 350000 - 100000); + assertEquals(left.mTotalTimeVisible, 350000 - 100000); } @Test - public void testEvent_END_OF_DAY() { + public void testEvent_ACTIVITY_PAUSED() { left.mPackageName = "com.test"; left.mBeginTimeStamp = 100000; - left.update("com.test.activity1", 100000, CONTINUE_PREVIOUS_DAY); - assertEquals(left.mLastTimeUsed, 100000); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), - new Integer(CONTINUE_PREVIOUS_DAY)); - assertEquals(left.mLaunchCount, 0); + left.update("com.test.activity1", 100000, ACTIVITY_PAUSED, 1); + assertEquals(left.mLastTimeUsed, 0); + assertEquals(left.mLastTimeVisible, 100000); + assertEquals(left.mActivities.get(1), ACTIVITY_PAUSED); - left.update(null, 350000, END_OF_DAY); - assertEquals(left.mLastTimeUsed, 350000); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), - new Integer(END_OF_DAY)); - assertEquals(left.mTotalTimeInForeground, 350000 - 100000); + left.update("com.test.activity1", 200000, Event.ACTIVITY_RESUMED, 1); + assertEquals(left.mLastTimeUsed, 200000); + assertEquals(left.mLastTimeVisible, 200000); + assertEquals(left.mActivities.get(1), Event.ACTIVITY_RESUMED); + assertEquals(left.mTotalTimeInForeground, 0); + assertEquals(left.mTotalTimeVisible, 200000 - 100000); + + left.update("com.test.activity1", 300000, ACTIVITY_PAUSED, 1); + assertEquals(left.mLastTimeUsed, 300000); + assertEquals(left.mLastTimeVisible, 300000); + assertEquals(left.mActivities.get(1), ACTIVITY_PAUSED); + assertEquals(left.mTotalTimeInForeground, 300000 - 200000); + assertEquals(left.mTotalTimeVisible, 300000 - 100000); + + left.update("com.test.activity1", 400000, ACTIVITY_STOPPED, 1); + assertEquals(left.mLastTimeUsed, 300000); + assertEquals(left.mLastTimeVisible, 400000); + assertEquals(left.mActivities.get(1), ACTIVITY_STOPPED); + assertEquals(left.mTotalTimeInForeground, 300000 - 200000); + assertEquals(left.mTotalTimeVisible, 400000 - 100000); } @Test - public void testForegroundActivityEventSequence() { + public void testEvent_CHANGE_TO_INVISIBLE() { left.mPackageName = "com.test"; left.mBeginTimeStamp = 100000; - left.update("com.test.activity1", 100000, CONTINUE_PREVIOUS_DAY); + left.update("com.test.activity1", 100000, ACTIVITY_RESUMED, 1); assertEquals(left.mLastTimeUsed, 100000); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), - new Integer(CONTINUE_PREVIOUS_DAY)); - assertEquals(left.mLaunchCount, 0); - - left.update("com.test.activity1", 350000, MOVE_TO_BACKGROUND); - assertEquals(left.mLastTimeUsed, 350000); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), null); - assertEquals(left.mTotalTimeInForeground, 250000 /*350000 - 100000*/); + assertEquals(left.mLastTimeVisible, 100000); + assertEquals(left.mActivities.get(1), ACTIVITY_RESUMED); - left.update("com.test.activity1", 450000, MOVE_TO_FOREGROUND); - assertEquals(left.mLastTimeUsed, 450000); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), - new Integer(MOVE_TO_FOREGROUND)); - assertEquals(left.mTotalTimeInForeground, 250000); - - left.update("com.test.activity1", 500000, MOVE_TO_BACKGROUND); - assertEquals(left.mLastTimeUsed, 500000); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), null); - assertEquals(left.mTotalTimeInForeground, 250000 + 50000 /*500000 - 450000*/); + left.update("com.test.activity1", 200000, ACTIVITY_STOPPED, 1); + assertEquals(left.mLastTimeUsed, 200000); + assertEquals(left.mLastTimeVisible, 200000); + assertEquals(left.mActivities.get(1), ACTIVITY_STOPPED); + assertEquals(left.mTotalTimeInForeground, 200000 - 100000); + assertEquals(left.mTotalTimeVisible, 200000 - 100000); + + left.update("com.test.activity1", 300000, ACTIVITY_RESUMED, 1); + assertEquals(left.mLastTimeUsed, 300000); + assertEquals(left.mLastTimeVisible, 300000); + assertEquals(left.mActivities.get(1), ACTIVITY_RESUMED); + assertEquals(left.mTotalTimeInForeground, 200000 - 100000); + assertEquals(left.mTotalTimeVisible, 200000 - 100000); } @Test - public void testForegroundActivityEventOutOfSequence() { + public void testEvent_ACTIVITY_DESTROYED() { left.mPackageName = "com.test"; left.mBeginTimeStamp = 100000; - left.update("com.test.activity1", 100000, CONTINUE_PREVIOUS_DAY); + left.update("com.test.activity1", 100000, ACTIVITY_RESUMED, 1); assertEquals(left.mLastTimeUsed, 100000); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), - new Integer(CONTINUE_PREVIOUS_DAY)); - assertEquals(left.mLaunchCount, 0); + assertEquals(left.mLastTimeVisible, 100000); + assertEquals(left.mActivities.get(1), ACTIVITY_RESUMED); - left.update("com.test.activity1", 150000, MOVE_TO_FOREGROUND); - assertEquals(left.mLastTimeUsed, 150000); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), - new Integer(MOVE_TO_FOREGROUND)); + left.update("com.test.activity1", 200000, ACTIVITY_DESTROYED, 1); + assertEquals(left.mLastTimeUsed, 200000); + assertEquals(left.mLastTimeVisible, 200000); + assertTrue(left.mActivities.indexOfKey(1) < 0); + assertEquals(left.mTotalTimeInForeground, 200000 - 100000); + assertEquals(left.mTotalTimeVisible, 200000 - 100000); + } + + @Test + public void testActivityEventOutOfOrder() { + left.mPackageName = "com.test"; + left.mBeginTimeStamp = 100000; + + left.update("com.test.activity1", 100000, Event.ACTIVITY_RESUMED, 1); + assertEquals(left.mLastTimeUsed, 100000); + assertEquals(left.mLastTimeVisible, 100000); + assertEquals(left.mActivities.get(1), Event.ACTIVITY_RESUMED); assertEquals(left.mLaunchCount, 1); - assertEquals(left.mTotalTimeInForeground, 50000 /*150000 - 100000*/); + assertEquals(left.mTotalTimeInForeground, 0); + assertEquals(left.mTotalTimeVisible, 0); - left.update("com.test.activity1", 200000, MOVE_TO_FOREGROUND); + left.update("com.test.activity1", 200000, Event.ACTIVITY_RESUMED, 1); assertEquals(left.mLastTimeUsed, 200000); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), - new Integer(MOVE_TO_FOREGROUND)); + assertEquals(left.mLastTimeVisible, 200000); + assertEquals(left.mActivities.get(1), Event.ACTIVITY_RESUMED); assertEquals(left.mLaunchCount, 2); assertEquals(left.mTotalTimeInForeground, 100000); + assertEquals(left.mTotalTimeVisible, 100000 /*200000 - 100000*/); - left.update("com.test.activity1", 250000, MOVE_TO_BACKGROUND); + left.update("com.test.activity1", 250000, ACTIVITY_PAUSED, 1); assertEquals(left.mLastTimeUsed, 250000); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), null); + assertEquals(left.mLastTimeVisible, 250000); + assertEquals(left.mActivities.get(1), ACTIVITY_PAUSED); assertEquals(left.mTotalTimeInForeground, 150000); + assertEquals(left.mTotalTimeVisible, 150000 /*250000 - 100000*/); - left.update("com.test.activity1", 300000, MOVE_TO_BACKGROUND); + left.update("com.test.activity1", 300000, ACTIVITY_PAUSED, 1); assertEquals(left.mLastTimeUsed, 250000); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), null); + assertEquals(left.mLastTimeVisible, 300000); + assertEquals(left.mActivities.get(1), ACTIVITY_PAUSED); assertEquals(left.mTotalTimeInForeground, 150000); + assertEquals(left.mTotalTimeVisible, 200000 /*300000 - 100000*/); - left.update("com.test.activity1", 350000, MOVE_TO_FOREGROUND); + left.update("com.test.activity1", 350000, Event.ACTIVITY_RESUMED, 1); assertEquals(left.mLastTimeUsed, 350000); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), - new Integer(MOVE_TO_FOREGROUND)); + assertEquals(left.mLastTimeVisible, 350000); + assertEquals(left.mActivities.get(1), Event.ACTIVITY_RESUMED); assertEquals(left.mTotalTimeInForeground, 150000); + assertEquals(left.mTotalTimeVisible, 250000 /*350000 - 100000*/); - left.update("com.test.activity1", 400000, END_OF_DAY); + left.update("com.test.activity1", 400000, END_OF_DAY, 1); assertEquals(left.mLastTimeUsed, 400000); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), - new Integer(END_OF_DAY)); + assertEquals(left.mLastTimeVisible, 400000); + assertEquals(left.mActivities.get(1), Event.ACTIVITY_RESUMED); assertEquals(left.mTotalTimeInForeground, 200000); + assertEquals(left.mTotalTimeVisible, 300000 /*400000 - 100000*/); } @Test @@ -265,28 +320,41 @@ public class UsageStatsTest { left.mPackageName = "com.test"; left.mBeginTimeStamp = 100000; - left.update("com.test.activity1", 100000, CONTINUE_PREVIOUS_DAY); - left.update("com.test.activity2", 100000, CONTINUE_PREVIOUS_DAY); + left.update("com.test.activity1", 100000, Event.ACTIVITY_RESUMED, 1); + left.update("com.test.activity2", 100000, Event.ACTIVITY_RESUMED, 2); assertEquals(left.mLastTimeUsed, 100000); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), - new Integer(CONTINUE_PREVIOUS_DAY)); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity2"), - new Integer(CONTINUE_PREVIOUS_DAY)); - assertEquals(left.mLaunchCount, 0); + assertEquals(left.mLastTimeVisible, 100000); + assertEquals(left.mActivities.get(1), Event.ACTIVITY_RESUMED); + assertEquals(left.mActivities.get(2), Event.ACTIVITY_RESUMED); + assertEquals(left.mLaunchCount, 2); - left.update("com.test.activity1", 350000, MOVE_TO_BACKGROUND); + left.update("com.test.activity1", 350000, ACTIVITY_PAUSED, 1); assertEquals(left.mLastTimeUsed, 350000); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), null); + assertEquals(left.mLastTimeVisible, 350000); + assertEquals(left.mActivities.get(1), ACTIVITY_PAUSED); assertEquals(left.mTotalTimeInForeground, 250000 /*350000 - 100000*/); + assertEquals(left.mTotalTimeVisible, 250000 /*350000 - 100000*/); - left.update("com.test.activity2", 450000, MOVE_TO_BACKGROUND); + left.update("com.test.activity2", 450000, ACTIVITY_PAUSED, 2); assertEquals(left.mLastTimeUsed, 450000); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity2"), null); + assertEquals(left.mLastTimeVisible, 450000); + assertEquals(left.mActivities.get(2), ACTIVITY_PAUSED); assertEquals(left.mTotalTimeInForeground, 250000 + 100000 /*450000 - 350000*/); + assertEquals(left.mTotalTimeVisible, 250000 + 100000 /*450000 - 350000*/); + + left.update("com.test.activity1", 550000, ACTIVITY_STOPPED, 1); + assertEquals(left.mLastTimeUsed, 450000); + assertEquals(left.mLastTimeVisible, 550000); + assertEquals(left.mActivities.get(1), ACTIVITY_STOPPED); + assertEquals(left.mTotalTimeInForeground, 350000); + assertEquals(left.mTotalTimeVisible, 350000 + 100000 /*550000 - 450000*/); - left.update(null, 500000, END_OF_DAY); + left.update("com.test.activity2", 650000, ACTIVITY_STOPPED, 2); assertEquals(left.mLastTimeUsed, 450000); + assertEquals(left.mLastTimeVisible, 650000); + assertEquals(left.mActivities.get(2), ACTIVITY_STOPPED); assertEquals(left.mTotalTimeInForeground, 350000); + assertEquals(left.mTotalTimeVisible, 450000 + 100000 /*650000 - 550000*/); } @Test @@ -294,15 +362,14 @@ public class UsageStatsTest { left.mPackageName = "com.test"; left.mBeginTimeStamp = 100000; - left.update("com.test.service1", 200000, FOREGROUND_SERVICE_START); + left.update("com.test.service1", 200000, FOREGROUND_SERVICE_START, 0); assertEquals(left.mLastTimeForegroundServiceUsed, 200000); - assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"), + assertEquals(left.mForegroundServices.get("com.test.service1"), new Integer(FOREGROUND_SERVICE_START)); - assertEquals(left.mLaunchCount, 0); - left.update("com.test.service1", 350000, FOREGROUND_SERVICE_STOP); + left.update("com.test.service1", 350000, FOREGROUND_SERVICE_STOP, 0); assertEquals(left.mLastTimeForegroundServiceUsed, 350000); - assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"), null); + assertEquals(left.mForegroundServices.get("com.test.service1"), null); assertEquals(left.mTotalTimeForegroundServiceUsed, 350000 - 200000); } @@ -311,15 +378,15 @@ public class UsageStatsTest { left.mPackageName = "com.test"; left.mBeginTimeStamp = 100000; - left.update("com.test.service1", 100000, CONTINUING_FOREGROUND_SERVICE); + left.update("com.test.service1", 100000, + CONTINUING_FOREGROUND_SERVICE, 0); assertEquals(left.mLastTimeForegroundServiceUsed, 100000); - assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"), + assertEquals(left.mForegroundServices.get("com.test.service1"), new Integer(CONTINUING_FOREGROUND_SERVICE)); - assertEquals(left.mLaunchCount, 0); - left.update("com.test.service1", 350000, FOREGROUND_SERVICE_STOP); + left.update("com.test.service1", 350000, FOREGROUND_SERVICE_STOP, 0); assertEquals(left.mLastTimeForegroundServiceUsed, 350000); - assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"), null); + assertEquals(left.mForegroundServices.get("com.test.service1"), null); assertEquals(left.mTotalTimeForegroundServiceUsed, 350000 - 100000); } @@ -329,16 +396,15 @@ public class UsageStatsTest { left.mBeginTimeStamp = 100000; left.update("com.test.service1", 100000, - CONTINUING_FOREGROUND_SERVICE); + CONTINUING_FOREGROUND_SERVICE, 0); assertEquals(left.mLastTimeForegroundServiceUsed, 100000); - assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"), + assertEquals(left.mForegroundServices.get("com.test.service1"), new Integer(CONTINUING_FOREGROUND_SERVICE)); - assertEquals(left.mLaunchCount, 0); - left.update(null, 350000, ROLLOVER_FOREGROUND_SERVICE); + left.update(null, 350000, ROLLOVER_FOREGROUND_SERVICE, 0); assertEquals(left.mLastTimeForegroundServiceUsed, 350000); - assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"), - new Integer(ROLLOVER_FOREGROUND_SERVICE)); + assertEquals(left.mForegroundServices.get("com.test.service1"), + new Integer(CONTINUING_FOREGROUND_SERVICE)); assertEquals(left.mTotalTimeForegroundServiceUsed, 350000 - 100000); } @@ -348,27 +414,28 @@ public class UsageStatsTest { left.mBeginTimeStamp = 100000; left.update("com.test.service1", 100000, - CONTINUING_FOREGROUND_SERVICE); + CONTINUING_FOREGROUND_SERVICE, 0); assertEquals(left.mLastTimeForegroundServiceUsed, 100000); - assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"), + assertEquals(left.mForegroundServices.get("com.test.service1"), new Integer(CONTINUING_FOREGROUND_SERVICE)); assertEquals(left.mLaunchCount, 0); - left.update("com.test.service1", 350000, FOREGROUND_SERVICE_STOP); + left.update("com.test.service1", 350000, FOREGROUND_SERVICE_STOP, 0); assertEquals(left.mLastTimeForegroundServiceUsed, 350000); - assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"), null); + assertEquals(left.mForegroundServices.get("com.test.service1"), null); assertEquals(left.mTotalTimeForegroundServiceUsed, 250000 /*350000 - 100000*/); - left.update("com.test.service1", 450000, FOREGROUND_SERVICE_START); + left.update("com.test.service1", 450000, FOREGROUND_SERVICE_START, 0); assertEquals(left.mLastTimeForegroundServiceUsed, 450000); - assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"), + assertEquals(left.mForegroundServices.get("com.test.service1"), new Integer(FOREGROUND_SERVICE_START)); assertEquals(left.mTotalTimeForegroundServiceUsed, 250000); - left.update("com.test.service1", 500000, FOREGROUND_SERVICE_STOP); + left.update("com.test.service1", 500000, FOREGROUND_SERVICE_STOP, 0); assertEquals(left.mLastTimeForegroundServiceUsed, 500000); - assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"), null); - assertEquals(left.mTotalTimeForegroundServiceUsed, 250000 + 50000 /*500000 - 450000*/); + assertEquals(left.mForegroundServices.get("com.test.service1"), null); + assertEquals(left.mTotalTimeForegroundServiceUsed, + 250000 + 50000 /*500000 - 450000*/); } @Test @@ -377,27 +444,27 @@ public class UsageStatsTest { left.mBeginTimeStamp = 100000; left.update("com.test.service1", 100000, - CONTINUING_FOREGROUND_SERVICE); + CONTINUING_FOREGROUND_SERVICE, 0); left.update("com.test.service2", 100000, - CONTINUING_FOREGROUND_SERVICE); + CONTINUING_FOREGROUND_SERVICE, 0); assertEquals(left.mLastTimeForegroundServiceUsed, 100000); - assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"), + assertEquals(left.mForegroundServices.get("com.test.service1"), new Integer(CONTINUING_FOREGROUND_SERVICE)); - assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service2"), + assertEquals(left.mForegroundServices.get("com.test.service2"), new Integer(CONTINUING_FOREGROUND_SERVICE)); - assertEquals(left.mLaunchCount, 0); - left.update("com.test.service1", 350000, FOREGROUND_SERVICE_STOP); + left.update("com.test.service1", 350000, FOREGROUND_SERVICE_STOP, 0); assertEquals(left.mLastTimeForegroundServiceUsed, 350000); - assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"), null); + assertEquals(left.mForegroundServices.get("com.test.service1"), null); assertEquals(left.mTotalTimeForegroundServiceUsed, 250000 /*350000 - 100000*/); - left.update("com.test.service2", 450000, FOREGROUND_SERVICE_STOP); + left.update("com.test.service2", 450000, FOREGROUND_SERVICE_STOP, 0); assertEquals(left.mLastTimeForegroundServiceUsed, 450000); - assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service2"), null); - assertEquals(left.mTotalTimeForegroundServiceUsed, 250000 + 100000 /*450000 - 350000*/); + assertEquals(left.mForegroundServices.get("com.test.service2"), null); + assertEquals(left.mTotalTimeForegroundServiceUsed, + 250000 + 100000 /*450000 - 350000*/); - left.update(null, 500000, ROLLOVER_FOREGROUND_SERVICE); + left.update(null, 500000, ROLLOVER_FOREGROUND_SERVICE, 0); assertEquals(left.mLastTimeForegroundServiceUsed, 450000); assertEquals(left.mTotalTimeForegroundServiceUsed, 350000); } @@ -407,76 +474,117 @@ public class UsageStatsTest { left.mPackageName = "com.test"; left.mBeginTimeStamp = 100000; - left.update("com.test.activity1", 100000, CONTINUE_PREVIOUS_DAY); - left.update("com.test.activity2", 100000, CONTINUE_PREVIOUS_DAY); + left.update("com.test.activity1", 100000, Event.ACTIVITY_RESUMED, 1); + left.update("com.test.activity2", 100000, Event.ACTIVITY_RESUMED, 2); left.update("com.test.service1", 100000, - CONTINUING_FOREGROUND_SERVICE); + CONTINUING_FOREGROUND_SERVICE, 0); left.update("com.test.service2", 100000, - CONTINUING_FOREGROUND_SERVICE); + CONTINUING_FOREGROUND_SERVICE, 0); assertEquals(left.mLastTimeUsed, 100000); assertEquals(left.mLastTimeForegroundServiceUsed, 100000); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), - new Integer(CONTINUE_PREVIOUS_DAY)); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity2"), - new Integer(CONTINUE_PREVIOUS_DAY)); - assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"), + assertEquals(left.mActivities.get(1), Event.ACTIVITY_RESUMED); + assertEquals(left.mActivities.get(2), Event.ACTIVITY_RESUMED); + assertEquals(left.mForegroundServices.get("com.test.service1"), new Integer(CONTINUING_FOREGROUND_SERVICE)); - assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service2"), + assertEquals(left.mForegroundServices.get("com.test.service2"), new Integer(CONTINUING_FOREGROUND_SERVICE)); - assertEquals(left.mLaunchCount, 0); + assertEquals(left.mLaunchCount, 2); - left.update("com.test.activity1", 350000, MOVE_TO_BACKGROUND); + left.update("com.test.activity1", 350000, ACTIVITY_PAUSED, 1); assertEquals(left.mLastTimeUsed, 350000); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), null); + assertEquals(left.mLastTimeVisible, 350000); + assertEquals(left.mActivities.get(1), ACTIVITY_PAUSED); assertEquals(left.mTotalTimeInForeground, 250000 /*350000 - 100000*/); + assertEquals(left.mTotalTimeVisible, 250000 /*350000 - 100000*/); - left.update("com.test.service1", 400000, FOREGROUND_SERVICE_STOP); + left.update("com.test.service1", 400000, FOREGROUND_SERVICE_STOP, 0); assertEquals(left.mLastTimeForegroundServiceUsed, 400000); - assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"), null); + assertEquals(left.mForegroundServices.get("com.test.service1"), null); assertEquals(left.mTotalTimeForegroundServiceUsed, 300000 /*400000 - 100000*/); - left.update("com.test.activity2", 450000, MOVE_TO_BACKGROUND); + left.update("com.test.activity2", 450000, ACTIVITY_PAUSED, 2); assertEquals(left.mLastTimeUsed, 450000); - assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity2"), null); + assertEquals(left.mLastTimeVisible, 450000); + assertEquals(left.mActivities.get(2), ACTIVITY_PAUSED); assertEquals(left.mTotalTimeInForeground, 250000 + 100000 /*450000 - 350000*/); + assertEquals(left.mTotalTimeVisible, 250000 + 100000 /*450000 - 350000*/); - left.update("com.test.service2", 500000, FOREGROUND_SERVICE_STOP); + left.update("com.test.service2", 500000, FOREGROUND_SERVICE_STOP, 0); assertEquals(left.mLastTimeForegroundServiceUsed, 500000); - assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service2"), null); - assertEquals(left.mTotalTimeForegroundServiceUsed, 300000 + 100000 /*500000 - 400000*/); + assertEquals(left.mForegroundServices.get("com.test.service2"), null); + assertEquals(left.mTotalTimeForegroundServiceUsed, + 300000 + 100000 /*500000 - 400000*/); - left.update(null, 550000, END_OF_DAY); + left.update(null, 550000, END_OF_DAY, 0); assertEquals(left.mLastTimeUsed, 450000); + assertEquals(left.mLastTimeVisible, 550000); assertEquals(left.mTotalTimeInForeground, 350000); - left.update(null, 550000, ROLLOVER_FOREGROUND_SERVICE); + assertEquals(left.mTotalTimeVisible, 450000); + + left.update(null, 550000, ROLLOVER_FOREGROUND_SERVICE, 0); assertEquals(left.mLastTimeForegroundServiceUsed, 500000); assertEquals(left.mTotalTimeForegroundServiceUsed, 400000); } + @Test + public void testEvent_FLUSH_TO_DISK() { + testClosingEvent(FLUSH_TO_DISK); + } + + private void testClosingEvent(int eventType) { + // When these three closing events are received, all open activities/services need to be + // closed and usage stats are updated. + if (eventType != FLUSH_TO_DISK) { + fail("Closing eventType must be one of FLUSH_TO_DISK"); + } + + left.mPackageName = "com.test"; + left.mBeginTimeStamp = 100000; + + left.update("com.test.activity1", 100000, Event.ACTIVITY_RESUMED, 1); + assertEquals(left.mLastTimeUsed, 100000); + assertEquals(left.mLastTimeVisible, 100000); + assertEquals(left.mActivities.get(1), Event.ACTIVITY_RESUMED); + + left.update("com.test.service1", 150000, FOREGROUND_SERVICE_START, 0); + assertEquals(left.mLastTimeForegroundServiceUsed, 150000); + assertEquals(left.mForegroundServices.get("com.test.service1"), + new Integer(FOREGROUND_SERVICE_START)); + + left.update(null, 200000, eventType, 0); + assertEquals(left.mLastTimeUsed, 200000); + assertEquals(left.mLastTimeVisible, 200000); + assertEquals(left.mTotalTimeInForeground, 200000 - 100000); + assertEquals(left.mTotalTimeVisible, 200000 - 100000); + assertEquals(left.mLastTimeForegroundServiceUsed, 200000); + assertEquals(left.mTotalTimeForegroundServiceUsed, 200000 - 150000); + } + void compareUsageStats(UsageStats us1, UsageStats us2) { assertEquals(us1.mPackageName, us2.mPackageName); assertEquals(us1.mBeginTimeStamp, us2.mBeginTimeStamp); assertEquals(us1.mLastTimeUsed, us2.mLastTimeUsed); + assertEquals(us1.mLastTimeVisible, us2.mLastTimeVisible); assertEquals(us1.mLastTimeForegroundServiceUsed, us2.mLastTimeForegroundServiceUsed); assertEquals(us1.mTotalTimeInForeground, us2.mTotalTimeInForeground); assertEquals(us1.mTotalTimeForegroundServiceUsed, us2.mTotalTimeForegroundServiceUsed); assertEquals(us1.mAppLaunchCount, us2.mAppLaunchCount); - assertEquals(us1.mLastForegroundActivityEventMap.size(), - us2.mLastForegroundActivityEventMap.size()); - for (int i = 0; i < us1.mLastForegroundActivityEventMap.size(); i++) { - assertEquals(us1.mLastForegroundActivityEventMap.keyAt(i), - us2.mLastForegroundActivityEventMap.keyAt(i)); - assertEquals(us1.mLastForegroundActivityEventMap.valueAt(i), - us2.mLastForegroundActivityEventMap.valueAt(i)); + assertEquals(us1.mActivities.size(), + us2.mActivities.size()); + for (int i = 0; i < us1.mActivities.size(); i++) { + assertEquals(us1.mActivities.keyAt(i), + us2.mActivities.keyAt(i)); + assertEquals(us1.mActivities.valueAt(i), + us2.mActivities.valueAt(i)); } - assertEquals(us1.mLastForegroundServiceEventMap.size(), - us2.mLastForegroundServiceEventMap.size()); - for (int i = 0; i < us1.mLastForegroundServiceEventMap.size(); i++) { - assertEquals(us1.mLastForegroundServiceEventMap.keyAt(i), - us2.mLastForegroundServiceEventMap.keyAt(i)); - assertEquals(us1.mLastForegroundServiceEventMap.valueAt(i), - us2.mLastForegroundServiceEventMap.valueAt(i)); + assertEquals(us1.mForegroundServices.size(), + us2.mForegroundServices.size()); + for (int i = 0; i < us1.mForegroundServices.size(); i++) { + assertEquals(us1.mForegroundServices.keyAt(i), + us2.mForegroundServices.keyAt(i)); + assertEquals(us1.mForegroundServices.valueAt(i), + us2.mForegroundServices.valueAt(i)); } assertEquals(us1.mChooserCounts, us2.mChooserCounts); } diff --git a/core/tests/coretests/src/android/text/MeasuredParagraphTest.java b/core/tests/coretests/src/android/text/MeasuredParagraphTest.java index 3d15eb9577b5..a0dca2c0dc4f 100644 --- a/core/tests/coretests/src/android/text/MeasuredParagraphTest.java +++ b/core/tests/coretests/src/android/text/MeasuredParagraphTest.java @@ -133,7 +133,8 @@ public class MeasuredParagraphTest { public void buildForStaticLayout() { MeasuredParagraph mt = null; - mt = MeasuredParagraph.buildForStaticLayout(PAINT, "XXX", 0, 3, LTR, false, false, null); + mt = MeasuredParagraph.buildForStaticLayout( + PAINT, "XXX", 0, 3, LTR, false, false, null /* no hint */, null); assertNotNull(mt); assertNotNull(mt.getChars()); assertEquals("XXX", charsToString(mt.getChars())); @@ -147,8 +148,8 @@ public class MeasuredParagraphTest { assertNotNull(mt.getMeasuredText()); // Recycle it - MeasuredParagraph mt2 = - MeasuredParagraph.buildForStaticLayout(PAINT, "_VVV_", 1, 4, RTL, false, false, mt); + MeasuredParagraph mt2 = MeasuredParagraph.buildForStaticLayout( + PAINT, "_VVV_", 1, 4, RTL, false, false, null /* no hint */, mt); assertEquals(mt2, mt); assertNotNull(mt2.getChars()); assertEquals("VVV", charsToString(mt.getChars())); diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java index 4ee45bfd8bc8..70c90eb05b17 100644 --- a/graphics/java/android/graphics/drawable/DrawableWrapper.java +++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java @@ -65,7 +65,7 @@ public abstract class DrawableWrapper extends Drawable implements Drawable.Callb */ public DrawableWrapper(@Nullable Drawable dr) { mState = null; - mDrawable = dr; + setDrawable(dr); } /** diff --git a/graphics/java/android/graphics/text/MeasuredText.java b/graphics/java/android/graphics/text/MeasuredText.java index 6f786517ba12..2536619bb7c8 100644 --- a/graphics/java/android/graphics/text/MeasuredText.java +++ b/graphics/java/android/graphics/text/MeasuredText.java @@ -19,6 +19,7 @@ package android.graphics.text; import android.annotation.FloatRange; import android.annotation.IntRange; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.Px; import android.graphics.Paint; import android.graphics.Rect; @@ -49,12 +50,17 @@ import libcore.util.NativeAllocationRegistry; */ public class MeasuredText { private long mNativePtr; + private boolean mComputeHyphenation; + private boolean mComputeLayout; private @NonNull char[] mChars; // Use builder instead. - private MeasuredText(long ptr, @NonNull char[] chars) { + private MeasuredText(long ptr, @NonNull char[] chars, boolean computeHyphenation, + boolean computeLayout) { mNativePtr = ptr; mChars = chars; + mComputeHyphenation = computeHyphenation; + mComputeLayout = computeLayout; } /** @@ -172,6 +178,7 @@ public class MeasuredText { private boolean mComputeHyphenation = false; private boolean mComputeLayout = true; private int mCurrentOffset = 0; + private @Nullable MeasuredText mHintMt = null; /** * Construct a builder. @@ -188,6 +195,27 @@ public class MeasuredText { } /** + * Construct a builder with existing MeasuredText. + * + * The MeasuredText returned by build method will hold a reference of the text. Developer is + * not supposed to modify the text. + * + * @param text a text + */ + public Builder(@NonNull MeasuredText text) { + Preconditions.checkNotNull(text); + mText = text.mChars; + mNativePtr = nInitBuilder(); + if (!text.mComputeLayout) { + throw new IllegalArgumentException( + "The input MeasuredText must not be created with setComputeLayout(false)."); + } + mComputeHyphenation = text.mComputeHyphenation; + mComputeLayout = text.mComputeLayout; + mHintMt = text; + } + + /** * Apply styles to the given length. * * Keeps an internal offset which increases at every append. The initial value for this @@ -282,10 +310,16 @@ public class MeasuredText { if (mCurrentOffset != mText.length) { throw new IllegalStateException("Style info has not been provided for all text."); } + if (mHintMt != null && mHintMt.mComputeHyphenation != mComputeHyphenation) { + throw new IllegalArgumentException( + "The hyphenation configuration is different from given hint MeasuredText"); + } try { - long ptr = nBuildMeasuredText(mNativePtr, mText, mComputeHyphenation, + long hintPtr = (mHintMt == null) ? 0 : mHintMt.getNativePtr(); + long ptr = nBuildMeasuredText(mNativePtr, hintPtr, mText, mComputeHyphenation, + mComputeLayout); + final MeasuredText res = new MeasuredText(ptr, mText, mComputeHyphenation, mComputeLayout); - MeasuredText res = new MeasuredText(ptr, mText); sRegistry.registerNativeAllocation(res, ptr); return res; } finally { @@ -339,6 +373,7 @@ public class MeasuredText { private static native long nBuildMeasuredText( /* Non Zero */ long nativeBuilderPtr, + long hintMtPtr, @NonNull char[] text, boolean computeHyphenation, boolean computeLayout); diff --git a/libs/androidfw/LocaleData.cpp b/libs/androidfw/LocaleData.cpp index 889d166d853b..020cef6012e9 100644 --- a/libs/androidfw/LocaleData.cpp +++ b/libs/androidfw/LocaleData.cpp @@ -34,11 +34,11 @@ inline uint32_t packLocale(const char* language, const char* region) { } inline uint32_t dropRegion(uint32_t packed_locale) { - return packed_locale & 0xFFFF0000lu; + return packed_locale & 0xFFFF0000LU; } inline bool hasRegion(uint32_t packed_locale) { - return (packed_locale & 0x0000FFFFlu) != 0; + return (packed_locale & 0x0000FFFFLU) != 0; } const size_t SCRIPT_LENGTH = 4; @@ -122,9 +122,9 @@ inline bool isRepresentative(uint32_t language_and_region, const char* script) { return (REPRESENTATIVE_LOCALES.count(packed_locale) != 0); } -const uint32_t US_SPANISH = 0x65735553lu; // es-US -const uint32_t MEXICAN_SPANISH = 0x65734D58lu; // es-MX -const uint32_t LATIN_AMERICAN_SPANISH = 0x6573A424lu; // es-419 +const uint32_t US_SPANISH = 0x65735553LU; // es-US +const uint32_t MEXICAN_SPANISH = 0x65734D58LU; // es-MX +const uint32_t LATIN_AMERICAN_SPANISH = 0x6573A424LU; // es-419 // The two locales es-US and es-MX are treated as special fallbacks for es-419. // If there is no es-419, they are considered its equivalent. @@ -225,8 +225,8 @@ void localeDataComputeScript(char out[4], const char* language, const char* regi } const uint32_t ENGLISH_STOP_LIST[2] = { - 0x656E0000lu, // en - 0x656E8400lu, // en-001 + 0x656E0000LU, // en + 0x656E8400LU, // en-001 }; const char ENGLISH_CHARS[2] = {'e', 'n'}; const char LATIN_CHARS[4] = {'L', 'a', 't', 'n'}; diff --git a/libs/androidfw/LocaleDataTables.cpp b/libs/androidfw/LocaleDataTables.cpp index 7c381efec7ec..c276a238e2e1 100644 --- a/libs/androidfw/LocaleDataTables.cpp +++ b/libs/androidfw/LocaleDataTables.cpp @@ -1446,733 +1446,733 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({ }); std::unordered_set<uint64_t> REPRESENTATIVE_LOCALES({ - 0x616145544C61746Ellu, // aa_Latn_ET - 0x616247454379726Cllu, // ab_Cyrl_GE - 0xC42047484C61746Ellu, // abr_Latn_GH - 0x904049444C61746Ellu, // ace_Latn_ID - 0x9C4055474C61746Ellu, // ach_Latn_UG - 0x806047484C61746Ellu, // ada_Latn_GH - 0xE06052554379726Cllu, // ady_Cyrl_RU - 0x6165495241767374llu, // ae_Avst_IR - 0x8480544E41726162llu, // aeb_Arab_TN - 0x61665A414C61746Ellu, // af_Latn_ZA - 0xC0C0434D4C61746Ellu, // agq_Latn_CM - 0xB8E0494E41686F6Dllu, // aho_Ahom_IN - 0x616B47484C61746Ellu, // ak_Latn_GH - 0xA940495158737578llu, // akk_Xsux_IQ - 0xB560584B4C61746Ellu, // aln_Latn_XK - 0xCD6052554379726Cllu, // alt_Cyrl_RU - 0x616D455445746869llu, // am_Ethi_ET - 0xB9804E474C61746Ellu, // amo_Latn_NG - 0xE5C049444C61746Ellu, // aoz_Latn_ID - 0x8DE0544741726162llu, // apd_Arab_TG - 0x6172454741726162llu, // ar_Arab_EG - 0x8A20495241726D69llu, // arc_Armi_IR - 0x8A204A4F4E626174llu, // arc_Nbat_JO - 0x8A20535950616C6Dllu, // arc_Palm_SY - 0xB620434C4C61746Ellu, // arn_Latn_CL - 0xBA20424F4C61746Ellu, // aro_Latn_BO - 0xC220445A41726162llu, // arq_Arab_DZ - 0xE2204D4141726162llu, // ary_Arab_MA - 0xE620454741726162llu, // arz_Arab_EG - 0x6173494E42656E67llu, // as_Beng_IN - 0x8240545A4C61746Ellu, // asa_Latn_TZ - 0x9240555353676E77llu, // ase_Sgnw_US - 0xCE4045534C61746Ellu, // ast_Latn_ES - 0xA66043414C61746Ellu, // atj_Latn_CA - 0x617652554379726Cllu, // av_Cyrl_RU - 0x82C0494E44657661llu, // awa_Deva_IN - 0x6179424F4C61746Ellu, // ay_Latn_BO - 0x617A495241726162llu, // az_Arab_IR - 0x617A415A4C61746Ellu, // az_Latn_AZ - 0x626152554379726Cllu, // ba_Cyrl_RU - 0xAC01504B41726162llu, // bal_Arab_PK - 0xB40149444C61746Ellu, // ban_Latn_ID - 0xBC014E5044657661llu, // bap_Deva_NP - 0xC40141544C61746Ellu, // bar_Latn_AT - 0xC801434D4C61746Ellu, // bas_Latn_CM - 0xDC01434D42616D75llu, // bax_Bamu_CM - 0x882149444C61746Ellu, // bbc_Latn_ID - 0xA421434D4C61746Ellu, // bbj_Latn_CM - 0xA04143494C61746Ellu, // bci_Latn_CI - 0x626542594379726Cllu, // be_Cyrl_BY - 0xA481534441726162llu, // bej_Arab_SD - 0xB0815A4D4C61746Ellu, // bem_Latn_ZM - 0xD88149444C61746Ellu, // bew_Latn_ID - 0xE481545A4C61746Ellu, // bez_Latn_TZ - 0x8CA1434D4C61746Ellu, // bfd_Latn_CM - 0xC0A1494E54616D6Cllu, // bfq_Taml_IN - 0xCCA1504B41726162llu, // bft_Arab_PK - 0xE0A1494E44657661llu, // bfy_Deva_IN - 0x626742474379726Cllu, // bg_Cyrl_BG - 0x88C1494E44657661llu, // bgc_Deva_IN - 0xB4C1504B41726162llu, // bgn_Arab_PK - 0xDCC154524772656Bllu, // bgx_Grek_TR - 0x84E1494E44657661llu, // bhb_Deva_IN - 0xA0E1494E44657661llu, // bhi_Deva_IN - 0xA8E150484C61746Ellu, // bhk_Latn_PH - 0xB8E1494E44657661llu, // bho_Deva_IN - 0x626956554C61746Ellu, // bi_Latn_VU - 0xA90150484C61746Ellu, // bik_Latn_PH - 0xB5014E474C61746Ellu, // bin_Latn_NG - 0xA521494E44657661llu, // bjj_Deva_IN - 0xB52149444C61746Ellu, // bjn_Latn_ID - 0xB141434D4C61746Ellu, // bkm_Latn_CM - 0xD14150484C61746Ellu, // bku_Latn_PH - 0xCD61564E54617674llu, // blt_Tavt_VN - 0x626D4D4C4C61746Ellu, // bm_Latn_ML - 0xC1814D4C4C61746Ellu, // bmq_Latn_ML - 0x626E424442656E67llu, // bn_Beng_BD - 0x626F434E54696274llu, // bo_Tibt_CN - 0xE1E1494E42656E67llu, // bpy_Beng_IN - 0xA201495241726162llu, // bqi_Arab_IR - 0xD60143494C61746Ellu, // bqv_Latn_CI - 0x627246524C61746Ellu, // br_Latn_FR - 0x8221494E44657661llu, // bra_Deva_IN - 0x9E21504B41726162llu, // brh_Arab_PK - 0xDE21494E44657661llu, // brx_Deva_IN - 0x627342414C61746Ellu, // bs_Latn_BA - 0xC2414C5242617373llu, // bsq_Bass_LR - 0xCA41434D4C61746Ellu, // bss_Latn_CM - 0xBA6150484C61746Ellu, // bto_Latn_PH - 0xD661504B44657661llu, // btv_Deva_PK - 0x828152554379726Cllu, // bua_Cyrl_RU - 0x8A8159544C61746Ellu, // buc_Latn_YT - 0x9A8149444C61746Ellu, // bug_Latn_ID - 0xB281434D4C61746Ellu, // bum_Latn_CM - 0x86A147514C61746Ellu, // bvb_Latn_GQ - 0xB701455245746869llu, // byn_Ethi_ER - 0xD701434D4C61746Ellu, // byv_Latn_CM - 0x93214D4C4C61746Ellu, // bze_Latn_ML - 0x636145534C61746Ellu, // ca_Latn_ES - 0x9C424E474C61746Ellu, // cch_Latn_NG - 0xBC42494E42656E67llu, // ccp_Beng_IN - 0xBC42424443616B6Dllu, // ccp_Cakm_BD - 0x636552554379726Cllu, // ce_Cyrl_RU - 0x848250484C61746Ellu, // ceb_Latn_PH - 0x98C255474C61746Ellu, // cgg_Latn_UG - 0x636847554C61746Ellu, // ch_Latn_GU - 0xA8E2464D4C61746Ellu, // chk_Latn_FM - 0xB0E252554379726Cllu, // chm_Cyrl_RU - 0xB8E255534C61746Ellu, // cho_Latn_US - 0xBCE243414C61746Ellu, // chp_Latn_CA - 0xC4E2555343686572llu, // chr_Cher_US - 0x81224B4841726162llu, // cja_Arab_KH - 0xB122564E4368616Dllu, // cjm_Cham_VN - 0x8542495141726162llu, // ckb_Arab_IQ - 0x636F46524C61746Ellu, // co_Latn_FR - 0xBDC24547436F7074llu, // cop_Copt_EG - 0xC9E250484C61746Ellu, // cps_Latn_PH - 0x6372434143616E73llu, // cr_Cans_CA - 0xA622434143616E73llu, // crj_Cans_CA - 0xAA22434143616E73llu, // crk_Cans_CA - 0xAE22434143616E73llu, // crl_Cans_CA - 0xB222434143616E73llu, // crm_Cans_CA - 0xCA2253434C61746Ellu, // crs_Latn_SC - 0x6373435A4C61746Ellu, // cs_Latn_CZ - 0x8642504C4C61746Ellu, // csb_Latn_PL - 0xDA42434143616E73llu, // csw_Cans_CA - 0x8E624D4D50617563llu, // ctd_Pauc_MM - 0x637552554379726Cllu, // cu_Cyrl_RU - 0x63754247476C6167llu, // cu_Glag_BG - 0x637652554379726Cllu, // cv_Cyrl_RU - 0x637947424C61746Ellu, // cy_Latn_GB - 0x6461444B4C61746Ellu, // da_Latn_DK - 0xA80355534C61746Ellu, // dak_Latn_US - 0xC40352554379726Cllu, // dar_Cyrl_RU - 0xD4034B454C61746Ellu, // dav_Latn_KE - 0x8843494E41726162llu, // dcc_Arab_IN - 0x646544454C61746Ellu, // de_Latn_DE - 0xB48343414C61746Ellu, // den_Latn_CA - 0xC4C343414C61746Ellu, // dgr_Latn_CA - 0x91234E454C61746Ellu, // dje_Latn_NE - 0xA5A343494C61746Ellu, // dnj_Latn_CI - 0xA1C3494E41726162llu, // doi_Arab_IN - 0x864344454C61746Ellu, // dsb_Latn_DE - 0xB2634D4C4C61746Ellu, // dtm_Latn_ML - 0xBE634D594C61746Ellu, // dtp_Latn_MY - 0xE2634E5044657661llu, // dty_Deva_NP - 0x8283434D4C61746Ellu, // dua_Latn_CM - 0x64764D5654686161llu, // dv_Thaa_MV - 0xBB03534E4C61746Ellu, // dyo_Latn_SN - 0xD30342464C61746Ellu, // dyu_Latn_BF - 0x647A425454696274llu, // dz_Tibt_BT - 0xD0244B454C61746Ellu, // ebu_Latn_KE - 0x656547484C61746Ellu, // ee_Latn_GH - 0xA0A44E474C61746Ellu, // efi_Latn_NG - 0xACC449544C61746Ellu, // egl_Latn_IT - 0xE0C4454745677970llu, // egy_Egyp_EG - 0xE1444D4D4B616C69llu, // eky_Kali_MM - 0x656C47524772656Bllu, // el_Grek_GR - 0x656E47424C61746Ellu, // en_Latn_GB - 0x656E55534C61746Ellu, // en_Latn_US - 0x656E474253686177llu, // en_Shaw_GB - 0x657345534C61746Ellu, // es_Latn_ES - 0x65734D584C61746Ellu, // es_Latn_MX - 0x657355534C61746Ellu, // es_Latn_US - 0xD24455534C61746Ellu, // esu_Latn_US - 0x657445454C61746Ellu, // et_Latn_EE - 0xCE6449544974616Cllu, // ett_Ital_IT - 0x657545534C61746Ellu, // eu_Latn_ES - 0xBAC4434D4C61746Ellu, // ewo_Latn_CM - 0xCEE445534C61746Ellu, // ext_Latn_ES - 0x6661495241726162llu, // fa_Arab_IR - 0xB40547514C61746Ellu, // fan_Latn_GQ - 0x6666474E41646C6Dllu, // ff_Adlm_GN - 0x6666534E4C61746Ellu, // ff_Latn_SN - 0xB0A54D4C4C61746Ellu, // ffm_Latn_ML - 0x666946494C61746Ellu, // fi_Latn_FI - 0x8105534441726162llu, // fia_Arab_SD - 0xAD0550484C61746Ellu, // fil_Latn_PH - 0xCD0553454C61746Ellu, // fit_Latn_SE - 0x666A464A4C61746Ellu, // fj_Latn_FJ - 0x666F464F4C61746Ellu, // fo_Latn_FO - 0xB5C5424A4C61746Ellu, // fon_Latn_BJ - 0x667246524C61746Ellu, // fr_Latn_FR - 0x8A2555534C61746Ellu, // frc_Latn_US - 0xBE2546524C61746Ellu, // frp_Latn_FR - 0xC62544454C61746Ellu, // frr_Latn_DE - 0xCA2544454C61746Ellu, // frs_Latn_DE - 0x8685434D41726162llu, // fub_Arab_CM - 0x8E8557464C61746Ellu, // fud_Latn_WF - 0x9685474E4C61746Ellu, // fuf_Latn_GN - 0xC2854E454C61746Ellu, // fuq_Latn_NE - 0xC68549544C61746Ellu, // fur_Latn_IT - 0xD6854E474C61746Ellu, // fuv_Latn_NG - 0xC6A553444C61746Ellu, // fvr_Latn_SD - 0x66794E4C4C61746Ellu, // fy_Latn_NL - 0x676149454C61746Ellu, // ga_Latn_IE - 0x800647484C61746Ellu, // gaa_Latn_GH - 0x98064D444C61746Ellu, // gag_Latn_MD - 0xB406434E48616E73llu, // gan_Hans_CN - 0xE00649444C61746Ellu, // gay_Latn_ID - 0xB026494E44657661llu, // gbm_Deva_IN - 0xE426495241726162llu, // gbz_Arab_IR - 0xC44647464C61746Ellu, // gcr_Latn_GF - 0x676447424C61746Ellu, // gd_Latn_GB - 0xE486455445746869llu, // gez_Ethi_ET - 0xB4C64E5044657661llu, // ggn_Deva_NP - 0xAD064B494C61746Ellu, // gil_Latn_KI - 0xA926504B41726162llu, // gjk_Arab_PK - 0xD126504B41726162llu, // gju_Arab_PK - 0x676C45534C61746Ellu, // gl_Latn_ES - 0xA966495241726162llu, // glk_Arab_IR - 0x676E50594C61746Ellu, // gn_Latn_PY - 0xB1C6494E44657661llu, // gom_Deva_IN - 0xB5C6494E54656C75llu, // gon_Telu_IN - 0xC5C649444C61746Ellu, // gor_Latn_ID - 0xC9C64E4C4C61746Ellu, // gos_Latn_NL - 0xCDC65541476F7468llu, // got_Goth_UA - 0x8A26435943707274llu, // grc_Cprt_CY - 0x8A2647524C696E62llu, // grc_Linb_GR - 0xCE26494E42656E67llu, // grt_Beng_IN - 0xDA4643484C61746Ellu, // gsw_Latn_CH - 0x6775494E47756A72llu, // gu_Gujr_IN - 0x868642524C61746Ellu, // gub_Latn_BR - 0x8A86434F4C61746Ellu, // guc_Latn_CO - 0xC68647484C61746Ellu, // gur_Latn_GH - 0xE6864B454C61746Ellu, // guz_Latn_KE - 0x6776494D4C61746Ellu, // gv_Latn_IM - 0xC6A64E5044657661llu, // gvr_Deva_NP - 0xA2C643414C61746Ellu, // gwi_Latn_CA - 0x68614E474C61746Ellu, // ha_Latn_NG - 0xA807434E48616E73llu, // hak_Hans_CN - 0xD80755534C61746Ellu, // haw_Latn_US - 0xE407414641726162llu, // haz_Arab_AF - 0x6865494C48656272llu, // he_Hebr_IL - 0x6869494E44657661llu, // hi_Deva_IN - 0x9507464A4C61746Ellu, // hif_Latn_FJ - 0xAD0750484C61746Ellu, // hil_Latn_PH - 0xD1675452486C7577llu, // hlu_Hluw_TR - 0x8D87434E506C7264llu, // hmd_Plrd_CN - 0x8DA7504B41726162llu, // hnd_Arab_PK - 0x91A7494E44657661llu, // hne_Deva_IN - 0xA5A74C41486D6E67llu, // hnj_Hmng_LA - 0xB5A750484C61746Ellu, // hnn_Latn_PH - 0xB9A7504B41726162llu, // hno_Arab_PK - 0x686F50474C61746Ellu, // ho_Latn_PG - 0x89C7494E44657661llu, // hoc_Deva_IN - 0xA5C7494E44657661llu, // hoj_Deva_IN - 0x687248524C61746Ellu, // hr_Latn_HR - 0x864744454C61746Ellu, // hsb_Latn_DE - 0xB647434E48616E73llu, // hsn_Hans_CN - 0x687448544C61746Ellu, // ht_Latn_HT - 0x687548554C61746Ellu, // hu_Latn_HU - 0x6879414D41726D6Ellu, // hy_Armn_AM - 0x687A4E414C61746Ellu, // hz_Latn_NA - 0x696146524C61746Ellu, // ia_Latn_FR - 0x80284D594C61746Ellu, // iba_Latn_MY - 0x84284E474C61746Ellu, // ibb_Latn_NG - 0x696449444C61746Ellu, // id_Latn_ID - 0x69674E474C61746Ellu, // ig_Latn_NG - 0x6969434E59696969llu, // ii_Yiii_CN - 0x696B55534C61746Ellu, // ik_Latn_US - 0xCD4843414C61746Ellu, // ikt_Latn_CA - 0xB96850484C61746Ellu, // ilo_Latn_PH - 0x696E49444C61746Ellu, // in_Latn_ID - 0x9DA852554379726Cllu, // inh_Cyrl_RU - 0x697349534C61746Ellu, // is_Latn_IS - 0x697449544C61746Ellu, // it_Latn_IT - 0x6975434143616E73llu, // iu_Cans_CA - 0x6977494C48656272llu, // iw_Hebr_IL - 0x9F2852554C61746Ellu, // izh_Latn_RU - 0x6A614A504A70616Ellu, // ja_Jpan_JP - 0xB0094A4D4C61746Ellu, // jam_Latn_JM - 0xB8C9434D4C61746Ellu, // jgo_Latn_CM - 0x8989545A4C61746Ellu, // jmc_Latn_TZ - 0xAD894E5044657661llu, // jml_Deva_NP - 0xCE89444B4C61746Ellu, // jut_Latn_DK - 0x6A7649444C61746Ellu, // jv_Latn_ID - 0x6A7749444C61746Ellu, // jw_Latn_ID - 0x6B61474547656F72llu, // ka_Geor_GE - 0x800A555A4379726Cllu, // kaa_Cyrl_UZ - 0x840A445A4C61746Ellu, // kab_Latn_DZ - 0x880A4D4D4C61746Ellu, // kac_Latn_MM - 0xA40A4E474C61746Ellu, // kaj_Latn_NG - 0xB00A4B454C61746Ellu, // kam_Latn_KE - 0xB80A4D4C4C61746Ellu, // kao_Latn_ML - 0x8C2A52554379726Cllu, // kbd_Cyrl_RU - 0xE02A4E4541726162llu, // kby_Arab_NE - 0x984A4E474C61746Ellu, // kcg_Latn_NG - 0xA84A5A574C61746Ellu, // kck_Latn_ZW - 0x906A545A4C61746Ellu, // kde_Latn_TZ - 0x9C6A544741726162llu, // kdh_Arab_TG - 0xCC6A544854686169llu, // kdt_Thai_TH - 0x808A43564C61746Ellu, // kea_Latn_CV - 0xB48A434D4C61746Ellu, // ken_Latn_CM - 0xB8AA43494C61746Ellu, // kfo_Latn_CI - 0xC4AA494E44657661llu, // kfr_Deva_IN - 0xE0AA494E44657661llu, // kfy_Deva_IN - 0x6B6743444C61746Ellu, // kg_Latn_CD - 0x90CA49444C61746Ellu, // kge_Latn_ID - 0xBCCA42524C61746Ellu, // kgp_Latn_BR - 0x80EA494E4C61746Ellu, // kha_Latn_IN - 0x84EA434E54616C75llu, // khb_Talu_CN - 0xB4EA494E44657661llu, // khn_Deva_IN - 0xC0EA4D4C4C61746Ellu, // khq_Latn_ML - 0xCCEA494E4D796D72llu, // kht_Mymr_IN - 0xD8EA504B41726162llu, // khw_Arab_PK - 0x6B694B454C61746Ellu, // ki_Latn_KE - 0xD10A54524C61746Ellu, // kiu_Latn_TR - 0x6B6A4E414C61746Ellu, // kj_Latn_NA - 0x992A4C414C616F6Fllu, // kjg_Laoo_LA - 0x6B6B434E41726162llu, // kk_Arab_CN - 0x6B6B4B5A4379726Cllu, // kk_Cyrl_KZ - 0xA54A434D4C61746Ellu, // kkj_Latn_CM - 0x6B6C474C4C61746Ellu, // kl_Latn_GL - 0xB56A4B454C61746Ellu, // kln_Latn_KE - 0x6B6D4B484B686D72llu, // km_Khmr_KH - 0x858A414F4C61746Ellu, // kmb_Latn_AO - 0x6B6E494E4B6E6461llu, // kn_Knda_IN - 0x6B6F4B524B6F7265llu, // ko_Kore_KR - 0xA1CA52554379726Cllu, // koi_Cyrl_RU - 0xA9CA494E44657661llu, // kok_Deva_IN - 0xC9CA464D4C61746Ellu, // kos_Latn_FM - 0x91EA4C524C61746Ellu, // kpe_Latn_LR - 0x8A2A52554379726Cllu, // krc_Cyrl_RU - 0xA22A534C4C61746Ellu, // kri_Latn_SL - 0xA62A50484C61746Ellu, // krj_Latn_PH - 0xAE2A52554C61746Ellu, // krl_Latn_RU - 0xD22A494E44657661llu, // kru_Deva_IN - 0x6B73494E41726162llu, // ks_Arab_IN - 0x864A545A4C61746Ellu, // ksb_Latn_TZ - 0x964A434D4C61746Ellu, // ksf_Latn_CM - 0x9E4A44454C61746Ellu, // ksh_Latn_DE - 0x6B75495141726162llu, // ku_Arab_IQ - 0x6B7554524C61746Ellu, // ku_Latn_TR - 0xB28A52554379726Cllu, // kum_Cyrl_RU - 0x6B7652554379726Cllu, // kv_Cyrl_RU - 0xC6AA49444C61746Ellu, // kvr_Latn_ID - 0xDEAA504B41726162llu, // kvx_Arab_PK - 0x6B7747424C61746Ellu, // kw_Latn_GB - 0xB2EA544854686169llu, // kxm_Thai_TH - 0xBEEA504B41726162llu, // kxp_Arab_PK - 0x6B79434E41726162llu, // ky_Arab_CN - 0x6B794B474379726Cllu, // ky_Cyrl_KG - 0x6B7954524C61746Ellu, // ky_Latn_TR - 0x6C6156414C61746Ellu, // la_Latn_VA - 0x840B47524C696E61llu, // lab_Lina_GR - 0x8C0B494C48656272llu, // lad_Hebr_IL - 0x980B545A4C61746Ellu, // lag_Latn_TZ - 0x9C0B504B41726162llu, // lah_Arab_PK - 0xA40B55474C61746Ellu, // laj_Latn_UG - 0x6C624C554C61746Ellu, // lb_Latn_LU - 0x902B52554379726Cllu, // lbe_Cyrl_RU - 0xD82B49444C61746Ellu, // lbw_Latn_ID - 0xBC4B434E54686169llu, // lcp_Thai_CN - 0xBC8B494E4C657063llu, // lep_Lepc_IN - 0xE48B52554379726Cllu, // lez_Cyrl_RU - 0x6C6755474C61746Ellu, // lg_Latn_UG - 0x6C694E4C4C61746Ellu, // li_Latn_NL - 0x950B4E5044657661llu, // lif_Deva_NP - 0x950B494E4C696D62llu, // lif_Limb_IN - 0xA50B49544C61746Ellu, // lij_Latn_IT - 0xC90B434E4C697375llu, // lis_Lisu_CN - 0xBD2B49444C61746Ellu, // ljp_Latn_ID - 0xA14B495241726162llu, // lki_Arab_IR - 0xCD4B55534C61746Ellu, // lkt_Latn_US - 0xB58B494E54656C75llu, // lmn_Telu_IN - 0xB98B49544C61746Ellu, // lmo_Latn_IT - 0x6C6E43444C61746Ellu, // ln_Latn_CD - 0x6C6F4C414C616F6Fllu, // lo_Laoo_LA - 0xADCB43444C61746Ellu, // lol_Latn_CD - 0xE5CB5A4D4C61746Ellu, // loz_Latn_ZM - 0x8A2B495241726162llu, // lrc_Arab_IR - 0x6C744C544C61746Ellu, // lt_Latn_LT - 0x9A6B4C564C61746Ellu, // ltg_Latn_LV - 0x6C7543444C61746Ellu, // lu_Latn_CD - 0x828B43444C61746Ellu, // lua_Latn_CD - 0xBA8B4B454C61746Ellu, // luo_Latn_KE - 0xE28B4B454C61746Ellu, // luy_Latn_KE - 0xE68B495241726162llu, // luz_Arab_IR - 0x6C764C564C61746Ellu, // lv_Latn_LV - 0xAECB544854686169llu, // lwl_Thai_TH - 0x9F2B434E48616E73llu, // lzh_Hans_CN - 0xE72B54524C61746Ellu, // lzz_Latn_TR - 0x8C0C49444C61746Ellu, // mad_Latn_ID - 0x940C434D4C61746Ellu, // maf_Latn_CM - 0x980C494E44657661llu, // mag_Deva_IN - 0xA00C494E44657661llu, // mai_Deva_IN - 0xA80C49444C61746Ellu, // mak_Latn_ID - 0xB40C474D4C61746Ellu, // man_Latn_GM - 0xB40C474E4E6B6F6Fllu, // man_Nkoo_GN - 0xC80C4B454C61746Ellu, // mas_Latn_KE - 0xE40C4D584C61746Ellu, // maz_Latn_MX - 0x946C52554379726Cllu, // mdf_Cyrl_RU - 0x9C6C50484C61746Ellu, // mdh_Latn_PH - 0xC46C49444C61746Ellu, // mdr_Latn_ID - 0xB48C534C4C61746Ellu, // men_Latn_SL - 0xC48C4B454C61746Ellu, // mer_Latn_KE - 0x80AC544841726162llu, // mfa_Arab_TH - 0x90AC4D554C61746Ellu, // mfe_Latn_MU - 0x6D674D474C61746Ellu, // mg_Latn_MG - 0x9CCC4D5A4C61746Ellu, // mgh_Latn_MZ - 0xB8CC434D4C61746Ellu, // mgo_Latn_CM - 0xBCCC4E5044657661llu, // mgp_Deva_NP - 0xE0CC545A4C61746Ellu, // mgy_Latn_TZ - 0x6D684D484C61746Ellu, // mh_Latn_MH - 0x6D694E5A4C61746Ellu, // mi_Latn_NZ - 0xB50C49444C61746Ellu, // min_Latn_ID - 0xC90C495148617472llu, // mis_Hatr_IQ - 0x6D6B4D4B4379726Cllu, // mk_Cyrl_MK - 0x6D6C494E4D6C796Dllu, // ml_Mlym_IN - 0xC96C53444C61746Ellu, // mls_Latn_SD - 0x6D6E4D4E4379726Cllu, // mn_Cyrl_MN - 0x6D6E434E4D6F6E67llu, // mn_Mong_CN - 0xA1AC494E42656E67llu, // mni_Beng_IN - 0xD9AC4D4D4D796D72llu, // mnw_Mymr_MM - 0x91CC43414C61746Ellu, // moe_Latn_CA - 0x9DCC43414C61746Ellu, // moh_Latn_CA - 0xC9CC42464C61746Ellu, // mos_Latn_BF - 0x6D72494E44657661llu, // mr_Deva_IN - 0x8E2C4E5044657661llu, // mrd_Deva_NP - 0xA62C52554379726Cllu, // mrj_Cyrl_RU - 0xBA2C42444D726F6Fllu, // mro_Mroo_BD - 0x6D734D594C61746Ellu, // ms_Latn_MY - 0x6D744D544C61746Ellu, // mt_Latn_MT - 0xC66C494E44657661llu, // mtr_Deva_IN - 0x828C434D4C61746Ellu, // mua_Latn_CM - 0xCA8C55534C61746Ellu, // mus_Latn_US - 0xE2AC504B41726162llu, // mvy_Arab_PK - 0xAACC4D4C4C61746Ellu, // mwk_Latn_ML - 0xC6CC494E44657661llu, // mwr_Deva_IN - 0xD6CC49444C61746Ellu, // mwv_Latn_ID - 0x8AEC5A574C61746Ellu, // mxc_Latn_ZW - 0x6D794D4D4D796D72llu, // my_Mymr_MM - 0xD70C52554379726Cllu, // myv_Cyrl_RU - 0xDF0C55474C61746Ellu, // myx_Latn_UG - 0xE70C49524D616E64llu, // myz_Mand_IR - 0xB72C495241726162llu, // mzn_Arab_IR - 0x6E614E524C61746Ellu, // na_Latn_NR - 0xB40D434E48616E73llu, // nan_Hans_CN - 0xBC0D49544C61746Ellu, // nap_Latn_IT - 0xC00D4E414C61746Ellu, // naq_Latn_NA - 0x6E624E4F4C61746Ellu, // nb_Latn_NO - 0x9C4D4D584C61746Ellu, // nch_Latn_MX - 0x6E645A574C61746Ellu, // nd_Latn_ZW - 0x886D4D5A4C61746Ellu, // ndc_Latn_MZ - 0xC86D44454C61746Ellu, // nds_Latn_DE - 0x6E654E5044657661llu, // ne_Deva_NP - 0xD88D4E5044657661llu, // new_Deva_NP - 0x6E674E414C61746Ellu, // ng_Latn_NA - 0xACCD4D5A4C61746Ellu, // ngl_Latn_MZ - 0x90ED4D584C61746Ellu, // nhe_Latn_MX - 0xD8ED4D584C61746Ellu, // nhw_Latn_MX - 0xA50D49444C61746Ellu, // nij_Latn_ID - 0xD10D4E554C61746Ellu, // niu_Latn_NU - 0xB92D494E4C61746Ellu, // njo_Latn_IN - 0x6E6C4E4C4C61746Ellu, // nl_Latn_NL - 0x998D434D4C61746Ellu, // nmg_Latn_CM - 0x6E6E4E4F4C61746Ellu, // nn_Latn_NO - 0x9DAD434D4C61746Ellu, // nnh_Latn_CM - 0x6E6F4E4F4C61746Ellu, // no_Latn_NO - 0x8DCD54484C616E61llu, // nod_Lana_TH - 0x91CD494E44657661llu, // noe_Deva_IN - 0xB5CD534552756E72llu, // non_Runr_SE - 0xBA0D474E4E6B6F6Fllu, // nqo_Nkoo_GN - 0x6E725A414C61746Ellu, // nr_Latn_ZA - 0xAA4D434143616E73llu, // nsk_Cans_CA - 0xBA4D5A414C61746Ellu, // nso_Latn_ZA - 0xCA8D53534C61746Ellu, // nus_Latn_SS - 0x6E7655534C61746Ellu, // nv_Latn_US - 0xC2ED434E4C61746Ellu, // nxq_Latn_CN - 0x6E794D574C61746Ellu, // ny_Latn_MW - 0xB30D545A4C61746Ellu, // nym_Latn_TZ - 0xB70D55474C61746Ellu, // nyn_Latn_UG - 0xA32D47484C61746Ellu, // nzi_Latn_GH - 0x6F6346524C61746Ellu, // oc_Latn_FR - 0x6F6D45544C61746Ellu, // om_Latn_ET - 0x6F72494E4F727961llu, // or_Orya_IN - 0x6F7347454379726Cllu, // os_Cyrl_GE - 0x824E55534F736765llu, // osa_Osge_US - 0xAA6E4D4E4F726B68llu, // otk_Orkh_MN - 0x7061504B41726162llu, // pa_Arab_PK - 0x7061494E47757275llu, // pa_Guru_IN - 0x980F50484C61746Ellu, // pag_Latn_PH - 0xAC0F495250686C69llu, // pal_Phli_IR - 0xAC0F434E50686C70llu, // pal_Phlp_CN - 0xB00F50484C61746Ellu, // pam_Latn_PH - 0xBC0F41574C61746Ellu, // pap_Latn_AW - 0xD00F50574C61746Ellu, // pau_Latn_PW - 0x8C4F46524C61746Ellu, // pcd_Latn_FR - 0xB04F4E474C61746Ellu, // pcm_Latn_NG - 0x886F55534C61746Ellu, // pdc_Latn_US - 0xCC6F43414C61746Ellu, // pdt_Latn_CA - 0xB88F49525870656Fllu, // peo_Xpeo_IR - 0xACAF44454C61746Ellu, // pfl_Latn_DE - 0xB4EF4C4250686E78llu, // phn_Phnx_LB - 0x814F494E42726168llu, // pka_Brah_IN - 0xB94F4B454C61746Ellu, // pko_Latn_KE - 0x706C504C4C61746Ellu, // pl_Latn_PL - 0xC98F49544C61746Ellu, // pms_Latn_IT - 0xCDAF47524772656Bllu, // pnt_Grek_GR - 0xB5CF464D4C61746Ellu, // pon_Latn_FM - 0x822F504B4B686172llu, // pra_Khar_PK - 0x8E2F495241726162llu, // prd_Arab_IR - 0x7073414641726162llu, // ps_Arab_AF - 0x707442524C61746Ellu, // pt_Latn_BR - 0xD28F47414C61746Ellu, // puu_Latn_GA - 0x717550454C61746Ellu, // qu_Latn_PE - 0x8A9047544C61746Ellu, // quc_Latn_GT - 0x9A9045434C61746Ellu, // qug_Latn_EC - 0xA411494E44657661llu, // raj_Deva_IN - 0x945152454C61746Ellu, // rcf_Latn_RE - 0xA49149444C61746Ellu, // rej_Latn_ID - 0xB4D149544C61746Ellu, // rgn_Latn_IT - 0x8111494E4C61746Ellu, // ria_Latn_IN - 0x95114D4154666E67llu, // rif_Tfng_MA - 0xC9314E5044657661llu, // rjs_Deva_NP - 0xCD51424442656E67llu, // rkt_Beng_BD - 0x726D43484C61746Ellu, // rm_Latn_CH - 0x959146494C61746Ellu, // rmf_Latn_FI - 0xB99143484C61746Ellu, // rmo_Latn_CH - 0xCD91495241726162llu, // rmt_Arab_IR - 0xD19153454C61746Ellu, // rmu_Latn_SE - 0x726E42494C61746Ellu, // rn_Latn_BI - 0x99B14D5A4C61746Ellu, // rng_Latn_MZ - 0x726F524F4C61746Ellu, // ro_Latn_RO - 0x85D149444C61746Ellu, // rob_Latn_ID - 0x95D1545A4C61746Ellu, // rof_Latn_TZ - 0xB271464A4C61746Ellu, // rtm_Latn_FJ - 0x727552554379726Cllu, // ru_Cyrl_RU - 0x929155414379726Cllu, // rue_Cyrl_UA - 0x9A9153424C61746Ellu, // rug_Latn_SB - 0x727752574C61746Ellu, // rw_Latn_RW - 0xAAD1545A4C61746Ellu, // rwk_Latn_TZ - 0xD3114A504B616E61llu, // ryu_Kana_JP - 0x7361494E44657661llu, // sa_Deva_IN - 0x941247484C61746Ellu, // saf_Latn_GH - 0x9C1252554379726Cllu, // sah_Cyrl_RU - 0xC0124B454C61746Ellu, // saq_Latn_KE - 0xC81249444C61746Ellu, // sas_Latn_ID - 0xCC12494E4C61746Ellu, // sat_Latn_IN - 0xE412494E53617572llu, // saz_Saur_IN - 0xBC32545A4C61746Ellu, // sbp_Latn_TZ - 0x736349544C61746Ellu, // sc_Latn_IT - 0xA852494E44657661llu, // sck_Deva_IN - 0xB45249544C61746Ellu, // scn_Latn_IT - 0xB85247424C61746Ellu, // sco_Latn_GB - 0xC85243414C61746Ellu, // scs_Latn_CA - 0x7364504B41726162llu, // sd_Arab_PK - 0x7364494E44657661llu, // sd_Deva_IN - 0x7364494E4B686F6Allu, // sd_Khoj_IN - 0x7364494E53696E64llu, // sd_Sind_IN - 0x887249544C61746Ellu, // sdc_Latn_IT - 0x9C72495241726162llu, // sdh_Arab_IR - 0x73654E4F4C61746Ellu, // se_Latn_NO - 0x949243494C61746Ellu, // sef_Latn_CI - 0x9C924D5A4C61746Ellu, // seh_Latn_MZ - 0xA0924D584C61746Ellu, // sei_Latn_MX - 0xC8924D4C4C61746Ellu, // ses_Latn_ML - 0x736743464C61746Ellu, // sg_Latn_CF - 0x80D249454F67616Dllu, // sga_Ogam_IE - 0xC8D24C544C61746Ellu, // sgs_Latn_LT - 0xA0F24D4154666E67llu, // shi_Tfng_MA - 0xB4F24D4D4D796D72llu, // shn_Mymr_MM - 0x73694C4B53696E68llu, // si_Sinh_LK - 0x8D1245544C61746Ellu, // sid_Latn_ET - 0x736B534B4C61746Ellu, // sk_Latn_SK - 0xC552504B41726162llu, // skr_Arab_PK - 0x736C53494C61746Ellu, // sl_Latn_SI - 0xA172504C4C61746Ellu, // sli_Latn_PL - 0xE17249444C61746Ellu, // sly_Latn_ID - 0x736D57534C61746Ellu, // sm_Latn_WS - 0x819253454C61746Ellu, // sma_Latn_SE - 0xA59253454C61746Ellu, // smj_Latn_SE - 0xB59246494C61746Ellu, // smn_Latn_FI - 0xBD92494C53616D72llu, // smp_Samr_IL - 0xC99246494C61746Ellu, // sms_Latn_FI - 0x736E5A574C61746Ellu, // sn_Latn_ZW - 0xA9B24D4C4C61746Ellu, // snk_Latn_ML - 0x736F534F4C61746Ellu, // so_Latn_SO - 0xD1D2544854686169llu, // sou_Thai_TH - 0x7371414C4C61746Ellu, // sq_Latn_AL - 0x737252534379726Cllu, // sr_Cyrl_RS - 0x737252534C61746Ellu, // sr_Latn_RS - 0x8632494E536F7261llu, // srb_Sora_IN - 0xB63253524C61746Ellu, // srn_Latn_SR - 0xC632534E4C61746Ellu, // srr_Latn_SN - 0xDE32494E44657661llu, // srx_Deva_IN - 0x73735A414C61746Ellu, // ss_Latn_ZA - 0xE25245524C61746Ellu, // ssy_Latn_ER - 0x73745A414C61746Ellu, // st_Latn_ZA - 0xC27244454C61746Ellu, // stq_Latn_DE - 0x737549444C61746Ellu, // su_Latn_ID - 0xAA92545A4C61746Ellu, // suk_Latn_TZ - 0xCA92474E4C61746Ellu, // sus_Latn_GN - 0x737653454C61746Ellu, // sv_Latn_SE - 0x7377545A4C61746Ellu, // sw_Latn_TZ - 0x86D2595441726162llu, // swb_Arab_YT - 0x8AD243444C61746Ellu, // swc_Latn_CD - 0x9AD244454C61746Ellu, // swg_Latn_DE - 0xD6D2494E44657661llu, // swv_Deva_IN - 0xB6F249444C61746Ellu, // sxn_Latn_ID - 0xAF12424442656E67llu, // syl_Beng_BD - 0xC712495153797263llu, // syr_Syrc_IQ - 0xAF32504C4C61746Ellu, // szl_Latn_PL - 0x7461494E54616D6Cllu, // ta_Taml_IN - 0xA4134E5044657661llu, // taj_Deva_NP - 0xD83350484C61746Ellu, // tbw_Latn_PH - 0xE053494E4B6E6461llu, // tcy_Knda_IN - 0x8C73434E54616C65llu, // tdd_Tale_CN - 0x98734E5044657661llu, // tdg_Deva_NP - 0x9C734E5044657661llu, // tdh_Deva_NP - 0x7465494E54656C75llu, // te_Telu_IN - 0xB093534C4C61746Ellu, // tem_Latn_SL - 0xB89355474C61746Ellu, // teo_Latn_UG - 0xCC93544C4C61746Ellu, // tet_Latn_TL - 0x7467504B41726162llu, // tg_Arab_PK - 0x7467544A4379726Cllu, // tg_Cyrl_TJ - 0x7468544854686169llu, // th_Thai_TH - 0xACF34E5044657661llu, // thl_Deva_NP - 0xC0F34E5044657661llu, // thq_Deva_NP - 0xC4F34E5044657661llu, // thr_Deva_NP - 0x7469455445746869llu, // ti_Ethi_ET - 0x9913455245746869llu, // tig_Ethi_ER - 0xD5134E474C61746Ellu, // tiv_Latn_NG - 0x746B544D4C61746Ellu, // tk_Latn_TM - 0xAD53544B4C61746Ellu, // tkl_Latn_TK - 0xC553415A4C61746Ellu, // tkr_Latn_AZ - 0xCD534E5044657661llu, // tkt_Deva_NP - 0x746C50484C61746Ellu, // tl_Latn_PH - 0xE173415A4C61746Ellu, // tly_Latn_AZ - 0x9D934E454C61746Ellu, // tmh_Latn_NE - 0x746E5A414C61746Ellu, // tn_Latn_ZA - 0x746F544F4C61746Ellu, // to_Latn_TO - 0x99D34D574C61746Ellu, // tog_Latn_MW - 0xA1F350474C61746Ellu, // tpi_Latn_PG - 0x747254524C61746Ellu, // tr_Latn_TR - 0xD23354524C61746Ellu, // tru_Latn_TR - 0xD63354574C61746Ellu, // trv_Latn_TW - 0x74735A414C61746Ellu, // ts_Latn_ZA - 0x8E5347524772656Bllu, // tsd_Grek_GR - 0x96534E5044657661llu, // tsf_Deva_NP - 0x9A5350484C61746Ellu, // tsg_Latn_PH - 0xA653425454696274llu, // tsj_Tibt_BT - 0x747452554379726Cllu, // tt_Cyrl_RU - 0xA67355474C61746Ellu, // ttj_Latn_UG - 0xCA73544854686169llu, // tts_Thai_TH - 0xCE73415A4C61746Ellu, // ttt_Latn_AZ - 0xB2934D574C61746Ellu, // tum_Latn_MW - 0xAEB354564C61746Ellu, // tvl_Latn_TV - 0xC2D34E454C61746Ellu, // twq_Latn_NE - 0x9AF3434E54616E67llu, // txg_Tang_CN - 0x747950464C61746Ellu, // ty_Latn_PF - 0xD71352554379726Cllu, // tyv_Cyrl_RU - 0xB3334D414C61746Ellu, // tzm_Latn_MA - 0xB07452554379726Cllu, // udm_Cyrl_RU - 0x7567434E41726162llu, // ug_Arab_CN - 0x75674B5A4379726Cllu, // ug_Cyrl_KZ - 0x80D4535955676172llu, // uga_Ugar_SY - 0x756B55414379726Cllu, // uk_Cyrl_UA - 0xA174464D4C61746Ellu, // uli_Latn_FM - 0x8594414F4C61746Ellu, // umb_Latn_AO - 0xC5B4494E42656E67llu, // unr_Beng_IN - 0xC5B44E5044657661llu, // unr_Deva_NP - 0xDDB4494E42656E67llu, // unx_Beng_IN - 0x7572504B41726162llu, // ur_Arab_PK - 0x757A414641726162llu, // uz_Arab_AF - 0x757A555A4C61746Ellu, // uz_Latn_UZ - 0xA0154C5256616969llu, // vai_Vaii_LR - 0x76655A414C61746Ellu, // ve_Latn_ZA - 0x889549544C61746Ellu, // vec_Latn_IT - 0xBC9552554C61746Ellu, // vep_Latn_RU - 0x7669564E4C61746Ellu, // vi_Latn_VN - 0x891553584C61746Ellu, // vic_Latn_SX - 0xC97542454C61746Ellu, // vls_Latn_BE - 0x959544454C61746Ellu, // vmf_Latn_DE - 0xD9954D5A4C61746Ellu, // vmw_Latn_MZ - 0xCDD552554C61746Ellu, // vot_Latn_RU - 0xBA3545454C61746Ellu, // vro_Latn_EE - 0xB695545A4C61746Ellu, // vun_Latn_TZ - 0x776142454C61746Ellu, // wa_Latn_BE - 0x901643484C61746Ellu, // wae_Latn_CH - 0xAC16455445746869llu, // wal_Ethi_ET - 0xC41650484C61746Ellu, // war_Latn_PH - 0xBC3641554C61746Ellu, // wbp_Latn_AU - 0xC036494E54656C75llu, // wbq_Telu_IN - 0xC436494E44657661llu, // wbr_Deva_IN - 0xC97657464C61746Ellu, // wls_Latn_WF - 0xA1B64B4D41726162llu, // wni_Arab_KM - 0x776F534E4C61746Ellu, // wo_Latn_SN - 0xB276494E44657661llu, // wtm_Deva_IN - 0xD296434E48616E73llu, // wuu_Hans_CN - 0xD41742524C61746Ellu, // xav_Latn_BR - 0xC457545243617269llu, // xcr_Cari_TR - 0x78685A414C61746Ellu, // xh_Latn_ZA - 0x897754524C796369llu, // xlc_Lyci_TR - 0x8D7754524C796469llu, // xld_Lydi_TR - 0x9597474547656F72llu, // xmf_Geor_GE - 0xB597434E4D616E69llu, // xmn_Mani_CN - 0xC59753444D657263llu, // xmr_Merc_SD - 0x81B753414E617262llu, // xna_Narb_SA - 0xC5B7494E44657661llu, // xnr_Deva_IN - 0x99D755474C61746Ellu, // xog_Latn_UG - 0xC5F7495250727469llu, // xpr_Prti_IR - 0x8257594553617262llu, // xsa_Sarb_YE - 0xC6574E5044657661llu, // xsr_Deva_NP - 0xB8184D5A4C61746Ellu, // yao_Latn_MZ - 0xBC18464D4C61746Ellu, // yap_Latn_FM - 0xD418434D4C61746Ellu, // yav_Latn_CM - 0x8438434D4C61746Ellu, // ybb_Latn_CM - 0x796F4E474C61746Ellu, // yo_Latn_NG - 0xAE3842524C61746Ellu, // yrl_Latn_BR - 0x82984D584C61746Ellu, // yua_Latn_MX - 0x9298434E48616E73llu, // yue_Hans_CN - 0x9298484B48616E74llu, // yue_Hant_HK - 0x7A61434E4C61746Ellu, // za_Latn_CN - 0x981953444C61746Ellu, // zag_Latn_SD - 0xA4794B4D41726162llu, // zdj_Arab_KM - 0x80994E4C4C61746Ellu, // zea_Latn_NL - 0x9CD94D4154666E67llu, // zgh_Tfng_MA - 0x7A685457426F706Fllu, // zh_Bopo_TW - 0x7A68545748616E62llu, // zh_Hanb_TW - 0x7A68434E48616E73llu, // zh_Hans_CN - 0x7A68545748616E74llu, // zh_Hant_TW - 0xB17954474C61746Ellu, // zlm_Latn_TG - 0xA1994D594C61746Ellu, // zmi_Latn_MY - 0x7A755A414C61746Ellu, // zu_Latn_ZA - 0x833954524C61746Ellu, // zza_Latn_TR + 0x616145544C61746ELLU, // aa_Latn_ET + 0x616247454379726CLLU, // ab_Cyrl_GE + 0xC42047484C61746ELLU, // abr_Latn_GH + 0x904049444C61746ELLU, // ace_Latn_ID + 0x9C4055474C61746ELLU, // ach_Latn_UG + 0x806047484C61746ELLU, // ada_Latn_GH + 0xE06052554379726CLLU, // ady_Cyrl_RU + 0x6165495241767374LLU, // ae_Avst_IR + 0x8480544E41726162LLU, // aeb_Arab_TN + 0x61665A414C61746ELLU, // af_Latn_ZA + 0xC0C0434D4C61746ELLU, // agq_Latn_CM + 0xB8E0494E41686F6DLLU, // aho_Ahom_IN + 0x616B47484C61746ELLU, // ak_Latn_GH + 0xA940495158737578LLU, // akk_Xsux_IQ + 0xB560584B4C61746ELLU, // aln_Latn_XK + 0xCD6052554379726CLLU, // alt_Cyrl_RU + 0x616D455445746869LLU, // am_Ethi_ET + 0xB9804E474C61746ELLU, // amo_Latn_NG + 0xE5C049444C61746ELLU, // aoz_Latn_ID + 0x8DE0544741726162LLU, // apd_Arab_TG + 0x6172454741726162LLU, // ar_Arab_EG + 0x8A20495241726D69LLU, // arc_Armi_IR + 0x8A204A4F4E626174LLU, // arc_Nbat_JO + 0x8A20535950616C6DLLU, // arc_Palm_SY + 0xB620434C4C61746ELLU, // arn_Latn_CL + 0xBA20424F4C61746ELLU, // aro_Latn_BO + 0xC220445A41726162LLU, // arq_Arab_DZ + 0xE2204D4141726162LLU, // ary_Arab_MA + 0xE620454741726162LLU, // arz_Arab_EG + 0x6173494E42656E67LLU, // as_Beng_IN + 0x8240545A4C61746ELLU, // asa_Latn_TZ + 0x9240555353676E77LLU, // ase_Sgnw_US + 0xCE4045534C61746ELLU, // ast_Latn_ES + 0xA66043414C61746ELLU, // atj_Latn_CA + 0x617652554379726CLLU, // av_Cyrl_RU + 0x82C0494E44657661LLU, // awa_Deva_IN + 0x6179424F4C61746ELLU, // ay_Latn_BO + 0x617A495241726162LLU, // az_Arab_IR + 0x617A415A4C61746ELLU, // az_Latn_AZ + 0x626152554379726CLLU, // ba_Cyrl_RU + 0xAC01504B41726162LLU, // bal_Arab_PK + 0xB40149444C61746ELLU, // ban_Latn_ID + 0xBC014E5044657661LLU, // bap_Deva_NP + 0xC40141544C61746ELLU, // bar_Latn_AT + 0xC801434D4C61746ELLU, // bas_Latn_CM + 0xDC01434D42616D75LLU, // bax_Bamu_CM + 0x882149444C61746ELLU, // bbc_Latn_ID + 0xA421434D4C61746ELLU, // bbj_Latn_CM + 0xA04143494C61746ELLU, // bci_Latn_CI + 0x626542594379726CLLU, // be_Cyrl_BY + 0xA481534441726162LLU, // bej_Arab_SD + 0xB0815A4D4C61746ELLU, // bem_Latn_ZM + 0xD88149444C61746ELLU, // bew_Latn_ID + 0xE481545A4C61746ELLU, // bez_Latn_TZ + 0x8CA1434D4C61746ELLU, // bfd_Latn_CM + 0xC0A1494E54616D6CLLU, // bfq_Taml_IN + 0xCCA1504B41726162LLU, // bft_Arab_PK + 0xE0A1494E44657661LLU, // bfy_Deva_IN + 0x626742474379726CLLU, // bg_Cyrl_BG + 0x88C1494E44657661LLU, // bgc_Deva_IN + 0xB4C1504B41726162LLU, // bgn_Arab_PK + 0xDCC154524772656BLLU, // bgx_Grek_TR + 0x84E1494E44657661LLU, // bhb_Deva_IN + 0xA0E1494E44657661LLU, // bhi_Deva_IN + 0xA8E150484C61746ELLU, // bhk_Latn_PH + 0xB8E1494E44657661LLU, // bho_Deva_IN + 0x626956554C61746ELLU, // bi_Latn_VU + 0xA90150484C61746ELLU, // bik_Latn_PH + 0xB5014E474C61746ELLU, // bin_Latn_NG + 0xA521494E44657661LLU, // bjj_Deva_IN + 0xB52149444C61746ELLU, // bjn_Latn_ID + 0xB141434D4C61746ELLU, // bkm_Latn_CM + 0xD14150484C61746ELLU, // bku_Latn_PH + 0xCD61564E54617674LLU, // blt_Tavt_VN + 0x626D4D4C4C61746ELLU, // bm_Latn_ML + 0xC1814D4C4C61746ELLU, // bmq_Latn_ML + 0x626E424442656E67LLU, // bn_Beng_BD + 0x626F434E54696274LLU, // bo_Tibt_CN + 0xE1E1494E42656E67LLU, // bpy_Beng_IN + 0xA201495241726162LLU, // bqi_Arab_IR + 0xD60143494C61746ELLU, // bqv_Latn_CI + 0x627246524C61746ELLU, // br_Latn_FR + 0x8221494E44657661LLU, // bra_Deva_IN + 0x9E21504B41726162LLU, // brh_Arab_PK + 0xDE21494E44657661LLU, // brx_Deva_IN + 0x627342414C61746ELLU, // bs_Latn_BA + 0xC2414C5242617373LLU, // bsq_Bass_LR + 0xCA41434D4C61746ELLU, // bss_Latn_CM + 0xBA6150484C61746ELLU, // bto_Latn_PH + 0xD661504B44657661LLU, // btv_Deva_PK + 0x828152554379726CLLU, // bua_Cyrl_RU + 0x8A8159544C61746ELLU, // buc_Latn_YT + 0x9A8149444C61746ELLU, // bug_Latn_ID + 0xB281434D4C61746ELLU, // bum_Latn_CM + 0x86A147514C61746ELLU, // bvb_Latn_GQ + 0xB701455245746869LLU, // byn_Ethi_ER + 0xD701434D4C61746ELLU, // byv_Latn_CM + 0x93214D4C4C61746ELLU, // bze_Latn_ML + 0x636145534C61746ELLU, // ca_Latn_ES + 0x9C424E474C61746ELLU, // cch_Latn_NG + 0xBC42494E42656E67LLU, // ccp_Beng_IN + 0xBC42424443616B6DLLU, // ccp_Cakm_BD + 0x636552554379726CLLU, // ce_Cyrl_RU + 0x848250484C61746ELLU, // ceb_Latn_PH + 0x98C255474C61746ELLU, // cgg_Latn_UG + 0x636847554C61746ELLU, // ch_Latn_GU + 0xA8E2464D4C61746ELLU, // chk_Latn_FM + 0xB0E252554379726CLLU, // chm_Cyrl_RU + 0xB8E255534C61746ELLU, // cho_Latn_US + 0xBCE243414C61746ELLU, // chp_Latn_CA + 0xC4E2555343686572LLU, // chr_Cher_US + 0x81224B4841726162LLU, // cja_Arab_KH + 0xB122564E4368616DLLU, // cjm_Cham_VN + 0x8542495141726162LLU, // ckb_Arab_IQ + 0x636F46524C61746ELLU, // co_Latn_FR + 0xBDC24547436F7074LLU, // cop_Copt_EG + 0xC9E250484C61746ELLU, // cps_Latn_PH + 0x6372434143616E73LLU, // cr_Cans_CA + 0xA622434143616E73LLU, // crj_Cans_CA + 0xAA22434143616E73LLU, // crk_Cans_CA + 0xAE22434143616E73LLU, // crl_Cans_CA + 0xB222434143616E73LLU, // crm_Cans_CA + 0xCA2253434C61746ELLU, // crs_Latn_SC + 0x6373435A4C61746ELLU, // cs_Latn_CZ + 0x8642504C4C61746ELLU, // csb_Latn_PL + 0xDA42434143616E73LLU, // csw_Cans_CA + 0x8E624D4D50617563LLU, // ctd_Pauc_MM + 0x637552554379726CLLU, // cu_Cyrl_RU + 0x63754247476C6167LLU, // cu_Glag_BG + 0x637652554379726CLLU, // cv_Cyrl_RU + 0x637947424C61746ELLU, // cy_Latn_GB + 0x6461444B4C61746ELLU, // da_Latn_DK + 0xA80355534C61746ELLU, // dak_Latn_US + 0xC40352554379726CLLU, // dar_Cyrl_RU + 0xD4034B454C61746ELLU, // dav_Latn_KE + 0x8843494E41726162LLU, // dcc_Arab_IN + 0x646544454C61746ELLU, // de_Latn_DE + 0xB48343414C61746ELLU, // den_Latn_CA + 0xC4C343414C61746ELLU, // dgr_Latn_CA + 0x91234E454C61746ELLU, // dje_Latn_NE + 0xA5A343494C61746ELLU, // dnj_Latn_CI + 0xA1C3494E41726162LLU, // doi_Arab_IN + 0x864344454C61746ELLU, // dsb_Latn_DE + 0xB2634D4C4C61746ELLU, // dtm_Latn_ML + 0xBE634D594C61746ELLU, // dtp_Latn_MY + 0xE2634E5044657661LLU, // dty_Deva_NP + 0x8283434D4C61746ELLU, // dua_Latn_CM + 0x64764D5654686161LLU, // dv_Thaa_MV + 0xBB03534E4C61746ELLU, // dyo_Latn_SN + 0xD30342464C61746ELLU, // dyu_Latn_BF + 0x647A425454696274LLU, // dz_Tibt_BT + 0xD0244B454C61746ELLU, // ebu_Latn_KE + 0x656547484C61746ELLU, // ee_Latn_GH + 0xA0A44E474C61746ELLU, // efi_Latn_NG + 0xACC449544C61746ELLU, // egl_Latn_IT + 0xE0C4454745677970LLU, // egy_Egyp_EG + 0xE1444D4D4B616C69LLU, // eky_Kali_MM + 0x656C47524772656BLLU, // el_Grek_GR + 0x656E47424C61746ELLU, // en_Latn_GB + 0x656E55534C61746ELLU, // en_Latn_US + 0x656E474253686177LLU, // en_Shaw_GB + 0x657345534C61746ELLU, // es_Latn_ES + 0x65734D584C61746ELLU, // es_Latn_MX + 0x657355534C61746ELLU, // es_Latn_US + 0xD24455534C61746ELLU, // esu_Latn_US + 0x657445454C61746ELLU, // et_Latn_EE + 0xCE6449544974616CLLU, // ett_Ital_IT + 0x657545534C61746ELLU, // eu_Latn_ES + 0xBAC4434D4C61746ELLU, // ewo_Latn_CM + 0xCEE445534C61746ELLU, // ext_Latn_ES + 0x6661495241726162LLU, // fa_Arab_IR + 0xB40547514C61746ELLU, // fan_Latn_GQ + 0x6666474E41646C6DLLU, // ff_Adlm_GN + 0x6666534E4C61746ELLU, // ff_Latn_SN + 0xB0A54D4C4C61746ELLU, // ffm_Latn_ML + 0x666946494C61746ELLU, // fi_Latn_FI + 0x8105534441726162LLU, // fia_Arab_SD + 0xAD0550484C61746ELLU, // fil_Latn_PH + 0xCD0553454C61746ELLU, // fit_Latn_SE + 0x666A464A4C61746ELLU, // fj_Latn_FJ + 0x666F464F4C61746ELLU, // fo_Latn_FO + 0xB5C5424A4C61746ELLU, // fon_Latn_BJ + 0x667246524C61746ELLU, // fr_Latn_FR + 0x8A2555534C61746ELLU, // frc_Latn_US + 0xBE2546524C61746ELLU, // frp_Latn_FR + 0xC62544454C61746ELLU, // frr_Latn_DE + 0xCA2544454C61746ELLU, // frs_Latn_DE + 0x8685434D41726162LLU, // fub_Arab_CM + 0x8E8557464C61746ELLU, // fud_Latn_WF + 0x9685474E4C61746ELLU, // fuf_Latn_GN + 0xC2854E454C61746ELLU, // fuq_Latn_NE + 0xC68549544C61746ELLU, // fur_Latn_IT + 0xD6854E474C61746ELLU, // fuv_Latn_NG + 0xC6A553444C61746ELLU, // fvr_Latn_SD + 0x66794E4C4C61746ELLU, // fy_Latn_NL + 0x676149454C61746ELLU, // ga_Latn_IE + 0x800647484C61746ELLU, // gaa_Latn_GH + 0x98064D444C61746ELLU, // gag_Latn_MD + 0xB406434E48616E73LLU, // gan_Hans_CN + 0xE00649444C61746ELLU, // gay_Latn_ID + 0xB026494E44657661LLU, // gbm_Deva_IN + 0xE426495241726162LLU, // gbz_Arab_IR + 0xC44647464C61746ELLU, // gcr_Latn_GF + 0x676447424C61746ELLU, // gd_Latn_GB + 0xE486455445746869LLU, // gez_Ethi_ET + 0xB4C64E5044657661LLU, // ggn_Deva_NP + 0xAD064B494C61746ELLU, // gil_Latn_KI + 0xA926504B41726162LLU, // gjk_Arab_PK + 0xD126504B41726162LLU, // gju_Arab_PK + 0x676C45534C61746ELLU, // gl_Latn_ES + 0xA966495241726162LLU, // glk_Arab_IR + 0x676E50594C61746ELLU, // gn_Latn_PY + 0xB1C6494E44657661LLU, // gom_Deva_IN + 0xB5C6494E54656C75LLU, // gon_Telu_IN + 0xC5C649444C61746ELLU, // gor_Latn_ID + 0xC9C64E4C4C61746ELLU, // gos_Latn_NL + 0xCDC65541476F7468LLU, // got_Goth_UA + 0x8A26435943707274LLU, // grc_Cprt_CY + 0x8A2647524C696E62LLU, // grc_Linb_GR + 0xCE26494E42656E67LLU, // grt_Beng_IN + 0xDA4643484C61746ELLU, // gsw_Latn_CH + 0x6775494E47756A72LLU, // gu_Gujr_IN + 0x868642524C61746ELLU, // gub_Latn_BR + 0x8A86434F4C61746ELLU, // guc_Latn_CO + 0xC68647484C61746ELLU, // gur_Latn_GH + 0xE6864B454C61746ELLU, // guz_Latn_KE + 0x6776494D4C61746ELLU, // gv_Latn_IM + 0xC6A64E5044657661LLU, // gvr_Deva_NP + 0xA2C643414C61746ELLU, // gwi_Latn_CA + 0x68614E474C61746ELLU, // ha_Latn_NG + 0xA807434E48616E73LLU, // hak_Hans_CN + 0xD80755534C61746ELLU, // haw_Latn_US + 0xE407414641726162LLU, // haz_Arab_AF + 0x6865494C48656272LLU, // he_Hebr_IL + 0x6869494E44657661LLU, // hi_Deva_IN + 0x9507464A4C61746ELLU, // hif_Latn_FJ + 0xAD0750484C61746ELLU, // hil_Latn_PH + 0xD1675452486C7577LLU, // hlu_Hluw_TR + 0x8D87434E506C7264LLU, // hmd_Plrd_CN + 0x8DA7504B41726162LLU, // hnd_Arab_PK + 0x91A7494E44657661LLU, // hne_Deva_IN + 0xA5A74C41486D6E67LLU, // hnj_Hmng_LA + 0xB5A750484C61746ELLU, // hnn_Latn_PH + 0xB9A7504B41726162LLU, // hno_Arab_PK + 0x686F50474C61746ELLU, // ho_Latn_PG + 0x89C7494E44657661LLU, // hoc_Deva_IN + 0xA5C7494E44657661LLU, // hoj_Deva_IN + 0x687248524C61746ELLU, // hr_Latn_HR + 0x864744454C61746ELLU, // hsb_Latn_DE + 0xB647434E48616E73LLU, // hsn_Hans_CN + 0x687448544C61746ELLU, // ht_Latn_HT + 0x687548554C61746ELLU, // hu_Latn_HU + 0x6879414D41726D6ELLU, // hy_Armn_AM + 0x687A4E414C61746ELLU, // hz_Latn_NA + 0x696146524C61746ELLU, // ia_Latn_FR + 0x80284D594C61746ELLU, // iba_Latn_MY + 0x84284E474C61746ELLU, // ibb_Latn_NG + 0x696449444C61746ELLU, // id_Latn_ID + 0x69674E474C61746ELLU, // ig_Latn_NG + 0x6969434E59696969LLU, // ii_Yiii_CN + 0x696B55534C61746ELLU, // ik_Latn_US + 0xCD4843414C61746ELLU, // ikt_Latn_CA + 0xB96850484C61746ELLU, // ilo_Latn_PH + 0x696E49444C61746ELLU, // in_Latn_ID + 0x9DA852554379726CLLU, // inh_Cyrl_RU + 0x697349534C61746ELLU, // is_Latn_IS + 0x697449544C61746ELLU, // it_Latn_IT + 0x6975434143616E73LLU, // iu_Cans_CA + 0x6977494C48656272LLU, // iw_Hebr_IL + 0x9F2852554C61746ELLU, // izh_Latn_RU + 0x6A614A504A70616ELLU, // ja_Jpan_JP + 0xB0094A4D4C61746ELLU, // jam_Latn_JM + 0xB8C9434D4C61746ELLU, // jgo_Latn_CM + 0x8989545A4C61746ELLU, // jmc_Latn_TZ + 0xAD894E5044657661LLU, // jml_Deva_NP + 0xCE89444B4C61746ELLU, // jut_Latn_DK + 0x6A7649444C61746ELLU, // jv_Latn_ID + 0x6A7749444C61746ELLU, // jw_Latn_ID + 0x6B61474547656F72LLU, // ka_Geor_GE + 0x800A555A4379726CLLU, // kaa_Cyrl_UZ + 0x840A445A4C61746ELLU, // kab_Latn_DZ + 0x880A4D4D4C61746ELLU, // kac_Latn_MM + 0xA40A4E474C61746ELLU, // kaj_Latn_NG + 0xB00A4B454C61746ELLU, // kam_Latn_KE + 0xB80A4D4C4C61746ELLU, // kao_Latn_ML + 0x8C2A52554379726CLLU, // kbd_Cyrl_RU + 0xE02A4E4541726162LLU, // kby_Arab_NE + 0x984A4E474C61746ELLU, // kcg_Latn_NG + 0xA84A5A574C61746ELLU, // kck_Latn_ZW + 0x906A545A4C61746ELLU, // kde_Latn_TZ + 0x9C6A544741726162LLU, // kdh_Arab_TG + 0xCC6A544854686169LLU, // kdt_Thai_TH + 0x808A43564C61746ELLU, // kea_Latn_CV + 0xB48A434D4C61746ELLU, // ken_Latn_CM + 0xB8AA43494C61746ELLU, // kfo_Latn_CI + 0xC4AA494E44657661LLU, // kfr_Deva_IN + 0xE0AA494E44657661LLU, // kfy_Deva_IN + 0x6B6743444C61746ELLU, // kg_Latn_CD + 0x90CA49444C61746ELLU, // kge_Latn_ID + 0xBCCA42524C61746ELLU, // kgp_Latn_BR + 0x80EA494E4C61746ELLU, // kha_Latn_IN + 0x84EA434E54616C75LLU, // khb_Talu_CN + 0xB4EA494E44657661LLU, // khn_Deva_IN + 0xC0EA4D4C4C61746ELLU, // khq_Latn_ML + 0xCCEA494E4D796D72LLU, // kht_Mymr_IN + 0xD8EA504B41726162LLU, // khw_Arab_PK + 0x6B694B454C61746ELLU, // ki_Latn_KE + 0xD10A54524C61746ELLU, // kiu_Latn_TR + 0x6B6A4E414C61746ELLU, // kj_Latn_NA + 0x992A4C414C616F6FLLU, // kjg_Laoo_LA + 0x6B6B434E41726162LLU, // kk_Arab_CN + 0x6B6B4B5A4379726CLLU, // kk_Cyrl_KZ + 0xA54A434D4C61746ELLU, // kkj_Latn_CM + 0x6B6C474C4C61746ELLU, // kl_Latn_GL + 0xB56A4B454C61746ELLU, // kln_Latn_KE + 0x6B6D4B484B686D72LLU, // km_Khmr_KH + 0x858A414F4C61746ELLU, // kmb_Latn_AO + 0x6B6E494E4B6E6461LLU, // kn_Knda_IN + 0x6B6F4B524B6F7265LLU, // ko_Kore_KR + 0xA1CA52554379726CLLU, // koi_Cyrl_RU + 0xA9CA494E44657661LLU, // kok_Deva_IN + 0xC9CA464D4C61746ELLU, // kos_Latn_FM + 0x91EA4C524C61746ELLU, // kpe_Latn_LR + 0x8A2A52554379726CLLU, // krc_Cyrl_RU + 0xA22A534C4C61746ELLU, // kri_Latn_SL + 0xA62A50484C61746ELLU, // krj_Latn_PH + 0xAE2A52554C61746ELLU, // krl_Latn_RU + 0xD22A494E44657661LLU, // kru_Deva_IN + 0x6B73494E41726162LLU, // ks_Arab_IN + 0x864A545A4C61746ELLU, // ksb_Latn_TZ + 0x964A434D4C61746ELLU, // ksf_Latn_CM + 0x9E4A44454C61746ELLU, // ksh_Latn_DE + 0x6B75495141726162LLU, // ku_Arab_IQ + 0x6B7554524C61746ELLU, // ku_Latn_TR + 0xB28A52554379726CLLU, // kum_Cyrl_RU + 0x6B7652554379726CLLU, // kv_Cyrl_RU + 0xC6AA49444C61746ELLU, // kvr_Latn_ID + 0xDEAA504B41726162LLU, // kvx_Arab_PK + 0x6B7747424C61746ELLU, // kw_Latn_GB + 0xB2EA544854686169LLU, // kxm_Thai_TH + 0xBEEA504B41726162LLU, // kxp_Arab_PK + 0x6B79434E41726162LLU, // ky_Arab_CN + 0x6B794B474379726CLLU, // ky_Cyrl_KG + 0x6B7954524C61746ELLU, // ky_Latn_TR + 0x6C6156414C61746ELLU, // la_Latn_VA + 0x840B47524C696E61LLU, // lab_Lina_GR + 0x8C0B494C48656272LLU, // lad_Hebr_IL + 0x980B545A4C61746ELLU, // lag_Latn_TZ + 0x9C0B504B41726162LLU, // lah_Arab_PK + 0xA40B55474C61746ELLU, // laj_Latn_UG + 0x6C624C554C61746ELLU, // lb_Latn_LU + 0x902B52554379726CLLU, // lbe_Cyrl_RU + 0xD82B49444C61746ELLU, // lbw_Latn_ID + 0xBC4B434E54686169LLU, // lcp_Thai_CN + 0xBC8B494E4C657063LLU, // lep_Lepc_IN + 0xE48B52554379726CLLU, // lez_Cyrl_RU + 0x6C6755474C61746ELLU, // lg_Latn_UG + 0x6C694E4C4C61746ELLU, // li_Latn_NL + 0x950B4E5044657661LLU, // lif_Deva_NP + 0x950B494E4C696D62LLU, // lif_Limb_IN + 0xA50B49544C61746ELLU, // lij_Latn_IT + 0xC90B434E4C697375LLU, // lis_Lisu_CN + 0xBD2B49444C61746ELLU, // ljp_Latn_ID + 0xA14B495241726162LLU, // lki_Arab_IR + 0xCD4B55534C61746ELLU, // lkt_Latn_US + 0xB58B494E54656C75LLU, // lmn_Telu_IN + 0xB98B49544C61746ELLU, // lmo_Latn_IT + 0x6C6E43444C61746ELLU, // ln_Latn_CD + 0x6C6F4C414C616F6FLLU, // lo_Laoo_LA + 0xADCB43444C61746ELLU, // lol_Latn_CD + 0xE5CB5A4D4C61746ELLU, // loz_Latn_ZM + 0x8A2B495241726162LLU, // lrc_Arab_IR + 0x6C744C544C61746ELLU, // lt_Latn_LT + 0x9A6B4C564C61746ELLU, // ltg_Latn_LV + 0x6C7543444C61746ELLU, // lu_Latn_CD + 0x828B43444C61746ELLU, // lua_Latn_CD + 0xBA8B4B454C61746ELLU, // luo_Latn_KE + 0xE28B4B454C61746ELLU, // luy_Latn_KE + 0xE68B495241726162LLU, // luz_Arab_IR + 0x6C764C564C61746ELLU, // lv_Latn_LV + 0xAECB544854686169LLU, // lwl_Thai_TH + 0x9F2B434E48616E73LLU, // lzh_Hans_CN + 0xE72B54524C61746ELLU, // lzz_Latn_TR + 0x8C0C49444C61746ELLU, // mad_Latn_ID + 0x940C434D4C61746ELLU, // maf_Latn_CM + 0x980C494E44657661LLU, // mag_Deva_IN + 0xA00C494E44657661LLU, // mai_Deva_IN + 0xA80C49444C61746ELLU, // mak_Latn_ID + 0xB40C474D4C61746ELLU, // man_Latn_GM + 0xB40C474E4E6B6F6FLLU, // man_Nkoo_GN + 0xC80C4B454C61746ELLU, // mas_Latn_KE + 0xE40C4D584C61746ELLU, // maz_Latn_MX + 0x946C52554379726CLLU, // mdf_Cyrl_RU + 0x9C6C50484C61746ELLU, // mdh_Latn_PH + 0xC46C49444C61746ELLU, // mdr_Latn_ID + 0xB48C534C4C61746ELLU, // men_Latn_SL + 0xC48C4B454C61746ELLU, // mer_Latn_KE + 0x80AC544841726162LLU, // mfa_Arab_TH + 0x90AC4D554C61746ELLU, // mfe_Latn_MU + 0x6D674D474C61746ELLU, // mg_Latn_MG + 0x9CCC4D5A4C61746ELLU, // mgh_Latn_MZ + 0xB8CC434D4C61746ELLU, // mgo_Latn_CM + 0xBCCC4E5044657661LLU, // mgp_Deva_NP + 0xE0CC545A4C61746ELLU, // mgy_Latn_TZ + 0x6D684D484C61746ELLU, // mh_Latn_MH + 0x6D694E5A4C61746ELLU, // mi_Latn_NZ + 0xB50C49444C61746ELLU, // min_Latn_ID + 0xC90C495148617472LLU, // mis_Hatr_IQ + 0x6D6B4D4B4379726CLLU, // mk_Cyrl_MK + 0x6D6C494E4D6C796DLLU, // ml_Mlym_IN + 0xC96C53444C61746ELLU, // mls_Latn_SD + 0x6D6E4D4E4379726CLLU, // mn_Cyrl_MN + 0x6D6E434E4D6F6E67LLU, // mn_Mong_CN + 0xA1AC494E42656E67LLU, // mni_Beng_IN + 0xD9AC4D4D4D796D72LLU, // mnw_Mymr_MM + 0x91CC43414C61746ELLU, // moe_Latn_CA + 0x9DCC43414C61746ELLU, // moh_Latn_CA + 0xC9CC42464C61746ELLU, // mos_Latn_BF + 0x6D72494E44657661LLU, // mr_Deva_IN + 0x8E2C4E5044657661LLU, // mrd_Deva_NP + 0xA62C52554379726CLLU, // mrj_Cyrl_RU + 0xBA2C42444D726F6FLLU, // mro_Mroo_BD + 0x6D734D594C61746ELLU, // ms_Latn_MY + 0x6D744D544C61746ELLU, // mt_Latn_MT + 0xC66C494E44657661LLU, // mtr_Deva_IN + 0x828C434D4C61746ELLU, // mua_Latn_CM + 0xCA8C55534C61746ELLU, // mus_Latn_US + 0xE2AC504B41726162LLU, // mvy_Arab_PK + 0xAACC4D4C4C61746ELLU, // mwk_Latn_ML + 0xC6CC494E44657661LLU, // mwr_Deva_IN + 0xD6CC49444C61746ELLU, // mwv_Latn_ID + 0x8AEC5A574C61746ELLU, // mxc_Latn_ZW + 0x6D794D4D4D796D72LLU, // my_Mymr_MM + 0xD70C52554379726CLLU, // myv_Cyrl_RU + 0xDF0C55474C61746ELLU, // myx_Latn_UG + 0xE70C49524D616E64LLU, // myz_Mand_IR + 0xB72C495241726162LLU, // mzn_Arab_IR + 0x6E614E524C61746ELLU, // na_Latn_NR + 0xB40D434E48616E73LLU, // nan_Hans_CN + 0xBC0D49544C61746ELLU, // nap_Latn_IT + 0xC00D4E414C61746ELLU, // naq_Latn_NA + 0x6E624E4F4C61746ELLU, // nb_Latn_NO + 0x9C4D4D584C61746ELLU, // nch_Latn_MX + 0x6E645A574C61746ELLU, // nd_Latn_ZW + 0x886D4D5A4C61746ELLU, // ndc_Latn_MZ + 0xC86D44454C61746ELLU, // nds_Latn_DE + 0x6E654E5044657661LLU, // ne_Deva_NP + 0xD88D4E5044657661LLU, // new_Deva_NP + 0x6E674E414C61746ELLU, // ng_Latn_NA + 0xACCD4D5A4C61746ELLU, // ngl_Latn_MZ + 0x90ED4D584C61746ELLU, // nhe_Latn_MX + 0xD8ED4D584C61746ELLU, // nhw_Latn_MX + 0xA50D49444C61746ELLU, // nij_Latn_ID + 0xD10D4E554C61746ELLU, // niu_Latn_NU + 0xB92D494E4C61746ELLU, // njo_Latn_IN + 0x6E6C4E4C4C61746ELLU, // nl_Latn_NL + 0x998D434D4C61746ELLU, // nmg_Latn_CM + 0x6E6E4E4F4C61746ELLU, // nn_Latn_NO + 0x9DAD434D4C61746ELLU, // nnh_Latn_CM + 0x6E6F4E4F4C61746ELLU, // no_Latn_NO + 0x8DCD54484C616E61LLU, // nod_Lana_TH + 0x91CD494E44657661LLU, // noe_Deva_IN + 0xB5CD534552756E72LLU, // non_Runr_SE + 0xBA0D474E4E6B6F6FLLU, // nqo_Nkoo_GN + 0x6E725A414C61746ELLU, // nr_Latn_ZA + 0xAA4D434143616E73LLU, // nsk_Cans_CA + 0xBA4D5A414C61746ELLU, // nso_Latn_ZA + 0xCA8D53534C61746ELLU, // nus_Latn_SS + 0x6E7655534C61746ELLU, // nv_Latn_US + 0xC2ED434E4C61746ELLU, // nxq_Latn_CN + 0x6E794D574C61746ELLU, // ny_Latn_MW + 0xB30D545A4C61746ELLU, // nym_Latn_TZ + 0xB70D55474C61746ELLU, // nyn_Latn_UG + 0xA32D47484C61746ELLU, // nzi_Latn_GH + 0x6F6346524C61746ELLU, // oc_Latn_FR + 0x6F6D45544C61746ELLU, // om_Latn_ET + 0x6F72494E4F727961LLU, // or_Orya_IN + 0x6F7347454379726CLLU, // os_Cyrl_GE + 0x824E55534F736765LLU, // osa_Osge_US + 0xAA6E4D4E4F726B68LLU, // otk_Orkh_MN + 0x7061504B41726162LLU, // pa_Arab_PK + 0x7061494E47757275LLU, // pa_Guru_IN + 0x980F50484C61746ELLU, // pag_Latn_PH + 0xAC0F495250686C69LLU, // pal_Phli_IR + 0xAC0F434E50686C70LLU, // pal_Phlp_CN + 0xB00F50484C61746ELLU, // pam_Latn_PH + 0xBC0F41574C61746ELLU, // pap_Latn_AW + 0xD00F50574C61746ELLU, // pau_Latn_PW + 0x8C4F46524C61746ELLU, // pcd_Latn_FR + 0xB04F4E474C61746ELLU, // pcm_Latn_NG + 0x886F55534C61746ELLU, // pdc_Latn_US + 0xCC6F43414C61746ELLU, // pdt_Latn_CA + 0xB88F49525870656FLLU, // peo_Xpeo_IR + 0xACAF44454C61746ELLU, // pfl_Latn_DE + 0xB4EF4C4250686E78LLU, // phn_Phnx_LB + 0x814F494E42726168LLU, // pka_Brah_IN + 0xB94F4B454C61746ELLU, // pko_Latn_KE + 0x706C504C4C61746ELLU, // pl_Latn_PL + 0xC98F49544C61746ELLU, // pms_Latn_IT + 0xCDAF47524772656BLLU, // pnt_Grek_GR + 0xB5CF464D4C61746ELLU, // pon_Latn_FM + 0x822F504B4B686172LLU, // pra_Khar_PK + 0x8E2F495241726162LLU, // prd_Arab_IR + 0x7073414641726162LLU, // ps_Arab_AF + 0x707442524C61746ELLU, // pt_Latn_BR + 0xD28F47414C61746ELLU, // puu_Latn_GA + 0x717550454C61746ELLU, // qu_Latn_PE + 0x8A9047544C61746ELLU, // quc_Latn_GT + 0x9A9045434C61746ELLU, // qug_Latn_EC + 0xA411494E44657661LLU, // raj_Deva_IN + 0x945152454C61746ELLU, // rcf_Latn_RE + 0xA49149444C61746ELLU, // rej_Latn_ID + 0xB4D149544C61746ELLU, // rgn_Latn_IT + 0x8111494E4C61746ELLU, // ria_Latn_IN + 0x95114D4154666E67LLU, // rif_Tfng_MA + 0xC9314E5044657661LLU, // rjs_Deva_NP + 0xCD51424442656E67LLU, // rkt_Beng_BD + 0x726D43484C61746ELLU, // rm_Latn_CH + 0x959146494C61746ELLU, // rmf_Latn_FI + 0xB99143484C61746ELLU, // rmo_Latn_CH + 0xCD91495241726162LLU, // rmt_Arab_IR + 0xD19153454C61746ELLU, // rmu_Latn_SE + 0x726E42494C61746ELLU, // rn_Latn_BI + 0x99B14D5A4C61746ELLU, // rng_Latn_MZ + 0x726F524F4C61746ELLU, // ro_Latn_RO + 0x85D149444C61746ELLU, // rob_Latn_ID + 0x95D1545A4C61746ELLU, // rof_Latn_TZ + 0xB271464A4C61746ELLU, // rtm_Latn_FJ + 0x727552554379726CLLU, // ru_Cyrl_RU + 0x929155414379726CLLU, // rue_Cyrl_UA + 0x9A9153424C61746ELLU, // rug_Latn_SB + 0x727752574C61746ELLU, // rw_Latn_RW + 0xAAD1545A4C61746ELLU, // rwk_Latn_TZ + 0xD3114A504B616E61LLU, // ryu_Kana_JP + 0x7361494E44657661LLU, // sa_Deva_IN + 0x941247484C61746ELLU, // saf_Latn_GH + 0x9C1252554379726CLLU, // sah_Cyrl_RU + 0xC0124B454C61746ELLU, // saq_Latn_KE + 0xC81249444C61746ELLU, // sas_Latn_ID + 0xCC12494E4C61746ELLU, // sat_Latn_IN + 0xE412494E53617572LLU, // saz_Saur_IN + 0xBC32545A4C61746ELLU, // sbp_Latn_TZ + 0x736349544C61746ELLU, // sc_Latn_IT + 0xA852494E44657661LLU, // sck_Deva_IN + 0xB45249544C61746ELLU, // scn_Latn_IT + 0xB85247424C61746ELLU, // sco_Latn_GB + 0xC85243414C61746ELLU, // scs_Latn_CA + 0x7364504B41726162LLU, // sd_Arab_PK + 0x7364494E44657661LLU, // sd_Deva_IN + 0x7364494E4B686F6ALLU, // sd_Khoj_IN + 0x7364494E53696E64LLU, // sd_Sind_IN + 0x887249544C61746ELLU, // sdc_Latn_IT + 0x9C72495241726162LLU, // sdh_Arab_IR + 0x73654E4F4C61746ELLU, // se_Latn_NO + 0x949243494C61746ELLU, // sef_Latn_CI + 0x9C924D5A4C61746ELLU, // seh_Latn_MZ + 0xA0924D584C61746ELLU, // sei_Latn_MX + 0xC8924D4C4C61746ELLU, // ses_Latn_ML + 0x736743464C61746ELLU, // sg_Latn_CF + 0x80D249454F67616DLLU, // sga_Ogam_IE + 0xC8D24C544C61746ELLU, // sgs_Latn_LT + 0xA0F24D4154666E67LLU, // shi_Tfng_MA + 0xB4F24D4D4D796D72LLU, // shn_Mymr_MM + 0x73694C4B53696E68LLU, // si_Sinh_LK + 0x8D1245544C61746ELLU, // sid_Latn_ET + 0x736B534B4C61746ELLU, // sk_Latn_SK + 0xC552504B41726162LLU, // skr_Arab_PK + 0x736C53494C61746ELLU, // sl_Latn_SI + 0xA172504C4C61746ELLU, // sli_Latn_PL + 0xE17249444C61746ELLU, // sly_Latn_ID + 0x736D57534C61746ELLU, // sm_Latn_WS + 0x819253454C61746ELLU, // sma_Latn_SE + 0xA59253454C61746ELLU, // smj_Latn_SE + 0xB59246494C61746ELLU, // smn_Latn_FI + 0xBD92494C53616D72LLU, // smp_Samr_IL + 0xC99246494C61746ELLU, // sms_Latn_FI + 0x736E5A574C61746ELLU, // sn_Latn_ZW + 0xA9B24D4C4C61746ELLU, // snk_Latn_ML + 0x736F534F4C61746ELLU, // so_Latn_SO + 0xD1D2544854686169LLU, // sou_Thai_TH + 0x7371414C4C61746ELLU, // sq_Latn_AL + 0x737252534379726CLLU, // sr_Cyrl_RS + 0x737252534C61746ELLU, // sr_Latn_RS + 0x8632494E536F7261LLU, // srb_Sora_IN + 0xB63253524C61746ELLU, // srn_Latn_SR + 0xC632534E4C61746ELLU, // srr_Latn_SN + 0xDE32494E44657661LLU, // srx_Deva_IN + 0x73735A414C61746ELLU, // ss_Latn_ZA + 0xE25245524C61746ELLU, // ssy_Latn_ER + 0x73745A414C61746ELLU, // st_Latn_ZA + 0xC27244454C61746ELLU, // stq_Latn_DE + 0x737549444C61746ELLU, // su_Latn_ID + 0xAA92545A4C61746ELLU, // suk_Latn_TZ + 0xCA92474E4C61746ELLU, // sus_Latn_GN + 0x737653454C61746ELLU, // sv_Latn_SE + 0x7377545A4C61746ELLU, // sw_Latn_TZ + 0x86D2595441726162LLU, // swb_Arab_YT + 0x8AD243444C61746ELLU, // swc_Latn_CD + 0x9AD244454C61746ELLU, // swg_Latn_DE + 0xD6D2494E44657661LLU, // swv_Deva_IN + 0xB6F249444C61746ELLU, // sxn_Latn_ID + 0xAF12424442656E67LLU, // syl_Beng_BD + 0xC712495153797263LLU, // syr_Syrc_IQ + 0xAF32504C4C61746ELLU, // szl_Latn_PL + 0x7461494E54616D6CLLU, // ta_Taml_IN + 0xA4134E5044657661LLU, // taj_Deva_NP + 0xD83350484C61746ELLU, // tbw_Latn_PH + 0xE053494E4B6E6461LLU, // tcy_Knda_IN + 0x8C73434E54616C65LLU, // tdd_Tale_CN + 0x98734E5044657661LLU, // tdg_Deva_NP + 0x9C734E5044657661LLU, // tdh_Deva_NP + 0x7465494E54656C75LLU, // te_Telu_IN + 0xB093534C4C61746ELLU, // tem_Latn_SL + 0xB89355474C61746ELLU, // teo_Latn_UG + 0xCC93544C4C61746ELLU, // tet_Latn_TL + 0x7467504B41726162LLU, // tg_Arab_PK + 0x7467544A4379726CLLU, // tg_Cyrl_TJ + 0x7468544854686169LLU, // th_Thai_TH + 0xACF34E5044657661LLU, // thl_Deva_NP + 0xC0F34E5044657661LLU, // thq_Deva_NP + 0xC4F34E5044657661LLU, // thr_Deva_NP + 0x7469455445746869LLU, // ti_Ethi_ET + 0x9913455245746869LLU, // tig_Ethi_ER + 0xD5134E474C61746ELLU, // tiv_Latn_NG + 0x746B544D4C61746ELLU, // tk_Latn_TM + 0xAD53544B4C61746ELLU, // tkl_Latn_TK + 0xC553415A4C61746ELLU, // tkr_Latn_AZ + 0xCD534E5044657661LLU, // tkt_Deva_NP + 0x746C50484C61746ELLU, // tl_Latn_PH + 0xE173415A4C61746ELLU, // tly_Latn_AZ + 0x9D934E454C61746ELLU, // tmh_Latn_NE + 0x746E5A414C61746ELLU, // tn_Latn_ZA + 0x746F544F4C61746ELLU, // to_Latn_TO + 0x99D34D574C61746ELLU, // tog_Latn_MW + 0xA1F350474C61746ELLU, // tpi_Latn_PG + 0x747254524C61746ELLU, // tr_Latn_TR + 0xD23354524C61746ELLU, // tru_Latn_TR + 0xD63354574C61746ELLU, // trv_Latn_TW + 0x74735A414C61746ELLU, // ts_Latn_ZA + 0x8E5347524772656BLLU, // tsd_Grek_GR + 0x96534E5044657661LLU, // tsf_Deva_NP + 0x9A5350484C61746ELLU, // tsg_Latn_PH + 0xA653425454696274LLU, // tsj_Tibt_BT + 0x747452554379726CLLU, // tt_Cyrl_RU + 0xA67355474C61746ELLU, // ttj_Latn_UG + 0xCA73544854686169LLU, // tts_Thai_TH + 0xCE73415A4C61746ELLU, // ttt_Latn_AZ + 0xB2934D574C61746ELLU, // tum_Latn_MW + 0xAEB354564C61746ELLU, // tvl_Latn_TV + 0xC2D34E454C61746ELLU, // twq_Latn_NE + 0x9AF3434E54616E67LLU, // txg_Tang_CN + 0x747950464C61746ELLU, // ty_Latn_PF + 0xD71352554379726CLLU, // tyv_Cyrl_RU + 0xB3334D414C61746ELLU, // tzm_Latn_MA + 0xB07452554379726CLLU, // udm_Cyrl_RU + 0x7567434E41726162LLU, // ug_Arab_CN + 0x75674B5A4379726CLLU, // ug_Cyrl_KZ + 0x80D4535955676172LLU, // uga_Ugar_SY + 0x756B55414379726CLLU, // uk_Cyrl_UA + 0xA174464D4C61746ELLU, // uli_Latn_FM + 0x8594414F4C61746ELLU, // umb_Latn_AO + 0xC5B4494E42656E67LLU, // unr_Beng_IN + 0xC5B44E5044657661LLU, // unr_Deva_NP + 0xDDB4494E42656E67LLU, // unx_Beng_IN + 0x7572504B41726162LLU, // ur_Arab_PK + 0x757A414641726162LLU, // uz_Arab_AF + 0x757A555A4C61746ELLU, // uz_Latn_UZ + 0xA0154C5256616969LLU, // vai_Vaii_LR + 0x76655A414C61746ELLU, // ve_Latn_ZA + 0x889549544C61746ELLU, // vec_Latn_IT + 0xBC9552554C61746ELLU, // vep_Latn_RU + 0x7669564E4C61746ELLU, // vi_Latn_VN + 0x891553584C61746ELLU, // vic_Latn_SX + 0xC97542454C61746ELLU, // vls_Latn_BE + 0x959544454C61746ELLU, // vmf_Latn_DE + 0xD9954D5A4C61746ELLU, // vmw_Latn_MZ + 0xCDD552554C61746ELLU, // vot_Latn_RU + 0xBA3545454C61746ELLU, // vro_Latn_EE + 0xB695545A4C61746ELLU, // vun_Latn_TZ + 0x776142454C61746ELLU, // wa_Latn_BE + 0x901643484C61746ELLU, // wae_Latn_CH + 0xAC16455445746869LLU, // wal_Ethi_ET + 0xC41650484C61746ELLU, // war_Latn_PH + 0xBC3641554C61746ELLU, // wbp_Latn_AU + 0xC036494E54656C75LLU, // wbq_Telu_IN + 0xC436494E44657661LLU, // wbr_Deva_IN + 0xC97657464C61746ELLU, // wls_Latn_WF + 0xA1B64B4D41726162LLU, // wni_Arab_KM + 0x776F534E4C61746ELLU, // wo_Latn_SN + 0xB276494E44657661LLU, // wtm_Deva_IN + 0xD296434E48616E73LLU, // wuu_Hans_CN + 0xD41742524C61746ELLU, // xav_Latn_BR + 0xC457545243617269LLU, // xcr_Cari_TR + 0x78685A414C61746ELLU, // xh_Latn_ZA + 0x897754524C796369LLU, // xlc_Lyci_TR + 0x8D7754524C796469LLU, // xld_Lydi_TR + 0x9597474547656F72LLU, // xmf_Geor_GE + 0xB597434E4D616E69LLU, // xmn_Mani_CN + 0xC59753444D657263LLU, // xmr_Merc_SD + 0x81B753414E617262LLU, // xna_Narb_SA + 0xC5B7494E44657661LLU, // xnr_Deva_IN + 0x99D755474C61746ELLU, // xog_Latn_UG + 0xC5F7495250727469LLU, // xpr_Prti_IR + 0x8257594553617262LLU, // xsa_Sarb_YE + 0xC6574E5044657661LLU, // xsr_Deva_NP + 0xB8184D5A4C61746ELLU, // yao_Latn_MZ + 0xBC18464D4C61746ELLU, // yap_Latn_FM + 0xD418434D4C61746ELLU, // yav_Latn_CM + 0x8438434D4C61746ELLU, // ybb_Latn_CM + 0x796F4E474C61746ELLU, // yo_Latn_NG + 0xAE3842524C61746ELLU, // yrl_Latn_BR + 0x82984D584C61746ELLU, // yua_Latn_MX + 0x9298434E48616E73LLU, // yue_Hans_CN + 0x9298484B48616E74LLU, // yue_Hant_HK + 0x7A61434E4C61746ELLU, // za_Latn_CN + 0x981953444C61746ELLU, // zag_Latn_SD + 0xA4794B4D41726162LLU, // zdj_Arab_KM + 0x80994E4C4C61746ELLU, // zea_Latn_NL + 0x9CD94D4154666E67LLU, // zgh_Tfng_MA + 0x7A685457426F706FLLU, // zh_Bopo_TW + 0x7A68545748616E62LLU, // zh_Hanb_TW + 0x7A68434E48616E73LLU, // zh_Hans_CN + 0x7A68545748616E74LLU, // zh_Hant_TW + 0xB17954474C61746ELLU, // zlm_Latn_TG + 0xA1994D594C61746ELLU, // zmi_Latn_MY + 0x7A755A414C61746ELLU, // zu_Latn_ZA + 0x833954524C61746ELLU, // zza_Latn_TR }); const std::unordered_map<uint32_t, uint32_t> ARAB_PARENTS({ diff --git a/media/java/android/media/AudioFocusInfo.java b/media/java/android/media/AudioFocusInfo.java index 5467a69ea0bb..0a9ca025e2b0 100644 --- a/media/java/android/media/AudioFocusInfo.java +++ b/media/java/android/media/AudioFocusInfo.java @@ -80,16 +80,12 @@ public final class AudioFocusInfo implements Parcelable { * The audio attributes for the audio focus request. * @return non-null {@link AudioAttributes}. */ - @SystemApi public AudioAttributes getAttributes() { return mAttributes; } - @SystemApi public int getClientUid() { return mClientUid; } - @SystemApi public String getClientId() { return mClientId; } - @SystemApi public String getPackageName() { return mPackageName; } /** @@ -99,7 +95,6 @@ public final class AudioFocusInfo implements Parcelable { * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}, * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}. */ - @SystemApi public int getGainRequest() { return mGainRequest; } /** @@ -109,7 +104,6 @@ public final class AudioFocusInfo implements Parcelable { * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT} or * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}. */ - @SystemApi public int getLossReceived() { return mLossReceived; } /** @hide */ @@ -124,7 +118,6 @@ public final class AudioFocusInfo implements Parcelable { * {@link AudioManager#AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS}, and * {@link AudioManager#AUDIOFOCUS_FLAG_LOCK}. */ - @SystemApi public int getFlags() { return mFlags; } @Override diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index d10900e5d160..da52a268e384 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -5152,6 +5152,15 @@ public class AudioManager { return reportedSurroundFormats; } + /** + * Return if audio haptic coupled playback is supported or not. + * + * @return whether audio haptic playback supported. + */ + public static boolean isHapticPlaybackSupported() { + return AudioSystem.isHapticPlaybackSupported(); + } + //--------------------------------------------------------- // Inner classes diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 082a375470ee..36f635a8e572 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -933,6 +933,11 @@ public class AudioSystem */ public static native int setA11yServicesUids(int[] uids); + /** + * @see AudioManager#isHapticPlaybackSupported() + */ + public static native boolean isHapticPlaybackSupported(); + // Items shared with audio service /** diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index 242ae46f4d33..0375de3cc496 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -27,7 +27,6 @@ import android.media.MediaCodecInfo.CodecCapabilities; import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.os.IBinder; import android.os.IHwBinder; import android.os.Looper; import android.os.Message; @@ -1427,6 +1426,24 @@ import java.util.concurrent.locks.ReentrantLock; <td>⎆</td> </tr> <tr> + <td>(29+)</td> + <td>29+</td> + <td>29+</td> + <td>29+</td> + <td>(29+)</td> + <td>(29+)</td> + <td>-</td> + <td class=fn>{@link #setAudioPresentation setAudioPresentation}</td> + <td></td> + <td></td> + <td></td> + <td></td> + <td></td> + <td></td> + <td></td> + <td></td> + </tr> + <tr> <td>-</td> <td>-</td> <td>18+</td> @@ -3260,6 +3277,19 @@ final public class MediaCodec { public native final void setVideoScalingMode(@VideoScalingMode int mode); /** + * Sets the audio presentation. + * @param presentation see {@link AudioPresentation}. In particular, id should be set. + */ + public void setAudioPresentation(@NonNull AudioPresentation presentation) { + if (presentation == null) { + throw new IllegalArgumentException("audio presentation is null"); + } + native_setAudioPresentation(presentation.getPresentationId(), presentation.getProgramId()); + } + + private native void native_setAudioPresentation(int presentationId, int programId); + + /** * Get the component name. If the codec was created by createDecoderByType * or createEncoderByType, what component is chosen is not known beforehand. * @throws IllegalStateException if in the Released state. diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java index c91d4d3de442..0fb392bfc0fe 100644 --- a/media/java/android/media/MediaMuxer.java +++ b/media/java/android/media/MediaMuxer.java @@ -18,10 +18,10 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.media.MediaCodec; import android.media.MediaCodec.BufferInfo; + import dalvik.system.CloseGuard; import java.io.FileDescriptor; @@ -269,8 +269,10 @@ final public class MediaMuxer { public static final int MUXER_OUTPUT_3GPP = MUXER_OUTPUT_FIRST + 2; /** HEIF media file format*/ public static final int MUXER_OUTPUT_HEIF = MUXER_OUTPUT_FIRST + 3; + /** Ogg media file format*/ + public static final int MUXER_OUTPUT_OGG = MUXER_OUTPUT_FIRST + 4; /** @hide */ - public static final int MUXER_OUTPUT_LAST = MUXER_OUTPUT_HEIF; + public static final int MUXER_OUTPUT_LAST = MUXER_OUTPUT_OGG; }; /** @hide */ @@ -279,6 +281,7 @@ final public class MediaMuxer { OutputFormat.MUXER_OUTPUT_WEBM, OutputFormat.MUXER_OUTPUT_3GPP, OutputFormat.MUXER_OUTPUT_HEIF, + OutputFormat.MUXER_OUTPUT_OGG, }) @Retention(RetentionPolicy.SOURCE) public @interface Format {} diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index d4bfd6175a09..8ced021b1025 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -22,17 +22,17 @@ import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; import android.hardware.Camera; -import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.PersistableBundle; -import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; import android.view.Surface; +import com.android.internal.annotations.GuardedBy; + import java.io.File; import java.io.FileDescriptor; import java.io.IOException; @@ -41,8 +41,6 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; -import com.android.internal.annotations.GuardedBy; - /** * Used to record audio and video. The recording control is based on a * simple state machine (see below). @@ -450,6 +448,9 @@ public class MediaRecorder implements AudioRouting /** VP8/VORBIS data in a WEBM container */ public static final int WEBM = 9; + + /** Opus data in a Ogg container */ + public static final int OGG = 11; }; /** @@ -474,6 +475,8 @@ public class MediaRecorder implements AudioRouting public static final int AAC_ELD = 5; /** Ogg Vorbis audio codec */ public static final int VORBIS = 6; + /** Opus audio codec */ + public static final int OPUS = 7; } /** diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java index 8bc1d35fef36..7fb3aa6d79f9 100644 --- a/media/java/android/media/audiopolicy/AudioMix.java +++ b/media/java/android/media/audiopolicy/AudioMix.java @@ -81,14 +81,12 @@ public class AudioMix { * An audio mix behavior where the output of the mix is sent to the original destination of * the audio signal, i.e. an output device for an output mix, or a recording for an input mix. */ - @SystemApi public static final int ROUTE_FLAG_RENDER = 0x1; /** * An audio mix behavior where the output of the mix is rerouted back to the framework and * is accessible for injection or capture through the {@link AudioTrack} and {@link AudioRecord} * APIs. */ - @SystemApi public static final int ROUTE_FLAG_LOOP_BACK = 0x1 << 1; private static final int ROUTE_FLAG_SUPPORTED = ROUTE_FLAG_RENDER | ROUTE_FLAG_LOOP_BACK; @@ -113,31 +111,23 @@ public class AudioMix { // MIX_STATE_* values to keep in sync with frameworks/av/include/media/AudioPolicy.h /** - * @hide * State of a mix before its policy is enabled. */ - @SystemApi public static final int MIX_STATE_DISABLED = -1; /** - * @hide * State of a mix when there is no audio to mix. */ - @SystemApi public static final int MIX_STATE_IDLE = 0; /** - * @hide * State of a mix that is actively mixing audio. */ - @SystemApi public static final int MIX_STATE_MIXING = 1; /** - * @hide * The current mixing state. * @return one of {@link #MIX_STATE_DISABLED}, {@link #MIX_STATE_IDLE}, * {@link #MIX_STATE_MIXING}. */ - @SystemApi public int getMixState() { return mMixState; } @@ -201,9 +191,7 @@ public class AudioMix { /** * Builder class for {@link AudioMix} objects - * */ - @SystemApi public static class Builder { private AudioMixingRule mRule = null; private AudioFormat mFormat = null; @@ -224,7 +212,6 @@ public class AudioMix { * @param rule a non-null {@link AudioMixingRule} instance. * @throws IllegalArgumentException */ - @SystemApi public Builder(AudioMixingRule rule) throws IllegalArgumentException { if (rule == null) { @@ -284,7 +271,6 @@ public class AudioMix { * @return the same Builder instance. * @throws IllegalArgumentException */ - @SystemApi public Builder setFormat(AudioFormat format) throws IllegalArgumentException { if (format == null) { @@ -302,7 +288,6 @@ public class AudioMix { * @return the same Builder instance. * @throws IllegalArgumentException */ - @SystemApi public Builder setRouteFlags(@RouteFlags int routeFlags) throws IllegalArgumentException { if (routeFlags == 0) { @@ -329,7 +314,6 @@ public class AudioMix { * @return the same Builder instance * @throws IllegalArgumentException */ - @SystemApi public Builder setDevice(@NonNull AudioDeviceInfo device) throws IllegalArgumentException { if (device == null) { throw new IllegalArgumentException("Illegal null AudioDeviceInfo argument"); @@ -347,7 +331,6 @@ public class AudioMix { * @return a new {@link AudioMix} object * @throws IllegalArgumentException if no {@link AudioMixingRule} has been set. */ - @SystemApi public AudioMix build() throws IllegalArgumentException { if (mRule == null) { throw new IllegalArgumentException("Illegal null AudioMixingRule"); diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java index fbee62a86dcd..6c48cdb7b643 100644 --- a/media/java/android/media/audiopolicy/AudioMixingRule.java +++ b/media/java/android/media/audiopolicy/AudioMixingRule.java @@ -54,7 +54,6 @@ public class AudioMixingRule { * {@link Builder#addMixRule(int, Object)} where the Object parameter is an instance of * {@link AudioAttributes}. */ - @SystemApi public static final int RULE_MATCH_ATTRIBUTE_USAGE = 0x1; /** * A rule requiring the capture preset information of the {@link AudioAttributes} to match. @@ -62,14 +61,12 @@ public class AudioMixingRule { * {@link Builder#addMixRule(int, Object)} where the Object parameter is an instance of * {@link AudioAttributes}. */ - @SystemApi public static final int RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET = 0x1 << 1; /** * A rule requiring the UID of the audio stream to match that specified. * This mixing rule can be added with {@link Builder#addMixRule(int, Object)} where the Object * parameter is an instance of {@link java.lang.Integer}. */ - @SystemApi public static final int RULE_MATCH_UID = 0x1 << 2; private final static int RULE_EXCLUSION_MASK = 0x8000; @@ -239,7 +236,6 @@ public class AudioMixingRule { /** * Builder class for {@link AudioMixingRule} objects */ - @SystemApi public static class Builder { private ArrayList<AudioMixMatchCriterion> mCriteria; private int mTargetMixType = AudioMix.MIX_TYPE_INVALID; @@ -247,7 +243,6 @@ public class AudioMixingRule { /** * Constructs a new Builder with no rules. */ - @SystemApi public Builder() { mCriteria = new ArrayList<AudioMixMatchCriterion>(); } @@ -262,7 +257,6 @@ public class AudioMixingRule { * @throws IllegalArgumentException * @see #excludeRule(AudioAttributes, int) */ - @SystemApi public Builder addRule(AudioAttributes attrToMatch, int rule) throws IllegalArgumentException { if (!isValidAttributesSystemApiRule(rule)) { @@ -291,7 +285,6 @@ public class AudioMixingRule { * @throws IllegalArgumentException * @see #addRule(AudioAttributes, int) */ - @SystemApi public Builder excludeRule(AudioAttributes attrToMatch, int rule) throws IllegalArgumentException { if (!isValidAttributesSystemApiRule(rule)) { @@ -313,7 +306,6 @@ public class AudioMixingRule { * @throws IllegalArgumentException * @see #excludeMixRule(int, Object) */ - @SystemApi public Builder addMixRule(int rule, Object property) throws IllegalArgumentException { if (!isValidSystemApiRule(rule)) { throw new IllegalArgumentException("Illegal rule value " + rule); @@ -343,7 +335,6 @@ public class AudioMixingRule { * @return the same Builder instance. * @throws IllegalArgumentException */ - @SystemApi public Builder excludeMixRule(int rule, Object property) throws IllegalArgumentException { if (!isValidSystemApiRule(rule)) { throw new IllegalArgumentException("Illegal rule value " + rule); diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java index 11107e2dd420..6103f55745f9 100644 --- a/media/java/android/media/audiopolicy/AudioPolicy.java +++ b/media/java/android/media/audiopolicy/AudioPolicy.java @@ -58,12 +58,10 @@ public class AudioPolicy { /** * The status of an audio policy that is valid but cannot be used because it is not registered. */ - @SystemApi public static final int POLICY_STATUS_UNREGISTERED = 1; /** * The status of an audio policy that is valid, successfully registered and thus active. */ - @SystemApi public static final int POLICY_STATUS_REGISTERED = 2; private int mStatus; @@ -75,7 +73,6 @@ public class AudioPolicy { * The behavior of a policy with regards to audio focus where it relies on the application * to do the ducking, the is the legacy and default behavior. */ - @SystemApi public static final int FOCUS_POLICY_DUCKING_IN_APP = 0; public static final int FOCUS_POLICY_DUCKING_DEFAULT = FOCUS_POLICY_DUCKING_IN_APP; /** @@ -85,7 +82,6 @@ public class AudioPolicy { * <br>Can only be used after having set a listener with * {@link AudioPolicy#setAudioPolicyFocusListener(AudioPolicyFocusListener)}. */ - @SystemApi public static final int FOCUS_POLICY_DUCKING_IN_POLICY = 1; private AudioPolicyFocusListener mFocusListener; @@ -133,7 +129,6 @@ public class AudioPolicy { * Builder class for {@link AudioPolicy} objects. * By default the policy to be created doesn't govern audio focus decisions. */ - @SystemApi public static class Builder { private ArrayList<AudioMix> mMixes; private Context mContext; @@ -147,7 +142,6 @@ public class AudioPolicy { * Constructs a new Builder with no audio mixes. * @param context the context for the policy */ - @SystemApi public Builder(Context context) { mMixes = new ArrayList<AudioMix>(); mContext = context; @@ -159,7 +153,6 @@ public class AudioPolicy { * @return the same Builder instance. * @throws IllegalArgumentException */ - @SystemApi public Builder addMix(@NonNull AudioMix mix) throws IllegalArgumentException { if (mix == null) { throw new IllegalArgumentException("Illegal null AudioMix argument"); @@ -174,7 +167,6 @@ public class AudioPolicy { * @return the same Builder instance. * @throws IllegalArgumentException */ - @SystemApi public Builder setLooper(@NonNull Looper looper) throws IllegalArgumentException { if (looper == null) { throw new IllegalArgumentException("Illegal null Looper argument"); @@ -187,7 +179,6 @@ public class AudioPolicy { * Sets the audio focus listener for the policy. * @param l a {@link AudioPolicy.AudioPolicyFocusListener} */ - @SystemApi public void setAudioPolicyFocusListener(AudioPolicyFocusListener l) { mFocusListener = l; } @@ -201,7 +192,6 @@ public class AudioPolicy { * @param enforce true if the policy will govern audio focus decisions. * @return the same Builder instance. */ - @SystemApi public Builder setIsAudioFocusPolicy(boolean isFocusPolicy) { mIsFocusPolicy = isFocusPolicy; return this; @@ -211,12 +201,10 @@ public class AudioPolicy { * Sets the audio policy status listener. * @param l a {@link AudioPolicy.AudioPolicyStatusListener} */ - @SystemApi public void setAudioPolicyStatusListener(AudioPolicyStatusListener l) { mStatusListener = l; } - @SystemApi /** * Sets the callback to receive all volume key-related events. * The callback will only be called if the device is configured to handle volume events @@ -240,7 +228,6 @@ public class AudioPolicy { * {@link AudioPolicy.AudioPolicyStatusListener} but the policy was configured * as an audio focus policy with {@link #setIsAudioFocusPolicy(boolean)}. */ - @SystemApi public AudioPolicy build() { if (mStatusListener != null) { // the AudioPolicy status listener includes updates on each mix activity state @@ -258,7 +245,6 @@ public class AudioPolicy { } /** - * @hide * Update the current configuration of the set of audio mixes by adding new ones, while * keeping the policy registered. * This method can only be called on a registered policy. @@ -266,7 +252,6 @@ public class AudioPolicy { * @return {@link AudioManager#SUCCESS} if the change was successful, {@link AudioManager#ERROR} * otherwise. */ - @SystemApi public int attachMixes(@NonNull List<AudioMix> mixes) { if (mixes == null) { throw new IllegalArgumentException("Illegal null list of AudioMix"); @@ -299,7 +284,6 @@ public class AudioPolicy { } /** - * @hide * Update the current configuration of the set of audio mixes by removing some, while * keeping the policy registered. * This method can only be called on a registered policy. @@ -307,7 +291,6 @@ public class AudioPolicy { * @return {@link AudioManager#SUCCESS} if the change was successful, {@link AudioManager#ERROR} * otherwise. */ - @SystemApi public int detachMixes(@NonNull List<AudioMix> mixes) { if (mixes == null) { throw new IllegalArgumentException("Illegal null list of AudioMix"); @@ -405,7 +388,6 @@ public class AudioPolicy { * Returns the current behavior for audio focus-related ducking. * @return {@link #FOCUS_POLICY_DUCKING_IN_APP} or {@link #FOCUS_POLICY_DUCKING_IN_POLICY} */ - @SystemApi public int getFocusDuckingBehavior() { return mConfig.mDuckingPolicy; } @@ -422,7 +404,6 @@ public class AudioPolicy { * @throws IllegalArgumentException * @throws IllegalStateException */ - @SystemApi public int setFocusDuckingBehavior(int behavior) throws IllegalArgumentException, IllegalStateException { if ((behavior != FOCUS_POLICY_DUCKING_IN_APP) @@ -466,7 +447,6 @@ public class AudioPolicy { * with {@link AudioManager#registerAudioPolicy(AudioPolicy)}. * @throws IllegalArgumentException */ - @SystemApi public AudioRecord createAudioRecordSink(AudioMix mix) throws IllegalArgumentException { if (!policyReadyToUse()) { Log.e(TAG, "Cannot create AudioRecord sink for AudioMix"); @@ -506,7 +486,6 @@ public class AudioPolicy { * with {@link AudioManager#registerAudioPolicy(AudioPolicy)}. * @throws IllegalArgumentException */ - @SystemApi public AudioTrack createAudioTrackSource(AudioMix mix) throws IllegalArgumentException { if (!policyReadyToUse()) { Log.e(TAG, "Cannot create AudioTrack source for AudioMix"); @@ -528,18 +507,15 @@ public class AudioPolicy { return at; } - @SystemApi public int getStatus() { return mStatus; } - @SystemApi public static abstract class AudioPolicyStatusListener { public void onStatusChange() {} public void onMixStateUpdate(AudioMix mix) {} } - @SystemApi public static abstract class AudioPolicyFocusListener { public void onAudioFocusGrant(AudioFocusInfo afi, int requestResult) {} public void onAudioFocusLoss(AudioFocusInfo afi, boolean wasNotified) {} @@ -563,7 +539,6 @@ public class AudioPolicy { public void onAudioFocusAbandon(AudioFocusInfo afi) {} } - @SystemApi /** * Callback class to receive volume change-related events. * See {@link #Builder.setAudioPolicyVolumeCallback(AudioPolicyCallback)} to configure the diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java index ec2d9bab5107..e8f188c7a27c 100644 --- a/media/java/android/media/tv/TvInputManager.java +++ b/media/java/android/media/tv/TvInputManager.java @@ -1332,7 +1332,6 @@ public final class TvInputManager { * * @return the list of content ratings blocked by the user. */ - @SystemApi public List<TvContentRating> getBlockedRatings() { try { List<TvContentRating> ratings = new ArrayList<>(); diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index 503720939113..257860890437 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -752,6 +752,13 @@ void JMediaCodec::setVideoScalingMode(int mode) { } } +void JMediaCodec::selectAudioPresentation(const int32_t presentationId, const int32_t programId) { + sp<AMessage> msg = new AMessage; + msg->setInt32("audio-presentation-presentation-id", presentationId); + msg->setInt32("audio-presentation-program-id", programId); + (void)mCodec->setParameters(msg); +} + static jthrowable createCodecException( JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) { ScopedLocalRef<jclass> clazz( @@ -1874,6 +1881,18 @@ static void android_media_MediaCodec_setVideoScalingMode( codec->setVideoScalingMode(mode); } +static void android_media_MediaCodec_setAudioPresentation( + JNIEnv *env, jobject thiz, jint presentationId, jint programId) { + sp<JMediaCodec> codec = getMediaCodec(env, thiz); + + if (codec == NULL) { + throwExceptionAsNecessary(env, INVALID_OPERATION); + return; + } + + codec->selectAudioPresentation((int32_t)presentationId, (int32_t)programId); +} + static void android_media_MediaCodec_native_init(JNIEnv *env) { ScopedLocalRef<jclass> clazz( env, env->FindClass("android/media/MediaCodec")); @@ -2183,6 +2202,9 @@ static const JNINativeMethod gMethods[] = { { "setVideoScalingMode", "(I)V", (void *)android_media_MediaCodec_setVideoScalingMode }, + { "native_setAudioPresentation", "(II)V", + (void *)android_media_MediaCodec_setAudioPresentation }, + { "native_init", "()V", (void *)android_media_MediaCodec_native_init }, { "native_setup", "(Ljava/lang/String;ZZ)V", diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h index 985f55a89254..0a53f1a0e268 100644 --- a/media/jni/android_media_MediaCodec.h +++ b/media/jni/android_media_MediaCodec.h @@ -128,6 +128,8 @@ struct JMediaCodec : public AHandler { void setVideoScalingMode(int mode); + void selectAudioPresentation(const int32_t presentationId, const int32_t programId); + protected: virtual ~JMediaCodec(); diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp index 29238d3b8ea4..f3442f4b4d33 100644 --- a/media/jni/android_media_MediaExtractor.cpp +++ b/media/jni/android_media_MediaExtractor.cpp @@ -500,17 +500,17 @@ static jlong android_media_MediaExtractor_getSampleTime( if (extractor == NULL) { jniThrowException(env, "java/lang/IllegalStateException", NULL); - return -1ll; + return -1LL; } int64_t sampleTimeUs; status_t err = extractor->getSampleTime(&sampleTimeUs); if (err == ERROR_END_OF_STREAM) { - return -1ll; + return -1LL; } else if (err != OK) { jniThrowException(env, "java/lang/IllegalArgumentException", NULL); - return -1ll; + return -1LL; } return (jlong) sampleTimeUs; @@ -522,17 +522,17 @@ static jlong android_media_MediaExtractor_getSampleSize( if (extractor == NULL) { jniThrowException(env, "java/lang/IllegalStateException", NULL); - return -1ll; + return -1LL; } size_t sampleSize; status_t err = extractor->getSampleSize(&sampleSize); if (err == ERROR_END_OF_STREAM) { - return -1ll; + return -1LL; } else if (err != OK) { jniThrowException(env, "java/lang/IllegalArgumentException", NULL); - return -1ll; + return -1LL; } return (jlong) sampleSize; @@ -858,13 +858,13 @@ static jlong android_media_MediaExtractor_getCachedDurationUs( if (extractor == NULL) { jniThrowException(env, "java/lang/IllegalStateException", NULL); - return -1ll; + return -1LL; } int64_t cachedDurationUs; bool eos; if (!extractor->getCachedDuration(&cachedDurationUs, &eos)) { - return -1ll; + return -1LL; } return (jlong) cachedDurationUs; diff --git a/packages/PackageInstaller/res/values-mr/strings.xml b/packages/PackageInstaller/res/values-mr/strings.xml index d751c42a2df7..01f3e5b5bd82 100644 --- a/packages/PackageInstaller/res/values-mr/strings.xml +++ b/packages/PackageInstaller/res/values-mr/strings.xml @@ -22,17 +22,17 @@ <string name="cancel" msgid="1018267193425558088">"रद्द करा"</string> <string name="installing" msgid="4921993079741206516">"इंस्टॉल होत आहे…"</string> <string name="installing_app" msgid="1165095864863849422">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> इंस्टॉल होत आहे…"</string> - <string name="install_done" msgid="5987363587661783896">"अॅप इंस्टॉल झाले."</string> + <string name="install_done" msgid="5987363587661783896">"अॅप इंस्टॉल झाले."</string> <string name="install_confirm_question" msgid="8176284075816604590">"तुम्हाला हे अॅप्लिकेशन इंस्टॉल करायचे आहे का?"</string> <string name="install_confirm_question_update" msgid="7942235418781274635">"तुम्हाच्या विद्यमान अॅप्लिकेशनवर अपडेट इंस्टॉल करायचे आहे का? तुमचा विद्यमान डेटा गमावणार नाही."</string> <string name="install_confirm_question_update_system" msgid="4713001702777910263">"तुम्हाला या बिल्ट-इन अॅप्लिकेशनवर अपडेट इंस्टॉल करायचे आहे का? तुमचा विद्यमान डेटा गमावणार नाही."</string> - <string name="install_failed" msgid="5777824004474125469">"अॅप इंस्टॉल झाले नाही."</string> + <string name="install_failed" msgid="5777824004474125469">"अॅप इंस्टॉल झाले नाही."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"पॅकेज इंस्टॉल होण्यापासून ब्लॉक केले होते."</string> - <string name="install_failed_conflict" msgid="3493184212162521426">"पॅकेजचा विद्यमान पॅकेजशी विरोध असल्याने अॅप इंस्टॉल झाले नाही."</string> - <string name="install_failed_incompatible" product="tablet" msgid="6019021440094927928">"तुमच्या टॅबलेटशी कंपॅटिबल नसल्याने अॅप इंस्टॉल झाले नाही."</string> - <string name="install_failed_incompatible" product="tv" msgid="2890001324362291683">"हे अॅप तुमच्या टीव्हीशी कंपॅटिबल नाही."</string> - <string name="install_failed_incompatible" product="default" msgid="7254630419511645826">"तुमच्या फोनशी कंपॅटिबल नसल्याने अॅप इंस्टॉल झाले नाही."</string> - <string name="install_failed_invalid_apk" msgid="8581007676422623930">"पॅकेज अयोग्य असल्याचे दिसत असल्याने अॅप इंस्टॉल झाले नाही."</string> + <string name="install_failed_conflict" msgid="3493184212162521426">"पॅकेजचा विद्यमान पॅकेजशी विरोध असल्याने अॅप इंस्टॉल झाले नाही."</string> + <string name="install_failed_incompatible" product="tablet" msgid="6019021440094927928">"तुमच्या टॅबलेटशी कंपॅटिबल नसल्याने अॅप इंस्टॉल झाले नाही."</string> + <string name="install_failed_incompatible" product="tv" msgid="2890001324362291683">"हे अॅप तुमच्या टीव्हीशी कंपॅटिबल नाही."</string> + <string name="install_failed_incompatible" product="default" msgid="7254630419511645826">"तुमच्या फोनशी कंपॅटिबल नसल्याने अॅप इंस्टॉल झाले नाही."</string> + <string name="install_failed_invalid_apk" msgid="8581007676422623930">"पॅकेज अयोग्य असल्याचे दिसत असल्याने अॅप इंस्टॉल झाले नाही."</string> <string name="install_failed_msg" product="tablet" msgid="6298387264270562442">"<xliff:g id="APP_NAME">%1$s</xliff:g> तुमच्या टॅबलेटवर इंस्टॉल केले जाऊ शकत नाही."</string> <string name="install_failed_msg" product="tv" msgid="1920009940048975221">"<xliff:g id="APP_NAME">%1$s</xliff:g> तुमच्या टीव्हीवर इंस्टॉल केले जाऊ शकत नाही."</string> <string name="install_failed_msg" product="default" msgid="6484461562647915707">"<xliff:g id="APP_NAME">%1$s</xliff:g> तुमच्या फोनवर इंस्टॉल केले जाऊ शकत नाही."</string> @@ -44,20 +44,20 @@ <string name="manage_applications" msgid="5400164782453975580">"अॅप्स व्यवस्थापन"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"जागा संपली"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> इंस्टॉल केले जाऊ शकत नाही. काही जागा मोकळी करा आणि पुन्हा प्रयत्न करा."</string> - <string name="app_not_found_dlg_title" msgid="5107924008597470285">"अॅप आढळले नाही"</string> - <string name="app_not_found_dlg_text" msgid="5219983779377811611">"इंस्टॉल केलेल्या अॅप्सच्या सूचीमध्ये अॅप आढळले नाही."</string> + <string name="app_not_found_dlg_title" msgid="5107924008597470285">"अॅप आढळले नाही"</string> + <string name="app_not_found_dlg_text" msgid="5219983779377811611">"इंस्टॉल केलेल्या अॅप्सच्या सूचीमध्ये अॅप आढळले नाही."</string> <string name="user_is_not_allowed_dlg_title" msgid="6915293433252210232">"अनुमती नाही"</string> <string name="user_is_not_allowed_dlg_text" msgid="3468447791330611681">"हे अनइंस्टॉल करण्याची विद्यमान वापरकर्त्यास अनुमती नाही."</string> <string name="generic_error_dlg_title" msgid="5863195085927067752">"एरर"</string> - <string name="generic_error_dlg_text" msgid="5287861443265795232">"अॅप अनइंस्टॉल करणे शक्य झाले नाही."</string> - <string name="uninstall_application_title" msgid="4045420072401428123">"अॅप अनइंस्टॉल करा"</string> + <string name="generic_error_dlg_text" msgid="5287861443265795232">"अॅप अनइंस्टॉल करणे शक्य झाले नाही."</string> + <string name="uninstall_application_title" msgid="4045420072401428123">"अॅप अनइंस्टॉल करा"</string> <string name="uninstall_update_title" msgid="824411791011583031">"अपडेट अनइंस्टॉल करा"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> खालील अॅपचा भाग आहे:"</string> - <string name="uninstall_application_text" msgid="3816830743706143980">"तुम्हाला हे अॅप अनइंस्टॉल करायचे आहे का?"</string> - <string name="uninstall_application_text_all_users" msgid="575491774380227119">"तुम्हाला हे अॅप "<b>"सर्व"</b>" वापरकर्त्यांसाठी अनइंस्टॉल करायचे आहे का? अॅप्लिकेशन आणि त्याचा डेटा डिव्हाइसवरील "<b>"सर्व"</b>" वापरकर्त्यांकडून काढला जाईल."</string> + <string name="uninstall_application_text" msgid="3816830743706143980">"तुम्हाला हे अॅप अनइंस्टॉल करायचे आहे का?"</string> + <string name="uninstall_application_text_all_users" msgid="575491774380227119">"तुम्हाला हे अॅप "<b>"सर्व"</b>" वापरकर्त्यांसाठी अनइंस्टॉल करायचे आहे का? अॅप्लिकेशन आणि त्याचा डेटा डिव्हाइसवरील "<b>"सर्व"</b>" वापरकर्त्यांकडून काढला जाईल."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"तुम्हाला <xliff:g id="USERNAME">%1$s</xliff:g> वापरकर्त्यासाठी हे अॅप अनइंस्टॉल करायचे आहे का?"</string> - <string name="uninstall_update_text" msgid="863648314632448705">"फॅक्टरी आवृत्तीसह हे अॅप बदलायचे का? सर्व डेटा काढला जाईल."</string> - <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"फॅक्टरी आवृत्तीसह हे अॅप बदलायचे? सर्व डेटा काढला जाईल. हे कार्य प्रोफाइल असलेल्यांसह या डिव्हाइसच्या सर्व वापरकर्त्यांना प्रभावित करते."</string> + <string name="uninstall_update_text" msgid="863648314632448705">"फॅक्टरी आवृत्तीसह हे अॅप बदलायचे का? सर्व डेटा काढला जाईल."</string> + <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"फॅक्टरी आवृत्तीसह हे अॅप बदलायचे? सर्व डेटा काढला जाईल. हे कार्य प्रोफाइल असलेल्यांसह या डिव्हाइसच्या सर्व वापरकर्त्यांना प्रभावित करते."</string> <string name="uninstalling_notification_channel" msgid="840153394325714653">"अनइंस्टॉल रन होत आहेत"</string> <string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"अनइंस्टॉल करता आले नाही"</string> <string name="uninstalling" msgid="8709566347688966845">"अनइंस्टॉल करत आहे…"</string> @@ -68,7 +68,7 @@ <string name="uninstall_failed_app" msgid="5506028705017601412">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> अनइंस्टॉल करता आले नाही."</string> <string name="uninstall_failed_device_policy_manager" msgid="785293813665540305">"अॅक्टिव्ह डिव्हाइस प्रशासक अॅप अनइंस्टॉल करू शकत नाही"</string> <string name="uninstall_failed_device_policy_manager_of_user" msgid="4813104025494168064">"<xliff:g id="USERNAME">%1$s</xliff:g> साठी अॅक्टिव्ह डिव्हाइस प्रशासक अॅप अनइंस्टॉल करू शकत नाही"</string> - <string name="uninstall_all_blocked_profile_owner" msgid="2009393666026751501">"हे अॅप काही वापरकर्ते किंवा प्रोफाइलसाठी आवश्यक आहे आणि इतरांसाठी अनइंस्टॉल करण्यात आले"</string> + <string name="uninstall_all_blocked_profile_owner" msgid="2009393666026751501">"हे अॅप काही वापरकर्ते किंवा प्रोफाइलसाठी आवश्यक आहे आणि इतरांसाठी अनइंस्टॉल करण्यात आले"</string> <string name="uninstall_blocked_profile_owner" msgid="6373897407002404848">"तुमच्या प्रोफाइलसाठी हे अॅप आवश्यक आहे आणि अनइंस्टॉल केले जाऊ शकत नाही."</string> <string name="uninstall_blocked_device_owner" msgid="6724602931761073901">"तुमच्या डिव्हाइस प्रशासकास हे अॅप आवश्यक आहे आणि ते अनइंस्टॉल केले जाऊ शकत नाही."</string> <string name="manage_device_administrators" msgid="3092696419363842816">"डिव्हाइस प्रशासक अॅप्स व्यवस्थापित करा"</string> @@ -77,18 +77,18 @@ <string name="Parse_error_dlg_text" msgid="1661404001063076789">"पॅकेज पार्स करण्यात समस्या आली."</string> <string name="wear_not_allowed_dlg_title" msgid="8664785993465117517">"Android Wear"</string> <string name="wear_not_allowed_dlg_text" msgid="704615521550939237">"इंस्टॉल करा/अनइंस्टॉल करा क्रिया Wear वर सपोर्ट करत नाहीत."</string> - <string name="message_staging" msgid="8032722385658438567">"अॅप सुरुवातीच्या स्थितीत आहे…"</string> + <string name="message_staging" msgid="8032722385658438567">"अॅप सुरुवातीच्या स्थितीत आहे…"</string> <string name="app_name_unknown" msgid="6881210203354323926">"अज्ञात"</string> <string name="untrusted_external_source_warning" product="tablet" msgid="6539403649459942547">"तुमच्या सुरक्षिततेसाठी, तुमच्या टॅबलेटला या स्रोताकडील अज्ञात अॅप्स इंस्टॉल करण्याची अनुमती नाही."</string> <string name="untrusted_external_source_warning" product="tv" msgid="1206648674551321364">"तुमच्या सुरक्षिततेसाठी, तुमच्या टीव्हीला या स्रोताकडील अज्ञात अॅप्स इंस्टॉल करण्याची अनुमती नाही."</string> <string name="untrusted_external_source_warning" product="default" msgid="7279739265754475165">"तुमच्या सुरक्षिततेसाठी, तुमच्या फोनला या स्रोताकडील अज्ञात अॅप्स इंस्टॉल करण्याची अनुमती नाही."</string> - <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"तुमचा फोन आणि वैयक्तिक डेटा अज्ञात अॅप्सकडून होणार्या अटॅकमुळे अधिक असुरक्षित आहे. हे अॅप इंस्टॉल करून, तुम्ही सहमती देता की ते वापरल्याने होणार्या तुमच्या फोनचे कोणत्याही प्रकारे होणारे नुकसान किंवा डेटा हानीसाठी तुम्ही जबाबदार आहात."</string> - <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"तुमचा टॅबलेट आणि वैयक्तिक डेटा अज्ञात अॅप्सकडून होणार्या अटॅकमुळे अधिक असुरक्षित आहे. हे अॅप इंस्टॉल करून, तुम्ही सहमती देता की ते वापरल्याने तुमच्या टॅबलेटचे कोणत्याही प्रकारे होणारे नुकसान किंवा डेटा हानीसाठी तुम्ही जबाबदार आहात."</string> - <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"तुमचा टीव्ही आणि वैयक्तिक डेटा अज्ञात अॅप्सकडून होणार्या अटॅकमुळे अधिक असुरक्षित आहे. हे अॅप इंस्टॉल करून, तुम्ही सहमती देता की ते वापरल्याने तुमच्या टीव्हीचे कोणत्याही प्रकारे होणारे नुकसान किंवा डेटा हानीसाठी तुम्ही जबाबदार आहात."</string> + <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"तुमचा फोन आणि वैयक्तिक डेटा अज्ञात अॅप्सकडून होणार्या अटॅकमुळे अधिक असुरक्षित आहे. हे अॅप इंस्टॉल करून, तुम्ही सहमती देता की ते वापरल्याने होणार्या तुमच्या फोनचे कोणत्याही प्रकारे होणारे नुकसान किंवा डेटा हानीसाठी तुम्ही जबाबदार आहात."</string> + <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"तुमचा टॅबलेट आणि वैयक्तिक डेटा अज्ञात अॅप्सकडून होणार्या अटॅकमुळे अधिक असुरक्षित आहे. हे अॅप इंस्टॉल करून, तुम्ही सहमती देता की ते वापरल्याने तुमच्या टॅबलेटचे कोणत्याही प्रकारे होणारे नुकसान किंवा डेटा हानीसाठी तुम्ही जबाबदार आहात."</string> + <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"तुमचा टीव्ही आणि वैयक्तिक डेटा अज्ञात अॅप्सकडून होणार्या अटॅकमुळे अधिक असुरक्षित आहे. हे अॅप इंस्टॉल करून, तुम्ही सहमती देता की ते वापरल्याने तुमच्या टीव्हीचे कोणत्याही प्रकारे होणारे नुकसान किंवा डेटा हानीसाठी तुम्ही जबाबदार आहात."</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"सुरू ठेवा"</string> <string name="external_sources_settings" msgid="4046964413071713807">"सेटिंग्ज"</string> <string name="wear_app_channel" msgid="1960809674709107850">"wear अॅप्स इंस्टॉल/अनइंस्टॉल करत आहे"</string> - <string name="app_installed_notification_channel_description" msgid="2695385797601574123">"अॅप इंस्टॉल सूचना"</string> + <string name="app_installed_notification_channel_description" msgid="2695385797601574123">"अॅप इंस्टॉल सूचना"</string> <string name="notification_installation_success_message" msgid="6450467996056038442">"यशस्वीरित्या इंस्टॉल केले"</string> <string name="notification_installation_success_status" msgid="3172502643504323321">"\"<xliff:g id="APPNAME">%1$s</xliff:g>\" यशस्वीरित्या इंस्टॉल झाले"</string> </resources> diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml index 8ebb182ac51c..5b09b29e8b05 100644 --- a/packages/SettingsLib/res/values-mr/strings.xml +++ b/packages/SettingsLib/res/values-mr/strings.xml @@ -184,7 +184,7 @@ <string name="category_work" msgid="8699184680584175622">"कार्य"</string> <string name="development_settings_title" msgid="215179176067683667">"डेव्हलपर पर्याय"</string> <string name="development_settings_enable" msgid="542530994778109538">"डेव्हलपर पर्याय सुरू करा"</string> - <string name="development_settings_summary" msgid="1815795401632854041">"अॅप विकासासाठी पर्याय सेट करा"</string> + <string name="development_settings_summary" msgid="1815795401632854041">"अॅप विकासासाठी पर्याय सेट करा"</string> <string name="development_settings_not_available" msgid="4308569041701535607">"या वापरकर्त्यासाठी डेव्हलपर पर्याय उपलब्ध नाहीत"</string> <string name="vpn_settings_not_available" msgid="956841430176985598">"या वापरकर्त्यासाठी VPN सेटिंग्ज उपलब्ध नाहीत"</string> <string name="tethering_settings_not_available" msgid="6765770438438291012">"या वापरकर्त्यासाठी टेदरिंग सेटिंग्ज उपलब्ध नाहीत"</string> @@ -202,9 +202,9 @@ <string name="oem_unlock_enable_summary" msgid="4720281828891618376">"बूटलोडर अनलॉक करण्यासाठी अनुमती द्या"</string> <string name="confirm_enable_oem_unlock_title" msgid="4802157344812385674">"OEM अनलॉक करण्यास अनुमती द्यायची?"</string> <string name="confirm_enable_oem_unlock_text" msgid="5517144575601647022">"चेतावणी: हे सेटिंग चालू असताना या डिव्हाइस वर डिव्हाइस संरक्षण वैशिष्ट्ये काम करणार नाहीत."</string> - <string name="mock_location_app" msgid="7966220972812881854">"बनावट स्थान अॅप निवडा"</string> - <string name="mock_location_app_not_set" msgid="809543285495344223">"कोणताही बनावट स्थान अॅप सेट केला नाही"</string> - <string name="mock_location_app_set" msgid="8966420655295102685">"बनावट स्थान अॅप: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="mock_location_app" msgid="7966220972812881854">"बनावट स्थान अॅप निवडा"</string> + <string name="mock_location_app_not_set" msgid="809543285495344223">"कोणताही बनावट स्थान अॅप सेट केला नाही"</string> + <string name="mock_location_app_set" msgid="8966420655295102685">"बनावट स्थान अॅप: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="debug_networking_category" msgid="7044075693643009662">"नेटवर्किंग"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"वायरलेस डिस्प्ले प्रमाणीकरण"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"वाय-फाय व्हर्बोझ लॉगिंग सुरू करा"</string> @@ -261,11 +261,11 @@ <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"नावांशिवाय ब्लूटूथ डीव्हाइस (फक्त MAC पत्ते) दाखवले जातील"</string> <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"रिमोट डिव्हाइसमध्ये सहन न होणारा मोठा आवाज किंवा नियंत्रणाचा अभाव यासारखी आवाजाची समस्या असल्यास ब्लूटूथ संपूर्ण आवाज वैशिष्ट्य बंद करते."</string> <string name="enable_terminal_title" msgid="95572094356054120">"स्थानिक टर्मिनल"</string> - <string name="enable_terminal_summary" msgid="67667852659359206">"स्थानिक शेल प्रवेश देणारा टर्मिनल अॅप सुरू करा"</string> + <string name="enable_terminal_summary" msgid="67667852659359206">"स्थानिक शेल प्रवेश देणारा टर्मिनल अॅप सुरू करा"</string> <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP तपासणी"</string> <string name="hdcp_checking_dialog_title" msgid="5141305530923283">"HDCP तपासणी वर्तन सेट करा"</string> <string name="debug_debugging_category" msgid="6781250159513471316">"डीबग करणे"</string> - <string name="debug_app" msgid="8349591734751384446">"डीबग अॅप निवडा"</string> + <string name="debug_app" msgid="8349591734751384446">"डीबग अॅप निवडा"</string> <string name="debug_app_not_set" msgid="718752499586403499">"कोणतेही डीबग अॅप्लिकेशन सेट नाही"</string> <string name="debug_app_set" msgid="2063077997870280017">"अॅप्लिकेशन डीबग करत आहे: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="select_application" msgid="5156029161289091703">"अॅप्लिकेशन निवडा"</string> @@ -315,7 +315,7 @@ <string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"वापरकर्त्याने प्रत्येक अॅक्टिव्हिटी सोडताच ती नष्ट करा"</string> <string name="app_process_limit_title" msgid="4280600650253107163">"पार्श्वभूमी प्रक्रिया मर्यादा"</string> <string name="show_all_anrs" msgid="4924885492787069007">"बॅकग्राउंड ANR दाखवा"</string> - <string name="show_all_anrs_summary" msgid="6636514318275139826">"बॅकग्राउंड अॅप्ससाठी अॅप प्रतिसाद देत नाही दाखवते"</string> + <string name="show_all_anrs_summary" msgid="6636514318275139826">"बॅकग्राउंड अॅप्ससाठी अॅप प्रतिसाद देत नाही दाखवते"</string> <string name="show_notification_channel_warnings" msgid="1399948193466922683">"सूचना चॅनेल चेतावण्या दाखवा"</string> <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"एखादे अॅप वैध चॅनेलशिवाय सूचना पोस्ट करते तेव्हा स्क्रीनवर चेतावणी देते"</string> <string name="force_allow_on_external" msgid="3215759785081916381">"बाह्यवर अॅप्सना अनुमती देण्याची सक्ती करा"</string> @@ -343,7 +343,7 @@ <string name="inactive_apps_title" msgid="9042996804461901648">"स्टँडबाय अॅप्स"</string> <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"निष्क्रिय. टॉगल करण्यासाठी टॅप करा."</string> <string name="inactive_app_active_summary" msgid="4174921824958516106">"सक्रिय. टॉगल करण्यासाठी टॅप करा."</string> - <string name="standby_bucket_summary" msgid="6567835350910684727">"अॅप स्टँडबाय स्थिती: <xliff:g id="BUCKET"> %s</xliff:g>"</string> + <string name="standby_bucket_summary" msgid="6567835350910684727">"अॅप स्टँडबाय स्थिती: <xliff:g id="BUCKET"> %s</xliff:g>"</string> <string name="runningservices_settings_title" msgid="8097287939865165213">"चालू सेवा"</string> <string name="runningservices_settings_summary" msgid="854608995821032748">"सध्या चालत असलेल्या सेवा पहा आणि नियंत्रित करा"</string> <string name="select_webview_provider_title" msgid="4628592979751918907">"वेबदृश्य अंमलबजावणी"</string> @@ -422,7 +422,7 @@ <string name="use_system_language_to_select_input_method_subtypes" msgid="5747329075020379587">"सिस्टम भाषा वापरा"</string> <string name="failed_to_open_app_settings_toast" msgid="1251067459298072462">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> साठी सेटिंग्ज उघडण्यात अयशस्वी"</string> <string name="ime_security_warning" msgid="4135828934735934248">"ही इनपुट पद्धत पासवर्ड आणि क्रेडिट कार्ड नंबर यासह, तुम्ही टाइप करता तो सर्व मजकूर संकलित करण्यात सक्षम होऊ शकते. ही <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> अॅपवरून येते. ही इनपुट पद्धत वापरायची?"</string> - <string name="direct_boot_unaware_dialog_message" msgid="7870273558547549125">"टीप: रीबूट केल्यानंतर, तुम्ही तुमचा फोन अनलॉक करे पर्यंत हे अॅप सुरू होऊ शकत नाही"</string> + <string name="direct_boot_unaware_dialog_message" msgid="7870273558547549125">"टीप: रीबूट केल्यानंतर, तुम्ही तुमचा फोन अनलॉक करे पर्यंत हे अॅप सुरू होऊ शकत नाही"</string> <string name="ims_reg_title" msgid="7609782759207241443">"IMS नोंदणी स्थिती"</string> <string name="ims_reg_status_registered" msgid="933003316932739188">"नोंदवलेले"</string> <string name="ims_reg_status_not_registered" msgid="6529783773485229486">"नोंदवलेले नाही"</string> @@ -449,6 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"प्रत्येक वेळी विचारा"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"तुम्ही बंद करेपर्यंत"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"आत्ताच"</string> - <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"अपडेट केलेले ग्राफिक ड्राइव्हर डेव्हलमेंटमध्ये वापरण्यासाठी अॅप निवडा"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"अपडेट केलेले ग्राफिक ड्राइव्हर डेव्हलमेंटमध्ये वापरण्यासाठी अॅप निवडा"</string> <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"फोनचा स्पीकर"</string> </resources> diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index ae9c5f2e21a4..e810ba248850 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -40,7 +40,7 @@ <string name="connected_via_passpoint" msgid="2826205693803088747">"Tilkoblet via %1$s"</string> <string name="available_via_passpoint" msgid="1617440946846329613">"Tilgjengelig via %1$s"</string> <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Tilkoblet – ingen Internett-tilgang"</string> - <string name="wifi_status_no_internet" msgid="5784710974669608361">"Ingen Internett-tilkobling"</string> + <string name="wifi_status_no_internet" msgid="5784710974669608361">"Ingen internettilkobling"</string> <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Pålogging kreves"</string> <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Tilgangspunktet er midlertidig fullt"</string> <string name="connected_via_carrier" msgid="7583780074526041912">"Tilkoblet via %1$s"</string> @@ -75,7 +75,7 @@ <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Internett-tilgang"</string> <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Kontaktdeling"</string> <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Bruk til kontaktdeling"</string> - <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Deling av Internett-tilkobling"</string> + <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Deling av internettilkobling"</string> <string name="bluetooth_profile_map" msgid="1019763341565580450">"Tekstmeldinger"</string> <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Tilgang til SIM-kortet"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD-lyd: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> @@ -90,7 +90,7 @@ <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Ikke koblet til tjener for filoverføring"</string> <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Koblet til inndataenhet"</string> <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Koblet til enhet for Internett-tilgang"</string> - <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Deler lokal Internett-tilkobling med enhet"</string> + <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Deler lokal internettilkobling med enhet"</string> <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Bruk for Internett-tilgang"</string> <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Bruk for kart"</string> <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Bruk for tilgang til SIM-kortet"</string> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 424368d2600c..b071355986f5 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -418,7 +418,7 @@ public class SettingsProvider extends ContentProvider { case Settings.CALL_METHOD_PUT_CONFIG: { String value = getSettingValue(args); final boolean makeDefault = getSettingMakeDefault(args); - insertConfigSetting(name, value, null, makeDefault, requestingUserId, false); + insertConfigSetting(name, value, makeDefault); break; } @@ -447,7 +447,7 @@ public class SettingsProvider extends ContentProvider { case Settings.CALL_METHOD_RESET_CONFIG: { final int mode = getResetModeEnforcingPermission(args); String prefix = getSettingPrefix(args); - resetConfigSetting(requestingUserId, mode, prefix); + resetConfigSetting(mode, prefix); break; } @@ -466,7 +466,7 @@ public class SettingsProvider extends ContentProvider { } case Settings.CALL_METHOD_DELETE_CONFIG: { - int rows = deleteConfigSetting(name, requestingUserId, false) ? 1 : 0; + int rows = deleteConfigSetting(name) ? 1 : 0; Bundle result = new Bundle(); result.putInt(RESULT_ROWS_DELETED, rows); return result; @@ -1067,38 +1067,33 @@ public class SettingsProvider extends ContentProvider { } } - private boolean insertConfigSetting(String name, String value, String tag, - boolean makeDefault, int requestingUserId, boolean forceNotify) { + private boolean insertConfigSetting(String name, String value, boolean makeDefault) { if (DEBUG) { Slog.v(LOG_TAG, "insertConfigSetting(" + name + ", " + value + ", " - + ", " + tag + ", " + makeDefault + ", " + requestingUserId - + ", " + forceNotify + ")"); + + makeDefault + ")"); } - return mutateConfigSetting(name, value, tag, makeDefault, requestingUserId, - MUTATION_OPERATION_INSERT, forceNotify, 0); + return mutateConfigSetting(name, value, null, makeDefault, + MUTATION_OPERATION_INSERT, 0); } - private boolean deleteConfigSetting(String name, int requestingUserId, boolean forceNotify) { + private boolean deleteConfigSetting(String name) { if (DEBUG) { - Slog.v(LOG_TAG, "deleteConfigSetting(" + name + ", " + requestingUserId - + ", " + forceNotify + ")"); + Slog.v(LOG_TAG, "deleteConfigSetting(" + name + ")"); } - return mutateConfigSetting(name, null, null, false, requestingUserId, - MUTATION_OPERATION_DELETE, forceNotify, 0); + return mutateConfigSetting(name, null, null, false, + MUTATION_OPERATION_DELETE, 0); } - private void resetConfigSetting(int requestingUserId, int mode, String prefix) { + private void resetConfigSetting(int mode, String prefix) { if (DEBUG) { - Slog.v(LOG_TAG, "resetConfigSetting(" + requestingUserId + ", " - + mode + ", " + prefix + ")"); + Slog.v(LOG_TAG, "resetConfigSetting(" + mode + ", " + prefix + ")"); } - mutateConfigSetting(null, null, prefix, false, requestingUserId, - MUTATION_OPERATION_RESET, false, mode); + mutateConfigSetting(null, null, prefix, false, + MUTATION_OPERATION_RESET, mode); } private boolean mutateConfigSetting(String name, String value, String prefix, - boolean makeDefault, int requestingUserId, int operation, boolean forceNotify, - int mode) { + boolean makeDefault, int operation, int mode) { // TODO(b/117663715): check the new permission when it's added. // enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS); @@ -1107,13 +1102,13 @@ public class SettingsProvider extends ContentProvider { switch (operation) { case MUTATION_OPERATION_INSERT: { return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_CONFIG, - UserHandle.USER_SYSTEM, name, value, null, makeDefault, - getCallingPackage(), forceNotify, null); + UserHandle.USER_SYSTEM, name, value, null, makeDefault, true, + getCallingPackage(), false, null); } case MUTATION_OPERATION_DELETE: { return mSettingsRegistry.deleteSettingLocked(SETTINGS_TYPE_CONFIG, - UserHandle.USER_SYSTEM, name, forceNotify, null); + UserHandle.USER_SYSTEM, name, false, null); } case MUTATION_OPERATION_RESET: { @@ -2631,13 +2626,20 @@ public class SettingsProvider extends ContentProvider { public boolean insertSettingLocked(int type, int userId, String name, String value, String tag, boolean makeDefault, String packageName, boolean forceNotify, Set<String> criticalSettings) { + return insertSettingLocked(type, userId, name, value, tag, makeDefault, false, + packageName, forceNotify, criticalSettings); + } + + public boolean insertSettingLocked(int type, int userId, String name, String value, + String tag, boolean makeDefault, boolean forceNonSystemPackage, String packageName, + boolean forceNotify, Set<String> criticalSettings) { final int key = makeKey(type, userId); boolean success = false; SettingsState settingsState = peekSettingsStateLocked(key); if (settingsState != null) { success = settingsState.insertSettingLocked(name, value, - tag, makeDefault, packageName); + tag, makeDefault, forceNonSystemPackage, packageName); } if (success && criticalSettings != null && criticalSettings.contains(name)) { diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java index ae2ca3f87ae7..521163f50ca1 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java @@ -377,6 +377,13 @@ final class SettingsState { @GuardedBy("mLock") public boolean insertSettingLocked(String name, String value, String tag, boolean makeDefault, String packageName) { + return insertSettingLocked(name, value, tag, makeDefault, false, packageName); + } + + // The settings provider must hold its lock when calling here. + @GuardedBy("mLock") + public boolean insertSettingLocked(String name, String value, String tag, + boolean makeDefault, boolean forceNonSystemPackage, String packageName) { if (TextUtils.isEmpty(name)) { return false; } @@ -387,7 +394,7 @@ final class SettingsState { Setting newState; if (oldState != null) { - if (!oldState.update(value, makeDefault, packageName, tag, false)) { + if (!oldState.update(value, makeDefault, packageName, tag, forceNonSystemPackage)) { return false; } newState = oldState; diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java index 59de6a7e64b9..9d0462e14b63 100644 --- a/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java +++ b/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java @@ -17,10 +17,9 @@ package com.android.providers.settings; import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNull; -import static org.junit.Assert.assertNotNull; - import android.content.ContentResolver; import android.net.Uri; import android.os.Bundle; @@ -147,10 +146,10 @@ public class DeviceConfigServiceTest { } @Test - public void testReset_setUntrustedDefault() throws Exception { + public void testReset() throws Exception { String newValue = "value2"; - // make sValue the untrusted default (set by root) + // make sValue the default value executeShellCommand( "device_config put " + sNamespace + " " + sKey + " " + sValue + " default"); // make newValue the current value @@ -159,40 +158,19 @@ public class DeviceConfigServiceTest { String result = getFromContentProvider(mContentResolver, sNamespace, sKey); assertEquals(newValue, result); + // reset values that were set by untrusted packages executeShellCommand("device_config reset untrusted_defaults " + sNamespace); result = getFromContentProvider(mContentResolver, sNamespace, sKey); - // back to the default + // the default value has been restored assertEquals(sValue, result); + // clear values that were set by untrusted packages executeShellCommand("device_config reset trusted_defaults " + sNamespace); result = getFromContentProvider(mContentResolver, sNamespace, sKey); - // not trusted default was set + // even the default value is gone now assertNull(result); } - @Test - public void testReset_setTrustedDefault() throws Exception { - String newValue = "value2"; - - // make sValue the trusted default (set by system) - putWithContentProvider(mContentResolver, sNamespace, sKey, sValue, true); - // make newValue the current value - executeShellCommand( - "device_config put " + sNamespace + " " + sKey + " " + newValue); - String result = getFromContentProvider(mContentResolver, sNamespace, sKey); - assertEquals(newValue, result); - - executeShellCommand("device_config reset untrusted_defaults " + sNamespace); - result = getFromContentProvider(mContentResolver, sNamespace, sKey); - // back to the default - assertEquals(sValue, result); - - executeShellCommand("device_config reset trusted_defaults " + sNamespace); - result = getFromContentProvider(mContentResolver, sNamespace, sKey); - // our trusted default is still set - assertEquals(sValue, result); - } - private static void executeShellCommand(String command) throws IOException { InputStream is = new FileInputStream(InstrumentationRegistry.getInstrumentation() .getUiAutomation().executeShellCommand(command).getFileDescriptor()); @@ -212,8 +190,7 @@ public class DeviceConfigServiceTest { if (makeDefault) { args.putBoolean(Settings.CALL_METHOD_MAKE_DEFAULT_KEY, true); } - resolver.call( - CONFIG_CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, compositeName, args); + resolver.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, compositeName, args); } private static String getFromContentProvider(ContentResolver resolver, String namespace, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java index ba69f3bb1bc2..9391737fe23c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java @@ -218,88 +218,7 @@ public class NotificationRemoteInputManager implements Dumpable { return false; } - ViewParent p = view.getParent(); - RemoteInputView riv = null; - while (p != null) { - if (p instanceof View) { - View pv = (View) p; - if (pv.isRootNamespace()) { - riv = findRemoteInputView(pv); - break; - } - } - p = p.getParent(); - } - ExpandableNotificationRow row = null; - while (p != null) { - if (p instanceof ExpandableNotificationRow) { - row = (ExpandableNotificationRow) p; - break; - } - p = p.getParent(); - } - - if (row == null) { - return false; - } - - row.setUserExpanded(true); - - if (!mLockscreenUserManager.shouldAllowLockscreenRemoteInput()) { - final int userId = pendingIntent.getCreatorUserHandle().getIdentifier(); - if (mLockscreenUserManager.isLockscreenPublicMode(userId)) { - mCallback.onLockedRemoteInput(row, view); - return true; - } - if (mUserManager.getUserInfo(userId).isManagedProfile() - && mKeyguardManager.isDeviceLocked(userId)) { - mCallback.onLockedWorkRemoteInput(userId, row, view); - return true; - } - } - - if (riv == null) { - riv = findRemoteInputView(row.getPrivateLayout().getExpandedChild()); - if (riv == null) { - return false; - } - if (!row.getPrivateLayout().getExpandedChild().isShown()) { - mCallback.onMakeExpandedVisibleForRemoteInput(row, view); - return true; - } - } - - int width = view.getWidth(); - if (view instanceof TextView) { - // Center the reveal on the text which might be off-center from the TextView - TextView tv = (TextView) view; - if (tv.getLayout() != null) { - int innerWidth = (int) tv.getLayout().getLineWidth(0); - innerWidth += tv.getCompoundPaddingLeft() + tv.getCompoundPaddingRight(); - width = Math.min(width, innerWidth); - } - } - int cx = view.getLeft() + width / 2; - int cy = view.getTop() + view.getHeight() / 2; - int w = riv.getWidth(); - int h = riv.getHeight(); - int r = Math.max( - Math.max(cx + cy, cx + (h - cy)), - Math.max((w - cx) + cy, (w - cx) + (h - cy))); - - riv.setRevealParameters(cx, cy, r); - riv.setPendingIntent(pendingIntent); - riv.setRemoteInput(inputs, input); - riv.focusAnimated(); - - return true; - } - - private RemoteInputView findRemoteInputView(View v) { - if (v == null) { - return null; - } - return (RemoteInputView) v.findViewWithTag(RemoteInputView.VIEW_TAG); + return activateRemoteInput(view, inputs, input, pendingIntent); } }; @@ -355,6 +274,102 @@ public class NotificationRemoteInputManager implements Dumpable { } /** + * Activates a given {@link RemoteInput} + * + * @param view The view of the action button or suggestion chip that was tapped. + * @param inputs The remote inputs that need to be sent to the app. + * @param input The remote input that needs to be activated. + * @param pendingIntent The pending intent to be sent to the app. + * @return Whether the {@link RemoteInput} was activated. + */ + public boolean activateRemoteInput(View view, RemoteInput[] inputs, RemoteInput input, + PendingIntent pendingIntent) { + + ViewParent p = view.getParent(); + RemoteInputView riv = null; + while (p != null) { + if (p instanceof View) { + View pv = (View) p; + if (pv.isRootNamespace()) { + riv = findRemoteInputView(pv); + break; + } + } + p = p.getParent(); + } + ExpandableNotificationRow row = null; + while (p != null) { + if (p instanceof ExpandableNotificationRow) { + row = (ExpandableNotificationRow) p; + break; + } + p = p.getParent(); + } + + if (row == null) { + return false; + } + + row.setUserExpanded(true); + + if (!mLockscreenUserManager.shouldAllowLockscreenRemoteInput()) { + final int userId = pendingIntent.getCreatorUserHandle().getIdentifier(); + if (mLockscreenUserManager.isLockscreenPublicMode(userId)) { + mCallback.onLockedRemoteInput(row, view); + return true; + } + if (mUserManager.getUserInfo(userId).isManagedProfile() + && mKeyguardManager.isDeviceLocked(userId)) { + mCallback.onLockedWorkRemoteInput(userId, row, view); + return true; + } + } + + if (riv == null) { + riv = findRemoteInputView(row.getPrivateLayout().getExpandedChild()); + if (riv == null) { + return false; + } + if (!row.getPrivateLayout().getExpandedChild().isShown()) { + mCallback.onMakeExpandedVisibleForRemoteInput(row, view); + return true; + } + } + + int width = view.getWidth(); + if (view instanceof TextView) { + // Center the reveal on the text which might be off-center from the TextView + TextView tv = (TextView) view; + if (tv.getLayout() != null) { + int innerWidth = (int) tv.getLayout().getLineWidth(0); + innerWidth += tv.getCompoundPaddingLeft() + tv.getCompoundPaddingRight(); + width = Math.min(width, innerWidth); + } + } + int cx = view.getLeft() + width / 2; + int cy = view.getTop() + view.getHeight() / 2; + int w = riv.getWidth(); + int h = riv.getHeight(); + int r = Math.max( + Math.max(cx + cy, cx + (h - cy)), + Math.max((w - cx) + cy, (w - cx) + (h - cy))); + + riv.setRevealParameters(cx, cy, r); + riv.setPendingIntent(pendingIntent); + riv.setRemoteInput(inputs, input); + riv.focusAnimated(); + + return true; + } + + private RemoteInputView findRemoteInputView(View v) { + if (v == null) { + return null; + } + return (RemoteInputView) v.findViewWithTag(RemoteInputView.VIEW_TAG); + } + + /** * Adds all the notification lifetime extenders. Each extender represents a reason for the * NotificationRemoteInputManager to keep a notification lifetime extended. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AlertTransferListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AlertTransferListener.java new file mode 100644 index 000000000000..13e991ba2431 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AlertTransferListener.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.statusbar.notification; + +/** + * Listener interface for when NotificationEntryManager needs to tell + * NotificationGroupAlertTransferHelper things. Will eventually grow to be a general-purpose + * listening interface for the NotificationEntryManager. + */ +public interface AlertTransferListener { + /** + * Called when a new notification is posted. At this point, the notification is "pending": its + * views haven't been inflated yet and most of the system pretends like it doesn't exist yet. + */ + void onPendingEntryAdded(NotificationData.Entry entry); + + /** + * Called when an existing notification's views are reinflated (usually due to an update being + * posted to that notification). + */ + void onEntryReinflated(NotificationData.Entry entry); + + /** + * Called when a notification has been removed (either because the user swiped it away or + * because the developer retracted it). + */ + void onEntryRemoved(NotificationData.Entry entry); +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java index d9fe98257d4c..f543b4622611 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java @@ -588,7 +588,7 @@ public class NotificationData { } public boolean areGutsExposed() { - return row != null && row.getGuts().isExposed(); + return row != null && row.getGuts() != null && row.getGuts().isExposed(); } public boolean isChildInGroup() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index 16a3849a6eec..e1b381b5f0b6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -61,7 +61,6 @@ import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.EventLogTags; import com.android.systemui.ForegroundServiceController; -import com.android.systemui.InitController; import com.android.systemui.R; import com.android.systemui.UiOffloadThread; import com.android.systemui.bubbles.BubbleController; @@ -83,7 +82,6 @@ import com.android.systemui.statusbar.notification.row.NotificationInflater; import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag; import com.android.systemui.statusbar.notification.row.RowInflaterTask; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; -import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; @@ -117,8 +115,6 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. private final NotificationGroupManager mGroupManager = Dependency.get(NotificationGroupManager.class); - private final NotificationGroupAlertTransferHelper mGroupAlertTransferHelper = - Dependency.get(NotificationGroupAlertTransferHelper.class); private final NotificationGutsManager mGutsManager = Dependency.get(NotificationGutsManager.class); private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class); @@ -157,6 +153,7 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. = new ArrayList<>(); private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener; private NotificationViewHierarchyManager.StatusBarStateListener mStatusBarStateListener; + @Nullable private AlertTransferListener mAlertTransferListener; private final class NotificationClicker implements View.OnClickListener { @@ -258,12 +255,10 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. mMessagingUtil = new NotificationMessagingUtil(context); mBubbleController.setDismissListener(this /* bubbleEventListener */); mNotificationData = new NotificationData(); - Dependency.get(InitController.class).addPostInitTask(this::onPostInit); } - private void onPostInit() { - mGroupAlertTransferHelper.setPendingEntries(mPendingNotifications); - mGroupManager.addOnGroupChangeListener(mGroupAlertTransferHelper); + public void setAlertTransferListener(AlertTransferListener listener) { + mAlertTransferListener = listener; } /** @@ -587,7 +582,9 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. mVisualStabilityManager.onLowPriorityUpdated(entry); mPresenter.updateNotificationViews(); } - mGroupAlertTransferHelper.onInflationFinished(entry); + if (mAlertTransferListener != null) { + mAlertTransferListener.onEntryReinflated(entry); + } } } entry.setLowPriorityStateUpdated(false); @@ -600,8 +597,12 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. private void removeNotificationInternal(String key, @Nullable NotificationListenerService.RankingMap ranking, boolean forceRemove) { + final NotificationData.Entry entry = mNotificationData.get(key); + abortExistingInflation(key); - mGroupAlertTransferHelper.cleanUpPendingAlertInfo(key); + if (mAlertTransferListener != null) { + mAlertTransferListener.onEntryRemoved(entry); + } // Attempt to remove notifications from their alert managers (heads up, ambient pulse). // Though the remove itself may fail, it lets the manager know to remove as soon as @@ -620,8 +621,6 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. mAmbientPulseManager.removeNotification(key, false /* ignoreEarliestRemovalTime */); } - NotificationData.Entry entry = mNotificationData.get(key); - if (entry == null) { mCallback.onNotificationRemoved(key, null /* old */); return; @@ -846,7 +845,9 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. mNotificationData.getImportance(key)); mPendingNotifications.put(key, shadeEntry); - mGroupAlertTransferHelper.onPendingEntryAdded(shadeEntry); + if (mAlertTransferListener != null) { + mAlertTransferListener.onPendingEntryAdded(shadeEntry); + } } @VisibleForTesting @@ -1231,6 +1232,15 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. } /** + * @return An iterator for all "pending" notifications. Pending notifications are newly-posted + * notifications whose views have not yet been inflated. In general, the system pretends like + * these don't exist, although there are a couple exceptions. + */ + public Iterable<NotificationData.Entry> getPendingNotificationsIterator() { + return mPendingNotifications.values(); + } + + /** * Callback for NotificationEntryManager. */ public interface Callback { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 8214ea6c7616..8bed3663cf49 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -1098,6 +1098,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mHeadsUpManager = headsUpManager; } + public HeadsUpManager getHeadsUpManager() { + return mHeadsUpManager; + } + public void setGutsView(MenuItem item) { if (mGuts != null && item.getGutsView() instanceof NotificationGuts.GutsContent) { ((NotificationGuts.GutsContent) item.getGutsView()).setGutsParent(mGuts); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java index 689d6d530308..edd54ca936fa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java @@ -91,6 +91,7 @@ public class NotificationContentView extends FrameLayout { private SmartReplyConstants mSmartReplyConstants; private SmartReplyView mExpandedSmartReplyView; + private SmartReplyView mHeadsUpSmartReplyView; private SmartReplyController mSmartReplyController; private NotificationViewWrapper mContractedWrapper; @@ -253,6 +254,9 @@ public class NotificationContentView extends FrameLayout { } if (mHeadsUpChild != null) { int maxHeight = mHeadsUpHeight; + if (mHeadsUpSmartReplyView != null) { + maxHeight += mHeadsUpSmartReplyView.getHeightUpperLimit(); + } maxHeight += mHeadsUpWrapper.getExtraMeasureHeight(); int size = maxHeight; ViewGroup.LayoutParams layoutParams = mHeadsUpChild.getLayoutParams(); @@ -955,6 +959,9 @@ public class NotificationContentView extends FrameLayout { if (mExpandedSmartReplyView != null) { mExpandedSmartReplyView.setBackgroundTintColor(color); } + if (mHeadsUpSmartReplyView != null) { + mHeadsUpSmartReplyView.setBackgroundTintColor(color); + } } public int getVisibleType() { @@ -1472,6 +1479,10 @@ public class NotificationContentView extends FrameLayout { entry, smartRepliesAndActions.smartReplies.choices.length); } } + if (mHeadsUpChild != null) { + mHeadsUpSmartReplyView = + applySmartReplyView(mHeadsUpChild, smartRepliesAndActions, entry); + } } private SmartReplyView applySmartReplyView(View view, @@ -1520,7 +1531,8 @@ public class NotificationContentView extends FrameLayout { } if (smartRepliesAndActions.smartActions != null) { smartReplyView.addSmartActions( - smartRepliesAndActions.smartActions, mSmartReplyController, entry); + smartRepliesAndActions.smartActions, mSmartReplyController, entry, + mContainingNotification.getHeadsUpManager()); } smartReplyContainer.setVisibility(View.VISIBLE); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java index 2a68fa598603..dd81c4e20d6d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java @@ -29,7 +29,9 @@ import com.android.systemui.statusbar.AmbientPulseManager.OnAmbientChangedListen import com.android.systemui.statusbar.InflationTask; import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarStateController.StateListener; +import com.android.systemui.statusbar.notification.AlertTransferListener; import com.android.systemui.statusbar.notification.NotificationData.Entry; +import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.row.NotificationInflater.AsyncInflationTask; import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag; import com.android.systemui.statusbar.phone.NotificationGroupManager.NotificationGroup; @@ -38,8 +40,6 @@ import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; import java.util.Objects; /** @@ -47,8 +47,8 @@ import java.util.Objects; * {@link HeadsUpManager}, {@link AmbientPulseManager}. In particular, this class deals with keeping * the correct notification in a group alerting based off the group suppression. */ -public class NotificationGroupAlertTransferHelper implements OnGroupChangeListener, - OnHeadsUpChangedListener, OnAmbientChangedListener, StateListener { +public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedListener, + OnAmbientChangedListener, StateListener { private static final long ALERT_TRANSFER_TIMEOUT = 300; @@ -69,15 +69,7 @@ public class NotificationGroupAlertTransferHelper implements OnGroupChangeListen private final NotificationGroupManager mGroupManager = Dependency.get(NotificationGroupManager.class); - // TODO(b/119637830): It would be good if GroupManager already had all pending notifications as - // normal children (i.e. add notifications to GroupManager before inflation) so that we don't - // have to have this dependency. We'd also have to worry less about the suppression not being up - // to date. - /** - * Notifications that are currently inflating for the first time. Used to remove an incorrectly - * alerting notification faster. - */ - private HashMap<String, Entry> mPendingNotifications; + private NotificationEntryManager mEntryManager; private boolean mIsDozing; @@ -85,6 +77,23 @@ public class NotificationGroupAlertTransferHelper implements OnGroupChangeListen Dependency.get(StatusBarStateController.class).addCallback(this); } + /** Causes the TransferHelper to register itself as a listener to the appropriate classes. */ + public void bind(NotificationEntryManager entryManager, + NotificationGroupManager groupManager) { + if (mEntryManager != null) { + throw new IllegalStateException("Already bound."); + } + + // TODO(b/119637830): It would be good if GroupManager already had all pending notifications + // as normal children (i.e. add notifications to GroupManager before inflation) so that we + // don't have to have this dependency. We'd also have to worry less about the suppression + // not being up to date. + mEntryManager = entryManager; + + mEntryManager.setAlertTransferListener(mAlertTransferListener); + groupManager.addOnGroupChangeListener(mOnGroupChangeListener); + } + /** * Whether or not a notification has transferred its alert state to the notification and * the notification should alert after inflating. @@ -97,25 +106,10 @@ public class NotificationGroupAlertTransferHelper implements OnGroupChangeListen return alertInfo != null && alertInfo.isStillValid(); } - /** - * Removes any alerts pending on this entry. Note that this will not stop any inflation tasks - * started by a transfer, so this should only be used as clean-up for when inflation is stopped - * and the pending alert no longer needs to happen. - * - * @param key notification key that may have info that needs to be cleaned up - */ - public void cleanUpPendingAlertInfo(@NonNull String key) { - mPendingAlerts.remove(key); - } - public void setHeadsUpManager(HeadsUpManager headsUpManager) { mHeadsUpManager = headsUpManager; } - public void setPendingEntries(HashMap<String, Entry> pendingNotifications) { - mPendingNotifications = pendingNotifications; - } - @Override public void onStateChanged(int newState) {} @@ -130,43 +124,45 @@ public class NotificationGroupAlertTransferHelper implements OnGroupChangeListen mIsDozing = isDozing; } - @Override - public void onGroupCreated(NotificationGroup group, String groupKey) { - mGroupAlertEntries.put(groupKey, new GroupAlertEntry(group)); - } + private final OnGroupChangeListener mOnGroupChangeListener = new OnGroupChangeListener() { + @Override + public void onGroupCreated(NotificationGroup group, String groupKey) { + mGroupAlertEntries.put(groupKey, new GroupAlertEntry(group)); + } - @Override - public void onGroupRemoved(NotificationGroup group, String groupKey) { - mGroupAlertEntries.remove(groupKey); - } + @Override + public void onGroupRemoved(NotificationGroup group, String groupKey) { + mGroupAlertEntries.remove(groupKey); + } - @Override - public void onGroupSuppressionChanged(NotificationGroup group, boolean suppressed) { - AlertingNotificationManager alertManager = getActiveAlertManager(); - if (suppressed) { - if (alertManager.isAlerting(group.summary.key)) { - handleSuppressedSummaryAlerted(group.summary, alertManager); - } - } else { - // Group summary can be null if we are no longer suppressed because the summary was - // removed. In that case, we don't need to alert the summary. - if (group.summary == null) { - return; - } - GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(mGroupManager.getGroupKey( - group.summary.notification)); - // Group is no longer suppressed. We should check if we need to transfer the alert - // back to the summary now that it's no longer suppressed. - if (groupAlertEntry.mAlertSummaryOnNextAddition) { - if (!alertManager.isAlerting(group.summary.key)) { - alertNotificationWhenPossible(group.summary, alertManager); + @Override + public void onGroupSuppressionChanged(NotificationGroup group, boolean suppressed) { + AlertingNotificationManager alertManager = getActiveAlertManager(); + if (suppressed) { + if (alertManager.isAlerting(group.summary.key)) { + handleSuppressedSummaryAlerted(group.summary, alertManager); } - groupAlertEntry.mAlertSummaryOnNextAddition = false; } else { - checkShouldTransferBack(groupAlertEntry); + // Group summary can be null if we are no longer suppressed because the summary was + // removed. In that case, we don't need to alert the summary. + if (group.summary == null) { + return; + } + GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(mGroupManager.getGroupKey( + group.summary.notification)); + // Group is no longer suppressed. We should check if we need to transfer the alert + // back to the summary now that it's no longer suppressed. + if (groupAlertEntry.mAlertSummaryOnNextAddition) { + if (!alertManager.isAlerting(group.summary.key)) { + alertNotificationWhenPossible(group.summary, alertManager); + } + groupAlertEntry.mAlertSummaryOnNextAddition = false; + } else { + checkShouldTransferBack(groupAlertEntry); + } } } - } + }; @Override public void onAmbientStateChanged(Entry entry, boolean isAmbient) { @@ -185,37 +181,42 @@ public class NotificationGroupAlertTransferHelper implements OnGroupChangeListen } } - /** - * Called when the entry's reinflation has finished. If there is an alert pending, we then - * show the alert. - * - * @param entry entry whose inflation has finished - */ - public void onInflationFinished(@NonNull Entry entry) { - PendingAlertInfo alertInfo = mPendingAlerts.remove(entry.key); - if (alertInfo != null) { - if (alertInfo.isStillValid()) { - alertNotificationWhenPossible(entry, getActiveAlertManager()); - } else { - // The transfer is no longer valid. Free the content. - entry.getRow().freeContentViewWhenSafe(alertInfo.mAlertManager.getContentFlag()); + private final AlertTransferListener mAlertTransferListener = new AlertTransferListener() { + // Called when a new notification has been posted but is not inflated yet. We use this to + // see as early as we can if we need to abort a transfer. + @Override + public void onPendingEntryAdded(Entry entry) { + String groupKey = mGroupManager.getGroupKey(entry.notification); + GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(groupKey); + if (groupAlertEntry != null) { + checkShouldTransferBack(groupAlertEntry); } } - } - /** - * Called when a new notification has been posted but is not inflated yet. We use this to see - * as early as we can if we need to abort a transfer. - * - * @param entry entry that has been added - */ - public void onPendingEntryAdded(@NonNull Entry entry) { - String groupKey = mGroupManager.getGroupKey(entry.notification); - GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(groupKey); - if (groupAlertEntry != null) { - checkShouldTransferBack(groupAlertEntry); + // Called when the entry's reinflation has finished. If there is an alert pending, we + // then show the alert. + @Override + public void onEntryReinflated(Entry entry) { + PendingAlertInfo alertInfo = mPendingAlerts.remove(entry.key); + if (alertInfo != null) { + if (alertInfo.isStillValid()) { + alertNotificationWhenPossible(entry, getActiveAlertManager()); + } else { + // The transfer is no longer valid. Free the content. + entry.getRow().freeContentViewWhenSafe( + alertInfo.mAlertManager.getContentFlag()); + } + } } - } + + @Override + public void onEntryRemoved(Entry entry) { + // Removes any alerts pending on this entry. Note that this will not stop any inflation + // tasks started by a transfer, so this should only be used as clean-up for when + // inflation is stopped and the pending alert no longer needs to happen. + mPendingAlerts.remove(entry.key); + } + }; /** * Gets the number of new notifications pending inflation that will be added to the group @@ -225,11 +226,11 @@ public class NotificationGroupAlertTransferHelper implements OnGroupChangeListen * @return the number of new notifications that will be added to the group */ private int getPendingChildrenNotAlerting(@NonNull NotificationGroup group) { - if (mPendingNotifications == null) { + if (mEntryManager == null) { return 0; } int number = 0; - Collection<Entry> values = mPendingNotifications.values(); + Iterable<Entry> values = mEntryManager.getPendingNotificationsIterator(); for (Entry entry : values) { if (isPendingNotificationInGroup(entry, group) && onlySummaryAlerts(entry)) { number++; @@ -245,10 +246,10 @@ public class NotificationGroupAlertTransferHelper implements OnGroupChangeListen * @return true if a pending notification will add to this group */ private boolean pendingInflationsWillAddChildren(@NonNull NotificationGroup group) { - if (mPendingNotifications == null) { + if (mEntryManager == null) { return false; } - Collection<Entry> values = mPendingNotifications.values(); + Iterable<Entry> values = mEntryManager.getPendingNotificationsIterator(); for (Entry entry : values) { if (isPendingNotificationInGroup(entry, group)) { return true; 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 b351f1d9f150..a508f1bdbd34 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -121,8 +121,6 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.StatusBarIcon; -import com.android.internal.widget.MessagingGroup; -import com.android.internal.widget.MessagingMessage; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.ViewMediatorCallback; @@ -630,6 +628,8 @@ public class StatusBar extends SystemUI implements DemoMode, mBubbleController = Dependency.get(BubbleController.class); mBubbleController.setExpandListener(mBubbleExpandListener); + mGroupAlertTransferHelper.bind(mEntryManager, mGroupManager); + mColorExtractor.addOnColorsChangedListener(this); mStatusBarStateController.addCallback(this, StatusBarStateController.RANK_STATUS_BAR); @@ -1116,8 +1116,6 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void onDensityOrFontScaleChanged() { - MessagingMessage.dropCache(); - MessagingGroup.dropCache(); // TODO: Remove this. if (mBrightnessMirrorController != null) { mBrightnessMirrorController.onDensityOrFontScaleChanged(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index d99af1fb57bf..acdd5e995322 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -37,6 +37,8 @@ import android.widget.TextView; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.widget.MessagingGroup; +import com.android.internal.widget.MessagingMessage; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.Dependency; import com.android.systemui.InitController; @@ -62,9 +64,11 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener; import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; +import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardMonitor; -public class StatusBarNotificationPresenter implements NotificationPresenter { +public class StatusBarNotificationPresenter implements NotificationPresenter, + ConfigurationController.ConfigurationListener { private final LockscreenGestureLogger mLockscreenGestureLogger = Dependency.get(LockscreenGestureLogger.class); @@ -168,9 +172,13 @@ public class StatusBarNotificationPresenter implements NotificationPresenter { onUserSwitched(mLockscreenUserManager.getCurrentUserId()); }); + Dependency.get(ConfigurationController.class).addCallback(this); } + @Override public void onDensityOrFontScaleChanged() { + MessagingMessage.dropCache(); + MessagingGroup.dropCache(); if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) { mEntryManager.updateNotificationsOnDensityOrFontScaleChanged(); } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java index 2a4336e809a0..4fa8321fa1e9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java @@ -16,6 +16,8 @@ import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.InsetDrawable; import android.graphics.drawable.RippleDrawable; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.text.Layout; import android.text.TextPaint; import android.text.method.TransformationMethod; @@ -34,6 +36,7 @@ import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.ActivityStarter.OnDismissAction; +import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.SmartReplyController; import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationUtils; @@ -61,6 +64,8 @@ public class SmartReplyView extends ViewGroup { private final SmartReplyConstants mConstants; private final KeyguardDismissUtil mKeyguardDismissUtil; + private final NotificationRemoteInputManager mRemoteInputManager; + private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); /** * The upper bound for the height of this view in pixels. Notifications are automatically @@ -109,6 +114,7 @@ public class SmartReplyView extends ViewGroup { super(context, attrs); mConstants = Dependency.get(SmartReplyConstants.class); mKeyguardDismissUtil = Dependency.get(KeyguardDismissUtil.class); + mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class); mHeightUpperLimit = NotificationUtils.getFontScaledHeight(mContext, R.dimen.smart_reply_button_max_height); @@ -209,13 +215,15 @@ public class SmartReplyView extends ViewGroup { * notification are shown. */ public void addSmartActions(SmartActions smartActions, - SmartReplyController smartReplyController, NotificationData.Entry entry) { + SmartReplyController smartReplyController, NotificationData.Entry entry, + HeadsUpManager headsUpManager) { int numSmartActions = smartActions.actions.size(); for (int n = 0; n < numSmartActions; n++) { Notification.Action action = smartActions.actions.get(n); if (action.actionIntent != null) { Button actionButton = inflateActionButton( - getContext(), this, n, smartActions, smartReplyController, entry); + getContext(), this, n, smartActions, smartReplyController, entry, + headsUpManager); addView(actionButton); } } @@ -237,12 +245,22 @@ public class SmartReplyView extends ViewGroup { b.setText(choice); OnDismissAction action = () -> { + // TODO(b/111437455): Also for EDIT_CHOICES_BEFORE_SENDING_AUTO, depending on flags. + if (smartReplies.remoteInput.getEditChoicesBeforeSending() + == RemoteInput.EDIT_CHOICES_BEFORE_SENDING_ENABLED) { + entry.remoteInputText = choice; + mRemoteInputManager.activateRemoteInput(b, + new RemoteInput[] { smartReplies.remoteInput }, smartReplies.remoteInput, + smartReplies.pendingIntent); + return false; + } + smartReplyController.smartReplySent( entry, replyIndex, b.getText(), smartReplies.fromAssistant); Bundle results = new Bundle(); results.putString(smartReplies.remoteInput.getResultKey(), choice.toString()); Intent intent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND); - RemoteInput.addResultsToIntent(new RemoteInput[]{smartReplies.remoteInput}, intent, + RemoteInput.addResultsToIntent(new RemoteInput[] { smartReplies.remoteInput }, intent, results); RemoteInput.setResultsSource(intent, RemoteInput.SOURCE_CHOICE); entry.setHasSentReply(); @@ -274,7 +292,7 @@ public class SmartReplyView extends ViewGroup { @VisibleForTesting Button inflateActionButton(Context context, ViewGroup root, int actionIndex, SmartActions smartActions, SmartReplyController smartReplyController, - NotificationData.Entry entry) { + NotificationData.Entry entry, HeadsUpManager headsUpManager) { Notification.Action action = smartActions.actions.get(actionIndex); Button button = (Button) LayoutInflater.from(context).inflate( R.layout.smart_action_button, root, false); @@ -290,8 +308,12 @@ public class SmartReplyView extends ViewGroup { button.setOnClickListener(view -> getActivityStarter().startPendingIntentDismissingKeyguard( action.actionIntent, - () -> smartReplyController.smartActionClicked( - entry, actionIndex, action, smartActions.fromAssistant))); + () -> { + smartReplyController.smartActionClicked( + entry, actionIndex, action, smartActions.fromAssistant); + postOnUiThread(() -> + headsUpManager.removeNotification(entry.key, true)); + })); // TODO(b/119010281): handle accessibility @@ -301,6 +323,10 @@ public class SmartReplyView extends ViewGroup { return button; } + private void postOnUiThread(Runnable runnable) { + mMainThreadHandler.post(runnable); + } + @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new LayoutParams(mContext, attrs); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java index c3bc5110febe..ee39e10b4165 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java @@ -32,14 +32,19 @@ import android.testing.TestableLooper; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.AmbientPulseManager; +import com.android.systemui.statusbar.notification.AlertTransferListener; import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationData.Entry; +import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.policy.HeadsUpManager; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -49,13 +54,15 @@ import java.util.HashMap; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { - @Rule - public MockitoRule rule = MockitoJUnit.rule(); + @Rule public MockitoRule rule = MockitoJUnit.rule(); private NotificationGroupAlertTransferHelper mGroupAlertTransferHelper; private NotificationGroupManager mGroupManager; private AmbientPulseManager mAmbientPulseManager; private HeadsUpManager mHeadsUpManager; + @Mock private NotificationEntryManager mNotificationEntryManager; + @Captor private ArgumentCaptor<AlertTransferListener> mListenerCaptor; + private AlertTransferListener mAlertTransferListener; private final HashMap<String, Entry> mPendingEntries = new HashMap<>(); private final NotificationGroupTestHelper mGroupTestHelper = new NotificationGroupTestHelper(mContext); @@ -67,15 +74,19 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { mDependency.injectTestDependency(AmbientPulseManager.class, mAmbientPulseManager); mHeadsUpManager = new HeadsUpManager(mContext) {}; + when(mNotificationEntryManager.getPendingNotificationsIterator()) + .thenReturn(mPendingEntries.values()); + mGroupManager = new NotificationGroupManager(); mDependency.injectTestDependency(NotificationGroupManager.class, mGroupManager); mGroupManager.setHeadsUpManager(mHeadsUpManager); mGroupAlertTransferHelper = new NotificationGroupAlertTransferHelper(); mGroupAlertTransferHelper.setHeadsUpManager(mHeadsUpManager); - mGroupAlertTransferHelper.setPendingEntries(mPendingEntries); - mGroupManager.addOnGroupChangeListener(mGroupAlertTransferHelper); + mGroupAlertTransferHelper.bind(mNotificationEntryManager, mGroupManager); + verify(mNotificationEntryManager).setAlertTransferListener(mListenerCaptor.capture()); + mAlertTransferListener = mListenerCaptor.getValue(); mHeadsUpManager.addListener(mGroupAlertTransferHelper); mAmbientPulseManager.addListener(mGroupAlertTransferHelper); } @@ -110,7 +121,7 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { // Add second child notification so that summary is no longer suppressed. mPendingEntries.put(childEntry2.key, childEntry2); - mGroupAlertTransferHelper.onPendingEntryAdded(childEntry2); + mAlertTransferListener.onPendingEntryAdded(childEntry2); mGroupManager.onEntryAdded(childEntry2); // The alert state should transfer back to the summary as there is now more than one @@ -137,7 +148,7 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { // Add second child notification so that summary is no longer suppressed. mPendingEntries.put(childEntry2.key, childEntry2); - mGroupAlertTransferHelper.onPendingEntryAdded(childEntry2); + mAlertTransferListener.onPendingEntryAdded(childEntry2); mGroupManager.onEntryAdded(childEntry2); // Dozing changed so no reason to re-alert summary. @@ -175,7 +186,7 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) .thenReturn(true); - mGroupAlertTransferHelper.onInflationFinished(childEntry); + mAlertTransferListener.onEntryReinflated(childEntry); // Alert is immediately removed from summary, and we show child as its content is inflated. assertFalse(mHeadsUpManager.isAlerting(summaryEntry.key)); @@ -199,13 +210,13 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { // Add second child notification so that summary is no longer suppressed. mPendingEntries.put(childEntry2.key, childEntry2); - mGroupAlertTransferHelper.onPendingEntryAdded(childEntry2); + mAlertTransferListener.onPendingEntryAdded(childEntry2); mGroupManager.onEntryAdded(childEntry2); // Child entry finishes its inflation. when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) .thenReturn(true); - mGroupAlertTransferHelper.onInflationFinished(childEntry); + mAlertTransferListener.onEntryReinflated(childEntry); verify(childEntry.getRow(), times(1)).freeContentViewWhenSafe(mHeadsUpManager .getContentFlag()); @@ -225,7 +236,7 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { mGroupManager.onEntryAdded(summaryEntry); mGroupManager.onEntryAdded(childEntry); - mGroupAlertTransferHelper.cleanUpPendingAlertInfo(childEntry.key); + mAlertTransferListener.onEntryRemoved(childEntry); assertFalse(mGroupAlertTransferHelper.isAlertTransferPending(childEntry)); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java index 506fa974944a..c5bac9242b8b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java @@ -98,6 +98,7 @@ public class SmartReplyViewTest extends SysuiTestCase { private Notification mNotification; @Mock ActivityStarter mActivityStarter; + @Mock HeadsUpManager mHeadsUpManager; @Before public void setUp() { @@ -434,7 +435,8 @@ public class SmartReplyViewTest extends SysuiTestCase { mView.addSmartActions( new SmartReplyView.SmartActions(createActions(actionTitles), false), mLogger, - mEntry); + mEntry, + mHeadsUpManager); } private void setSmartRepliesAndActions(CharSequence[] choices, String[] actionTitles) { @@ -442,7 +444,8 @@ public class SmartReplyViewTest extends SysuiTestCase { mView.addSmartActions( new SmartReplyView.SmartActions(createActions(actionTitles), false), mLogger, - mEntry); + mEntry, + mHeadsUpManager); } private ViewGroup buildExpectedView(CharSequence[] choices, int lineCount) { @@ -747,7 +750,7 @@ public class SmartReplyViewTest extends SysuiTestCase { private Button inflateActionButton(Notification.Action action) { return mView.inflateActionButton(getContext(), mView, 0, new SmartReplyView.SmartActions(Collections.singletonList(action), false), - mLogger, mEntry); + mLogger, mEntry, mHeadsUpManager); } @Test diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto index f2ae16129164..2d3064017719 100644 --- a/proto/src/metrics_constants/metrics_constants.proto +++ b/proto/src/metrics_constants/metrics_constants.proto @@ -6627,6 +6627,16 @@ message MetricsEvent { // OS: Q ACTION_DISPLAY_FOLD = 1594; + // OPEN: WifiDppConfiguratorActivity (android.settings.WIFI_DPP_CONFIGURATOR_XXX action intents) + // CATEGORY: SETTINGS + // OS: Q + SETTINGS_WIFI_DPP_CONFIGURATOR = 1595; + + // OPEN: WifiDppEnrolleeActivity (android.settings.WIFI_DPP_ENROLLEE_XXX action intents) + // CATEGORY: SETTINGS + // OS: Q + SETTINGS_WIFI_DPP_ENROLLEE = 1596; + // ---- End Q Constants, all Q constants go above this line ---- // Add new aosp constants above this line. diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto index fba639c3fc4a..121267675329 100644 --- a/proto/src/system_messages.proto +++ b/proto/src/system_messages.proto @@ -216,6 +216,10 @@ message SystemMessage { // Package: android NOTE_SOFTAP_CONFIG_CHANGED = 50; + // Notify the user that connected to app suggested network. + // Package: android + NOTE_CONNECTED_TO_NETWORK_SUGGESTION = 51; + // ADD_NEW_IDS_ABOVE_THIS_LINE // Legacy IDs with arbitrary values appear below // Legacy IDs existed as stable non-conflicting constants prior to the O release diff --git a/services/core/Android.bp b/services/core/Android.bp index cccacf4bf837..4408db895537 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -7,7 +7,6 @@ java_library_static { "frameworks/native/aidl/binder", "frameworks/native/cmds/dumpstate/binder", "system/core/storaged/binder", - "system/netd/server/binder", "system/vold/binder", ], }, @@ -21,7 +20,6 @@ java_library_static { ":mediaupdateservice_aidl", "java/com/android/server/EventLogTags.logtags", "java/com/android/server/am/EventLogTags.logtags", - ":netd_metrics_aidl", ], libs: [ @@ -52,6 +50,7 @@ java_library_static { "android.hardware.contexthub-V1.0-java", "android.hidl.manager-V1.0-java", "netd_aidl_interface-java", + "netd_event_listener_interface-java", ], } diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 854c03f128dd..08034f734bea 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -48,6 +48,7 @@ import android.content.pm.PermissionInfo; import android.database.ContentObserver; import android.net.Uri; import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; @@ -1306,8 +1307,12 @@ class AlarmManagerService extends SystemService { // because kernel doesn't keep this after reboot setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY)); - // Also sure that we're booting with a halfway sensible current time - final long systemBuildTime = Environment.getRootDirectory().lastModified(); + // Ensure that we're booting with a halfway sensible current time. Use the + // most recent of Build.TIME, the root file system's timestamp, and the + // value of the ro.build.date.utc system property (which is in seconds). + final long systemBuildTime = Long.max( + 1000L * SystemProperties.getLong("ro.build.date.utc", -1L), + Long.max(Environment.getRootDirectory().lastModified(), Build.TIME)); if (mInjector.getCurrentTimeMillis() < systemBuildTime) { Slog.i(TAG, "Current time only " + mInjector.getCurrentTimeMillis() + ", advancing to build time " + systemBuildTime); diff --git a/services/core/java/com/android/server/AnyMotionDetector.java b/services/core/java/com/android/server/AnyMotionDetector.java index d56492521276..8c5ee7f35027 100644 --- a/services/core/java/com/android/server/AnyMotionDetector.java +++ b/services/core/java/com/android/server/AnyMotionDetector.java @@ -26,8 +26,6 @@ import android.os.PowerManager; import android.os.SystemClock; import android.util.Slog; -import java.lang.Float; - /** * Determines if the device has been set upon a stationary object. */ @@ -140,6 +138,13 @@ public class AnyMotionDetector { } } + /** + * If we do not have an accelerometer, we are not going to collect much data. + */ + public boolean hasSensor() { + return mAccelSensor != null; + } + /* * Acquire accel data until we determine AnyMotion status. */ diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index af9d4c8c69b6..08cb7a2f5047 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -43,6 +43,7 @@ import android.net.ConnectivityManager; import android.net.INetworkPolicyManager; import android.net.NetworkInfo; import android.net.Uri; +import android.os.BatteryManager; import android.os.BatteryStats; import android.os.Binder; import android.os.Bundle; @@ -272,6 +273,7 @@ public class DeviceIdleController extends SystemService private PowerManager mPowerManager; private INetworkPolicyManager mNetworkPolicyManager; private SensorManager mSensorManager; + private final boolean mUseMotionSensor; private Sensor mMotionSensor; private LocationRequest mLocationRequest; private Intent mIdleIntent; @@ -520,9 +522,10 @@ public class DeviceIdleController extends SystemService updateConnectivityState(intent); } break; case Intent.ACTION_BATTERY_CHANGED: { + boolean present = intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true); + boolean plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0; synchronized (DeviceIdleController.this) { - int plugged = intent.getIntExtra("plugged", 0); - updateChargingLocked(plugged != 0); + updateChargingLocked(present && plugged); } } break; case Intent.ACTION_PACKAGE_REMOVED: { @@ -1629,6 +1632,9 @@ public class DeviceIdleController extends SystemService mHandler = mInjector.getHandler(this); mAppStateTracker = mInjector.getAppStateTracker(context, FgThread.get().getLooper()); LocalServices.addService(AppStateTracker.class, mAppStateTracker); + + mUseMotionSensor = context.getResources().getBoolean( + com.android.internal.R.bool.config_autoPowerModeUseMotionSensor); } public DeviceIdleController(Context context) { @@ -1729,20 +1735,23 @@ public class DeviceIdleController extends SystemService ServiceManager.getService(Context.NETWORK_POLICY_SERVICE)); mNetworkPolicyManagerInternal = getLocalService(NetworkPolicyManagerInternal.class); mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE); - int sigMotionSensorId = getContext().getResources().getInteger( - com.android.internal.R.integer.config_autoPowerModeAnyMotionSensor); - if (sigMotionSensorId > 0) { - mMotionSensor = mSensorManager.getDefaultSensor(sigMotionSensorId, true); - } - if (mMotionSensor == null && getContext().getResources().getBoolean( - com.android.internal.R.bool.config_autoPowerModePreferWristTilt)) { - mMotionSensor = mSensorManager.getDefaultSensor( - Sensor.TYPE_WRIST_TILT_GESTURE, true); - } - if (mMotionSensor == null) { - // As a last ditch, fall back to SMD. - mMotionSensor = mSensorManager.getDefaultSensor( - Sensor.TYPE_SIGNIFICANT_MOTION, true); + + if (mUseMotionSensor) { + int sigMotionSensorId = getContext().getResources().getInteger( + com.android.internal.R.integer.config_autoPowerModeAnyMotionSensor); + if (sigMotionSensorId > 0) { + mMotionSensor = mSensorManager.getDefaultSensor(sigMotionSensorId, true); + } + if (mMotionSensor == null && getContext().getResources().getBoolean( + com.android.internal.R.bool.config_autoPowerModePreferWristTilt)) { + mMotionSensor = mSensorManager.getDefaultSensor( + Sensor.TYPE_WRIST_TILT_GESTURE, true); + } + if (mMotionSensor == null) { + // As a last ditch, fall back to SMD. + mMotionSensor = mSensorManager.getDefaultSensor( + Sensor.TYPE_SIGNIFICANT_MOTION, true); + } } if (getContext().getResources().getBoolean( @@ -2588,14 +2597,21 @@ public class DeviceIdleController extends SystemService mState = STATE_SENSING; if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE_PENDING to STATE_SENSING."); EventLogTags.writeDeviceIdle(mState, reason); - scheduleSensingTimeoutAlarmLocked(mConstants.SENSING_TIMEOUT); cancelLocatingLocked(); - mNotMoving = false; mLocated = false; mLastGenericLocation = null; mLastGpsLocation = null; - mAnyMotionDetector.checkForAnyMotion(); - break; + + // If we have an accelerometer, wait to find out whether we are moving. + if (mUseMotionSensor && mAnyMotionDetector.hasSensor()) { + scheduleSensingTimeoutAlarmLocked(mConstants.SENSING_TIMEOUT); + mNotMoving = false; + mAnyMotionDetector.checkForAnyMotion(); + break; + } + + mNotMoving = true; + // Otherwise, fall through and check this off the list of requirements. case STATE_SENSING: cancelSensingTimeoutAlarmLocked(); mState = STATE_LOCATING; @@ -2893,9 +2909,12 @@ public class DeviceIdleController extends SystemService void scheduleAlarmLocked(long delay, boolean idleUntil) { if (DEBUG) Slog.d(TAG, "scheduleAlarmLocked(" + delay + ", " + idleUntil + ")"); - if (mMotionSensor == null && !(mState == STATE_QUICK_DOZE_DELAY || mState == STATE_IDLE - || mState == STATE_IDLE_MAINTENANCE)) { - // If there is no motion sensor on this device, then we won't schedule + + if (mUseMotionSensor && mMotionSensor == null + && mState != STATE_QUICK_DOZE_DELAY + && mState != STATE_IDLE + && mState != STATE_IDLE_MAINTENANCE) { + // If there is no motion sensor on this device, but we need one, then we won't schedule // alarms, because we can't determine if the device is not moving. This effectively // turns off normal execution of device idling, although it is still possible to // manually poke it by pretending like the alarm is going off. @@ -3765,13 +3784,20 @@ public class DeviceIdleController extends SystemService pw.print(" mLightEnabled="); pw.print(mLightEnabled); pw.print(" mDeepEnabled="); pw.println(mDeepEnabled); pw.print(" mForceIdle="); pw.println(mForceIdle); - pw.print(" mMotionSensor="); pw.println(mMotionSensor); + pw.print(" mUseMotionSensor="); pw.print(mUseMotionSensor); + if (mUseMotionSensor) { + pw.print(" mMotionSensor="); pw.println(mMotionSensor); + } else { + pw.println(); + } pw.print(" mScreenOn="); pw.println(mScreenOn); pw.print(" mScreenLocked="); pw.println(mScreenLocked); pw.print(" mNetworkConnected="); pw.println(mNetworkConnected); pw.print(" mCharging="); pw.println(mCharging); pw.print(" mMotionActive="); pw.println(mMotionListener.active); - pw.print(" mNotMoving="); pw.println(mNotMoving); + if (mUseMotionSensor) { + pw.print(" mNotMoving="); pw.println(mNotMoving); + } pw.print(" mLocating="); pw.print(mLocating); pw.print(" mHasGps="); pw.print(mHasGps); pw.print(" mHasNetwork="); pw.print(mHasNetworkLocation); pw.print(" mLocated="); pw.println(mLocated); diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 87a42fa45143..4678fec377d0 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -956,18 +956,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub // INetworkManagementService members // @Override - public INetd getNetdService() throws RemoteException { - final CountDownLatch connectedSignal = mConnectedSignal; - if (connectedSignal != null) { - try { - connectedSignal.await(); - } catch (InterruptedException ignored) {} - } - - return mNetdService; - } - - @Override public String[] listInterfaces() { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); try { diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index bbb1d13bdcdc..9f353a80a5be 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -16,7 +16,9 @@ package com.android.server; +import android.app.ActivityManager; import android.app.AppOpsManager; +import android.app.IUidObserver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -111,6 +113,7 @@ public class VibratorService extends IVibratorService.Stub private final boolean mSupportsAmplitudeControl; private final int mDefaultVibrationAmplitude; private final SparseArray<VibrationEffect> mFallbackEffects; + private final SparseArray<Integer> mProcStatesCache = new SparseArray(); private final WorkSource mTmpWorkSource = new WorkSource(); private final Handler mH = new Handler(); private final Object mLock = new Object(); @@ -147,6 +150,25 @@ public class VibratorService extends IVibratorService.Stub native static void vibratorSetAmplitude(int amplitude); native static long vibratorPerformEffect(long effect, long strength); + private final IUidObserver mUidObserver = new IUidObserver.Stub() { + @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) { + mProcStatesCache.put(uid, procState); + } + + @Override public void onUidGone(int uid, boolean disabled) { + mProcStatesCache.delete(uid); + } + + @Override public void onUidActive(int uid) { + } + + @Override public void onUidIdle(int uid, boolean disabled) { + } + + @Override public void onUidCachedChanged(int uid, boolean cached) { + } + }; + private class Vibration implements IBinder.DeathRecipient { public final IBinder token; // Start time in CLOCK_BOOTTIME base. @@ -411,6 +433,14 @@ public class VibratorService extends IVibratorService.Stub } }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH); + try { + ActivityManager.getService().registerUidObserver(mUidObserver, + ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE, + ActivityManager.PROCESS_STATE_UNKNOWN, null); + } catch (RemoteException e) { + // ignored; both services live in system_server + } + updateVibrators(); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); @@ -502,6 +532,12 @@ public class VibratorService extends IVibratorService.Stub return; } verifyIncomingUid(uid); + if (mProcStatesCache.get(uid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) + > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) { + Slog.e(TAG, "Ignoring incoming vibration as process with uid = " + + uid + " is background"); + return; + } if (!verifyVibrationEffect(effect)) { return; } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index c9cab9852f83..69cfcc21cb19 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -2724,47 +2724,86 @@ public class ActivityManagerService extends IActivityManager.Stub return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0; } - void updateUsageStats(ComponentName activity, int uid, int userId, boolean resumed) { + /** + * Update battery stats on the activity' usage. + * @param activity + * @param uid + * @param userId + * @param resumed + */ + void updateBatteryStats(ComponentName activity, int uid, int userId, boolean resumed) { if (DEBUG_SWITCH) { Slog.d(TAG_SWITCH, - "updateUsageStats: comp=" + activity + "res=" + resumed); + "updateBatteryStats: comp=" + activity + "res=" + resumed); } final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); StatsLog.write(StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED, - uid, activity.getPackageName(), - activity.getShortClassName(), resumed ? - StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__FOREGROUND : + uid, activity.getPackageName(), activity.getShortClassName(), + resumed ? StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__FOREGROUND : StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__BACKGROUND); - if (resumed) { - if (mUsageStatsService != null) { - mUsageStatsService.reportEvent(activity, userId, - UsageEvents.Event.MOVE_TO_FOREGROUND); - - } - synchronized (stats) { + synchronized (stats) { + if (resumed) { stats.noteActivityResumedLocked(uid); + } else { + stats.noteActivityPausedLocked(uid); } - } else { + } + } + + /** + * Update UsageStas on the activity's usage. + * @param activity + * @param userId + * @param event + * @param appToken ActivityRecord's appToken. + */ + public void updateActivityUsageStats(ComponentName activity, int userId, int event, + IBinder appToken) { + if (DEBUG_SWITCH) { + Slog.d(TAG_SWITCH, "updateActivityUsageStats: comp=" + + activity + " hash=" + appToken.hashCode() + " event=" + event); + } + synchronized (this) { if (mUsageStatsService != null) { - mUsageStatsService.reportEvent(activity, userId, - UsageEvents.Event.MOVE_TO_BACKGROUND); + mUsageStatsService.reportEvent(activity, userId, event, appToken.hashCode()); } - synchronized (stats) { - stats.noteActivityPausedLocked(uid); + } + } + + /** + * Update UsageStats on this package's usage. + * @param packageName + * @param userId + * @param event + */ + public void updateActivityUsageStats(String packageName, int userId, int event) { + if (DEBUG_SWITCH) { + Slog.d(TAG_SWITCH, "updateActivityUsageStats: package=" + + packageName + " event=" + event); + } + synchronized (this) { + if (mUsageStatsService != null) { + mUsageStatsService.reportEvent(packageName, userId, event); } } } + /** + * Update Usages on this foreground service's usage. + * @param service + * @param userId + * @param started + */ void updateForegroundServiceUsageStats(ComponentName service, int userId, boolean started) { if (DEBUG_SWITCH) { Slog.d(TAG_SWITCH, "updateForegroundServiceUsageStats: comp=" - + service + "started=" + started); + + service + " started=" + started); } synchronized (this) { if (mUsageStatsService != null) { mUsageStatsService.reportEvent(service, userId, started ? UsageEvents.Event.FOREGROUND_SERVICE_START - : UsageEvents.Event.FOREGROUND_SERVICE_STOP); + : UsageEvents.Event.FOREGROUND_SERVICE_STOP, 0); } } } @@ -7608,7 +7647,7 @@ public class ActivityManagerService extends IActivityManager.Stub String extraOptions = null; switch (bugreportType) { case ActivityManager.BUGREPORT_OPTION_FULL: - // Default options. + extraOptions = "bugreportfull"; break; case ActivityManager.BUGREPORT_OPTION_INTERACTIVE: extraOptions = "bugreportplus"; @@ -19068,9 +19107,19 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public void updateUsageStats(ComponentName activity, int uid, int userId, boolean resumed) { + public void updateBatteryStats(ComponentName activity, int uid, int userId, + boolean resumed) { + synchronized (ActivityManagerService.this) { + ActivityManagerService.this.updateBatteryStats(activity, uid, userId, resumed); + } + } + + @Override + public void updateActivityUsageStats(ComponentName activity, int userId, int event, + IBinder appToken) { synchronized (ActivityManagerService.this) { - ActivityManagerService.this.updateUsageStats(activity, uid, userId, resumed); + ActivityManagerService.this.updateActivityUsageStats(activity, userId, event, + appToken); } } diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java index 9649ccd3c750..32219aa5955f 100644 --- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java +++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java @@ -282,9 +282,11 @@ public abstract class BiometricServiceBase extends SystemService public EnrollClientImpl(Context context, DaemonWrapper daemon, long halDeviceId, IBinder token, ServiceListener listener, int userId, int groupId, - byte[] cryptoToken, boolean restricted, String owner) { + byte[] cryptoToken, boolean restricted, String owner, + final int[] disabledFeatures) { super(context, getMetrics(), daemon, halDeviceId, token, listener, - userId, groupId, cryptoToken, restricted, owner, getBiometricUtils()); + userId, groupId, cryptoToken, restricted, owner, getBiometricUtils(), + disabledFeatures); } @Override @@ -408,7 +410,8 @@ public abstract class BiometricServiceBase extends SystemService int cancel() throws RemoteException; int remove(int groupId, int biometricId) throws RemoteException; int enumerate() throws RemoteException; - int enroll(byte[] cryptoToken, int groupId, int timeout) throws RemoteException; + int enroll(byte[] cryptoToken, int groupId, int timeout, + ArrayList<Integer> disabledFeatures) throws RemoteException; } /** diff --git a/services/core/java/com/android/server/biometrics/EnrollClient.java b/services/core/java/com/android/server/biometrics/EnrollClient.java index f858ef5ec6f8..8a0f0858cedc 100644 --- a/services/core/java/com/android/server/biometrics/EnrollClient.java +++ b/services/core/java/com/android/server/biometrics/EnrollClient.java @@ -34,15 +34,18 @@ public abstract class EnrollClient extends ClientMonitor { private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute private final byte[] mCryptoToken; private final BiometricUtils mBiometricUtils; + private final int[] mDisabledFeatures; public EnrollClient(Context context, Metrics metrics, BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token, BiometricServiceBase.ServiceListener listener, int userId, int groupId, - byte[] cryptoToken, boolean restricted, String owner, BiometricUtils utils) { + byte[] cryptoToken, boolean restricted, String owner, BiometricUtils utils, + final int[] disabledFeatures) { super(context, metrics, daemon, halDeviceId, token, listener, userId, groupId, restricted, owner, 0 /* cookie */); mBiometricUtils = utils; mCryptoToken = Arrays.copyOf(cryptoToken, cryptoToken.length); + mDisabledFeatures = Arrays.copyOf(disabledFeatures, disabledFeatures.length); } @Override @@ -74,7 +77,13 @@ public abstract class EnrollClient extends ClientMonitor { public int start() { final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC); try { - final int result = getDaemonWrapper().enroll(mCryptoToken, getGroupId(), timeout); + final ArrayList<Integer> disabledFeatures = new ArrayList<>(); + for (int i = 0; i < mDisabledFeatures.length; i++) { + disabledFeatures.add(mDisabledFeatures[i]); + } + + final int result = getDaemonWrapper().enroll(mCryptoToken, getGroupId(), timeout, + disabledFeatures); if (result != 0) { Slog.w(getLogTag(), "startEnroll failed, result=" + result); mMetricsLogger.histogram(mMetrics.tagEnrollStartError(), result); diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java index 557af0478b87..72f73f6aaf67 100644 --- a/services/core/java/com/android/server/biometrics/face/FaceService.java +++ b/services/core/java/com/android/server/biometrics/face/FaceService.java @@ -113,17 +113,17 @@ public class FaceService extends BiometricServiceBase { } @Override // Binder call - public void enroll(final IBinder token, final byte[] cryptoToken, final int userId, - final IFaceServiceReceiver receiver, final int flags, - final String opPackageName) { + public void enroll(final IBinder token, final byte[] cryptoToken, + final IFaceServiceReceiver receiver, final String opPackageName, + final int[] disabledFeatures) { checkPermission(MANAGE_BIOMETRIC); final boolean restricted = isRestricted(); final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId, - 0 /* groupId */, cryptoToken, restricted, opPackageName); + 0 /* groupId */, cryptoToken, restricted, opPackageName, disabledFeatures); - enrollInternal(client, userId); + enrollInternal(client, UserHandle.getCallingUserId()); } @Override // Binder call @@ -333,7 +333,7 @@ public class FaceService extends BiometricServiceBase { } @Override - public int setRequireAttention(boolean requireAttention, final byte[] token) { + public int setFeature(int feature, boolean enabled, final byte[] token) { checkPermission(MANAGE_BIOMETRIC); final ArrayList<Byte> byteToken = new ArrayList<>(); @@ -343,10 +343,11 @@ public class FaceService extends BiometricServiceBase { int result; try { - result = mDaemon != null ? mDaemon.setRequireAttention(requireAttention, byteToken) + result = mDaemon != null ? mDaemon.setFeature(feature, enabled, byteToken) : Status.INTERNAL_ERROR; } catch (RemoteException e) { - Slog.e(getTag(), "Unable to setRequireAttention to " + requireAttention, e); + Slog.e(getTag(), "Unable to set feature: " + feature + " to enabled:" + enabled, + e); result = Status.INTERNAL_ERROR; } @@ -354,17 +355,12 @@ public class FaceService extends BiometricServiceBase { } @Override - public boolean getRequireAttention(final byte[] token) { + public boolean getFeature(int feature) { checkPermission(MANAGE_BIOMETRIC); - final ArrayList<Byte> byteToken = new ArrayList<>(); - for (int i = 0; i < token.length; i++) { - byteToken.add(token[i]); - } - boolean result = true; try { - result = mDaemon != null ? mDaemon.getRequireAttention(byteToken).value : true; + result = mDaemon != null ? mDaemon.getFeature(feature) : true; } catch (RemoteException e) { Slog.e(getTag(), "Unable to getRequireAttention", e); } @@ -612,7 +608,8 @@ public class FaceService extends BiometricServiceBase { } @Override - public int enroll(byte[] cryptoToken, int groupId, int timeout) throws RemoteException { + public int enroll(byte[] cryptoToken, int groupId, int timeout, + ArrayList<Integer> disabledFeatures) throws RemoteException { IBiometricsFace daemon = getFaceDaemon(); if (daemon == null) { Slog.w(TAG, "enroll(): no face HAL!"); @@ -623,7 +620,7 @@ public class FaceService extends BiometricServiceBase { token.add(cryptoToken[i]); } // TODO: plumb requireAttention down from framework - return daemon.enroll(token, timeout, true /* requireAttention */); + return daemon.enroll(token, timeout, disabledFeatures); } }; diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java index 6a5bc61f2eb6..3895ef78b357 100644 --- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java @@ -144,7 +144,7 @@ public class FingerprintService extends BiometricServiceBase { final int groupId = userId; // default group for fingerprint enrollment final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId, groupId, - cryptoToken, restricted, opPackageName); + cryptoToken, restricted, opPackageName, new int[0] /* disabledFeatures */); enrollInternal(client, userId); } @@ -716,7 +716,8 @@ public class FingerprintService extends BiometricServiceBase { } @Override - public int enroll(byte[] cryptoToken, int groupId, int timeout) throws RemoteException { + public int enroll(byte[] cryptoToken, int groupId, int timeout, + ArrayList<Integer> disabledFeatures) throws RemoteException { IBiometricsFingerprint daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "enroll(): no fingerprint HAL!"); diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 360a7d105cce..cf8d21b66417 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -46,6 +46,8 @@ import android.hardware.display.DisplayManagerGlobal; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener; import android.hardware.display.DisplayViewport; +import android.hardware.display.DisplayedContentSample; +import android.hardware.display.DisplayedContentSamplingAttributes; import android.hardware.display.IDisplayManager; import android.hardware.display.IDisplayManagerCallback; import android.hardware.display.IVirtualDisplayCallback; @@ -1241,6 +1243,29 @@ public final class DisplayManagerService extends SystemService { } } + @VisibleForTesting + DisplayedContentSamplingAttributes getDisplayedContentSamplingAttributesInternal( + int displayId) { + IBinder displayToken = SurfaceControl.getBuiltInDisplay(displayId); + return SurfaceControl.getDisplayedContentSamplingAttributes(displayToken); + } + + @VisibleForTesting + boolean setDisplayedContentSamplingEnabledInternal( + int displayId, boolean enable, int componentMask, int maxFrames) { + IBinder displayToken = SurfaceControl.getBuiltInDisplay(displayId); + return SurfaceControl.setDisplayedContentSamplingEnabled( + displayToken, enable, componentMask, maxFrames); + } + + @VisibleForTesting + DisplayedContentSample getDisplayedContentSampleInternal(int displayId, + long maxFrames, long timestamp) { + IBinder displayToken = SurfaceControl.getBuiltInDisplay(displayId); + return SurfaceControl.getDisplayedContentSample( + displayToken, maxFrames, timestamp); + } + private void clearViewportsLocked() { mViewports.clear(); } @@ -2331,5 +2356,25 @@ public final class DisplayManagerService extends SystemService { } } } + + @Override + public DisplayedContentSamplingAttributes getDisplayedContentSamplingAttributes( + int displayId) { + return getDisplayedContentSamplingAttributesInternal(displayId); + } + + @Override + public boolean setDisplayedContentSamplingEnabled( + int displayId, boolean enable, int componentMask, int maxFrames) { + return setDisplayedContentSamplingEnabledInternal( + displayId, enable, componentMask, maxFrames); + } + + @Override + public DisplayedContentSample getDisplayedContentSample(int displayId, + long maxFrames, long timestamp) { + return getDisplayedContentSampleInternal(displayId, maxFrames, timestamp); + } + } } diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 2e9a71a178fb..bbec6a0055a6 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -164,6 +164,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements @GuardedBy("mSessions") private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>(); + // STOPSHIP: This is a temporary mock implementation of staged sessions. This variable + // shouldn't be needed at all. + @GuardedBy("mStagedSessions") + private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>(); + /** Historical sessions kept around for debugging purposes */ @GuardedBy("mSessions") private final List<String> mHistoricalSessions = new ArrayList<>(); @@ -481,10 +486,12 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements if (!PackageHelper.fitsOnInternal(mContext, params)) { throw new IOException("No suitable internal storage available"); } - } else { + } else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) { // For now, installs to adopted media are treated as internal from // an install flag point-of-view. params.installFlags |= PackageManager.INSTALL_INTERNAL; + } else { + params.installFlags |= PackageManager.INSTALL_INTERNAL; // Resolve best location for install, based on combination of // requested install flags, delta size, and manifest settings. @@ -536,6 +543,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements synchronized (mSessions) { mSessions.put(sessionId, session); } + if (params.isStaged) { + synchronized (mStagedSessions) { + mStagedSessions.put(sessionId, session); + } + } mCallbacks.notifySessionCreated(session.sessionId, session.userId); writeSessionsAsync(); @@ -666,6 +678,18 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } @Override + public ParceledListSlice<SessionInfo> getStagedSessions() { + final List<SessionInfo> result = new ArrayList<>(); + synchronized (mStagedSessions) { + for (int i = 0; i < mStagedSessions.size(); i++) { + final PackageInstallerSession session = mStagedSessions.valueAt(i); + result.add(session.generateInfo(false)); + } + } + return new ParceledListSlice<>(result); + } + + @Override public ParceledListSlice<SessionInfo> getAllSessions(int userId) { mPermissionManager.enforceCrossUserPermission( Binder.getCallingUid(), userId, true, false, "getAllSessions"); @@ -1110,6 +1134,18 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements mInstallHandler.post(new Runnable() { @Override public void run() { + // TODO: remove this mock implementation. + if (session.isStaged()) { + // If the session is aborted, don't keep it in memory. Only store + // sessions successfully staged. + if (!success) { + synchronized (mStagedSessions) { + mStagedSessions.remove(session.sessionId); + } + } else { + return; + } + } synchronized (mSessions) { mSessions.remove(session.sessionId); addHistoricalSessionLocked(session); diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index ea190a7301fc..26a92a4cdde4 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -125,7 +125,7 @@ import java.util.List; import java.util.concurrent.atomic.AtomicInteger; public class PackageInstallerSession extends IPackageInstallerSession.Stub { - private static final String TAG = "PackageInstaller"; + private static final String TAG = "PackageInstallerSession"; private static final boolean LOGD = true; private static final String REMOVE_SPLIT_MARKER_EXTENSION = ".removed"; @@ -147,6 +147,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private static final String ATTR_SEALED = "sealed"; private static final String ATTR_MULTI_PACKAGE = "multiPackage"; private static final String ATTR_PARENT_SESSION_ID = "parentSessionId"; + private static final String ATTR_STAGED_SESSION = "stagedSession"; private static final String ATTR_MODE = "mode"; private static final String ATTR_INSTALL_FLAGS = "installFlags"; private static final String ATTR_INSTALL_LOCATION = "installLocation"; @@ -463,6 +464,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { info.grantedRuntimePermissions = params.grantedRuntimePermissions; info.installFlags = params.installFlags; info.isMultiPackage = params.isMultiPackage; + info.isStaged = params.isStaged; info.parentSessionId = mParentSessionId; info.childSessionIds = mChildSessionIds.copyKeys(); if (info.childSessionIds == null) { @@ -1047,6 +1049,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (committingSession == null) { return; } + if (isStaged()) { + // STOPSHIP: implement staged sessions + dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null); + return; + } if (isMultiPackage()) { final int[] childSessionIds = getChildSessionIds(); List<PackageManagerService.ActiveInstallSession> childSessions = @@ -1816,6 +1823,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } @Override + public boolean isStaged() { + return params.isStaged; + } + + @Override public int[] getChildSessionIds() { final int[] childSessionIds = mChildSessionIds.copyKeys(); if (childSessionIds != null) { @@ -1838,6 +1850,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return; } session.setParentSessionId(this.sessionId); + // TODO: sanity check, if parent session is staged then child session should be + // marked as staged. addChildSessionIdInternal(sessionId); } } @@ -1975,6 +1989,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { pw.printPair("mFinalStatus", mFinalStatus); pw.printPair("mFinalMessage", mFinalMessage); pw.printPair("params.isMultiPackage", params.isMultiPackage); + pw.printPair("params.isStaged", params.isStaged); pw.println(); pw.decreaseIndent(); @@ -2026,6 +2041,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { writeBooleanAttribute(out, ATTR_SEALED, isSealed()); writeBooleanAttribute(out, ATTR_MULTI_PACKAGE, params.isMultiPackage); + writeBooleanAttribute(out, ATTR_STAGED_SESSION, params.isStaged); // TODO(patb,109941548): avoid writing to xml and instead infer / validate this after // we've read all sessions. writeIntAttribute(out, ATTR_PARENT_SESSION_ID, mParentSessionId); @@ -2140,6 +2156,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final SessionParams params = new SessionParams( SessionParams.MODE_INVALID); params.isMultiPackage = readBooleanAttribute(in, ATTR_MULTI_PACKAGE, false); + params.isStaged = readBooleanAttribute(in, ATTR_STAGED_SESSION, false); params.mode = readIntAttribute(in, ATTR_MODE); params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS); params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index edab94c963f1..3e9100e74d8c 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -15269,9 +15269,12 @@ public class PackageManagerService extends IPackageManager.Stub final DeletePackageAction deletePackageAction; // we only want to try to delete for non system apps if (prepareResult.replace && !prepareResult.system) { + final boolean killApp = (scanResult.request.scanFlags & SCAN_DONT_KILL_APP) == 0; + final int deleteFlags = PackageManager.DELETE_KEEP_DATA + | (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP); deletePackageAction = mayDeletePackageLocked(res.removedInfo, prepareResult.originalPs, prepareResult.disabledPs, - prepareResult.childPackageSettings); + prepareResult.childPackageSettings, deleteFlags, installArgs.user); if (deletePackageAction == null) { throw new ReconcileFailure( PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE, @@ -15353,12 +15356,9 @@ public class PackageManagerService extends IPackageManager.Stub } } } else { - final boolean killApp = (scanRequest.scanFlags & SCAN_DONT_KILL_APP) == 0; - final int deleteFlags = PackageManager.DELETE_KEEP_DATA - | (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP); try { executeDeletePackageLIF(reconciledPkg.deletePackageAction, packageName, - null, true, request.mAllUsers, deleteFlags, true, pkg); + true, request.mAllUsers, true, pkg); } catch (SystemDeleteException e) { if (Build.IS_ENG) { throw new RuntimeException("Unexpected failure", e); @@ -17818,12 +17818,23 @@ public class PackageManagerService extends IPackageManager.Stub public final PackageSetting deletingPs; public final PackageSetting disabledPs; public final PackageRemovedInfo outInfo; + public final int flags; + public final UserHandle user; + /** + * True if this package is an unupdated system app that may be deleted by the system. + * When true, disabledPs will be null. + */ + public final boolean mayDeleteUnupdatedSystemApp; private DeletePackageAction(PackageSetting deletingPs, PackageSetting disabledPs, - PackageRemovedInfo outInfo) { + PackageRemovedInfo outInfo, int flags, UserHandle user, + boolean mayDeleteUnupdatedSystemApp) { this.deletingPs = deletingPs; this.disabledPs = disabledPs; this.outInfo = outInfo; + this.flags = flags; + this.user = user; + this.mayDeleteUnupdatedSystemApp = mayDeleteUnupdatedSystemApp; } } @@ -17835,23 +17846,26 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy("mPackages") private static DeletePackageAction mayDeletePackageLocked( PackageRemovedInfo outInfo, PackageSetting ps, @Nullable PackageSetting disabledPs, - @Nullable PackageSetting[] children) { + @Nullable PackageSetting[] children, int flags, UserHandle user) { if (ps == null) { return null; } + boolean mayDeleteUnupdatedSystemApp = false; if (isSystemApp(ps)) { if (ps.parentPackageName != null) { Slog.w(TAG, "Attempt to delete child system package " + ps.pkg.packageName); return null; } - // Confirm if the system package has been updated - // An updated system app can be deleted. This will also have to restore - // the system pkg from system partition - // reader - if (disabledPs == null) { - Slog.w(TAG, - "Attempt to delete unknown system package " + ps.pkg.packageName); + if (((flags & PackageManager.DELETE_SYSTEM_APP) != 0) && user != null + && user.getIdentifier() != UserHandle.USER_ALL) { + mayDeleteUnupdatedSystemApp = true; + } else if (disabledPs == null) { + // Confirmed if the system package has been updated + // An updated system app can be deleted. This will also have to restore + // the system pkg from system partition + // reader + Slog.w(TAG, "Attempt to delete unknown system package " + ps.pkg.packageName); return null; } } @@ -17868,7 +17882,8 @@ public class PackageManagerService extends IPackageManager.Stub } } } - return new DeletePackageAction(ps, disabledPs, outInfo); + return new DeletePackageAction(ps, disabledPs, outInfo, flags, user, + mayDeleteUnupdatedSystemApp); } /* @@ -17883,7 +17898,7 @@ public class PackageManagerService extends IPackageManager.Stub final PackageSetting ps = mSettings.mPackages.get(packageName); final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps); PackageSetting[] children = mSettings.getChildSettingsLPr(ps); - action = mayDeletePackageLocked(outInfo, ps, disabledPs, children); + action = mayDeletePackageLocked(outInfo, ps, disabledPs, children, flags, user); } if (null == action) { return false; @@ -17892,8 +17907,8 @@ public class PackageManagerService extends IPackageManager.Stub if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: " + packageName + " user " + user); try { - executeDeletePackageLIF(action, packageName, user, deleteCodeAndResources, - allUserHandles, flags, writeSettings, replacingPackage); + executeDeletePackageLIF(action, packageName, deleteCodeAndResources, + allUserHandles, writeSettings, replacingPackage); } catch (SystemDeleteException e) { return false; } @@ -17910,11 +17925,13 @@ public class PackageManagerService extends IPackageManager.Stub /** Deletes a package. Only throws when install of a disabled package fails. */ private void executeDeletePackageLIF(DeletePackageAction action, - String packageName, UserHandle user, boolean deleteCodeAndResources, - int[] allUserHandles, int flags, boolean writeSettings, + String packageName, boolean deleteCodeAndResources, + int[] allUserHandles, boolean writeSettings, PackageParser.Package replacingPackage) throws SystemDeleteException { final PackageSetting ps = action.deletingPs; final PackageRemovedInfo outInfo = action.outInfo; + final UserHandle user = action.user; + final int flags = action.flags; final boolean systemApp = isSystemApp(ps); synchronized (mPackages) { @@ -17940,8 +17957,7 @@ public class PackageManagerService extends IPackageManager.Stub } - if (((!systemApp || (flags & PackageManager.DELETE_SYSTEM_APP) != 0) && user != null - && user.getIdentifier() != UserHandle.USER_ALL)) { + if (!systemApp || action.mayDeleteUnupdatedSystemApp) { // The caller is asking that the package only be deleted for a single // user. To do this, we just mark its uninstalled state and delete // its data. If this is a system app, we only allow this to happen if diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 77f8c3a0308a..37a35a25ac1e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -536,6 +536,7 @@ class PackageManagerShellCommand extends ShellCommand { boolean listInstaller = false; boolean showUid = false; boolean showVersionCode = false; + boolean listApexOnly = false; int uid = -1; int userId = UserHandle.USER_SYSTEM; try { @@ -576,6 +577,10 @@ class PackageManagerShellCommand extends ShellCommand { case "--show-versioncode": showVersionCode = true; break; + case "--apex-only": + getFlags |= PackageManager.MATCH_APEX; + listApexOnly = true; + break; case "--user": userId = UserHandle.parseUserArg(getNextArgRequired()); break; @@ -606,30 +611,34 @@ class PackageManagerShellCommand extends ShellCommand { if (filter != null && !info.packageName.contains(filter)) { continue; } - if (uid != -1 && info.applicationInfo.uid != uid) { + final boolean isApex = info.isApex; + if (uid != -1 && !isApex && info.applicationInfo.uid != uid) { continue; } - final boolean isSystem = + + final boolean isSystem = !isApex && (info.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0; - if ((!listDisabled || !info.applicationInfo.enabled) && - (!listEnabled || info.applicationInfo.enabled) && + final boolean isEnabled = !isApex && info.applicationInfo.enabled; + if ((!listDisabled || !isEnabled) && + (!listEnabled || isEnabled) && (!listSystem || isSystem) && - (!listThirdParty || !isSystem)) { + (!listThirdParty || !isSystem) && + (!listApexOnly || isApex)) { pw.print("package:"); - if (showSourceDir) { + if (showSourceDir && !isApex) { pw.print(info.applicationInfo.sourceDir); pw.print("="); } pw.print(info.packageName); - if (showVersionCode) { + if (showVersionCode && !isApex) { pw.print(" versionCode:"); pw.print(info.applicationInfo.versionCode); } - if (listInstaller) { + if (listInstaller && !isApex) { pw.print(" installer="); pw.print(mInterface.getInstallerPackageName(info.packageName)); } - if (showUid) { + if (showUid && !isApex) { pw.print(" uid:"); pw.print(info.applicationInfo.uid); } @@ -2284,6 +2293,9 @@ class PackageManagerShellCommand extends ShellCommand { case "--multi-package": sessionParams.setMultiPackage(); break; + case "--staged": + sessionParams.setStaged(); + break; default: throw new IllegalArgumentException("Unknown option " + opt); } @@ -2767,11 +2779,11 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" Prints all system libraries."); pw.println(""); pw.println(" list packages [-f] [-d] [-e] [-s] [-3] [-i] [-l] [-u] [-U] "); - pw.println(" [--uid UID] [--user USER_ID] [FILTER]"); + pw.println(" [--apex-only] [--uid UID] [--user USER_ID] [FILTER]"); pw.println(" Prints all packages; optionally only those whose name contains"); pw.println(" the text in FILTER. Options are:"); pw.println(" -f: see their associated file"); - pw.println(" -a: all known packages"); + pw.println(" -a: all known packages (but excluding APEXes)"); pw.println(" -d: filter to only show disabled packages"); pw.println(" -e: filter to only show enabled packages"); pw.println(" -s: filter to only show system packages"); @@ -2780,6 +2792,7 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" -l: ignored (used for compatibility with older releases)"); pw.println(" -U: also show the package UID"); pw.println(" -u: also include uninstalled packages"); + pw.println(" --apex-only: only show APEX packages"); pw.println(" --uid UID: filter to only show packages with the given UID"); pw.println(" --user USER_ID: only list packages belonging to the given user"); pw.println(""); @@ -2853,7 +2866,7 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" [--referrer URI] [--abi ABI_NAME] [--force-sdk]"); pw.println(" [--preload] [--instantapp] [--full] [--dont-kill]"); pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [--apex] [-S BYTES]"); - pw.println(" [--multi-package]"); + pw.println(" [--multi-package] [--staged]"); pw.println(" Like \"install\", but starts an install session. Use \"install-write\""); pw.println(" to push data into the session, and \"install-commit\" to finish."); pw.println(""); diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java index c5139b562065..cedb54801dc8 100644 --- a/services/core/java/com/android/server/power/BatterySaverPolicy.java +++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java @@ -111,7 +111,7 @@ public class BatterySaverPolicy extends ContentObserver { false, /* enableAdjustBrightness */ false, /* enableDataSaver */ true, /* enableFirewall */ - false, /* enableQuickDoze */ + true, /* enableQuickDoze */ new ArrayMap<>(), /* filesForInteractive */ new ArrayMap<>(), /* filesForNoninteractive */ true, /* forceAllAppsStandby */ diff --git a/services/core/java/com/android/server/signedconfig/SignatureVerifier.java b/services/core/java/com/android/server/signedconfig/SignatureVerifier.java new file mode 100644 index 000000000000..944db84acc71 --- /dev/null +++ b/services/core/java/com/android/server/signedconfig/SignatureVerifier.java @@ -0,0 +1,109 @@ +/* + * 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.signedconfig; + +import android.os.Build; +import android.util.Slog; + +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.spec.EncodedKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; + +/** + * Helper class for verifying config signatures. + */ +public class SignatureVerifier { + + private static final String TAG = "SignedConfig"; + private static final boolean DBG = false; + + private static final String DEBUG_KEY = + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaAn2XVifsLTHg616nTsOMVmlhBoECGbTEBTKKvdd2hO60" + + "pj1pnU8SMkhYfaNxZuKgw9LNvOwlFwStboIYeZ3lQ=="; + + private final PublicKey mDebugKey; + + public SignatureVerifier() { + mDebugKey = createKey(DEBUG_KEY); + } + + private static PublicKey createKey(String base64) { + EncodedKeySpec keySpec; + try { + byte[] key = Base64.getDecoder().decode(base64); + keySpec = new X509EncodedKeySpec(key); + } catch (IllegalArgumentException e) { + Slog.e(TAG, "Failed to base64 decode public key", e); + return null; + } + try { + KeyFactory factory = KeyFactory.getInstance("EC"); + return factory.generatePublic(keySpec); + } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { + Slog.e(TAG, "Failed to construct public key", e); + return null; + } + } + + /** + * Verify a signature for signed config. + * + * @param config Config as read from APK meta-data. + * @param base64Signature Signature as read from APK meta-data. + * @return {@code true} iff the signature was successfully verified. + */ + public boolean verifySignature(String config, String base64Signature) + throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { + byte[] signature; + try { + signature = Base64.getDecoder().decode(base64Signature); + } catch (IllegalArgumentException e) { + Slog.e(TAG, "Failed to base64 decode signature"); + return false; + } + byte[] data = config.getBytes(StandardCharsets.UTF_8); + if (DBG) Slog.i(TAG, "Data: " + Base64.getEncoder().encodeToString(data)); + + if (Build.IS_DEBUGGABLE) { + if (mDebugKey != null) { + if (DBG) Slog.w(TAG, "Trying to verify signature using debug key"); + Signature verifier = Signature.getInstance("SHA256withECDSA"); + verifier.initVerify(mDebugKey); + verifier.update(data); + if (verifier.verify(signature)) { + Slog.i(TAG, "Verified config using debug key"); + return true; + } else { + if (DBG) Slog.i(TAG, "Config verification failed using debug key"); + } + } else { + Slog.w(TAG, "Debuggable build, but have no debug key"); + } + } + // TODO verify production key. + Slog.w(TAG, "NO PRODUCTION KEY YET, FAILING VERIFICATION"); + return false; + } +} diff --git a/services/core/java/com/android/server/signedconfig/SignedConfig.java b/services/core/java/com/android/server/signedconfig/SignedConfig.java index e6bb800045c8..560a1e1cfe6c 100644 --- a/services/core/java/com/android/server/signedconfig/SignedConfig.java +++ b/services/core/java/com/android/server/signedconfig/SignedConfig.java @@ -33,19 +33,34 @@ import java.util.Set; * Represents signed configuration. * * <p>This configuration should only be used if the signature has already been verified. + * + * This class also parses signed config from JSON. The format expected is: + * <pre> + * { + * "version": 1 + * "config": [ + * { + * "min_sdk": 28, + * "max_sdk": 29, + * "values": { + * "key": "value", + * "key2": "value2" + * ... + * } + * }, + * ... + * ], + * } + * </pre> */ public class SignedConfig { private static final String KEY_VERSION = "version"; private static final String KEY_CONFIG = "config"; - private static final String CONFIG_KEY_MIN_SDK = "minSdk"; - private static final String CONFIG_KEY_MAX_SDK = "maxSdk"; + private static final String CONFIG_KEY_MIN_SDK = "min_sdk"; + private static final String CONFIG_KEY_MAX_SDK = "max_sdk"; private static final String CONFIG_KEY_VALUES = "values"; - // TODO it may be better to use regular key/value pairs in a JSON object, rather than an array - // of objects with the 2 keys below. - private static final String CONFIG_KEY_KEY = "key"; - private static final String CONFIG_KEY_VALUE = "value"; /** * Represents config values targeting an SDK range. @@ -141,14 +156,10 @@ public class SignedConfig { throws JSONException, InvalidConfigException { int minSdk = json.getInt(CONFIG_KEY_MIN_SDK); int maxSdk = json.getInt(CONFIG_KEY_MAX_SDK); - JSONArray valueArray = json.getJSONArray(CONFIG_KEY_VALUES); + JSONObject valuesJson = json.getJSONObject(CONFIG_KEY_VALUES); Map<String, String> values = new HashMap<>(); - for (int i = 0; i < valueArray.length(); ++i) { - JSONObject keyValuePair = valueArray.getJSONObject(i); - String key = keyValuePair.getString(CONFIG_KEY_KEY); - Object valueObject = keyValuePair.has(CONFIG_KEY_VALUE) - ? keyValuePair.get(CONFIG_KEY_VALUE) - : null; + for (String key : valuesJson.keySet()) { + Object valueObject = valuesJson.get(key); String value = valueObject == JSONObject.NULL || valueObject == null ? null : valueObject.toString(); diff --git a/services/core/java/com/android/server/signedconfig/SignedConfigApplicator.java b/services/core/java/com/android/server/signedconfig/SignedConfigApplicator.java index e4d799a2e3b7..4908964109ad 100644 --- a/services/core/java/com/android/server/signedconfig/SignedConfigApplicator.java +++ b/services/core/java/com/android/server/signedconfig/SignedConfigApplicator.java @@ -24,6 +24,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; +import java.security.GeneralSecurityException; import java.util.Arrays; import java.util.Collections; import java.util.Map; @@ -65,15 +66,21 @@ class SignedConfigApplicator { private final Context mContext; private final String mSourcePackage; + private final SignatureVerifier mVerifier; SignedConfigApplicator(Context context, String sourcePackage) { mContext = context; mSourcePackage = sourcePackage; + mVerifier = new SignatureVerifier(); } private boolean checkSignature(String data, String signature) { - Slog.w(TAG, "SIGNATURE CHECK NOT IMPLEMENTED YET!"); - return false; + try { + return mVerifier.verifySignature(data, signature); + } catch (GeneralSecurityException e) { + Slog.e(TAG, "Failed to verify signature", e); + return false; + } } private int getCurrentConfigVersion() { diff --git a/services/core/java/com/android/server/signedconfig/SignedConfigService.java b/services/core/java/com/android/server/signedconfig/SignedConfigService.java index be1d41dd392b..84ce93f04c74 100644 --- a/services/core/java/com/android/server/signedconfig/SignedConfigService.java +++ b/services/core/java/com/android/server/signedconfig/SignedConfigService.java @@ -29,6 +29,9 @@ import android.util.Slog; import com.android.server.LocalServices; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + /** * Signed config service. This is not an Android Service, but just owns a broadcast receiver for * receiving package install and update notifications from the package manager. @@ -81,6 +84,13 @@ public class SignedConfigService { && metaData.containsKey(KEY_CONFIG_SIGNATURE)) { String config = metaData.getString(KEY_CONFIG); String signature = metaData.getString(KEY_CONFIG_SIGNATURE); + try { + // Base64 encoding is standard (not URL safe) encoding: RFC4648 + config = new String(Base64.getDecoder().decode(config), StandardCharsets.UTF_8); + } catch (IllegalArgumentException iae) { + Slog.e(TAG, "Failed to base64 decode config from " + packageName); + return; + } if (DBG) { Slog.d(TAG, "Got signed config: " + config); Slog.d(TAG, "Got config signature: " + signature); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 4e9c5ab39ea8..88dd3c650a96 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -96,6 +96,7 @@ import static com.android.server.am.ActivityRecordProto.TRANSLUCENT; import static com.android.server.am.ActivityRecordProto.VISIBLE; import static com.android.server.am.EventLogTags.AM_RELAUNCH_ACTIVITY; import static com.android.server.am.EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY; +import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED; import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING; import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; @@ -122,8 +123,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE; -import static com.android.server.wm.ActivityTaskManagerService - .RELAUNCH_REASON_WINDOWING_MODE_RESIZE; +import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; import static com.android.server.wm.IdentifierProto.HASH_CODE; import static com.android.server.wm.IdentifierProto.TITLE; import static com.android.server.wm.IdentifierProto.USER_ID; @@ -157,6 +157,7 @@ import android.app.servertransaction.PauseActivityItem; import android.app.servertransaction.PipModeChangeItem; import android.app.servertransaction.ResumeActivityItem; import android.app.servertransaction.WindowVisibilityItem; +import android.app.usage.UsageEvents.Event; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -1035,8 +1036,6 @@ final class ActivityRecord extends ConfigurationContainer { inHistory = true; - final TaskWindowContainerController taskController = task.getWindowContainerController(); - // TODO(b/36505427): Maybe this call should be moved inside updateOverrideConfiguration() task.updateOverrideConfigurationFromLaunchBounds(); // Make sure override configuration is up-to-date before using to create window controller. @@ -1048,10 +1047,9 @@ final class ActivityRecord extends ConfigurationContainer { // TODO: Should this throw an exception instead? Slog.w(TAG, "Attempted to add existing app token: " + appToken); } else { - final Task container = taskController.mContainer; + final Task container = task.getTask(); if (container == null) { - throw new IllegalArgumentException("AppWindowContainerController: invalid " - + " controller=" + taskController); + throw new IllegalArgumentException("createAppWindowToken: invalid task =" + task); } mAppWindowToken = createAppWindow(mAtmService.mWindowManager, appToken, task.voiceSession != null, container.getDisplayContent(), @@ -1062,7 +1060,7 @@ final class ActivityRecord extends ConfigurationContainer { mLaunchTaskBehind, isAlwaysFocusable()); if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) { Slog.v(TAG, "addAppToken: " - + mAppWindowToken + " controller=" + taskController + " at " + + mAppWindowToken + " task=" + container + " at " + Integer.MAX_VALUE); } container.addChild(mAppWindowToken, Integer.MAX_VALUE /* add on top */); @@ -1148,7 +1146,7 @@ final class ActivityRecord extends ConfigurationContainer { + " r=" + this + " (" + prevTask.getStackId() + ")"); } - mAppWindowToken.reparent(newTask.getWindowContainerController(), position); + mAppWindowToken.reparent(newTask.getTask(), position); // Reparenting prevents informing the parent stack of activity removal in the case that // the new stack has the same parent. we must manually signal here if this is not the case. @@ -1801,6 +1799,18 @@ final class ActivityRecord extends ConfigurationContainer { } mAppWindowToken.detachChildren(); } + + if (state == RESUMED) { + mAtmService.updateBatteryStats(this, true); + mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_RESUMED); + } else if (state == PAUSED) { + mAtmService.updateBatteryStats(this, false); + mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_PAUSED); + } else if (state == STOPPED) { + mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_STOPPED); + } else if (state == DESTROYED) { + mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_DESTROYED); + } } ActivityState getState() { @@ -2774,7 +2784,7 @@ final class ActivityRecord extends ConfigurationContainer { final boolean hasResizeChange = hasResizeChange(changes & ~info.getRealConfigChanged()); if (hasResizeChange) { final boolean isDragResizing = - getTaskRecord().getWindowContainerController().isDragResizing(); + getTaskRecord().getTask().isDragResizing(); mRelaunchReason = isDragResizing ? RELAUNCH_REASON_FREE_RESIZE : RELAUNCH_REASON_WINDOWING_MODE_RESIZE; } else { diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index aca9702a45c8..1a6ae3e1aa7c 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -911,7 +911,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } void positionChildWindowContainerAtTop(TaskRecord child) { - mWindowContainerController.positionChildAtTop(child.getWindowContainerController(), + mWindowContainerController.positionChildAtTop(child.getTask(), true /* includingParents */); } @@ -921,7 +921,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // task to bottom, the next focusable stack on the same display should be focused. final ActivityStack nextFocusableStack = getDisplay().getNextFocusableStack( child.getStack(), true /* ignoreCurrent */); - mWindowContainerController.positionChildAtBottom(child.getWindowContainerController(), + mWindowContainerController.positionChildAtBottom(child.getTask(), nextFocusableStack == null /* includingParents */); } @@ -1617,7 +1617,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai try { EventLogTags.writeAmPauseActivity(prev.mUserId, System.identityHashCode(prev), prev.shortComponentName, "userLeaving=" + userLeaving); - mService.updateUsageStats(prev, false); mService.getLifecycleManager().scheduleTransaction(prev.app.getThread(), prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving, @@ -2984,7 +2983,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai position = getAdjustedPositionForTask(task, position, null /* starting */); mTaskHistory.remove(task); mTaskHistory.add(position, task); - mWindowContainerController.positionChildAt(task.getWindowContainerController(), position); + mWindowContainerController.positionChildAt(task.getTask(), position); updateTaskMovement(task, true); } @@ -4649,9 +4648,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai r.mUserId, System.identityHashCode(r), r.getTaskRecord().taskId, r.shortComponentName, "proc died without state saved"); - if (r.getState() == RESUMED) { - mService.updateUsageStats(r, false); - } } } else { // We have the current state for this activity, so @@ -5349,7 +5345,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai && !matchParentBounds() && task.isResizeable() && !isLockscreenShown) { task.updateOverrideConfiguration(getRequestedOverrideBounds()); } - task.createWindowContainer(toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0); + task.createTask(toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0); return task; } diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index e761ad86c770..4339e5138d1b 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -1868,7 +1868,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { stack.addTask(task, onTop, "restoreRecentTask"); // TODO: move call for creation here and other place into Stack.addTask() - task.createWindowContainer(onTop, true /* showForAllUsers */); + task.createTask(onTop, true /* showForAllUsers */); if (DEBUG_RECENTS) Slog.v(TAG_RECENTS, "Added restored task=" + task + " to stack=" + stack); final ArrayList<ActivityRecord> activities = task.mActivities; @@ -2040,9 +2040,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { mStoppingActivities.remove(r); final ActivityStack stack = r.getActivityStack(); - if (mRootActivityContainer.isTopDisplayFocusedStack(stack)) { - mService.updateUsageStats(r, true); - } if (stack.getDisplay().allResumedActivitiesComplete()) { mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); // Make sure activity & window visibility should be identical diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 182d1a0f9c5d..46ee08f740b0 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -5234,13 +5234,20 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mH.post(mAmInternal::updateCpuStats); } - void updateUsageStats(ActivityRecord component, boolean resumed) { - final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::updateUsageStats, + void updateBatteryStats(ActivityRecord component, boolean resumed) { + final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::updateBatteryStats, mAmInternal, component.mActivityComponent, component.app.mUid, component.mUserId, resumed); mH.sendMessage(m); } + void updateActivityUsageStats(ActivityRecord activity, int event) { + final Message m = PooledLambda.obtainMessage( + ActivityManagerInternal::updateActivityUsageStats, mAmInternal, + activity.mActivityComponent, activity.mUserId, event, activity.appToken); + mH.sendMessage(m); + } + void setBooting(boolean booting) { mAmInternal.setBooting(booting); } diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index c458c94b59e2..e0d3fbed4587 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -1175,21 +1175,14 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } } - void reparent(TaskWindowContainerController taskController, int position) { + void reparent(Task task, int position) { if (DEBUG_ADD_REMOVE) { Slog.i(TAG_WM, "reparent: moving app token=" + this - + " to task=" + taskController + " at " + position); + + " to task=" + task.mTaskId + " at " + position); } - final Task task = taskController.mContainer; if (task == null) { - throw new IllegalArgumentException("reparent: could not find task=" - + taskController); + throw new IllegalArgumentException("reparent: could not find task"); } - reparent(task, position); - getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); - } - - void reparent(Task task, int position) { final Task currentTask = getTask(); if (task == currentTask) { throw new IllegalArgumentException( @@ -1220,6 +1213,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree onDisplayChanged(displayContent); prevDisplayContent.setLayoutNeeded(); } + getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); } @Override diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java index 8f18aa56b001..0452977dc422 100644 --- a/services/core/java/com/android/server/wm/StackWindowController.java +++ b/services/core/java/com/android/server/wm/StackWindowController.java @@ -67,107 +67,87 @@ public class StackWindowController mStackId = stackId; mHandler = new H(new WeakReference<>(this), service.mH.getLooper()); - synchronized (mGlobalLock) { - final DisplayContent dc = mRoot.getDisplayContent(displayId); - if (dc == null) { - throw new IllegalArgumentException("Trying to add stackId=" + stackId - + " to unknown displayId=" + displayId); - } - - dc.createStack(stackId, onTop, this); - getRawBounds(outBounds); + final DisplayContent dc = mRoot.getDisplayContent(displayId); + if (dc == null) { + throw new IllegalArgumentException("Trying to add stackId=" + stackId + + " to unknown displayId=" + displayId); } + + dc.createStack(stackId, onTop, this); + getRawBounds(outBounds); } @Override public void removeContainer() { - synchronized (mGlobalLock) { - if (mContainer != null) { - mContainer.removeIfPossible(); - super.removeContainer(); - } + if (mContainer != null) { + mContainer.removeIfPossible(); + super.removeContainer(); } } - public void reparent(int displayId, Rect outStackBounds, boolean onTop) { - synchronized (mGlobalLock) { - if (mContainer == null) { - throw new IllegalArgumentException("Trying to move unknown stackId=" + mStackId - + " to displayId=" + displayId); - } - - final DisplayContent targetDc = mRoot.getDisplayContent(displayId); - if (targetDc == null) { - throw new IllegalArgumentException("Trying to move stackId=" + mStackId - + " to unknown displayId=" + displayId); - } + void reparent(int displayId, Rect outStackBounds, boolean onTop) { + if (mContainer == null) { + throw new IllegalArgumentException("Trying to move unknown stackId=" + mStackId + + " to displayId=" + displayId); + } - targetDc.moveStackToDisplay(mContainer, onTop); - getRawBounds(outStackBounds); + final DisplayContent targetDc = mRoot.getDisplayContent(displayId); + if (targetDc == null) { + throw new IllegalArgumentException("Trying to move stackId=" + mStackId + + " to unknown displayId=" + displayId); } + + targetDc.moveStackToDisplay(mContainer, onTop); + getRawBounds(outStackBounds); } - public void positionChildAt(TaskWindowContainerController child, int position) { - synchronized (mGlobalLock) { - if (DEBUG_STACK) Slog.i(TAG_WM, "positionChildAt: positioning task=" + child - + " at " + position); - if (child.mContainer == null) { - if (DEBUG_STACK) Slog.i(TAG_WM, - "positionChildAt: could not find task=" + this); - return; + void positionChildAt(Task child, int position) { + if (DEBUG_STACK) { + Slog.i(TAG_WM, "positionChildAt: positioning task=" + child + " at " + position); + } + if (child == null) { + if (DEBUG_STACK) { + Slog.i(TAG_WM, "positionChildAt: could not find task=" + this); } - if (mContainer == null) { - if (DEBUG_STACK) Slog.i(TAG_WM, - "positionChildAt: could not find stack for task=" + mContainer); - return; + return; + } + if (mContainer == null) { + if (DEBUG_STACK) { + Slog.i(TAG_WM, "positionChildAt: could not find stack for task=" + mContainer); } - child.mContainer.positionAt(position); - mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); + return; } + child.positionAt(position); + mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); } - public void positionChildAtTop(TaskWindowContainerController child, boolean includingParents) { + void positionChildAtTop(Task child, boolean includingParents) { if (child == null) { // TODO: Fix the call-points that cause this to happen. return; } - synchronized (mGlobalLock) { - final Task childTask = child.mContainer; - if (childTask == null) { - Slog.e(TAG_WM, "positionChildAtTop: task=" + child + " not found"); - return; - } - mContainer.positionChildAt(POSITION_TOP, childTask, includingParents); + mContainer.positionChildAt(POSITION_TOP, child, includingParents); - final DisplayContent displayContent = mContainer.getDisplayContent(); - if (displayContent.mAppTransition.isTransitionSet()) { - childTask.setSendingToBottom(false); - } - displayContent.layoutAndAssignWindowLayersIfNeeded(); + final DisplayContent displayContent = mContainer.getDisplayContent(); + if (displayContent.mAppTransition.isTransitionSet()) { + child.setSendingToBottom(false); } + displayContent.layoutAndAssignWindowLayersIfNeeded(); } - public void positionChildAtBottom(TaskWindowContainerController child, - boolean includingParents) { + void positionChildAtBottom(Task child, boolean includingParents) { if (child == null) { // TODO: Fix the call-points that cause this to happen. return; } - synchronized (mGlobalLock) { - final Task childTask = child.mContainer; - if (childTask == null) { - Slog.e(TAG_WM, "positionChildAtBottom: task=" + child + " not found"); - return; - } - mContainer.positionChildAt(POSITION_BOTTOM, childTask, includingParents); + mContainer.positionChildAt(POSITION_BOTTOM, child, includingParents); - if (mContainer.getDisplayContent().mAppTransition.isTransitionSet()) { - childTask.setSendingToBottom(true); - } - mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); + if (mContainer.getDisplayContent().mAppTransition.isTransitionSet()) { + child.setSendingToBottom(true); } + mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); } /** @@ -179,24 +159,20 @@ public class StackWindowController */ public void resize(Rect bounds, SparseArray<Rect> taskBounds, SparseArray<Rect> taskTempInsetBounds) { - synchronized (mGlobalLock) { - if (mContainer == null) { - throw new IllegalArgumentException("resizeStack: stack " + this + " not found."); - } - // We might trigger a configuration change. Save the current task bounds for freezing. - mContainer.prepareFreezingTaskBounds(); - if (mContainer.setBounds(bounds, taskBounds, taskTempInsetBounds) - && mContainer.isVisible()) { - mContainer.getDisplayContent().setLayoutNeeded(); - mService.mWindowPlacerLocked.performSurfacePlacement(); - } + if (mContainer == null) { + throw new IllegalArgumentException("resizeStack: stack " + this + " not found."); + } + // We might trigger a configuration change. Save the current task bounds for freezing. + mContainer.prepareFreezingTaskBounds(); + if (mContainer.setBounds(bounds, taskBounds, taskTempInsetBounds) + && mContainer.isVisible()) { + mContainer.getDisplayContent().setLayoutNeeded(); + mService.mWindowPlacerLocked.performSurfacePlacement(); } } public void onPipAnimationEndResize() { - synchronized (mService.mGlobalLock) { - mContainer.onPipAnimationEndResize(); - } + mContainer.onPipAnimationEndResize(); } /** @@ -205,45 +181,37 @@ public class StackWindowController public void getStackDockedModeBounds(Configuration parentConfig, Rect dockedBounds, Rect currentTempTaskBounds, Rect outStackBounds, Rect outTempTaskBounds) { - synchronized (mGlobalLock) { - if (mContainer != null) { - mContainer.getStackDockedModeBoundsLocked(parentConfig, dockedBounds, - currentTempTaskBounds, outStackBounds, outTempTaskBounds); - return; - } - outStackBounds.setEmpty(); - outTempTaskBounds.setEmpty(); + if (mContainer != null) { + mContainer.getStackDockedModeBoundsLocked(parentConfig, dockedBounds, + currentTempTaskBounds, outStackBounds, outTempTaskBounds); + return; } + outStackBounds.setEmpty(); + outTempTaskBounds.setEmpty(); } public void prepareFreezingTaskBounds() { - synchronized (mGlobalLock) { - if (mContainer == null) { - throw new IllegalArgumentException("prepareFreezingTaskBounds: stack " + this - + " not found."); - } - mContainer.prepareFreezingTaskBounds(); + if (mContainer == null) { + throw new IllegalArgumentException("prepareFreezingTaskBounds: stack " + this + + " not found."); } + mContainer.prepareFreezingTaskBounds(); } public void getRawBounds(Rect outBounds) { - synchronized (mGlobalLock) { - if (mContainer.matchParentBounds()) { - outBounds.setEmpty(); - } else { - mContainer.getRawBounds(outBounds); - } + if (mContainer.matchParentBounds()) { + outBounds.setEmpty(); + } else { + mContainer.getRawBounds(outBounds); } } public void getBounds(Rect outBounds) { - synchronized (mGlobalLock) { - if (mContainer != null) { - mContainer.getBounds(outBounds); - return; - } - outBounds.setEmpty(); + if (mContainer != null) { + mContainer.getBounds(outBounds); + return; } + outBounds.setEmpty(); } /** @@ -256,73 +224,71 @@ public class StackWindowController Rect nonDecorBounds, Rect stableBounds, boolean overrideWidth, boolean overrideHeight, float density, Configuration config, Configuration parentConfig, int windowingMode) { - synchronized (mGlobalLock) { - final TaskStack stack = mContainer; - final DisplayContent displayContent = stack.getDisplayContent(); - final DisplayInfo di = displayContent.getDisplayInfo(); - final DisplayCutout displayCutout = di.displayCutout; - final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy(); - - // Get the insets and display bounds - displayPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, - displayCutout, mTmpStableInsets); - displayPolicy.getNonDecorInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, - displayCutout, mTmpNonDecorInsets); - mTmpDisplayBounds.set(0, 0, di.logicalWidth, di.logicalHeight); - - int width; - int height; - - final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds(); - - config.windowConfiguration.setBounds(bounds); - config.windowConfiguration.setAppBounds(!bounds.isEmpty() ? bounds : null); - boolean intersectParentBounds = false; - - if (WindowConfiguration.isFloating(windowingMode)) { - // Floating tasks should not be resized to the screen's bounds. - - if (windowingMode == WindowConfiguration.WINDOWING_MODE_PINNED - && bounds.width() == mTmpDisplayBounds.width() - && bounds.height() == mTmpDisplayBounds.height()) { - // If the bounds we are animating is the same as the fullscreen stack - // dimensions, then apply the same inset calculations that we normally do for - // the fullscreen stack, without intersecting it with the display bounds - stableBounds.inset(mTmpStableInsets); - nonDecorBounds.inset(mTmpNonDecorInsets); - // Move app bounds to zero to apply intersection with parent correctly. They are - // used only for evaluating width and height, so it's OK to move them around. - config.windowConfiguration.getAppBounds().offsetTo(0, 0); - intersectParentBounds = true; - } - width = (int) (stableBounds.width() / density); - height = (int) (stableBounds.height() / density); - } else { - // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen - // area, i.e. the screen area without the system bars. - // Additionally task dimensions should not be bigger than its parents dimensions. - // The non decor inset are areas that could never be removed in Honeycomb. See - // {@link WindowManagerPolicy#getNonDecorInsetsLw}. - intersectDisplayBoundsExcludeInsets(nonDecorBounds, bounds, mTmpNonDecorInsets, - mTmpDisplayBounds, overrideWidth, overrideHeight); - intersectDisplayBoundsExcludeInsets(stableBounds, bounds, mTmpStableInsets, - mTmpDisplayBounds, overrideWidth, overrideHeight); - width = Math.min((int) (stableBounds.width() / density), - parentConfig.screenWidthDp); - height = Math.min((int) (stableBounds.height() / density), - parentConfig.screenHeightDp); + final TaskStack stack = mContainer; + final DisplayContent displayContent = stack.getDisplayContent(); + final DisplayInfo di = displayContent.getDisplayInfo(); + final DisplayCutout displayCutout = di.displayCutout; + final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy(); + + // Get the insets and display bounds + displayPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, + displayCutout, mTmpStableInsets); + displayPolicy.getNonDecorInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, + displayCutout, mTmpNonDecorInsets); + mTmpDisplayBounds.set(0, 0, di.logicalWidth, di.logicalHeight); + + int width; + int height; + + final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds(); + + config.windowConfiguration.setBounds(bounds); + config.windowConfiguration.setAppBounds(!bounds.isEmpty() ? bounds : null); + boolean intersectParentBounds = false; + + if (WindowConfiguration.isFloating(windowingMode)) { + // Floating tasks should not be resized to the screen's bounds. + + if (windowingMode == WindowConfiguration.WINDOWING_MODE_PINNED + && bounds.width() == mTmpDisplayBounds.width() + && bounds.height() == mTmpDisplayBounds.height()) { + // If the bounds we are animating is the same as the fullscreen stack + // dimensions, then apply the same inset calculations that we normally do for + // the fullscreen stack, without intersecting it with the display bounds + stableBounds.inset(mTmpStableInsets); + nonDecorBounds.inset(mTmpNonDecorInsets); + // Move app bounds to zero to apply intersection with parent correctly. They are + // used only for evaluating width and height, so it's OK to move them around. + config.windowConfiguration.getAppBounds().offsetTo(0, 0); intersectParentBounds = true; } + width = (int) (stableBounds.width() / density); + height = (int) (stableBounds.height() / density); + } else { + // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen + // area, i.e. the screen area without the system bars. + // Additionally task dimensions should not be bigger than its parents dimensions. + // The non decor inset are areas that could never be removed in Honeycomb. See + // {@link WindowManagerPolicy#getNonDecorInsetsLw}. + intersectDisplayBoundsExcludeInsets(nonDecorBounds, bounds, mTmpNonDecorInsets, + mTmpDisplayBounds, overrideWidth, overrideHeight); + intersectDisplayBoundsExcludeInsets(stableBounds, bounds, mTmpStableInsets, + mTmpDisplayBounds, overrideWidth, overrideHeight); + width = Math.min((int) (stableBounds.width() / density), + parentConfig.screenWidthDp); + height = Math.min((int) (stableBounds.height() / density), + parentConfig.screenHeightDp); + intersectParentBounds = true; + } - if (intersectParentBounds && config.windowConfiguration.getAppBounds() != null) { - config.windowConfiguration.getAppBounds().intersect(parentAppBounds); - } - - config.screenWidthDp = width; - config.screenHeightDp = height; - config.smallestScreenWidthDp = getSmallestWidthForTaskBounds( - bounds, density, windowingMode); + if (intersectParentBounds && config.windowConfiguration.getAppBounds() != null) { + config.windowConfiguration.getAppBounds().intersect(parentAppBounds); } + + config.screenWidthDp = width; + config.screenHeightDp = height; + config.smallestScreenWidthDp = getSmallestWidthForTaskBounds( + bounds, density, windowingMode); } /** diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 67657d0427ba..69d9810dd207 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -24,6 +24,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.content.res.Configuration.EMPTY; import static com.android.server.EventLogTags.WM_TASK_REMOVED; +import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; import static com.android.server.wm.TaskProto.APP_WINDOW_TOKENS; import static com.android.server.wm.TaskProto.BOUNDS; import static com.android.server.wm.TaskProto.DEFER_REMOVAL; @@ -38,6 +39,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.annotation.CallSuper; +import android.app.ActivityManager; import android.app.ActivityManager.TaskDescription; import android.content.pm.ActivityInfo; import android.content.res.Configuration; @@ -54,7 +56,7 @@ import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; import java.util.function.Consumer; -class Task extends WindowContainer<AppWindowToken> { +class Task extends WindowContainer<AppWindowToken> implements ConfigurationContainerListener{ static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_WM; // TODO: Track parent marks like this in WindowContainer. @@ -109,16 +111,24 @@ class Task extends WindowContainer<AppWindowToken> { /** @see #setCanAffectSystemUiFlags */ private boolean mCanAffectSystemUiFlags = true; + // TODO: remove after unification + TaskRecord mTaskRecord; + Task(int taskId, TaskStack stack, int userId, WindowManagerService service, int resizeMode, boolean supportsPictureInPicture, TaskDescription taskDescription, - TaskWindowContainerController controller) { + TaskRecord taskRecord) { super(service); mTaskId = taskId; mStack = stack; mUserId = userId; mResizeMode = resizeMode; mSupportsPictureInPicture = supportsPictureInPicture; - setController(controller); + mTaskRecord = taskRecord; + if (mTaskRecord != null) { + // This can be null when we call createTaskInStack in WindowTestUtils. Remove this after + // unification. + mTaskRecord.registerConfigurationChangeListener(this); + } setBounds(getRequestedOverrideBounds()); mTaskDescription = taskDescription; @@ -195,6 +205,21 @@ class Task extends WindowContainer<AppWindowToken> { super.removeImmediately(); } + void reparent(StackWindowController stackController, int position, boolean moveParents) { + if (DEBUG_STACK) { + Slog.i(TAG_WM, "reparent: moving taskId=" + mTaskId + + " to stack=" + stackController + " at " + position); + } + final TaskStack stack = stackController.mContainer; + if (stack == null) { + throw new IllegalArgumentException("reparent: could not find stack=" + + stackController); + } + reparent(stack, position, moveParents); + getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); + } + + void reparent(TaskStack stack, int position, boolean moveParents) { if (stack == mStack) { throw new IllegalArgumentException( @@ -300,6 +325,12 @@ class Task extends WindowContainer<AppWindowToken> { return boundsChange; } + void resize(boolean relayout, boolean forced) { + if (setBounds(getRequestedOverrideBounds(), forced) != BOUNDS_CHANGE_NONE && relayout) { + getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); + } + } + @Override void onDisplayChanged(DisplayContent dc) { adjustBoundsForDisplayChangeIfNeeded(dc); @@ -515,6 +546,15 @@ class Task extends WindowContainer<AppWindowToken> { return mDragResizeMode; } + /** + * Puts this task into docked drag resizing mode. See {@link DragResizeMode}. + * + * @param resizing Whether to put the task into drag resize mode. + */ + public void setTaskDockedResizing(boolean resizing) { + setDragResizing(resizing, DRAG_RESIZE_MODE_DOCKED_DIVIDER); + } + private void adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent) { if (displayContent == null) { return; @@ -556,9 +596,8 @@ class Task extends WindowContainer<AppWindowToken> { displayContent.rotateBounds(mRotation, newRotation, mTmpRect2); if (setBounds(mTmpRect2) != BOUNDS_CHANGE_NONE) { - final TaskWindowContainerController controller = getController(); - if (controller != null) { - controller.requestResize(getBounds(), RESIZE_MODE_SYSTEM_SCREEN_ROTATION); + if (mTaskRecord != null) { + mTaskRecord.requestResize(getBounds(), RESIZE_MODE_SYSTEM_SCREEN_ROTATION); } } } @@ -631,6 +670,20 @@ class Task extends WindowContainer<AppWindowToken> { return null; } + void positionChildAtTop(AppWindowToken aToken) { + positionChildAt(aToken, POSITION_TOP); + } + + void positionChildAt(AppWindowToken aToken, int position) { + if (aToken == null) { + Slog.w(TAG_WM, + "Attempted to position of non-existing app"); + return; + } + + positionChildAt(position, aToken, false /* includeParents */); + } + boolean isFullscreen() { if (useCurrentBounds()) { return matchParentBounds(); @@ -656,6 +709,10 @@ class Task extends WindowContainer<AppWindowToken> { mTaskDescription = taskDescription; } + void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) { + mTaskRecord.onSnapshotChanged(snapshot); + } + TaskDescription getTaskDescription() { return mTaskDescription; } @@ -666,11 +723,6 @@ class Task extends WindowContainer<AppWindowToken> { } @Override - TaskWindowContainerController getController() { - return (TaskWindowContainerController) super.getController(); - } - - @Override void forAllTasks(Consumer<Task> callback) { callback.accept(this); } diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java index b6a60090153c..56e634a51fe1 100644 --- a/services/core/java/com/android/server/wm/TaskRecord.java +++ b/services/core/java/com/android/server/wm/TaskRecord.java @@ -47,6 +47,7 @@ import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.provider.Settings.Secure.USER_SETUP_COMPLETE; import static android.view.Display.DEFAULT_DISPLAY; +import static com.android.server.EventLogTags.WM_TASK_CREATED; import static com.android.server.am.TaskRecordProto.ACTIVITIES; import static com.android.server.am.TaskRecordProto.ACTIVITY_TYPE; import static com.android.server.am.TaskRecordProto.BOUNDS; @@ -76,6 +77,10 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECEN import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; +import static com.android.server.wm.WindowContainer.POSITION_TOP; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static java.lang.Integer.MAX_VALUE; @@ -106,6 +111,7 @@ import android.os.UserHandle; import android.provider.Settings; import android.service.voice.IVoiceInteractionSession; import android.util.DisplayMetrics; +import android.util.EventLog; import android.util.Slog; import android.util.proto.ProtoOutputStream; @@ -125,8 +131,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Objects; -// TODO: Make package private again once move to WM package is complete. -public class TaskRecord extends ConfigurationContainer implements TaskWindowContainerListener { +class TaskRecord extends ConfigurationContainer { private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_ATM; private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE; private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS; @@ -318,7 +323,8 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont /** Helper object used for updating override configuration. */ private Configuration mTmpConfig = new Configuration(); - private TaskWindowContainerController mWindowContainerController; + // TODO: remove after unification + Task mTask; /** * Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int, @@ -424,43 +430,54 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont mService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity); } - TaskWindowContainerController getWindowContainerController() { - return mWindowContainerController; + Task getTask() { + return mTask; } - void createWindowContainer(boolean onTop, boolean showForAllUsers) { - if (mWindowContainerController != null) { - throw new IllegalArgumentException("Window container=" + mWindowContainerController + void createTask(boolean onTop, boolean showForAllUsers) { + if (mTask != null) { + throw new IllegalArgumentException("mTask=" + mTask + " already created for task=" + this); } final Rect bounds = updateOverrideConfigurationFromLaunchBounds(); - setWindowContainerController(new TaskWindowContainerController(taskId, this, - getStack().getWindowContainerController(), userId, bounds, - mResizeMode, mSupportsPictureInPicture, onTop, - showForAllUsers, lastTaskDescription)); - } + final StackWindowController stackController = getStack().getWindowContainerController(); - /** - * Should only be invoked from {@link #createWindowContainer(boolean, boolean)}. - */ - @VisibleForTesting - protected void setWindowContainerController(TaskWindowContainerController controller) { - if (mWindowContainerController != null) { - throw new IllegalArgumentException("Window container=" + mWindowContainerController - + " already created for task=" + this); + if (DEBUG_STACK) { + Slog.i(TAG_WM, "TaskRecord: taskId=" + taskId + + " stack=" + stackController + " bounds=" + bounds); } - mWindowContainerController = controller; - if (!mDisplayedBounds.isEmpty() && controller.mContainer != null) { - controller.mContainer.setOverrideDisplayedBounds(mDisplayedBounds); + final TaskStack stack = stackController.mContainer; + if (stack == null) { + throw new IllegalArgumentException("TaskRecord: invalid stack=" + + stackController); } + EventLog.writeEvent(WM_TASK_CREATED, taskId, stack.mStackId); + mTask = new Task(taskId, stack, userId, mService.mWindowManager, mResizeMode, + mSupportsPictureInPicture, lastTaskDescription, this); + final int position = onTop ? POSITION_TOP : POSITION_BOTTOM; + + if (!mDisplayedBounds.isEmpty()) { + mTask.setOverrideDisplayedBounds(mDisplayedBounds); + } + // We only want to move the parents to the parents if we are creating this task at the + // top of its stack. + stack.addTask(mTask, position, showForAllUsers, onTop /* moveParents */); + } + + void setTask(Task task) { + mTask = task; } void removeWindowContainer() { mService.getLockTaskController().clearLockedTask(this); - mWindowContainerController.removeContainer(); - mWindowContainerController = null; + if (mTask == null) { + if (DEBUG_STACK) Slog.i(TAG_WM, "removeTask: could not find taskId=" + taskId); + return; + } + mTask.removeIfPossible(); + mTask = null; if (!getWindowConfiguration().persistTaskBounds()) { // Reset current bounds for task whose bounds shouldn't be persisted so it uses // default configuration the next time it launches. @@ -469,7 +486,6 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont mService.getTaskChangeNotificationController().notifyTaskRemoved(taskId); } - @Override public void onSnapshotChanged(TaskSnapshot snapshot) { mService.getTaskChangeNotificationController().notifyTaskSnapshotChanged(taskId, snapshot); } @@ -479,17 +495,20 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont return; } mResizeMode = resizeMode; - mWindowContainerController.setResizeable(resizeMode); + mTask.setResizeable(resizeMode); mService.mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); mService.mRootActivityContainer.resumeFocusedStacksTopActivities(); } void setTaskDockedResizing(boolean resizing) { - mWindowContainerController.setTaskDockedResizing(resizing); + if (mTask == null) { + Slog.w(TAG_WM, "setTaskDockedResizing: taskId " + taskId + " not found."); + return; + } + mTask.setTaskDockedResizing(resizing); } // TODO: Consolidate this with the resize() method below. - @Override public void requestResize(Rect bounds, int resizeMode) { mService.resizeTask(taskId, bounds, resizeMode); } @@ -511,7 +530,7 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont return true; } - if (mWindowContainerController == null) { + if (mTask == null) { // Task doesn't exist in window manager yet (e.g. was restored from recents). // All we can do for now is update the bounds so it can be used when the task is // added to window manager. @@ -558,7 +577,7 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont } } } - mWindowContainerController.resize(kept, forced); + mTask.resize(kept, forced); saveLaunchingStateIfNeeded(); @@ -571,11 +590,15 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont // TODO: Investigate combining with the resize() method above. void resizeWindowContainer() { - mWindowContainerController.resize(false /* relayout */, false /* forced */); + mTask.resize(false /* relayout */, false /* forced */); } void getWindowContainerBounds(Rect bounds) { - mWindowContainerController.getBounds(bounds); + if (mTask != null) { + mTask.getBounds(bounds); + } else { + bounds.setEmpty(); + } } /** @@ -679,7 +702,7 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont // Must reparent first in window manager to avoid a situation where AM can delete the // we are coming from in WM before we reparent because it became empty. - mWindowContainerController.reparent(toStack.getWindowContainerController(), position, + mTask.reparent(toStack.getWindowContainerController(), position, moveStackMode == REPARENT_MOVE_STACK_TO_FRONT); final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT @@ -779,7 +802,11 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont } void cancelWindowTransition() { - mWindowContainerController.cancelWindowTransition(); + if (mTask == null) { + Slog.w(TAG_WM, "cancelWindowTransition: taskId " + taskId + " not found."); + return; + } + mTask.cancelTaskWindowTransition(); } /** @@ -1190,7 +1217,7 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont mActivities.add(newTop); // Make sure window manager is aware of the position change. - mWindowContainerController.positionChildAtTop(newTop.mAppWindowToken); + mTask.positionChildAtTop(newTop.mAppWindowToken); updateEffectiveIntent(); setFrontOfTask(); @@ -1275,7 +1302,7 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont if (r.mAppWindowToken != null) { // Only attempt to move in WM if the child has a controller. It is possible we haven't // created controller for the activity we are starting yet. - mWindowContainerController.positionChildAt(r.mAppWindowToken, index); + mTask.positionChildAt(r.mAppWindowToken, index); } // Make sure the list of display UID whitelists is updated @@ -1643,8 +1670,8 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont } lastTaskDescription = new TaskDescription(label, null, iconResource, iconFilename, colorPrimary, colorBackground, statusBarColor, navigationBarColor); - if (mWindowContainerController != null) { - mWindowContainerController.setTaskDescription(lastTaskDescription); + if (mTask != null) { + mTask.setTaskDescription(lastTaskDescription); } // Update the task affiliation color if we are the parent of the group if (taskId == mAffiliatedTaskId) { @@ -1879,9 +1906,8 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont } else { mDisplayedBounds.set(bounds); } - final TaskWindowContainerController controller = getWindowContainerController(); - if (controller != null && controller.mContainer != null) { - controller.mContainer.setOverrideDisplayedBounds( + if (mTask != null) { + mTask.setOverrideDisplayedBounds( mDisplayedBounds.isEmpty() ? null : mDisplayedBounds); } } diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 7ab4d086b70a..01a5622c2b60 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -191,9 +191,7 @@ class TaskSnapshotController { } else { mCache.putSnapshot(task, snapshot); mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot); - if (task.getController() != null) { - task.getController().reportSnapshotChanged(snapshot); - } + task.onSnapshotChanged(snapshot); } } } diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerController.java b/services/core/java/com/android/server/wm/TaskWindowContainerController.java deleted file mode 100644 index b87b65e432d3..000000000000 --- a/services/core/java/com/android/server/wm/TaskWindowContainerController.java +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.server.wm; - -import static com.android.server.EventLogTags.WM_TASK_CREATED; -import static com.android.server.wm.ConfigurationContainer.BOUNDS_CHANGE_NONE; -import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; -import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; -import static com.android.server.wm.WindowContainer.POSITION_TOP; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; - -import android.app.ActivityManager.TaskDescription; -import android.app.ActivityManager.TaskSnapshot; -import android.graphics.Rect; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.util.EventLog; -import android.util.Slog; - -import com.android.internal.annotations.VisibleForTesting; - -import java.lang.ref.WeakReference; - -/** - * Controller for the task container. This is created by activity manager to link task records to - * the task container they use in window manager. - * - * Test class: {@link TaskWindowContainerControllerTests} - */ -public class TaskWindowContainerController - extends WindowContainerController<Task, TaskWindowContainerListener> { - - private final int mTaskId; - private final H mHandler; - - public TaskWindowContainerController(int taskId, TaskWindowContainerListener listener, - StackWindowController stackController, int userId, Rect bounds, int resizeMode, - boolean supportsPictureInPicture, boolean toTop, boolean showForAllUsers, - TaskDescription taskDescription) { - this(taskId, listener, stackController, userId, bounds, resizeMode, - supportsPictureInPicture, toTop, showForAllUsers, taskDescription, - WindowManagerService.getInstance()); - } - - public TaskWindowContainerController(int taskId, TaskWindowContainerListener listener, - StackWindowController stackController, int userId, Rect bounds, int resizeMode, - boolean supportsPictureInPicture, boolean toTop, boolean showForAllUsers, - TaskDescription taskDescription, WindowManagerService service) { - super(listener, service); - mTaskId = taskId; - mHandler = new H(new WeakReference<>(this), service.mH.getLooper()); - - synchronized (mGlobalLock) { - if (DEBUG_STACK) Slog.i(TAG_WM, "TaskWindowContainerController: taskId=" + taskId - + " stack=" + stackController + " bounds=" + bounds); - - final TaskStack stack = stackController.mContainer; - if (stack == null) { - throw new IllegalArgumentException("TaskWindowContainerController: invalid stack=" - + stackController); - } - EventLog.writeEvent(WM_TASK_CREATED, taskId, stack.mStackId); - final Task task = createTask(taskId, stack, userId, resizeMode, - supportsPictureInPicture, taskDescription); - final int position = toTop ? POSITION_TOP : POSITION_BOTTOM; - // We only want to move the parents to the parents if we are creating this task at the - // top of its stack. - stack.addTask(task, position, showForAllUsers, toTop /* moveParents */); - } - } - - @VisibleForTesting - Task createTask(int taskId, TaskStack stack, int userId, int resizeMode, - boolean supportsPictureInPicture, TaskDescription taskDescription) { - return new Task(taskId, stack, userId, mService, resizeMode, supportsPictureInPicture, - taskDescription, this); - } - - @Override - public void removeContainer() { - synchronized (mGlobalLock) { - if (mContainer == null) { - if (DEBUG_STACK) Slog.i(TAG_WM, "removeTask: could not find taskId=" + mTaskId); - return; - } - mContainer.removeIfPossible(); - super.removeContainer(); - } - } - - void positionChildAtTop(AppWindowToken aToken) { - positionChildAt(aToken, POSITION_TOP); - } - - void positionChildAt(AppWindowToken aToken, int position) { - synchronized (mService.mGlobalLock) { - if (aToken == null) { - Slog.w(TAG_WM, - "Attempted to position of non-existing app"); - return; - } - - final Task task = mContainer; - if (task == null) { - throw new IllegalArgumentException("positionChildAt: invalid task=" + this); - } - task.positionChildAt(position, aToken, false /* includeParents */); - } - } - - public void reparent(StackWindowController stackController, int position, boolean moveParents) { - synchronized (mGlobalLock) { - if (DEBUG_STACK) Slog.i(TAG_WM, "reparent: moving taskId=" + mTaskId - + " to stack=" + stackController + " at " + position); - if (mContainer == null) { - if (DEBUG_STACK) Slog.i(TAG_WM, - "reparent: could not find taskId=" + mTaskId); - return; - } - final TaskStack stack = stackController.mContainer; - if (stack == null) { - throw new IllegalArgumentException("reparent: could not find stack=" - + stackController); - } - mContainer.reparent(stack, position, moveParents); - mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); - } - } - - public void setResizeable(int resizeMode) { - synchronized (mGlobalLock) { - if (mContainer != null) { - mContainer.setResizeable(resizeMode); - } - } - } - - public void resize(boolean relayout, boolean forced) { - synchronized (mGlobalLock) { - if (mContainer == null) { - throw new IllegalArgumentException("resizeTask: taskId " + mTaskId + " not found."); - } - - if (mContainer.setBounds( - mContainer.getRequestedOverrideBounds(), forced) != BOUNDS_CHANGE_NONE - && relayout) { - mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); - } - } - } - - public void getBounds(Rect bounds) { - synchronized (mGlobalLock) { - if (mContainer != null) { - mContainer.getBounds(bounds); - return; - } - bounds.setEmpty(); - } - } - - /** - * Puts this task into docked drag resizing mode. See {@link DragResizeMode}. - * - * @param resizing Whether to put the task into drag resize mode. - */ - public void setTaskDockedResizing(boolean resizing) { - synchronized (mGlobalLock) { - if (mContainer == null) { - Slog.w(TAG_WM, "setTaskDockedResizing: taskId " + mTaskId + " not found."); - return; - } - mContainer.setDragResizing(resizing, DRAG_RESIZE_MODE_DOCKED_DIVIDER); - } - } - - public void cancelWindowTransition() { - synchronized (mGlobalLock) { - if (mContainer == null) { - Slog.w(TAG_WM, "cancelWindowTransition: taskId " + mTaskId + " not found."); - return; - } - mContainer.cancelTaskWindowTransition(); - } - } - - public void setTaskDescription(TaskDescription taskDescription) { - synchronized (mGlobalLock) { - if (mContainer == null) { - Slog.w(TAG_WM, "setTaskDescription: taskId " + mTaskId + " not found."); - return; - } - mContainer.setTaskDescription(taskDescription); - } - } - - public boolean isDragResizing() { - synchronized (mGlobalLock) { - return mContainer.isDragResizing(); - } - } - - void reportSnapshotChanged(TaskSnapshot snapshot) { - mHandler.obtainMessage(H.REPORT_SNAPSHOT_CHANGED, snapshot).sendToTarget(); - } - - void requestResize(Rect bounds, int resizeMode) { - mHandler.obtainMessage(H.REQUEST_RESIZE, resizeMode, 0, bounds).sendToTarget(); - } - - @Override - public String toString() { - return "{TaskWindowContainerController taskId=" + mTaskId + "}"; - } - - private static final class H extends Handler { - - static final int REPORT_SNAPSHOT_CHANGED = 0; - static final int REQUEST_RESIZE = 1; - - private final WeakReference<TaskWindowContainerController> mController; - - H(WeakReference<TaskWindowContainerController> controller, Looper looper) { - super(looper); - mController = controller; - } - - @Override - public void handleMessage(Message msg) { - final TaskWindowContainerController controller = mController.get(); - final TaskWindowContainerListener listener = (controller != null) - ? controller.mListener : null; - if (listener == null) { - return; - } - switch (msg.what) { - case REPORT_SNAPSHOT_CHANGED: - listener.onSnapshotChanged((TaskSnapshot) msg.obj); - break; - case REQUEST_RESIZE: - listener.requestResize((Rect) msg.obj, msg.arg1); - break; - } - } - } -} diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerListener.java b/services/core/java/com/android/server/wm/TaskWindowContainerListener.java deleted file mode 100644 index af67de38e5b3..000000000000 --- a/services/core/java/com/android/server/wm/TaskWindowContainerListener.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.server.wm; - -import android.app.ActivityManager.TaskSnapshot; -import android.graphics.Rect; - -/** - * Interface used by the creator of {@link TaskWindowContainerController} to listen to changes with - * the task container. - */ -public interface TaskWindowContainerListener extends WindowContainerListener { - - /** Called when the snapshot of this task has changed. */ - void onSnapshotChanged(TaskSnapshot snapshot); - - /** Called when the task container would like its controller to resize. */ - void requestResize(Rect bounds, int resizeMode); -} diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java index 240b8206baf6..d8225b38487c 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java @@ -99,6 +99,11 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub { public void grantDeviceIdsAccessToProfileOwner(ComponentName who, int userId) { } @Override + public int getPasswordComplexity() { + return DevicePolicyManager.PASSWORD_COMPLEXITY_NONE; + } + + @Override public void installUpdateFromFile(ComponentName admin, ParcelFileDescriptor updateFileDescriptor, StartInstallingUpdateCallback listener) {} @@ -136,4 +141,10 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub { public boolean isUnattendedManagedKiosk() { return false; } + + @Override + public boolean startViewCalendarEventInManagedProfile(String packageName, long eventId, + long start, long end, boolean allDay, int flags) { + return false; + } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index bc550dc8bd12..ab27d21dc565 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -17,6 +17,7 @@ package com.android.server.devicepolicy; import static android.Manifest.permission.BIND_DEVICE_ADMIN; +import static android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY; import static android.Manifest.permission.MANAGE_CA_CERTIFICATES; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE; @@ -40,10 +41,13 @@ import static android.app.admin.DevicePolicyManager.CODE_USER_SETUP_COMPLETED; import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS; import static android.app.admin.DevicePolicyManager.DELEGATION_BLOCK_UNINSTALL; import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL; +import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_SELECTION; import static android.app.admin.DevicePolicyManager.DELEGATION_ENABLE_SYSTEM_APP; import static android.app.admin.DevicePolicyManager.DELEGATION_INSTALL_EXISTING_PACKAGE; import static android.app.admin.DevicePolicyManager.DELEGATION_KEEP_UNINSTALLED_PACKAGES; +import static android.app.admin.DevicePolicyManager.DELEGATION_NETWORK_LOGGING; import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS; +import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_INSTALLATION; import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT; import static android.app.admin.DevicePolicyManager.ID_TYPE_BASE_INFO; import static android.app.admin.DevicePolicyManager.ID_TYPE_IMEI; @@ -53,6 +57,7 @@ import static android.app.admin.DevicePolicyManager.LEAVE_ALL_SYSTEM_APPS_ENABLE import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_HOME; import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS; import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW; +import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_OFF; @@ -113,6 +118,7 @@ import android.app.admin.DeviceAdminReceiver; import android.app.admin.DevicePolicyCache; import android.app.admin.DevicePolicyEventLogger; import android.app.admin.DevicePolicyManager; +import android.app.admin.DevicePolicyManager.PasswordComplexity; import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.NetworkEvent; import android.app.admin.PasswordMetrics; @@ -124,6 +130,7 @@ import android.app.admin.SystemUpdatePolicy; import android.app.backup.IBackupManager; import android.app.trust.TrustManager; import android.app.usage.UsageStatsManagerInternal; +import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentValues; @@ -184,6 +191,7 @@ import android.os.UserManager; import android.os.UserManagerInternal; import android.os.UserManagerInternal.UserRestrictionsListener; import android.os.storage.StorageManager; +import android.provider.CalendarContract; import android.provider.ContactsContract.QuickContact; import android.provider.ContactsInternal; import android.provider.Settings; @@ -361,9 +369,24 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { DELEGATION_PACKAGE_ACCESS, DELEGATION_PERMISSION_GRANT, DELEGATION_INSTALL_EXISTING_PACKAGE, - DELEGATION_KEEP_UNINSTALLED_PACKAGES + DELEGATION_KEEP_UNINSTALLED_PACKAGES, + DELEGATION_NETWORK_LOGGING, + DELEGATION_CERT_SELECTION, + DELEGATION_PACKAGE_INSTALLATION }; + // Subset of delegations that can only be delegated by Device Owner. + private static final List<String> DEVICE_OWNER_DELEGATIONS = Arrays.asList(new String[] { + DELEGATION_NETWORK_LOGGING, + DELEGATION_PACKAGE_INSTALLATION + }); + + // Subset of delegations that only one single package within a given user can hold + private static final List<String> EXCLUSIVE_DELEGATIONS = Arrays.asList(new String[] { + DELEGATION_NETWORK_LOGGING, + DELEGATION_CERT_SELECTION, + }); + /** * System property whose value is either "true" or "false", indicating whether * device owner is present. @@ -4714,6 +4737,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override + @PasswordComplexity + public int getPasswordComplexity() { + final int callingUserId = mInjector.userHandleGetCallingUserId(); + enforceUserUnlocked(callingUserId); + mContext.enforceCallingOrSelfPermission( + GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY, + "Must have " + GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY + " permission."); + + synchronized (getLockObject()) { + int targetUserId = getCredentialOwner(callingUserId, /* parent= */ false); + PasswordMetrics metrics = getUserPasswordMetricsLocked(targetUserId); + return metrics == null ? PASSWORD_COMPLEXITY_NONE : metrics.determineComplexity(); + } + } + + @Override public int getCurrentFailedPasswordAttempts(int userHandle, boolean parent) { enforceFullCrossUsersPermission(userHandle); synchronized (getLockObject()) { @@ -5765,13 +5804,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } Intent intent = new Intent(DeviceAdminReceiver.ACTION_CHOOSE_PRIVATE_KEY_ALIAS); - intent.setComponent(aliasChooser); intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_SENDER_UID, uid); intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_URI, uri); intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_ALIAS, alias); intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_RESPONSE, response); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + final ComponentName delegateReceiver; + delegateReceiver = resolveDelegateReceiver(DELEGATION_CERT_SELECTION, + DeviceAdminReceiver.ACTION_CHOOSE_PRIVATE_KEY_ALIAS, caller.getIdentifier()); + + if (delegateReceiver != null) { + intent.setComponent(delegateReceiver); + } else { + intent.setComponent(aliasChooser); + } + final long id = mInjector.binderClearCallingIdentity(); try { mContext.sendOrderedBroadcastAsUser(intent, caller, null, new BroadcastReceiver() { @@ -5831,22 +5879,26 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { */ @Override public void setDelegatedScopes(ComponentName who, String delegatePackage, - List<String> scopes) throws SecurityException { + List<String> scopeList) throws SecurityException { Preconditions.checkNotNull(who, "ComponentName is null"); Preconditions.checkStringNotEmpty(delegatePackage, "Delegate package is null or empty"); - Preconditions.checkCollectionElementsNotNull(scopes, "Scopes"); + Preconditions.checkCollectionElementsNotNull(scopeList, "Scopes"); // Remove possible duplicates. - scopes = new ArrayList(new ArraySet(scopes)); + final ArrayList<String> scopes = new ArrayList(new ArraySet(scopeList)); // Ensure given scopes are valid. if (scopes.retainAll(Arrays.asList(DELEGATIONS))) { throw new IllegalArgumentException("Unexpected delegation scopes"); } - + final boolean hasDoDelegation = !Collections.disjoint(scopes, DEVICE_OWNER_DELEGATIONS); // Retrieve the user ID of the calling process. final int userId = mInjector.userHandleGetCallingUserId(); synchronized (getLockObject()) { // Ensure calling process is device/profile owner. - getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + if (hasDoDelegation) { + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); + } else { + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + } // Ensure the delegate is installed (skip this for DELEGATION_CERT_INSTALL in pre-N). if (shouldCheckIfDelegatePackageIsInstalled(delegatePackage, getTargetSdk(who.getPackageName(), userId), scopes)) { @@ -5859,31 +5911,57 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // Set the new delegate in user policies. final DevicePolicyData policy = getUserData(userId); + List<String> exclusiveScopes = null; if (!scopes.isEmpty()) { policy.mDelegationMap.put(delegatePackage, new ArrayList<>(scopes)); + exclusiveScopes = new ArrayList<>(scopes); + exclusiveScopes.retainAll(EXCLUSIVE_DELEGATIONS); } else { // Remove any delegation info if the given scopes list is empty. policy.mDelegationMap.remove(delegatePackage); } - - // Notify delegate package of updates. - final Intent intent = new Intent( - DevicePolicyManager.ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED); - // Only call receivers registered with Context#registerReceiver (don’t wake delegate). - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - // Limit components this intent resolves to to the delegate package. - intent.setPackage(delegatePackage); - // Include the list of delegated scopes as an extra. - intent.putStringArrayListExtra(DevicePolicyManager.EXTRA_DELEGATION_SCOPES, - (ArrayList<String>) scopes); - // Send the broadcast. - mContext.sendBroadcastAsUser(intent, UserHandle.of(userId)); - + sendDelegationChangedBroadcast(delegatePackage, scopes, userId); + + // If set, remove exclusive scopes from all other delegates + if (exclusiveScopes != null && !exclusiveScopes.isEmpty()) { + for (Map.Entry<String, List<String>> entry : policy.mDelegationMap.entrySet()) { + final String currentPackage = entry.getKey(); + final List<String> currentScopes = entry.getValue(); + + if (!currentPackage.equals(delegatePackage)) { + // Iterate through all other delegates + if (currentScopes.removeAll(exclusiveScopes)) { + // And if this delegate had some exclusive scopes which are now moved + // to the new delegate, notify about its delegation changes. + if (currentScopes.isEmpty()) { + policy.mDelegationMap.remove(currentPackage); + } + sendDelegationChangedBroadcast(currentPackage, + new ArrayList<>(currentScopes), userId); + } + } + } + } // Persist updates. saveSettingsLocked(userId); } } + private void sendDelegationChangedBroadcast(String delegatePackage, ArrayList<String> scopes, + int userId) { + // Notify delegate package of updates. + final Intent intent = new Intent( + DevicePolicyManager.ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED); + // Only call receivers registered with Context#registerReceiver (don’t wake delegate). + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + // Limit components this intent resolves to to the delegate package. + intent.setPackage(delegatePackage); + // Include the list of delegated scopes as an extra. + intent.putStringArrayListExtra(DevicePolicyManager.EXTRA_DELEGATION_SCOPES, scopes); + // Send the broadcast. + mContext.sendBroadcastAsUser(intent, UserHandle.of(userId)); + } + /** * Get the delegation scopes given to a delegate package by a device owner or profile owner. * @@ -5951,17 +6029,59 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { synchronized (getLockObject()) { // Ensure calling process is device/profile owner. getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - final DevicePolicyData policy = getUserData(userId); + return getDelegatePackagesInternalLocked(scope, userId); + } + } - // Create a list to hold the resulting delegate packages. - final List<String> delegatePackagesWithScope = new ArrayList<>(); - // Add all delegations containing scope to the result list. - for (int i = 0; i < policy.mDelegationMap.size(); i++) { - if (policy.mDelegationMap.valueAt(i).contains(scope)) { - delegatePackagesWithScope.add(policy.mDelegationMap.keyAt(i)); - } + private List<String> getDelegatePackagesInternalLocked(String scope, int userId) { + final DevicePolicyData policy = getUserData(userId); + + // Create a list to hold the resulting delegate packages. + final List<String> delegatePackagesWithScope = new ArrayList<>(); + // Add all delegations containing scope to the result list. + for (int i = 0; i < policy.mDelegationMap.size(); i++) { + if (policy.mDelegationMap.valueAt(i).contains(scope)) { + delegatePackagesWithScope.add(policy.mDelegationMap.keyAt(i)); + } + } + return delegatePackagesWithScope; + } + + /** + * Return the ComponentName of the receiver that handles the given broadcast action, from + * the app that holds the given delegation capability. If the app defines multiple receivers + * with the same intent action filter, will return any one of them nondeterministically. + * + * @return ComponentName of the receiver or {@null} if none exists. + */ + private ComponentName resolveDelegateReceiver(String scope, String action, int userId) { + + final List<String> delegates; + synchronized (getLockObject()) { + delegates = getDelegatePackagesInternalLocked(scope, userId); + } + if (delegates.size() != 1) { + Slog.wtf(LOG_TAG, "More than one delegate holds " + scope); + return null; + } + final String pkg = delegates.get(0); + Intent intent = new Intent(action); + intent.setPackage(pkg); + final List<ResolveInfo> receivers; + try { + receivers = mIPackageManager.queryIntentReceivers( + intent, null, 0, userId).getList(); + } catch (RemoteException e) { + return null; + } + final int count = receivers.size(); + if (count >= 1) { + if (count > 1) { + Slog.w(LOG_TAG, pkg + " defines more than one delegate receiver for " + action); } - return delegatePackagesWithScope; + return receivers.get(0).activityInfo.getComponentName(); + } else { + return null; } } @@ -6024,15 +6144,34 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { */ private void enforceCanManageScope(ComponentName who, String callerPackage, int reqPolicy, String scope) { + enforceCanManageScopeOrCheckPermission(who, callerPackage, reqPolicy, scope, null); + } + + /** + * Throw a security exception if a ComponentName is given and it is not a device/profile owner + * OR if the calling process is not a delegate of the given scope and does not hold the + * required permission. + */ + private void enforceCanManageScopeOrCheckPermission(@Nullable ComponentName who, + @NonNull String callerPackage, int reqPolicy, @NonNull String scope, + @Nullable String permission) { // If a ComponentName is given ensure it is a device or profile owner according to policy. if (who != null) { synchronized (getLockObject()) { getActiveAdminForCallerLocked(who, reqPolicy); } - // If no ComponentName is given ensure calling process has scope delegation. - } else if (!isCallerDelegate(callerPackage, scope)) { - throw new SecurityException("Caller with uid " + mInjector.binderGetCallingUid() - + " is not a delegate of scope " + scope + "."); + } else { + // If no ComponentName is given ensure calling process has scope delegation or required + // permission + if (isCallerDelegate(callerPackage, scope)) { + return; + } + if (permission == null) { + throw new SecurityException("Caller with uid " + mInjector.binderGetCallingUid() + + " is not a delegate of scope " + scope + "."); + } else { + mContext.enforceCallingOrSelfPermission(permission, null); + } } } @@ -6971,9 +7110,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - private void ensureDeviceOwnerAndAllUsersAffiliated(ComponentName who) throws SecurityException { + private void ensureDeviceOwnerAndAllUsersAffiliated(ComponentName who) + throws SecurityException { synchronized (getLockObject()) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); + } + ensureAllUsersAffiliated(); + } + + private void ensureAllUsersAffiliated() throws SecurityException { + synchronized (getLockObject()) { if (!areAllUsersAffiliatedWithDeviceLocked()) { throw new SecurityException("Not all users are affiliated."); } @@ -7032,14 +7178,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } void sendDeviceOwnerCommand(String action, Bundle extras) { - int deviceOwnerUserId; - ComponentName deviceOwnerComponent; + final int deviceOwnerUserId; synchronized (getLockObject()) { deviceOwnerUserId = mOwners.getDeviceOwnerUserId(); - deviceOwnerComponent = mOwners.getDeviceOwnerComponent(); } - sendActiveAdminCommand(action, extras, deviceOwnerUserId, - deviceOwnerComponent); + + ComponentName receiverComponent = null; + if (action.equals(DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE)) { + receiverComponent = resolveDelegateReceiver(DELEGATION_NETWORK_LOGGING, action, + deviceOwnerUserId); + } + if (receiverComponent == null) { + synchronized (getLockObject()) { + receiverComponent = mOwners.getDeviceOwnerComponent(); + } + } + sendActiveAdminCommand(action, extras, deviceOwnerUserId, receiverComponent); } private void sendProfileOwnerCommand(String action, Bundle extras, int userHandle) { @@ -12507,13 +12661,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override - public void setNetworkLoggingEnabled(ComponentName admin, boolean enabled) { + public void setNetworkLoggingEnabled(@Nullable ComponentName admin, + @NonNull String packageName, boolean enabled) { if (!mHasFeature) { return; } synchronized (getLockObject()) { - Preconditions.checkNotNull(admin); - getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); + enforceCanManageScope(admin, packageName, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER, + DELEGATION_NETWORK_LOGGING); if (enabled == isNetworkLoggingEnabledInternalLocked()) { // already in the requested state @@ -12614,12 +12769,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override - public boolean isNetworkLoggingEnabled(ComponentName admin) { + public boolean isNetworkLoggingEnabled(@Nullable ComponentName admin, + @NonNull String packageName) { if (!mHasFeature) { return false; } synchronized (getLockObject()) { - enforceDeviceOwnerOrManageUsers(); + enforceCanManageScopeOrCheckPermission(admin, packageName, + DeviceAdminInfo.USES_POLICY_DEVICE_OWNER, DELEGATION_NETWORK_LOGGING, + android.Manifest.permission.MANAGE_USERS); return isNetworkLoggingEnabledInternalLocked(); } } @@ -12637,12 +12795,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { * @see NetworkLoggingHandler#MAX_EVENTS_PER_BATCH */ @Override - public List<NetworkEvent> retrieveNetworkLogs(ComponentName admin, long batchToken) { + public List<NetworkEvent> retrieveNetworkLogs(@Nullable ComponentName admin, + @NonNull String packageName, long batchToken) { if (!mHasFeature) { return null; } - Preconditions.checkNotNull(admin); - ensureDeviceOwnerAndAllUsersAffiliated(admin); + enforceCanManageScope(admin, packageName, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER, + DELEGATION_NETWORK_LOGGING); + ensureAllUsersAffiliated(); synchronized (getLockObject()) { if (mNetworkLogger == null @@ -13658,4 +13818,59 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private PowerManagerInternal getPowerManagerInternal() { return mInjector.getPowerManagerInternal(); } + + @Override + public boolean startViewCalendarEventInManagedProfile(String packageName, long eventId, + long start, long end, boolean allDay, int flags) { + if (!mHasFeature) { + return false; + } + Preconditions.checkStringNotEmpty(packageName, "Package name is empty"); + + final int callingUid = mInjector.binderGetCallingUid(); + final int callingUserId = mInjector.userHandleGetCallingUserId(); + if (!isCallingFromPackage(packageName, callingUid)) { + throw new SecurityException("Input package name doesn't align with actual " + + "calling package."); + } + final long identity = mInjector.binderClearCallingIdentity(); + try { + final int workProfileUserId = getManagedUserId(callingUserId); + if (workProfileUserId < 0) { + return false; + } + if (!isPackageAllowedToAccessCalendarForUser(packageName, workProfileUserId)) { + Log.d(LOG_TAG, String.format("Package %s is not allowed to access cross-profile" + + "calendar APIs", packageName)); + return false; + } + final Intent intent = new Intent(CalendarContract.ACTION_VIEW_WORK_CALENDAR_EVENT); + intent.setPackage(packageName); + intent.putExtra(CalendarContract.EXTRA_EVENT_ID, eventId); + intent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, start); + intent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, end); + intent.putExtra(CalendarContract.EXTRA_EVENT_ALL_DAY, allDay); + intent.setFlags(flags); + try { + mContext.startActivityAsUser(intent, UserHandle.of(workProfileUserId)); + } catch (ActivityNotFoundException e) { + Log.e(LOG_TAG, "View event activity not found", e); + return false; + } + } finally { + mInjector.binderRestoreCallingIdentity(identity); + } + return true; + } + + private boolean isCallingFromPackage(String packageName, int callingUid) { + try { + final int packageUid = mInjector.getPackageManager().getPackageUidAsUser( + packageName, UserHandle.getUserId(callingUid)); + return packageUid == callingUid; + } catch (NameNotFoundException e) { + Log.d(LOG_TAG, "Calling package not found", e); + return false; + } + } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java b/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java index 7910598d8429..d8a875d7747b 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java @@ -16,6 +16,7 @@ package com.android.server.devicepolicy; +import android.app.admin.DevicePolicyEventLogger; import android.app.admin.DevicePolicyManager; import android.app.admin.StartInstallingUpdateCallback; import android.content.Context; @@ -26,6 +27,7 @@ import android.os.ParcelFileDescriptor; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; +import android.stats.devicepolicy.DevicePolicyEnums; import android.util.Log; import java.io.File; @@ -132,6 +134,10 @@ abstract class UpdateInstaller { protected void notifyCallbackOnError(int errorCode, String errorMessage) { cleanupUpdateFile(); + DevicePolicyEventLogger + .createEvent(DevicePolicyEnums.INSTALL_SYSTEM_UPDATE_ERROR) + .setInt(errorCode) + .write(); try { mCallback.onStartInstallingUpdateError(errorCode, errorMessage); } catch (RemoteException e) { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index c3a0ddaff85f..729fac5b1dff 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -21,6 +21,9 @@ import static android.app.admin.DevicePolicyManager.ID_TYPE_BASE_INFO; import static android.app.admin.DevicePolicyManager.ID_TYPE_IMEI; import static android.app.admin.DevicePolicyManager.ID_TYPE_MEID; import static android.app.admin.DevicePolicyManager.ID_TYPE_SERIAL; +import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH; +import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM; +import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE; import static android.app.admin.DevicePolicyManager.WIPE_EUICC; import static android.os.UserManagerInternal.CAMERA_DISABLED_GLOBALLY; import static android.os.UserManagerInternal.CAMERA_DISABLED_LOCALLY; @@ -48,6 +51,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import static org.mockito.hamcrest.MockitoHamcrest.argThat; +import static org.testng.Assert.assertThrows; import android.Manifest.permission; import android.annotation.RawRes; @@ -5133,6 +5137,71 @@ public class DevicePolicyManagerTest extends DpmTestBase { }); } + public void testGetPasswordComplexity_securityExceptionIfParentInstance() { + assertThrows(SecurityException.class, + () -> new DevicePolicyManagerTestable( + mServiceContext, + dpms, + /* parentInstance= */ true) + .getPasswordComplexity()); + } + + public void testGetPasswordComplexity_illegalStateExceptionIfLocked() { + when(getServices().userManager.isUserUnlocked(DpmMockContext.CALLER_USER_HANDLE)) + .thenReturn(false); + assertThrows(IllegalStateException.class, () -> dpm.getPasswordComplexity()); + } + + public void testGetPasswordComplexity_securityExceptionWithoutPermissions() { + when(getServices().userManager.isUserUnlocked(DpmMockContext.CALLER_USER_HANDLE)) + .thenReturn(true); + assertThrows(SecurityException.class, () -> dpm.getPasswordComplexity()); + } + + + public void testGetPasswordComplexity_currentUserNoPassword() { + when(getServices().userManager.isUserUnlocked(DpmMockContext.CALLER_USER_HANDLE)) + .thenReturn(true); + mServiceContext.permissions.add(permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY); + when(getServices().userManager.getCredentialOwnerProfile(DpmMockContext.CALLER_USER_HANDLE)) + .thenReturn(DpmMockContext.CALLER_USER_HANDLE); + + assertEquals(PASSWORD_COMPLEXITY_NONE, dpm.getPasswordComplexity()); + } + + public void testGetPasswordComplexity_currentUserHasPassword() { + when(getServices().userManager.isUserUnlocked(DpmMockContext.CALLER_USER_HANDLE)) + .thenReturn(true); + mServiceContext.permissions.add(permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY); + when(getServices().userManager.getCredentialOwnerProfile(DpmMockContext.CALLER_USER_HANDLE)) + .thenReturn(DpmMockContext.CALLER_USER_HANDLE); + dpms.mUserPasswordMetrics.put( + DpmMockContext.CALLER_USER_HANDLE, + PasswordMetrics.computeForPassword("asdf")); + + assertEquals(PASSWORD_COMPLEXITY_MEDIUM, dpm.getPasswordComplexity()); + } + + public void testGetPasswordComplexity_unifiedChallengeReturnsParentUserPassword() { + when(getServices().userManager.isUserUnlocked(DpmMockContext.CALLER_USER_HANDLE)) + .thenReturn(true); + mServiceContext.permissions.add(permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY); + + UserInfo parentUser = new UserInfo(); + parentUser.id = DpmMockContext.CALLER_USER_HANDLE + 10; + when(getServices().userManager.getCredentialOwnerProfile(DpmMockContext.CALLER_USER_HANDLE)) + .thenReturn(parentUser.id); + + dpms.mUserPasswordMetrics.put( + DpmMockContext.CALLER_USER_HANDLE, + PasswordMetrics.computeForPassword("asdf")); + dpms.mUserPasswordMetrics.put( + parentUser.id, + PasswordMetrics.computeForPassword("parentUser")); + + assertEquals(PASSWORD_COMPLEXITY_HIGH, dpm.getPasswordComplexity()); + } + private void configureProfileOwnerForDeviceIdAccess(ComponentName who, int userId) { final long ident = mServiceContext.binder.clearCallingIdentity(); mServiceContext.binder.callingUid = diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java index 3da61d69c742..4982d6e8817f 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java @@ -26,7 +26,12 @@ public class DevicePolicyManagerTestable extends DevicePolicyManager { public DevicePolicyManagerTestable(DpmMockContext context, DevicePolicyManagerServiceTestable dpms) { - super(context, dpms, /* parentInstance = */ false); + this(context, dpms, /* parentInstance= */ false); + } + + public DevicePolicyManagerTestable(DpmMockContext context, + DevicePolicyManagerServiceTestable dpms, boolean parentInstance) { + super(context, dpms, parentInstance); this.dpms = dpms; } diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java index b4212808d585..e9bfa8f4e0c8 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -18,11 +18,21 @@ package com.android.server.display; import static com.android.server.display.VirtualDisplayAdapter.UNIQUE_ID_PREFIX; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import android.content.Context; import android.hardware.display.BrightnessConfiguration; import android.hardware.display.Curve; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayViewport; +import android.hardware.display.DisplayedContentSample; +import android.hardware.display.DisplayedContentSamplingAttributes; import android.hardware.display.IVirtualDisplayCallback; import android.hardware.input.InputManagerInternal; import android.os.Handler; @@ -31,9 +41,9 @@ import android.view.Display; import android.view.DisplayInfo; import android.view.SurfaceControl; -import androidx.test.runner.AndroidJUnit4; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; import com.android.server.LocalServices; import com.android.server.SystemService; @@ -49,17 +59,8 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.util.Arrays; import java.util.List; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.Mockito.mock; +import java.util.stream.LongStream; @SmallTest @RunWith(AndroidJUnit4.class) @@ -397,6 +398,43 @@ public class DisplayManagerServiceTest { displayManager.validateBrightnessConfiguration(null); } + /** + * Tests that collection of display color sampling results are sensible. + */ + @Test + public void testDisplayedContentSampling() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mShortMockedInjector); + registerDefaultDisplays(displayManager); + + DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(0); + assertNotNull(ddi); + + DisplayedContentSamplingAttributes attr = + displayManager.getDisplayedContentSamplingAttributesInternal(0); + if (attr == null) return; //sampling not supported on device, skip remainder of test. + + boolean enabled = displayManager.setDisplayedContentSamplingEnabledInternal(0, true, 0, 0); + assertTrue(!enabled); + + displayManager.setDisplayedContentSamplingEnabledInternal(0, false, 0, 0); + DisplayedContentSample sample = displayManager.getDisplayedContentSampleInternal(0, 0, 0); + assertNotNull(sample); + + long numPixels = ddi.width * ddi.height * sample.getNumFrames(); + long[] samples = sample.getSampleComponent(DisplayedContentSample.ColorComponent.CHANNEL0); + assertTrue(samples.length == 0 || LongStream.of(samples).sum() == numPixels); + + samples = sample.getSampleComponent(DisplayedContentSample.ColorComponent.CHANNEL1); + assertTrue(samples.length == 0 || LongStream.of(samples).sum() == numPixels); + + samples = sample.getSampleComponent(DisplayedContentSample.ColorComponent.CHANNEL2); + assertTrue(samples.length == 0 || LongStream.of(samples).sum() == numPixels); + + samples = sample.getSampleComponent(DisplayedContentSample.ColorComponent.CHANNEL3); + assertTrue(samples.length == 0 || LongStream.of(samples).sum() == numPixels); + } + private void registerDefaultDisplays(DisplayManagerService displayManager) { Handler handler = displayManager.getDisplayHandler(); // Would prefer to call displayManager.onStart() directly here but it performs binderService diff --git a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java index 77f6a23c26b1..acf511e38738 100644 --- a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java +++ b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java @@ -20,7 +20,6 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.mock; import android.content.Context; -import android.os.Handler; import android.os.PowerManager; import android.os.PowerManager.ServiceType; import android.os.PowerSaveState; @@ -175,7 +174,7 @@ public class BatterySaverPolicyTest extends AndroidTestCase { @SmallTest public void testGetBatterySaverPolicy_PolicyQuickDoze_DefaultValueCorrect() { - testServiceDefaultValue_Off(ServiceType.QUICK_DOZE); + testServiceDefaultValue_On(ServiceType.QUICK_DOZE); } @SmallTest diff --git a/services/tests/servicestests/src/com/android/server/signedconfig/SignedConfigTest.java b/services/tests/servicestests/src/com/android/server/signedconfig/SignedConfigTest.java index 70fadd101a91..00a62a300487 100644 --- a/services/tests/servicestests/src/com/android/server/signedconfig/SignedConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/signedconfig/SignedConfigTest.java @@ -66,7 +66,7 @@ public class SignedConfigTest { @Test public void testParsePerSdkConfigSdkMinMax() throws JSONException, InvalidConfigException { - JSONObject json = new JSONObject("{\"minSdk\":2, \"maxSdk\": 3, \"values\": []}"); + JSONObject json = new JSONObject("{\"min_sdk\":2, \"max_sdk\": 3, \"values\": {}}"); SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig(json, emptySet(), emptyMap()); assertThat(config.minSdk).isEqualTo(2); @@ -75,7 +75,7 @@ public class SignedConfigTest { @Test public void testParsePerSdkConfigNoMinSdk() throws JSONException { - JSONObject json = new JSONObject("{\"maxSdk\": 3, \"values\": []}"); + JSONObject json = new JSONObject("{\"max_sdk\": 3, \"values\": {}}"); try { SignedConfig.parsePerSdkConfig(json, emptySet(), emptyMap()); fail("Expected InvalidConfigException or JSONException"); @@ -86,7 +86,7 @@ public class SignedConfigTest { @Test public void testParsePerSdkConfigNoMaxSdk() throws JSONException { - JSONObject json = new JSONObject("{\"minSdk\": 1, \"values\": []}"); + JSONObject json = new JSONObject("{\"min_sdk\": 1, \"values\": {}}"); try { SignedConfig.parsePerSdkConfig(json, emptySet(), emptyMap()); fail("Expected InvalidConfigException or JSONException"); @@ -97,7 +97,7 @@ public class SignedConfigTest { @Test public void testParsePerSdkConfigNoValues() throws JSONException { - JSONObject json = new JSONObject("{\"minSdk\": 1, \"maxSdk\": 3}"); + JSONObject json = new JSONObject("{\"min_sdk\": 1, \"max_sdk\": 3}"); try { SignedConfig.parsePerSdkConfig(json, emptySet(), emptyMap()); fail("Expected InvalidConfigException or JSONException"); @@ -108,7 +108,7 @@ public class SignedConfigTest { @Test public void testParsePerSdkConfigSdkNullMinSdk() throws JSONException { - JSONObject json = new JSONObject("{\"minSdk\":null, \"maxSdk\": 3, \"values\": []}"); + JSONObject json = new JSONObject("{\"min_sdk\":null, \"max_sdk\": 3, \"values\": {}}"); try { SignedConfig.parsePerSdkConfig(json, emptySet(), emptyMap()); fail("Expected InvalidConfigException or JSONException"); @@ -119,7 +119,7 @@ public class SignedConfigTest { @Test public void testParsePerSdkConfigSdkNullMaxSdk() throws JSONException { - JSONObject json = new JSONObject("{\"minSdk\":1, \"maxSdk\": null, \"values\": []}"); + JSONObject json = new JSONObject("{\"min_sdk\":1, \"max_sdk\": null, \"values\": {}}"); try { SignedConfig.parsePerSdkConfig(json, emptySet(), emptyMap()); fail("Expected InvalidConfigException or JSONException"); @@ -130,7 +130,7 @@ public class SignedConfigTest { @Test public void testParsePerSdkConfigNullValues() throws JSONException { - JSONObject json = new JSONObject("{\"minSdk\": 1, \"maxSdk\": 3, \"values\": null}"); + JSONObject json = new JSONObject("{\"min_sdk\": 1, \"max_sdk\": 3, \"values\": null}"); try { SignedConfig.parsePerSdkConfig(json, emptySet(), emptyMap()); fail("Expected InvalidConfigException or JSONException"); @@ -142,7 +142,7 @@ public class SignedConfigTest { @Test public void testParsePerSdkConfigZeroValues() throws JSONException, InvalidConfigException { - JSONObject json = new JSONObject("{\"minSdk\": 1, \"maxSdk\": 3, \"values\": []}"); + JSONObject json = new JSONObject("{\"min_sdk\": 1, \"max_sdk\": 3, \"values\": {}}"); SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig(json, setOf("a", "b"), emptyMap()); assertThat(config.values).hasSize(0); @@ -152,7 +152,7 @@ public class SignedConfigTest { public void testParsePerSdkConfigSingleKey() throws JSONException, InvalidConfigException { JSONObject json = new JSONObject( - "{\"minSdk\": 1, \"maxSdk\": 1, \"values\": [{\"key\":\"a\", \"value\": \"1\"}]}"); + "{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": {\"a\": \"1\"}}"); SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig(json, setOf("a", "b"), emptyMap()); assertThat(config.values).containsExactly("a", "1"); @@ -162,7 +162,7 @@ public class SignedConfigTest { public void testParsePerSdkConfigSingleKeyNullValue() throws JSONException, InvalidConfigException { JSONObject json = new JSONObject( - "{\"minSdk\": 1, \"maxSdk\": 1, \"values\": [{\"key\":\"a\", \"value\": null}]}"); + "{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": {\"a\": null}}"); SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig(json, setOf("a", "b"), emptyMap()); assertThat(config.values.keySet()).containsExactly("a"); @@ -173,8 +173,7 @@ public class SignedConfigTest { public void testParsePerSdkConfigMultiKeys() throws JSONException, InvalidConfigException { JSONObject json = new JSONObject( - "{\"minSdk\": 1, \"maxSdk\": 1, \"values\": [{\"key\":\"a\", \"value\": \"1\"}, " - + "{\"key\":\"c\", \"value\": \"2\"}]}"); + "{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": {\"a\": \"1\", \"c\": \"2\"}}"); SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig( json, setOf("a", "b", "c"), emptyMap()); assertThat(config.values).containsExactly("a", "1", "c", "2"); @@ -183,7 +182,7 @@ public class SignedConfigTest { @Test public void testParsePerSdkConfigSingleKeyNotAllowed() throws JSONException { JSONObject json = new JSONObject( - "{\"minSdk\": 1, \"maxSdk\": 1, \"values\": [{\"key\":\"a\", \"value\": \"1\"}]}"); + "{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": {\"a\": \"1\"}}"); try { SignedConfig.parsePerSdkConfig(json, setOf("b"), emptyMap()); fail("Expected InvalidConfigException or JSONException"); @@ -196,7 +195,7 @@ public class SignedConfigTest { public void testParsePerSdkConfigSingleKeyWithMap() throws JSONException, InvalidConfigException { JSONObject json = new JSONObject( - "{\"minSdk\": 1, \"maxSdk\": 1, \"values\": [{\"key\":\"a\", \"value\": \"1\"}]}"); + "{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": {\"a\": \"1\"}}"); SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig(json, setOf("a"), mapOf("a", mapOf("1", "one"))); assertThat(config.values).containsExactly("a", "one"); @@ -205,7 +204,7 @@ public class SignedConfigTest { @Test public void testParsePerSdkConfigSingleKeyWithMapInvalidValue() throws JSONException { JSONObject json = new JSONObject( - "{\"minSdk\": 1, \"maxSdk\": 1, \"values\": [{\"key\":\"a\", \"value\": \"2\"}]}"); + "{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": {\"a\": \"2\"}}"); try { SignedConfig.parsePerSdkConfig(json, setOf("b"), mapOf("a", mapOf("1", "one"))); fail("Expected InvalidConfigException"); @@ -218,8 +217,7 @@ public class SignedConfigTest { public void testParsePerSdkConfigMultiKeysWithMap() throws JSONException, InvalidConfigException { JSONObject json = new JSONObject( - "{\"minSdk\": 1, \"maxSdk\": 1, \"values\": [{\"key\":\"a\", \"value\": \"1\"}," - + "{\"key\":\"b\", \"value\": \"1\"}]}"); + "{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": {\"a\": \"1\", \"b\": \"1\"}}"); SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig(json, setOf("a", "b"), mapOf("a", mapOf("1", "one"))); assertThat(config.values).containsExactly("a", "one", "b", "1"); @@ -229,7 +227,7 @@ public class SignedConfigTest { public void testParsePerSdkConfigSingleKeyWithMapToNull() throws JSONException, InvalidConfigException { JSONObject json = new JSONObject( - "{\"minSdk\": 1, \"maxSdk\": 1, \"values\": [{\"key\":\"a\", \"value\": \"1\"}]}"); + "{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": {\"a\": \"1\"}}"); SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig(json, setOf("a"), mapOf("a", mapOf("1", null))); assertThat(config.values).containsExactly("a", null); @@ -241,25 +239,15 @@ public class SignedConfigTest { assertThat(mapOf(null, "allitnil")).containsExactly(null, "allitnil"); assertThat(mapOf(null, "allitnil").containsKey(null)).isTrue(); JSONObject json = new JSONObject( - "{\"minSdk\": 1, \"maxSdk\": 1, \"values\": [{\"key\":\"a\", \"value\": null}]}"); + "{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": {\"a\": null}}"); SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig(json, setOf("a"), mapOf("a", mapOf(null, "allitnil"))); assertThat(config.values).containsExactly("a", "allitnil"); } @Test - public void testParsePerSdkConfigSingleKeyNoValue() - throws JSONException, InvalidConfigException { - JSONObject json = new JSONObject( - "{\"minSdk\": 1, \"maxSdk\": 1, \"values\": [{\"key\":\"a\"}]}"); - SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig(json, setOf("a", "b"), - emptyMap()); - assertThat(config.values).containsExactly("a", null); - } - - @Test public void testParsePerSdkConfigValuesInvalid() throws JSONException { - JSONObject json = new JSONObject("{\"minSdk\": 1, \"maxSdk\": 1, \"values\": \"foo\"}"); + JSONObject json = new JSONObject("{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": \"foo\"}"); try { SignedConfig.parsePerSdkConfig(json, emptySet(), emptyMap()); fail("Expected InvalidConfigException or JSONException"); @@ -270,18 +258,7 @@ public class SignedConfigTest { @Test public void testParsePerSdkConfigConfigEntryInvalid() throws JSONException { - JSONObject json = new JSONObject("{\"minSdk\": 1, \"maxSdk\": 1, \"values\": [1, 2]}"); - try { - SignedConfig.parsePerSdkConfig(json, emptySet(), emptyMap()); - fail("Expected InvalidConfigException or JSONException"); - } catch (JSONException | InvalidConfigException e) { - // expected - } - } - - @Test - public void testParsePerSdkConfigConfigEntryNull() throws JSONException { - JSONObject json = new JSONObject("{\"minSdk\": 1, \"maxSdk\": 1, \"values\": [null]}"); + JSONObject json = new JSONObject("{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": [1, 2]}"); try { SignedConfig.parsePerSdkConfig(json, emptySet(), emptyMap()); fail("Expected InvalidConfigException or JSONException"); @@ -361,7 +338,7 @@ public class SignedConfigTest { @Test public void testParseSdkConfigSingle() throws InvalidConfigException { SignedConfig config = SignedConfig.parse( - "{\"version\": 1, \"config\":[{\"minSdk\": 1, \"maxSdk\": 1, \"values\": []}]}", + "{\"version\": 1, \"config\":[{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": {}}]}", emptySet(), emptyMap()); assertThat(config.perSdkConfig).hasSize(1); } @@ -369,8 +346,8 @@ public class SignedConfigTest { @Test public void testParseSdkConfigMultiple() throws InvalidConfigException { SignedConfig config = SignedConfig.parse( - "{\"version\": 1, \"config\":[{\"minSdk\": 1, \"maxSdk\": 1, \"values\": []}, " - + "{\"minSdk\": 2, \"maxSdk\": 2, \"values\": []}]}", emptySet(), + "{\"version\": 1, \"config\":[{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": {}}, " + + "{\"min_sdk\": 2, \"max_sdk\": 2, \"values\": {}}]}", emptySet(), emptyMap()); assertThat(config.perSdkConfig).hasSize(2); } diff --git a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java index bf7f53dd7d8f..860656bf47f4 100644 --- a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java +++ b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java @@ -16,6 +16,8 @@ package com.android.server.usage; +import static android.app.usage.UsageEvents.Event.MAX_EVENT_TYPE; + import static junit.framework.TestCase.fail; import static org.testng.Assert.assertEquals; @@ -136,9 +138,11 @@ public class UsageStatsDatabaseTest { event.mFlags |= Event.FLAG_IS_PACKAGE_INSTANT_APP; } - event.mClass = ".fake.class.name" + i % 11; + final int instanceId = i % 11; + event.mClass = ".fake.class.name" + instanceId; event.mTimeStamp = time; - event.mEventType = i % 19; //"random" event type + event.mEventType = i % (MAX_EVENT_TYPE + 1); //"random" event type + event.mInstanceId = instanceId; switch (event.mEventType) { case Event.CONFIGURATION_CHANGE: @@ -160,7 +164,8 @@ public class UsageStatsDatabaseTest { } mIntervalStats.events.insert(event); - mIntervalStats.update(event.mPackage, event.mClass, event.mTimeStamp, event.mEventType); + mIntervalStats.update(event.mPackage, event.mClass, event.mTimeStamp, event.mEventType, + event.mInstanceId); time += timeProgression; // Arbitrary progression of time } @@ -219,7 +224,9 @@ public class UsageStatsDatabaseTest { // mBeginTimeStamp is based on the enclosing IntervalStats, don't bother checking // mEndTimeStamp is based on the enclosing IntervalStats, don't bother checking assertEquals(us1.mLastTimeUsed, us2.mLastTimeUsed); + assertEquals(us1.mLastTimeVisible, us2.mLastTimeVisible); assertEquals(us1.mTotalTimeInForeground, us2.mTotalTimeInForeground); + assertEquals(us1.mTotalTimeVisible, us2.mTotalTimeVisible); assertEquals(us1.mLastTimeForegroundServiceUsed, us2.mLastTimeForegroundServiceUsed); assertEquals(us1.mTotalTimeForegroundServiceUsed, us2.mTotalTimeForegroundServiceUsed); // mLaunchCount not persisted, so skipped diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java index f6871b3182ca..85410f5e14df 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -82,17 +82,17 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testEmptyTaskCleanupOnRemove() { - assertNotNull(mTask.getWindowContainerController()); + assertNotNull(mTask.getTask()); mStack.removeTask(mTask, "testEmptyTaskCleanupOnRemove", REMOVE_TASK_MODE_DESTROYING); - assertNull(mTask.getWindowContainerController()); + assertNull(mTask.getTask()); } @Test public void testOccupiedTaskCleanupOnRemove() { final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build(); - assertNotNull(mTask.getWindowContainerController()); + assertNotNull(mTask.getTask()); mStack.removeTask(mTask, "testOccupiedTaskCleanupOnRemove", REMOVE_TASK_MODE_DESTROYING); - assertNotNull(mTask.getWindowContainerController()); + assertNotNull(mTask.getTask()); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index f553c35071a4..569c6d4af37d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -345,7 +345,7 @@ class ActivityTestsBase { mStack.moveToFront("test"); mStack.addTask(task, true, "creating test task"); task.setStack(mStack); - task.setWindowContainerController(); + task.setTask(); } task.touchActiveTime(); @@ -361,12 +361,12 @@ class ActivityTestsBase { } @Override - void createWindowContainer(boolean onTop, boolean showForAllUsers) { - setWindowContainerController(); + void createTask(boolean onTop, boolean showForAllUsers) { + setTask(); } - private void setWindowContainerController() { - setWindowContainerController(mock(TaskWindowContainerController.class)); + private void setTask() { + setTask(mock(Task.class)); } } } @@ -447,7 +447,11 @@ class ActivityTestsBase { } @Override - void updateUsageStats(ActivityRecord component, boolean resumed) { + void updateBatteryStats(ActivityRecord component, boolean resumed) { + } + + @Override + void updateActivityUsageStats(ActivityRecord activity, int event) { } @Override diff --git a/services/tests/wmtests/src/com/android/server/wm/StackWindowControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/StackWindowControllerTests.java index ce5b13cab1a7..5690b58737ab 100644 --- a/services/tests/wmtests/src/com/android/server/wm/StackWindowControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/StackWindowControllerTests.java @@ -41,17 +41,14 @@ public class StackWindowControllerTests extends WindowTestsBase { public void testRemoveContainer() { final StackWindowController stackController = createStackControllerOnDisplay(mDisplayContent); - final WindowTestUtils.TestTaskWindowContainerController taskController = - new WindowTestUtils.TestTaskWindowContainerController(stackController); + final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController); final TaskStack stack = stackController.mContainer; - final Task task = taskController.mContainer; assertNotNull(stack); assertNotNull(task); stackController.removeContainer(); // Assert that the container was removed. assertNull(stackController.mContainer); - assertNull(taskController.mContainer); assertNull(stack.getDisplayContent()); assertNull(task.getDisplayContent()); assertNull(task.mStack); @@ -61,11 +58,9 @@ public class StackWindowControllerTests extends WindowTestsBase { public void testRemoveContainer_deferRemoval() { final StackWindowController stackController = createStackControllerOnDisplay(mDisplayContent); - final WindowTestUtils.TestTaskWindowContainerController taskController = - new WindowTestUtils.TestTaskWindowContainerController(stackController); + final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController); final TaskStack stack = stackController.mContainer; - final WindowTestUtils.TestTask task = (WindowTestUtils.TestTask) taskController.mContainer; // Stack removal is deferred if one of its child is animating. task.setLocalIsAnimating(true); @@ -75,11 +70,12 @@ public class StackWindowControllerTests extends WindowTestsBase { // the stack window container is removed. assertNull(stackController.mContainer); assertNull(stack.getController()); - assertNotNull(taskController.mContainer); - assertNotNull(task.getController()); + assertNotNull(task); stack.removeImmediately(); - assertNull(taskController.mContainer); + // After removing, the task will be isolated. + assertNull(task.getParent()); + assertEquals(task.getChildCount(), 0); assertNull(task.getController()); } @@ -89,9 +85,7 @@ public class StackWindowControllerTests extends WindowTestsBase { final StackWindowController stack1Controller = createStackControllerOnDisplay(mDisplayContent); final TaskStack stack1 = stack1Controller.mContainer; - final WindowTestUtils.TestTaskWindowContainerController taskController = - new WindowTestUtils.TestTaskWindowContainerController(stack1Controller); - final WindowTestUtils.TestTask task1 = (WindowTestUtils.TestTask) taskController.mContainer; + final WindowTestUtils.TestTask task1 = WindowTestUtils.createTestTask(stack1Controller); task1.mOnDisplayChangedCalled = false; // Create second display and put second stack on it. diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java new file mode 100644 index 000000000000..3e32ed37a6f3 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +/** + * Test class for {@link Task}. + * + * Build/Install/Run: + * atest FrameworksServicesTests:TaskTests + */ +@SmallTest +@Presubmit +public class TaskTests extends WindowTestsBase { + + @Test + public void testRemoveContainer() { + final StackWindowController stackController1 = + createStackControllerOnDisplay(mDisplayContent); + final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController1); + final WindowTestUtils.TestAppWindowToken appToken = + WindowTestUtils.createAppWindowTokenInTask(mDisplayContent, task); + + task.removeIfPossible(); + // Assert that the container was removed. + assertNull(task.getParent()); + assertEquals(task.getChildCount(), 0); + assertNull(appToken.getParent()); + } + + @Test + public void testRemoveContainer_deferRemoval() { + final StackWindowController stackController1 = + createStackControllerOnDisplay(mDisplayContent); + final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController1); + final WindowTestUtils.TestAppWindowToken appToken = + WindowTestUtils.createAppWindowTokenInTask(mDisplayContent, task); + + task.mShouldDeferRemoval = true; + + task.removeIfPossible(); + // For the case of deferred removal the task will still be connected to the its app token + // until the task window container is removed. + assertNotNull(task.getParent()); + assertNotEquals(task.getChildCount(), 0); + assertNotNull(appToken.getParent()); + + task.removeImmediately(); + assertNull(task.getParent()); + assertEquals(task.getChildCount(), 0); + assertNull(appToken.getParent()); + } + + @Test + public void testReparent() { + final StackWindowController stackController1 = + createStackControllerOnDisplay(mDisplayContent); + final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController1); + final StackWindowController stackController2 = + createStackControllerOnDisplay(mDisplayContent); + final WindowTestUtils.TestTask task2 = WindowTestUtils.createTestTask(stackController2); + + boolean gotException = false; + try { + task.reparent(stackController1, 0, false/* moveParents */); + } catch (IllegalArgumentException e) { + gotException = true; + } + assertTrue("Should not be able to reparent to the same parent", gotException); + + final StackWindowController stackController3 = + createStackControllerOnDisplay(mDisplayContent); + stackController3.setContainer(null); + gotException = false; + try { + task.reparent(stackController3, 0, false/* moveParents */); + } catch (IllegalArgumentException e) { + gotException = true; + } + assertTrue("Should not be able to reparent to a stack that doesn't have a container", + gotException); + + task.reparent(stackController2, 0, false/* moveParents */); + assertEquals(stackController2.mContainer, task.getParent()); + assertEquals(0, task.positionInParent()); + assertEquals(1, task2.positionInParent()); + } + + @Test + public void testReparent_BetweenDisplays() { + // Create first stack on primary display. + final StackWindowController stack1Controller = + createStackControllerOnDisplay(mDisplayContent); + final TaskStack stack1 = stack1Controller.mContainer; + final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack1Controller); + task.mOnDisplayChangedCalled = false; + assertEquals(mDisplayContent, stack1.getDisplayContent()); + + // Create second display and put second stack on it. + final DisplayContent dc = createNewDisplay(); + final StackWindowController stack2Controller = createStackControllerOnDisplay(dc); + final TaskStack stack2 = stack2Controller.mContainer; + final WindowTestUtils.TestTask task2 = WindowTestUtils.createTestTask(stack2Controller); + // Reparent and check state + task.reparent(stack2Controller, 0, false /* moveParents */); + assertEquals(stack2, task.getParent()); + assertEquals(0, task.positionInParent()); + assertEquals(1, task2.positionInParent()); + assertTrue(task.mOnDisplayChangedCalled); + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskWindowContainerControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskWindowContainerControllerTests.java deleted file mode 100644 index bbf508dd1630..000000000000 --- a/services/tests/wmtests/src/com/android/server/wm/TaskWindowContainerControllerTests.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.wm; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import android.platform.test.annotations.Presubmit; - -import androidx.test.filters.SmallTest; - -import org.junit.Test; - -/** - * Test class for {@link TaskWindowContainerController}. - * - * Build/Install/Run: - * atest FrameworksServicesTests:TaskWindowContainerControllerTests - */ -@SmallTest -@Presubmit -public class TaskWindowContainerControllerTests extends WindowTestsBase { - - /* Comment out due to removal of AppWindowContainerController - @Test - public void testRemoveContainer() { - final WindowTestUtils.TestTaskWindowContainerController taskController = - new WindowTestUtils.TestTaskWindowContainerController(this); - final WindowTestUtils.TestAppWindowContainerController appController = - new WindowTestUtils.TestAppWindowContainerController(taskController); - - taskController.removeContainer(); - // Assert that the container was removed. - assertNull(taskController.mContainer); - assertNull(appController.mContainer); - } - */ - - /* Comment out due to removal of AppWindowContainerController - @Test - public void testRemoveContainer_deferRemoval() { - final WindowTestUtils.TestTaskWindowContainerController taskController = - new WindowTestUtils.TestTaskWindowContainerController(this); - final WindowTestUtils.TestAppWindowContainerController appController = - new WindowTestUtils.TestAppWindowContainerController(taskController); - - final WindowTestUtils.TestTask task = (WindowTestUtils.TestTask) taskController.mContainer; - final AppWindowToken app = appController.mContainer; - task.mShouldDeferRemoval = true; - - taskController.removeContainer(); - // For the case of deferred removal the task controller will no longer be connected to the - // container, but the app controller will still be connected to the its container until - // the task window container is removed. - assertNull(taskController.mContainer); - assertNull(task.getController()); - assertNotNull(appController.mContainer); - assertNotNull(app.getController()); - - task.removeImmediately(); - assertNull(appController.mContainer); - assertNull(app.getController()); - } - */ - - @Test - public void testReparent() { - final StackWindowController stackController1 = - createStackControllerOnDisplay(mDisplayContent); - final WindowTestUtils.TestTaskWindowContainerController taskController = - new WindowTestUtils.TestTaskWindowContainerController(stackController1); - final StackWindowController stackController2 = - createStackControllerOnDisplay(mDisplayContent); - final WindowTestUtils.TestTaskWindowContainerController taskController2 = - new WindowTestUtils.TestTaskWindowContainerController(stackController2); - - boolean gotException = false; - try { - taskController.reparent(stackController1, 0, false/* moveParents */); - } catch (IllegalArgumentException e) { - gotException = true; - } - assertTrue("Should not be able to reparent to the same parent", gotException); - - final StackWindowController stackController3 = - createStackControllerOnDisplay(mDisplayContent); - stackController3.setContainer(null); - gotException = false; - try { - taskController.reparent(stackController3, 0, false/* moveParents */); - } catch (IllegalArgumentException e) { - gotException = true; - } - assertTrue("Should not be able to reparent to a stack that doesn't have a container", - gotException); - - taskController.reparent(stackController2, 0, false/* moveParents */); - assertEquals(stackController2.mContainer, taskController.mContainer.getParent()); - assertEquals(0, ((WindowTestUtils.TestTask) taskController.mContainer).positionInParent()); - assertEquals(1, ((WindowTestUtils.TestTask) taskController2.mContainer).positionInParent()); - } - - @Test - public void testReparent_BetweenDisplays() { - // Create first stack on primary display. - final StackWindowController stack1Controller = - createStackControllerOnDisplay(mDisplayContent); - final TaskStack stack1 = stack1Controller.mContainer; - final WindowTestUtils.TestTaskWindowContainerController taskController = - new WindowTestUtils.TestTaskWindowContainerController(stack1Controller); - final WindowTestUtils.TestTask task1 = (WindowTestUtils.TestTask) taskController.mContainer; - task1.mOnDisplayChangedCalled = false; - assertEquals(mDisplayContent, stack1.getDisplayContent()); - - // Create second display and put second stack on it. - final DisplayContent dc = createNewDisplay(); - final StackWindowController stack2Controller = createStackControllerOnDisplay(dc); - final TaskStack stack2 = stack2Controller.mContainer; - final WindowTestUtils.TestTaskWindowContainerController taskController2 = - new WindowTestUtils.TestTaskWindowContainerController(stack2Controller); - final WindowTestUtils.TestTask task2 = - (WindowTestUtils.TestTask) taskController2.mContainer; - - // Reparent and check state - taskController.reparent(stack2Controller, 0, false /* moveParents */); - assertEquals(stack2, task1.getParent()); - assertEquals(0, task1.positionInParent()); - assertEquals(1, task2.positionInParent()); - assertTrue(task1.mOnDisplayChangedCalled); - } -} diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java index 65e18354a5ae..3170f5adf6c3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java @@ -141,6 +141,13 @@ public class WindowTestUtils { } } + /** Creates an {@link AppWindowToken} and adds it to the specified {@link Task}. */ + public static TestAppWindowToken createAppWindowTokenInTask(DisplayContent dc, Task task) { + final TestAppWindowToken newToken = createTestAppWindowToken(dc); + task.addChild(newToken, POSITION_TOP); + return newToken; + } + /** * An extension of {@link TestTaskStack}, which overrides package scoped methods that would not * normally be mocked out. @@ -264,9 +271,10 @@ public class WindowTestUtils { TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, int resizeMode, boolean supportsPictureInPicture, - TaskWindowContainerController controller) { + TaskRecord taskRecord) { super(taskId, stack, userId, service, resizeMode, supportsPictureInPicture, - new ActivityManager.TaskDescription(), controller); + new ActivityManager.TaskDescription(), taskRecord); + stack.addTask(this, POSITION_TOP); } boolean shouldDeferRemoval() { @@ -293,49 +301,10 @@ public class WindowTestUtils { } } - /** - * Used so we can gain access to some protected members of {@link TaskWindowContainerController} - * class. - */ - public static class TestTaskWindowContainerController extends TaskWindowContainerController { - - static final TaskWindowContainerListener NOP_LISTENER = new TaskWindowContainerListener() { - @Override - public void registerConfigurationChangeListener( - ConfigurationContainerListener listener) { - } - - @Override - public void unregisterConfigurationChangeListener( - ConfigurationContainerListener listener) { - } - - @Override - public void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) { - } - - @Override - public void requestResize(Rect bounds, int resizeMode) { - } - }; - - TestTaskWindowContainerController(WindowTestsBase testsBase) { - this(testsBase.createStackControllerOnDisplay(testsBase.mDisplayContent)); - } - - TestTaskWindowContainerController(StackWindowController stackController) { - super(sNextTaskId++, NOP_LISTENER, stackController, 0 /* userId */, null /* bounds */, - RESIZE_MODE_UNRESIZEABLE, false /* supportsPictureInPicture */, true /* toTop*/, - true /* showForAllUsers */, new ActivityManager.TaskDescription(), - stackController.mService); - } - - @Override - TestTask createTask(int taskId, TaskStack stack, int userId, int resizeMode, - boolean supportsPictureInPicture, ActivityManager.TaskDescription taskDescription) { - return new TestTask(taskId, stack, userId, mService, resizeMode, - supportsPictureInPicture, this); - } + public static TestTask createTestTask(StackWindowController stackWindowController) { + return new TestTask(sNextTaskId++, stackWindowController.mContainer, 0, + stackWindowController.mService, RESIZE_MODE_UNRESIZEABLE, false, + mock(TaskRecord.class)); } public static class TestIApplicationToken implements IApplicationToken { diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java index 4f573a475ae7..65ed85db17bd 100644 --- a/services/usage/java/com/android/server/usage/AppStandbyController.java +++ b/services/usage/java/com/android/server/usage/AppStandbyController.java @@ -842,8 +842,8 @@ public class AppStandbyController { final boolean previouslyIdle = mAppIdleHistory.isIdle( event.mPackage, userId, elapsedRealtime); // Inform listeners if necessary - if ((event.mEventType == UsageEvents.Event.MOVE_TO_FOREGROUND - || event.mEventType == UsageEvents.Event.MOVE_TO_BACKGROUND + if ((event.mEventType == UsageEvents.Event.ACTIVITY_RESUMED + || event.mEventType == UsageEvents.Event.ACTIVITY_PAUSED || event.mEventType == UsageEvents.Event.SYSTEM_INTERACTION || event.mEventType == UsageEvents.Event.USER_INTERACTION || event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN @@ -894,8 +894,8 @@ public class AppStandbyController { private int usageEventToSubReason(int eventType) { switch (eventType) { - case UsageEvents.Event.MOVE_TO_FOREGROUND: return REASON_SUB_USAGE_MOVE_TO_FOREGROUND; - case UsageEvents.Event.MOVE_TO_BACKGROUND: return REASON_SUB_USAGE_MOVE_TO_BACKGROUND; + case UsageEvents.Event.ACTIVITY_RESUMED: return REASON_SUB_USAGE_MOVE_TO_FOREGROUND; + case UsageEvents.Event.ACTIVITY_PAUSED: return REASON_SUB_USAGE_MOVE_TO_BACKGROUND; case UsageEvents.Event.SYSTEM_INTERACTION: return REASON_SUB_USAGE_SYSTEM_INTERACTION; case UsageEvents.Event.USER_INTERACTION: return REASON_SUB_USAGE_USER_INTERACTION; case UsageEvents.Event.NOTIFICATION_SEEN: return REASON_SUB_USAGE_NOTIFICATION_SEEN; diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java index 84052672f6d3..94cc6502a12d 100644 --- a/services/usage/java/com/android/server/usage/IntervalStats.java +++ b/services/usage/java/com/android/server/usage/IntervalStats.java @@ -15,10 +15,31 @@ */ package com.android.server.usage; +import static android.app.usage.UsageEvents.Event.ACTIVITY_DESTROYED; +import static android.app.usage.UsageEvents.Event.ACTIVITY_PAUSED; +import static android.app.usage.UsageEvents.Event.ACTIVITY_RESUMED; +import static android.app.usage.UsageEvents.Event.ACTIVITY_STOPPED; +import static android.app.usage.UsageEvents.Event.CONFIGURATION_CHANGE; +import static android.app.usage.UsageEvents.Event.CONTINUE_PREVIOUS_DAY; +import static android.app.usage.UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE; +import static android.app.usage.UsageEvents.Event.END_OF_DAY; +import static android.app.usage.UsageEvents.Event.FLUSH_TO_DISK; +import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_START; +import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_STOP; +import static android.app.usage.UsageEvents.Event.KEYGUARD_HIDDEN; +import static android.app.usage.UsageEvents.Event.KEYGUARD_SHOWN; +import static android.app.usage.UsageEvents.Event.NOTIFICATION_INTERRUPTION; +import static android.app.usage.UsageEvents.Event.ROLLOVER_FOREGROUND_SERVICE; +import static android.app.usage.UsageEvents.Event.SCREEN_INTERACTIVE; +import static android.app.usage.UsageEvents.Event.SCREEN_NON_INTERACTIVE; +import static android.app.usage.UsageEvents.Event.SHORTCUT_INVOCATION; +import static android.app.usage.UsageEvents.Event.STANDBY_BUCKET_CHANGED; +import static android.app.usage.UsageEvents.Event.SYSTEM_INTERACTION; + import android.app.usage.ConfigurationStats; import android.app.usage.EventList; import android.app.usage.EventStats; -import android.app.usage.UsageEvents; +import android.app.usage.UsageEvents.Event; import android.app.usage.UsageStats; import android.content.res.Configuration; import android.util.ArrayMap; @@ -125,8 +146,8 @@ public class IntervalStats { /** * Builds a UsageEvents.Event, but does not add it internally. */ - UsageEvents.Event buildEvent(String packageName, String className) { - UsageEvents.Event event = new UsageEvents.Event(); + Event buildEvent(String packageName, String className) { + Event event = new Event(); event.mPackage = getCachedStringRef(packageName); if (className != null) { event.mClass = getCachedStringRef(className); @@ -138,9 +159,9 @@ public class IntervalStats { * Builds a UsageEvents.Event from a proto, but does not add it internally. * Built here to take advantage of the cached String Refs */ - UsageEvents.Event buildEvent(ProtoInputStream parser, List<String> stringPool) + Event buildEvent(ProtoInputStream parser, List<String> stringPool) throws IOException { - final UsageEvents.Event event = new UsageEvents.Event(); + final Event event = new Event(); while (true) { switch (parser.nextField()) { case (int) IntervalStatsProto.Event.PACKAGE: @@ -190,20 +211,23 @@ public class IntervalStats { parser.readInt(IntervalStatsProto.Event.NOTIFICATION_CHANNEL_INDEX) - 1)); break; + case (int) IntervalStatsProto.Event.INSTANCE_ID: + event.mInstanceId = parser.readInt(IntervalStatsProto.Event.INSTANCE_ID); + break; case ProtoInputStream.NO_MORE_FIELDS: // Handle default values for certain events types switch (event.mEventType) { - case UsageEvents.Event.CONFIGURATION_CHANGE: + case CONFIGURATION_CHANGE: if (event.mConfiguration == null) { event.mConfiguration = new Configuration(); } break; - case UsageEvents.Event.SHORTCUT_INVOCATION: + case SHORTCUT_INVOCATION: if (event.mShortcutId == null) { event.mShortcutId = ""; } break; - case UsageEvents.Event.NOTIFICATION_INTERRUPTION: + case NOTIFICATION_INTERRUPTION: if (event.mNotificationChannelId == null) { event.mNotificationChannelId = ""; } @@ -220,14 +244,15 @@ public class IntervalStats { private boolean isStatefulEvent(int eventType) { switch (eventType) { - case UsageEvents.Event.MOVE_TO_FOREGROUND: - case UsageEvents.Event.MOVE_TO_BACKGROUND: - case UsageEvents.Event.FOREGROUND_SERVICE_START: - case UsageEvents.Event.FOREGROUND_SERVICE_STOP: - case UsageEvents.Event.END_OF_DAY: - case UsageEvents.Event.ROLLOVER_FOREGROUND_SERVICE: - case UsageEvents.Event.CONTINUE_PREVIOUS_DAY: - case UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE: + case ACTIVITY_RESUMED: + case ACTIVITY_PAUSED: + case ACTIVITY_STOPPED: + case FOREGROUND_SERVICE_START: + case FOREGROUND_SERVICE_STOP: + case END_OF_DAY: + case ROLLOVER_FOREGROUND_SERVICE: + case CONTINUE_PREVIOUS_DAY: + case CONTINUING_FOREGROUND_SERVICE: return true; } return false; @@ -238,17 +263,56 @@ public class IntervalStats { * interaction. Excludes those that are internally generated. */ private boolean isUserVisibleEvent(int eventType) { - return eventType != UsageEvents.Event.SYSTEM_INTERACTION - && eventType != UsageEvents.Event.STANDBY_BUCKET_CHANGED; + return eventType != SYSTEM_INTERACTION + && eventType != STANDBY_BUCKET_CHANGED; } /** + * Update the IntervalStats by a activity or foreground service event. + * @param packageName package name of this event. Is null if event targets to all packages. + * @param className class name of a activity or foreground service, could be null to if this + * is sent to all activities/services in this package. + * @param timeStamp Epoch timestamp in milliseconds. + * @param eventType event type as in {@link Event} + * @param instanceId if className is an activity, the hashCode of ActivityRecord's appToken. + * if className is not an activity, instanceId is not used. * @hide */ @VisibleForTesting - public void update(String packageName, String className, long timeStamp, int eventType) { - UsageStats usageStats = getOrCreateUsageStats(packageName); - usageStats.update(className, timeStamp, eventType); + public void update(String packageName, String className, long timeStamp, int eventType, + int instanceId) { + if (eventType == FLUSH_TO_DISK) { + // FLUSH_TO_DISK are sent to all packages. + final int size = packageStats.size(); + for (int i = 0; i < size; i++) { + UsageStats usageStats = packageStats.valueAt(i); + usageStats.update(null, timeStamp, eventType, instanceId); + } + } else if (eventType == ACTIVITY_DESTROYED) { + UsageStats usageStats = packageStats.get(packageName); + if (usageStats != null) { + // If previous event is not ACTIVITY_STOPPED, convert ACTIVITY_DESTROYED + // to ACTIVITY_STOPPED and add to event list. + // Otherwise do not add anything to event list. (Because we want to save space + // and we do not want a ACTIVITY_STOPPED followed by + // ACTIVITY_DESTROYED in event list). + final int index = usageStats.mActivities.indexOfKey(instanceId); + if (index >= 0) { + final int type = usageStats.mActivities.valueAt(index); + if (type != ACTIVITY_STOPPED) { + Event event = new Event(ACTIVITY_STOPPED, timeStamp); + event.mPackage = packageName; + event.mClass = className; + event.mInstanceId = instanceId; + addEvent(event); + } + } + usageStats.update(className, timeStamp, ACTIVITY_DESTROYED, instanceId); + } + } else { + UsageStats usageStats = getOrCreateUsageStats(packageName); + usageStats.update(className, timeStamp, eventType, instanceId); + } endTime = timeStamp; } @@ -256,7 +320,7 @@ public class IntervalStats { * @hide */ @VisibleForTesting - public void addEvent(UsageEvents.Event event) { + public void addEvent(Event event) { if (events == null) { events = new EventList(); } @@ -265,7 +329,7 @@ public class IntervalStats { if (event.mClass != null) { event.mClass = getCachedStringRef(event.mClass); } - if (event.mEventType == UsageEvents.Event.NOTIFICATION_INTERRUPTION) { + if (event.mEventType == NOTIFICATION_INTERRUPTION) { event.mNotificationChannelId = getCachedStringRef(event.mNotificationChannelId); } events.insert(event); @@ -338,13 +402,13 @@ public class IntervalStats { } void addEventStatsTo(List<EventStats> out) { - interactiveTracker.addToEventStats(out, UsageEvents.Event.SCREEN_INTERACTIVE, + interactiveTracker.addToEventStats(out, SCREEN_INTERACTIVE, beginTime, endTime); - nonInteractiveTracker.addToEventStats(out, UsageEvents.Event.SCREEN_NON_INTERACTIVE, + nonInteractiveTracker.addToEventStats(out, SCREEN_NON_INTERACTIVE, beginTime, endTime); - keyguardShownTracker.addToEventStats(out, UsageEvents.Event.KEYGUARD_SHOWN, + keyguardShownTracker.addToEventStats(out, KEYGUARD_SHOWN, beginTime, endTime); - keyguardHiddenTracker.addToEventStats(out, UsageEvents.Event.KEYGUARD_HIDDEN, + keyguardHiddenTracker.addToEventStats(out, KEYGUARD_HIDDEN, beginTime, endTime); } diff --git a/services/usage/java/com/android/server/usage/UsageStatsProto.java b/services/usage/java/com/android/server/usage/UsageStatsProto.java index 8e1c06091605..d70653781eff 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsProto.java +++ b/services/usage/java/com/android/server/usage/UsageStatsProto.java @@ -135,6 +135,15 @@ final class UsageStatsProto { stats.mTotalTimeForegroundServiceUsed = proto.readLong( IntervalStatsProto.UsageStats.TOTAL_TIME_SERVICE_USED_MS); break; + case (int) IntervalStatsProto.UsageStats.LAST_TIME_VISIBLE_MS: + // Time attributes stored is an offset of the beginTime. + stats.mLastTimeVisible = statsOut.beginTime + proto.readLong( + IntervalStatsProto.UsageStats.LAST_TIME_VISIBLE_MS); + break; + case (int) IntervalStatsProto.UsageStats.TOTAL_TIME_VISIBLE_MS: + stats.mTotalTimeVisible = proto.readLong( + IntervalStatsProto.UsageStats.TOTAL_TIME_VISIBLE_MS); + break; } } if (stats.mLastTimeUsed == 0) { @@ -337,6 +346,11 @@ final class UsageStatsProto { usageStats.mLastTimeForegroundServiceUsed - stats.beginTime); proto.write(IntervalStatsProto.UsageStats.TOTAL_TIME_SERVICE_USED_MS, usageStats.mTotalTimeForegroundServiceUsed); + // Time attributes stored as an offset of the beginTime. + proto.write(IntervalStatsProto.UsageStats.LAST_TIME_VISIBLE_MS, + usageStats.mLastTimeVisible - stats.beginTime); + proto.write(IntervalStatsProto.UsageStats.TOTAL_TIME_VISIBLE_MS, + usageStats.mTotalTimeVisible); proto.write(IntervalStatsProto.UsageStats.APP_LAUNCH_COUNT, usageStats.mAppLaunchCount); writeChooserCounts(proto, usageStats); proto.end(token); @@ -427,6 +441,7 @@ final class UsageStatsProto { proto.write(IntervalStatsProto.Event.TIME_MS, event.mTimeStamp - stats.beginTime); proto.write(IntervalStatsProto.Event.FLAGS, event.mFlags); proto.write(IntervalStatsProto.Event.TYPE, event.mEventType); + proto.write(IntervalStatsProto.Event.INSTANCE_ID, event.mInstanceId); switch (event.mEventType) { case UsageEvents.Event.CONFIGURATION_CHANGE: if (event.mConfiguration != null) { diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 262125212c14..57dc08fcd253 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -16,6 +16,12 @@ package com.android.server.usage; +import static android.app.usage.UsageEvents.Event.CHOOSER_ACTION; +import static android.app.usage.UsageEvents.Event.CONFIGURATION_CHANGE; +import static android.app.usage.UsageEvents.Event.FLUSH_TO_DISK; +import static android.app.usage.UsageEvents.Event.NOTIFICATION_INTERRUPTION; +import static android.app.usage.UsageEvents.Event.SHORTCUT_INVOCATION; + import android.Manifest; import android.app.ActivityManager; import android.app.AppOpsManager; @@ -28,10 +34,10 @@ 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; -import android.app.usage.UsageStatsManager.StandbyBuckets; import android.app.usage.UsageEvents.Event; import android.app.usage.UsageStats; +import android.app.usage.UsageStatsManager; +import android.app.usage.UsageStatsManager.StandbyBuckets; import android.app.usage.UsageStatsManagerInternal; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -75,9 +81,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.Arrays; import java.util.List; -import java.util.Map; import java.util.Set; -import java.util.concurrent.TimeUnit; /** * A service that collects, aggregates, and persists application usage data. @@ -106,6 +110,7 @@ public class UsageStatsService extends SystemService implements static final int MSG_FLUSH_TO_DISK = 1; static final int MSG_REMOVE_USER = 2; static final int MSG_UID_STATE_CHANGED = 3; + static final int MSG_REPORT_EVENT_TO_ALL_USERID = 4; private final Object mLock = new Object(); Handler mHandler; @@ -135,12 +140,10 @@ public class UsageStatsService extends SystemService implements @Override public void onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket, int reason) { - Event event = new Event(); - event.mEventType = Event.STANDBY_BUCKET_CHANGED; + Event event = new Event(Event.STANDBY_BUCKET_CHANGED, + SystemClock.elapsedRealtime()); event.mBucketAndReason = (bucket << 16) | (reason & 0xFFFF); event.mPackage = packageName; - // This will later be converted to system time. - event.mTimeStamp = SystemClock.elapsedRealtime(); mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget(); } @@ -397,7 +400,7 @@ public class UsageStatsService extends SystemService implements * Assuming the event's timestamp is measured in milliseconds since boot, * convert it to a system wall time. */ - private void convertToSystemTimeLocked(UsageEvents.Event event) { + private void convertToSystemTimeLocked(Event event) { event.mTimeStamp = Math.max(0, event.mTimeStamp - mRealTimeSnapshot) + mSystemTimeSnapshot; } @@ -406,7 +409,6 @@ public class UsageStatsService extends SystemService implements */ void shutdown() { synchronized (mLock) { - mHandler.removeMessages(MSG_REPORT_EVENT); flushToDiskLocked(); } } @@ -414,7 +416,7 @@ public class UsageStatsService extends SystemService implements /** * Called by the Binder stub. */ - void reportEvent(UsageEvents.Event event, int userId) { + void reportEvent(Event event, int userId) { synchronized (mLock) { final long timeNow = checkAndGetTimeLocked(); final long elapsedRealtime = SystemClock.elapsedRealtime(); @@ -431,14 +433,14 @@ public class UsageStatsService extends SystemService implements mAppStandby.reportEvent(event, elapsedRealtime, userId); switch (event.mEventType) { - case Event.MOVE_TO_FOREGROUND: + case Event.ACTIVITY_RESUMED: try { mAppTimeLimit.noteUsageStart(event.getPackageName(), userId); } catch (IllegalArgumentException iae) { Slog.e(TAG, "Failed to note usage start", iae); } break; - case Event.MOVE_TO_BACKGROUND: + case Event.ACTIVITY_PAUSED: try { mAppTimeLimit.noteUsageStop(event.getPackageName(), userId); } catch (IllegalArgumentException iae) { @@ -450,10 +452,31 @@ public class UsageStatsService extends SystemService implements } /** - * Called by the Binder stub. + * Some events like FLUSH_TO_DISK need to be sent to all userId. + * @param event + */ + void reportEventToAllUserId(Event event) { + synchronized (mLock) { + final int userCount = mUserState.size(); + for (int i = 0; i < userCount; i++) { + Event copy = new Event(event); + reportEvent(copy, mUserState.keyAt(i)); + } + } + } + + /** + * Called by the Handler for message MSG_FLUSH_TO_DISK. */ void flushToDisk() { synchronized (mLock) { + // Before flush to disk, report FLUSH_TO_DISK event to signal UsageStats to update app + // usage. In case of abrupt power shutdown like battery drain or cold temperature, + // all UsageStats has correct data up to last flush to disk. + // The FLUSH_TO_DISK event is an internal event, it will not show up in IntervalStats' + // EventList. + Event event = new Event(FLUSH_TO_DISK, SystemClock.elapsedRealtime()); + reportEventToAllUserId(event); flushToDiskLocked(); } } @@ -656,9 +679,11 @@ public class UsageStatsService extends SystemService implements public void handleMessage(Message msg) { switch (msg.what) { case MSG_REPORT_EVENT: - reportEvent((UsageEvents.Event) msg.obj, msg.arg1); + reportEvent((Event) msg.obj, msg.arg1); + break; + case MSG_REPORT_EVENT_TO_ALL_USERID: + reportEventToAllUserId((Event) msg.obj); break; - case MSG_FLUSH_TO_DISK: flushToDisk(); break; @@ -1120,20 +1145,11 @@ public class UsageStatsService extends SystemService implements return; } - UsageEvents.Event event = new UsageEvents.Event(); + Event event = new Event(CHOOSER_ACTION, SystemClock.elapsedRealtime()); event.mPackage = packageName; - - // This will later be converted to system time. - event.mTimeStamp = SystemClock.elapsedRealtime(); - - event.mEventType = Event.CHOOSER_ACTION; - event.mAction = action; - event.mContentType = contentType; - event.mContentAnnotations = annotations; - mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget(); } @@ -1251,37 +1267,29 @@ public class UsageStatsService extends SystemService implements private final class LocalService extends UsageStatsManagerInternal { @Override - public void reportEvent(ComponentName component, int userId, int eventType) { + public void reportEvent(ComponentName component, int userId, int eventType, + int instanceId) { if (component == null) { Slog.w(TAG, "Event reported without a component name"); return; } - UsageEvents.Event event = new UsageEvents.Event(); + Event event = new Event(eventType, SystemClock.elapsedRealtime()); event.mPackage = component.getPackageName(); event.mClass = component.getClassName(); - - // This will later be converted to system time. - event.mTimeStamp = SystemClock.elapsedRealtime(); - - event.mEventType = eventType; + event.mInstanceId = instanceId; mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget(); } @Override public void reportEvent(String packageName, int userId, int eventType) { if (packageName == null) { - Slog.w(TAG, "Event reported without a package name"); + Slog.w(TAG, "Event reported without a package name, eventType:" + eventType); return; } - UsageEvents.Event event = new UsageEvents.Event(); + Event event = new Event(eventType, SystemClock.elapsedRealtime()); event.mPackage = packageName; - - // This will later be converted to system time. - event.mTimeStamp = SystemClock.elapsedRealtime(); - - event.mEventType = eventType; mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget(); } @@ -1292,13 +1300,8 @@ public class UsageStatsService extends SystemService implements return; } - UsageEvents.Event event = new UsageEvents.Event(); + Event event = new Event(CONFIGURATION_CHANGE, SystemClock.elapsedRealtime()); event.mPackage = "android"; - - // This will later be converted to system time. - event.mTimeStamp = SystemClock.elapsedRealtime(); - - event.mEventType = UsageEvents.Event.CONFIGURATION_CHANGE; event.mConfiguration = new Configuration(config); mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget(); } @@ -1311,14 +1314,9 @@ public class UsageStatsService extends SystemService implements return; } - UsageEvents.Event event = new UsageEvents.Event(); + Event event = new Event(NOTIFICATION_INTERRUPTION, SystemClock.elapsedRealtime()); event.mPackage = packageName.intern(); event.mNotificationChannelId = channelId.intern(); - - // This will later be converted to system time. - event.mTimeStamp = SystemClock.elapsedRealtime(); - - event.mEventType = Event.NOTIFICATION_INTERRUPTION; mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget(); } @@ -1329,14 +1327,9 @@ public class UsageStatsService extends SystemService implements return; } - UsageEvents.Event event = new UsageEvents.Event(); + Event event = new Event(SHORTCUT_INVOCATION, SystemClock.elapsedRealtime()); event.mPackage = packageName.intern(); event.mShortcutId = shortcutId.intern(); - - // This will later be converted to system time. - event.mTimeStamp = SystemClock.elapsedRealtime(); - - event.mEventType = Event.SHORTCUT_INVOCATION; mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget(); } @@ -1372,7 +1365,7 @@ public class UsageStatsService extends SystemService implements // This method *WILL* do IO work, but we must block until it is finished or else // we might not shutdown cleanly. This is ok to do with the 'am' lock held, because // we are shutting down. - shutdown(); + UsageStatsService.this.shutdown(); } @Override diff --git a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java index 01e566cdd85f..ec475bf26bb3 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java +++ b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java @@ -61,11 +61,13 @@ final class UsageStatsXmlV1 { private static final String FLAGS_ATTR = "flags"; private static final String CLASS_ATTR = "class"; private static final String TOTAL_TIME_ACTIVE_ATTR = "timeActive"; + private static final String TOTAL_TIME_VISIBLE_ATTR = "timeVisible"; private static final String TOTAL_TIME_SERVICE_USED_ATTR = "timeServiceUsed"; private static final String COUNT_ATTR = "count"; private static final String ACTIVE_ATTR = "active"; private static final String LAST_EVENT_ATTR = "lastEvent"; private static final String TYPE_ATTR = "type"; + private static final String INSTANCE_ID_ATTR = "instanceId"; private static final String SHORTCUT_ID_ATTR = "shortcutId"; private static final String STANDBY_BUCKET_ATTR = "standbyBucket"; private static final String APP_LAUNCH_COUNT_ATTR = "appLaunchCount"; @@ -75,6 +77,7 @@ final class UsageStatsXmlV1 { // Time attributes stored as an offset of the beginTime. private static final String LAST_TIME_ACTIVE_ATTR = "lastTimeActive"; + private static final String LAST_TIME_VISIBLE_ATTR = "lastTimeVisible"; private static final String LAST_TIME_SERVICE_USED_ATTR = "lastTimeServiceUsed"; private static final String END_TIME_ATTR = "endTime"; private static final String TIME_ATTR = "time"; @@ -92,6 +95,13 @@ final class UsageStatsXmlV1 { parser, LAST_TIME_ACTIVE_ATTR); try { + stats.mLastTimeVisible = statsOut.beginTime + XmlUtils.readLongAttribute( + parser, LAST_TIME_VISIBLE_ATTR); + } catch (IOException e) { + Log.e(TAG, "Failed to parse mLastTimeVisible", e); + } + + try { stats.mLastTimeForegroundServiceUsed = statsOut.beginTime + XmlUtils.readLongAttribute( parser, LAST_TIME_SERVICE_USED_ATTR); } catch (IOException e) { @@ -101,8 +111,14 @@ final class UsageStatsXmlV1 { stats.mTotalTimeInForeground = XmlUtils.readLongAttribute(parser, TOTAL_TIME_ACTIVE_ATTR); try { + stats.mTotalTimeVisible = XmlUtils.readLongAttribute(parser, TOTAL_TIME_VISIBLE_ATTR); + } catch (IOException e) { + Log.e(TAG, "Failed to parse mTotalTimeVisible", e); + } + + try { stats.mTotalTimeForegroundServiceUsed = XmlUtils.readLongAttribute(parser, - TOTAL_TIME_SERVICE_USED_ATTR); + TOTAL_TIME_SERVICE_USED_ATTR); } catch (IOException e) { Log.e(TAG, "Failed to parse mTotalTimeForegroundServiceUsed", e); } @@ -199,6 +215,13 @@ final class UsageStatsXmlV1 { event.mTimeStamp = statsOut.beginTime + XmlUtils.readLongAttribute(parser, TIME_ATTR); event.mEventType = XmlUtils.readIntAttribute(parser, TYPE_ATTR); + + try { + event.mInstanceId = XmlUtils.readIntAttribute(parser, INSTANCE_ID_ATTR); + } catch (IOException e) { + Log.e(TAG, "Failed to parse mInstanceId", e); + } + switch (event.mEventType) { case UsageEvents.Event.CONFIGURATION_CHANGE: event.mConfiguration = new Configuration(); @@ -227,10 +250,13 @@ final class UsageStatsXmlV1 { // Write the time offset. XmlUtils.writeLongAttribute(xml, LAST_TIME_ACTIVE_ATTR, usageStats.mLastTimeUsed - stats.beginTime); + XmlUtils.writeLongAttribute(xml, LAST_TIME_VISIBLE_ATTR, + usageStats.mLastTimeVisible - stats.beginTime); XmlUtils.writeLongAttribute(xml, LAST_TIME_SERVICE_USED_ATTR, usageStats.mLastTimeForegroundServiceUsed - stats.beginTime); XmlUtils.writeStringAttribute(xml, PACKAGE_ATTR, usageStats.mPackageName); XmlUtils.writeLongAttribute(xml, TOTAL_TIME_ACTIVE_ATTR, usageStats.mTotalTimeInForeground); + XmlUtils.writeLongAttribute(xml, TOTAL_TIME_VISIBLE_ATTR, usageStats.mTotalTimeVisible); XmlUtils.writeLongAttribute(xml, TOTAL_TIME_SERVICE_USED_ATTR, usageStats.mTotalTimeForegroundServiceUsed); XmlUtils.writeIntAttribute(xml, LAST_EVENT_ATTR, usageStats.mLastEvent); @@ -317,6 +343,7 @@ final class UsageStatsXmlV1 { } XmlUtils.writeIntAttribute(xml, FLAGS_ATTR, event.mFlags); XmlUtils.writeIntAttribute(xml, TYPE_ATTR, event.mEventType); + XmlUtils.writeIntAttribute(xml, INSTANCE_ID_ATTR, event.mInstanceId); switch (event.mEventType) { case UsageEvents.Event.CONFIGURATION_CHANGE: diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java index 94d7dbb49b74..5128ae1f9130 100644 --- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java @@ -16,10 +16,18 @@ package com.android.server.usage; +import static android.app.usage.UsageStatsManager.INTERVAL_BEST; +import static android.app.usage.UsageStatsManager.INTERVAL_COUNT; +import static android.app.usage.UsageStatsManager.INTERVAL_DAILY; +import static android.app.usage.UsageStatsManager.INTERVAL_MONTHLY; +import static android.app.usage.UsageStatsManager.INTERVAL_WEEKLY; +import static android.app.usage.UsageStatsManager.INTERVAL_YEARLY; + import android.app.usage.ConfigurationStats; import android.app.usage.EventList; import android.app.usage.EventStats; import android.app.usage.UsageEvents; +import android.app.usage.UsageEvents.Event; import android.app.usage.UsageStats; import android.app.usage.UsageStatsManager; import android.content.Context; @@ -29,6 +37,7 @@ import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; +import android.util.SparseIntArray; import com.android.internal.util.IndentingPrintWriter; import com.android.server.usage.UsageStatsDatabase.StatCombiner; @@ -65,7 +74,7 @@ class UserUsageStatsService { private final int mUserId; // STOPSHIP: Temporary member variable for debugging b/110930764. - private UsageEvents.Event mLastEvent; + private Event mLastEvent; private static final long[] INTERVAL_LENGTH = new long[] { UnixCalendar.DAY_IN_MILLIS, UnixCalendar.WEEK_IN_MILLIS, @@ -87,7 +96,7 @@ class UserUsageStatsService { mContext = context; mDailyExpiryDate = new UnixCalendar(0); mDatabase = new UsageStatsDatabase(usageStatsDir); - mCurrentStats = new IntervalStats[UsageStatsManager.INTERVAL_COUNT]; + mCurrentStats = new IntervalStats[INTERVAL_COUNT]; mListener = listener; mLogPrefix = "User[" + Integer.toString(userId) + "] "; mUserId = userId; @@ -125,28 +134,6 @@ class UserUsageStatsService { updateRolloverDeadline(); } - // Now close off any events that were open at the time this was saved. - for (IntervalStats stat : mCurrentStats) { - final int pkgCount = stat.packageStats.size(); - for (int i = 0; i < pkgCount; i++) { - final UsageStats pkgStats = stat.packageStats.valueAt(i); - if (!pkgStats.mLastForegroundActivityEventMap.isEmpty() - || !pkgStats.mLastForegroundServiceEventMap.isEmpty()) { - if (!pkgStats.mLastForegroundActivityEventMap.isEmpty()) { - stat.update(pkgStats.mPackageName, null, stat.lastTimeSaved, - UsageEvents.Event.END_OF_DAY); - } - if (!pkgStats.mLastForegroundServiceEventMap.isEmpty()) { - stat.update(pkgStats.mPackageName, null , stat.lastTimeSaved, - UsageEvents.Event.ROLLOVER_FOREGROUND_SERVICE); - } - notifyStatsChanged(); - } - } - - stat.updateConfigurationStats(null, stat.lastTimeSaved); - } - if (mDatabase.isNewUpdate()) { notifyNewUpdate(); } @@ -158,40 +145,46 @@ class UserUsageStatsService { loadActiveStats(newTime); } - void reportEvent(UsageEvents.Event event) { + void reportEvent(Event event) { if (DEBUG) { Slog.d(TAG, mLogPrefix + "Got usage event for " + event.mPackage + "[" + event.mTimeStamp + "]: " + eventToString(event.mEventType)); } - mLastEvent = new UsageEvents.Event(event); + mLastEvent = new Event(event); if (event.mTimeStamp >= mDailyExpiryDate.getTimeInMillis()) { // Need to rollover rolloverStats(event.mTimeStamp); } - final IntervalStats currentDailyStats = mCurrentStats[UsageStatsManager.INTERVAL_DAILY]; + final IntervalStats currentDailyStats = mCurrentStats[INTERVAL_DAILY]; final Configuration newFullConfig = event.mConfiguration; - if (event.mEventType == UsageEvents.Event.CONFIGURATION_CHANGE && - currentDailyStats.activeConfiguration != null) { + if (event.mEventType == Event.CONFIGURATION_CHANGE + && currentDailyStats.activeConfiguration != null) { // Make the event configuration a delta. event.mConfiguration = Configuration.generateDelta( currentDailyStats.activeConfiguration, newFullConfig); } - if (event.mEventType != UsageEvents.Event.SYSTEM_INTERACTION) { + if (event.mEventType != Event.SYSTEM_INTERACTION + // ACTIVITY_DESTROYED is a private event. If there is preceding ACTIVITY_STOPPED + // ACTIVITY_DESTROYED will be dropped. Otherwise it will be converted to + // ACTIVITY_STOPPED. + && event.mEventType != Event.ACTIVITY_DESTROYED + // FLUSH_TO_DISK is a private event. + && event.mEventType != Event.FLUSH_TO_DISK) { currentDailyStats.addEvent(event); } boolean incrementAppLaunch = false; - if (event.mEventType == UsageEvents.Event.MOVE_TO_FOREGROUND) { + if (event.mEventType == Event.ACTIVITY_RESUMED) { if (event.mPackage != null && !event.mPackage.equals(mLastBackgroundedPackage)) { incrementAppLaunch = true; } - } else if (event.mEventType == UsageEvents.Event.MOVE_TO_BACKGROUND) { + } else if (event.mEventType == Event.ACTIVITY_PAUSED) { if (event.mPackage != null) { mLastBackgroundedPackage = event.mPackage; } @@ -199,10 +192,10 @@ class UserUsageStatsService { for (IntervalStats stats : mCurrentStats) { switch (event.mEventType) { - case UsageEvents.Event.CONFIGURATION_CHANGE: { + case Event.CONFIGURATION_CHANGE: { stats.updateConfigurationStats(newFullConfig, event.mTimeStamp); } break; - case UsageEvents.Event.CHOOSER_ACTION: { + case Event.CHOOSER_ACTION: { stats.updateChooserCounts(event.mPackage, event.mContentType, event.mAction); String[] annotations = event.mContentAnnotations; if (annotations != null) { @@ -211,21 +204,21 @@ class UserUsageStatsService { } } } break; - case UsageEvents.Event.SCREEN_INTERACTIVE: { + case Event.SCREEN_INTERACTIVE: { stats.updateScreenInteractive(event.mTimeStamp); } break; - case UsageEvents.Event.SCREEN_NON_INTERACTIVE: { + case Event.SCREEN_NON_INTERACTIVE: { stats.updateScreenNonInteractive(event.mTimeStamp); } break; - case UsageEvents.Event.KEYGUARD_SHOWN: { + case Event.KEYGUARD_SHOWN: { stats.updateKeyguardShown(event.mTimeStamp); } break; - case UsageEvents.Event.KEYGUARD_HIDDEN: { + case Event.KEYGUARD_HIDDEN: { stats.updateKeyguardHidden(event.mTimeStamp); } break; default: { stats.update(event.mPackage, event.getClassName(), - event.mTimeStamp, event.mEventType); + event.mTimeStamp, event.mEventType, event.mInstanceId); if (incrementAppLaunch) { stats.incrementAppLaunchCount(event.mPackage); } @@ -286,12 +279,12 @@ class UserUsageStatsService { */ private <T> List<T> queryStats(int intervalType, final long beginTime, final long endTime, StatCombiner<T> combiner) { - if (intervalType == UsageStatsManager.INTERVAL_BEST) { + if (intervalType == INTERVAL_BEST) { intervalType = mDatabase.findBestFitBucket(beginTime, endTime); if (intervalType < 0) { // Nothing saved to disk yet, so every stat is just as equal (no rollover has // occurred. - intervalType = UsageStatsManager.INTERVAL_DAILY; + intervalType = INTERVAL_DAILY; } } @@ -316,10 +309,10 @@ class UserUsageStatsService { } // STOPSHIP: Temporary logging for b/110930764. - if (intervalType == UsageStatsManager.INTERVAL_DAILY + if (intervalType == INTERVAL_DAILY && mLastEvent != null && mLastEvent.mTimeStamp >= beginTime) { final IntervalStats diskStats = mDatabase.getLatestUsageStats( - UsageStatsManager.INTERVAL_DAILY); + INTERVAL_DAILY); StringBuilder sb = new StringBuilder(256); sb.append("Last 24 hours of UsageStats missing! timeRange : "); sb.append(beginTime); @@ -395,11 +388,11 @@ class UserUsageStatsService { UsageEvents queryEvents(final long beginTime, final long endTime, boolean obfuscateInstantApps) { final ArraySet<String> names = new ArraySet<>(); - List<UsageEvents.Event> results = queryStats(UsageStatsManager.INTERVAL_DAILY, - beginTime, endTime, new StatCombiner<UsageEvents.Event>() { + List<Event> results = queryStats(INTERVAL_DAILY, + beginTime, endTime, new StatCombiner<Event>() { @Override public void combine(IntervalStats stats, boolean mutable, - List<UsageEvents.Event> accumulatedResult) { + List<Event> accumulatedResult) { if (stats.events == null) { return; } @@ -411,11 +404,13 @@ class UserUsageStatsService { return; } - UsageEvents.Event event = stats.events.get(i); + Event event = stats.events.get(i); if (obfuscateInstantApps) { event = event.getObfuscatedIfInstantApp(); } - names.add(event.mPackage); + if (event.mPackage != null) { + names.add(event.mPackage); + } if (event.mClass != null) { names.add(event.mClass); } @@ -437,7 +432,7 @@ class UserUsageStatsService { final String packageName) { final ArraySet<String> names = new ArraySet<>(); names.add(packageName); - final List<UsageEvents.Event> results = queryStats(UsageStatsManager.INTERVAL_DAILY, + final List<Event> results = queryStats(INTERVAL_DAILY, beginTime, endTime, (stats, mutable, accumulatedResult) -> { if (stats.events == null) { return; @@ -450,7 +445,7 @@ class UserUsageStatsService { return; } - final UsageEvents.Event event = stats.events.get(i); + final Event event = stats.events.get(i); if (!packageName.equals(event.mPackage)) { continue; } @@ -492,33 +487,33 @@ class UserUsageStatsService { // Make a note of which components need a new CONTINUE_PREVIOUS_DAY or // CONTINUING_FOREGROUND_SERVICE entry. final Configuration previousConfig = - mCurrentStats[UsageStatsManager.INTERVAL_DAILY].activeConfiguration; - ArraySet<String> continuePreviousDay = new ArraySet<>(); - ArrayMap<String, ArrayMap<String, Integer>> continuePreviousDayForegroundActivity = + mCurrentStats[INTERVAL_DAILY].activeConfiguration; + ArraySet<String> continuePkgs = new ArraySet<>(); + ArrayMap<String, SparseIntArray> continueActivity = new ArrayMap<>(); - ArrayMap<String, ArrayMap<String, Integer>> continuePreviousDayForegroundService = + ArrayMap<String, ArrayMap<String, Integer>> continueForegroundService = new ArrayMap<>(); for (IntervalStats stat : mCurrentStats) { final int pkgCount = stat.packageStats.size(); for (int i = 0; i < pkgCount; i++) { final UsageStats pkgStats = stat.packageStats.valueAt(i); - if (!pkgStats.mLastForegroundActivityEventMap.isEmpty() - || !pkgStats.mLastForegroundServiceEventMap.isEmpty()) { - if (!pkgStats.mLastForegroundActivityEventMap.isEmpty()) { - continuePreviousDayForegroundActivity.put(pkgStats.mPackageName, - pkgStats.mLastForegroundActivityEventMap); + if (pkgStats.mActivities.size() > 0 + || !pkgStats.mForegroundServices.isEmpty()) { + if (pkgStats.mActivities.size() > 0) { + continueActivity.put(pkgStats.mPackageName, + pkgStats.mActivities); stat.update(pkgStats.mPackageName, null, mDailyExpiryDate.getTimeInMillis() - 1, - UsageEvents.Event.END_OF_DAY); + Event.END_OF_DAY, 0); } - if (!pkgStats.mLastForegroundServiceEventMap.isEmpty()) { - continuePreviousDayForegroundService.put(pkgStats.mPackageName, - pkgStats.mLastForegroundServiceEventMap); + if (!pkgStats.mForegroundServices.isEmpty()) { + continueForegroundService.put(pkgStats.mPackageName, + pkgStats.mForegroundServices); stat.update(pkgStats.mPackageName, null, mDailyExpiryDate.getTimeInMillis() - 1, - UsageEvents.Event.ROLLOVER_FOREGROUND_SERVICE); + Event.ROLLOVER_FOREGROUND_SERVICE, 0); } - continuePreviousDay.add(pkgStats.mPackageName); + continuePkgs.add(pkgStats.mPackageName); notifyStatsChanged(); } } @@ -532,27 +527,27 @@ class UserUsageStatsService { mDatabase.prune(currentTimeMillis); loadActiveStats(currentTimeMillis); - final int continueCount = continuePreviousDay.size(); + final int continueCount = continuePkgs.size(); for (int i = 0; i < continueCount; i++) { - String pkgName = continuePreviousDay.valueAt(i); - final long beginTime = mCurrentStats[UsageStatsManager.INTERVAL_DAILY].beginTime; + String pkgName = continuePkgs.valueAt(i); + final long beginTime = mCurrentStats[INTERVAL_DAILY].beginTime; for (IntervalStats stat : mCurrentStats) { - if (continuePreviousDayForegroundActivity.containsKey(pkgName)) { - final ArrayMap<String, Integer> foregroundActivityEventMap = - continuePreviousDayForegroundActivity.get(pkgName); - final int size = foregroundActivityEventMap.size(); + if (continueActivity.containsKey(pkgName)) { + final SparseIntArray eventMap = + continueActivity.get(pkgName); + final int size = eventMap.size(); for (int j = 0; j < size; j++) { - stat.update(pkgName, foregroundActivityEventMap.keyAt(j), beginTime, - UsageEvents.Event.CONTINUE_PREVIOUS_DAY); + stat.update(pkgName, null, beginTime, + eventMap.valueAt(j), eventMap.keyAt(j)); } } - if (continuePreviousDayForegroundService.containsKey(pkgName)) { - final ArrayMap<String, Integer> foregroundServiceEventMap = - continuePreviousDayForegroundService.get(pkgName); - final int size = foregroundServiceEventMap.size(); + if (continueForegroundService.containsKey(pkgName)) { + final ArrayMap<String, Integer> eventMap = + continueForegroundService.get(pkgName); + final int size = eventMap.size(); for (int j = 0; j < size; j++) { - stat.update(pkgName, foregroundServiceEventMap.keyAt(j), beginTime, - UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE); + stat.update(pkgName, eventMap.keyAt(j), beginTime, + eventMap.valueAt(j), 0); } } stat.updateConfigurationStats(previousConfig, beginTime); @@ -611,7 +606,7 @@ class UserUsageStatsService { private void updateRolloverDeadline() { mDailyExpiryDate.setTimeInMillis( - mCurrentStats[UsageStatsManager.INTERVAL_DAILY].beginTime); + mCurrentStats[INTERVAL_DAILY].beginTime); mDailyExpiryDate.addDays(1); Slog.i(TAG, mLogPrefix + "Rollover scheduled @ " + sDateFormat.format(mDailyExpiryDate.getTimeInMillis()) + "(" + @@ -660,7 +655,7 @@ class UserUsageStatsService { } - void printEvent(IndentingPrintWriter pw, UsageEvents.Event event, boolean prettyDates) { + void printEvent(IndentingPrintWriter pw, Event event, boolean prettyDates) { pw.printPair("time", formatDateTime(event.mTimeStamp, prettyDates)); pw.printPair("type", eventToString(event.mEventType)); pw.printPair("package", event.mPackage); @@ -673,10 +668,15 @@ class UserUsageStatsService { if (event.mShortcutId != null) { pw.printPair("shortcutId", event.mShortcutId); } - if (event.mEventType == UsageEvents.Event.STANDBY_BUCKET_CHANGED) { + if (event.mEventType == Event.STANDBY_BUCKET_CHANGED) { pw.printPair("standbyBucket", event.getStandbyBucket()); pw.printPair("reason", UsageStatsManager.reasonToString(event.getStandbyReason())); + } else if (event.mEventType == Event.ACTIVITY_RESUMED + || event.mEventType == Event.ACTIVITY_PAUSED + || event.mEventType == Event.ACTIVITY_STOPPED) { + pw.printPair("instanceId", event.getInstanceId()); } + if (event.mNotificationChannelId != null) { pw.printPair("channelId", event.mNotificationChannelId); } @@ -691,11 +691,11 @@ class UserUsageStatsService { final long beginTime = yesterday.getTimeInMillis(); - List<UsageEvents.Event> events = queryStats(UsageStatsManager.INTERVAL_DAILY, - beginTime, endTime, new StatCombiner<UsageEvents.Event>() { + List<Event> events = queryStats(INTERVAL_DAILY, + beginTime, endTime, new StatCombiner<Event>() { @Override public void combine(IntervalStats stats, boolean mutable, - List<UsageEvents.Event> accumulatedResult) { + List<Event> accumulatedResult) { if (stats.events == null) { return; } @@ -707,7 +707,7 @@ class UserUsageStatsService { return; } - UsageEvents.Event event = stats.events.get(i); + Event event = stats.events.get(i); if (pkg != null && !pkg.equals(event.mPackage)) { continue; } @@ -727,7 +727,7 @@ class UserUsageStatsService { pw.println(")"); if (events != null) { pw.increaseIndent(); - for (UsageEvents.Event event : events) { + for (Event event : events) { printEvent(pw, event, prettyDates); } pw.decreaseIndent(); @@ -772,9 +772,17 @@ class UserUsageStatsService { continue; } pw.printPair("package", usageStats.mPackageName); - pw.printPair("totalTime", + pw.printPair("totalTimeUsed", formatElapsedTime(usageStats.mTotalTimeInForeground, prettyDates)); - pw.printPair("lastTime", formatDateTime(usageStats.mLastTimeUsed, prettyDates)); + pw.printPair("lastTimeUsed", formatDateTime(usageStats.mLastTimeUsed, prettyDates)); + pw.printPair("totalTimeVisible", + formatElapsedTime(usageStats.mTotalTimeVisible, prettyDates)); + pw.printPair("lastTimeVisible", + formatDateTime(usageStats.mLastTimeVisible, prettyDates)); + pw.printPair("totalTimeFS", + formatElapsedTime(usageStats.mTotalTimeForegroundServiceUsed, prettyDates)); + pw.printPair("lastTimeFS", + formatDateTime(usageStats.mLastTimeForegroundServiceUsed, prettyDates)); pw.printPair("appLaunchCount", usageStats.mAppLaunchCount); pw.println(); } @@ -845,7 +853,7 @@ class UserUsageStatsService { final EventList events = stats.events; final int eventCount = events != null ? events.size() : 0; for (int i = 0; i < eventCount; i++) { - final UsageEvents.Event event = events.get(i); + final Event event = events.get(i); if (pkg != null && !pkg.equals(event.mPackage)) { continue; } @@ -858,13 +866,13 @@ class UserUsageStatsService { private static String intervalToString(int interval) { switch (interval) { - case UsageStatsManager.INTERVAL_DAILY: + case INTERVAL_DAILY: return "daily"; - case UsageStatsManager.INTERVAL_WEEKLY: + case INTERVAL_WEEKLY: return "weekly"; - case UsageStatsManager.INTERVAL_MONTHLY: + case INTERVAL_MONTHLY: return "monthly"; - case UsageStatsManager.INTERVAL_YEARLY: + case INTERVAL_YEARLY: return "yearly"; default: return "?"; @@ -873,47 +881,49 @@ class UserUsageStatsService { private static String eventToString(int eventType) { switch (eventType) { - case UsageEvents.Event.NONE: + case Event.NONE: return "NONE"; - case UsageEvents.Event.MOVE_TO_BACKGROUND: - return "MOVE_TO_BACKGROUND"; - case UsageEvents.Event.MOVE_TO_FOREGROUND: - return "MOVE_TO_FOREGROUND"; - case UsageEvents.Event.FOREGROUND_SERVICE_START: + case Event.ACTIVITY_PAUSED: + return "ACTIVITY_PAUSED"; + case Event.ACTIVITY_RESUMED: + return "ACTIVITY_RESUMED"; + case Event.FOREGROUND_SERVICE_START: return "FOREGROUND_SERVICE_START"; - case UsageEvents.Event.FOREGROUND_SERVICE_STOP: + case Event.FOREGROUND_SERVICE_STOP: return "FOREGROUND_SERVICE_STOP"; - case UsageEvents.Event.END_OF_DAY: + case Event.ACTIVITY_STOPPED: + return "ACTIVITY_STOPPED"; + case Event.END_OF_DAY: return "END_OF_DAY"; - case UsageEvents.Event.ROLLOVER_FOREGROUND_SERVICE: + case Event.ROLLOVER_FOREGROUND_SERVICE: return "ROLLOVER_FOREGROUND_SERVICE"; - case UsageEvents.Event.CONTINUE_PREVIOUS_DAY: + case Event.CONTINUE_PREVIOUS_DAY: return "CONTINUE_PREVIOUS_DAY"; - case UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE: + case Event.CONTINUING_FOREGROUND_SERVICE: return "CONTINUING_FOREGROUND_SERVICE"; - case UsageEvents.Event.CONFIGURATION_CHANGE: + case Event.CONFIGURATION_CHANGE: return "CONFIGURATION_CHANGE"; - case UsageEvents.Event.SYSTEM_INTERACTION: + case Event.SYSTEM_INTERACTION: return "SYSTEM_INTERACTION"; - case UsageEvents.Event.USER_INTERACTION: + case Event.USER_INTERACTION: return "USER_INTERACTION"; - case UsageEvents.Event.SHORTCUT_INVOCATION: + case Event.SHORTCUT_INVOCATION: return "SHORTCUT_INVOCATION"; - case UsageEvents.Event.CHOOSER_ACTION: + case Event.CHOOSER_ACTION: return "CHOOSER_ACTION"; - case UsageEvents.Event.NOTIFICATION_SEEN: + case Event.NOTIFICATION_SEEN: return "NOTIFICATION_SEEN"; - case UsageEvents.Event.STANDBY_BUCKET_CHANGED: + case Event.STANDBY_BUCKET_CHANGED: return "STANDBY_BUCKET_CHANGED"; - case UsageEvents.Event.NOTIFICATION_INTERRUPTION: + case Event.NOTIFICATION_INTERRUPTION: return "NOTIFICATION_INTERRUPTION"; - case UsageEvents.Event.SLICE_PINNED: + case Event.SLICE_PINNED: return "SLICE_PINNED"; - case UsageEvents.Event.SLICE_PINNED_PRIV: + case Event.SLICE_PINNED_PRIV: return "SLICE_PINNED_PRIV"; - case UsageEvents.Event.SCREEN_INTERACTIVE: + case Event.SCREEN_INTERACTIVE: return "SCREEN_INTERACTIVE"; - case UsageEvents.Event.SCREEN_NON_INTERACTIVE: + case Event.SCREEN_NON_INTERACTIVE: return "SCREEN_NON_INTERACTIVE"; case UsageEvents.Event.KEYGUARD_SHOWN: return "KEYGUARD_SHOWN"; diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 9f0bdd715359..49030f59064a 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -460,6 +460,12 @@ public class TelecomManager { "android.telecom.extra.START_CALL_WITH_RTT"; /** + * A boolean extra set to indicate whether an app is eligible to be bound to when there are + * ongoing calls on the device. + */ + public static final String EXTRA_IS_ENABLED = "android.telecom.extra.IS_ENABLED"; + + /** * A boolean meta-data value indicating whether an {@link InCallService} implements an * in-call user interface. Dialer implementations (see {@link #getDefaultDialerPackage()}) which * would also like to replace the in-call interface should set this meta-data to {@code true} in @@ -471,8 +477,6 @@ public class TelecomManager { * A boolean meta-data value indicating whether an {@link InCallService} implements an * in-call user interface to be used while the device is in car-mode (see * {@link android.content.res.Configuration.UI_MODE_TYPE_CAR}). - * - * @hide */ public static final String METADATA_IN_CALL_SERVICE_CAR_MODE_UI = "android.telecom.IN_CALL_SERVICE_CAR_MODE_UI"; @@ -1462,7 +1466,6 @@ public class TelecomManager { * otherwise. */ @RequiresPermission(Manifest.permission.ANSWER_PHONE_CALLS) - @SystemApi public boolean endCall() { try { if (isServiceConnected()) { @@ -1539,7 +1542,6 @@ public class TelecomManager { /** * Returns whether TTY is supported on this device. */ - @SystemApi @RequiresPermission(anyOf = { android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE @@ -2040,7 +2042,6 @@ public class TelecomManager { } catch (RemoteException e) { Log.e(TAG, "RemoteException handleCallIntent: " + e); } - } private ITelecomService getTelecomService() { diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java index 6a396ce33093..1cbe5a26caed 100644 --- a/telephony/java/android/provider/Telephony.java +++ b/telephony/java/android/provider/Telephony.java @@ -3640,8 +3640,9 @@ public final class Telephony { /** * Generates a content {@link Uri} used to receive updates on precise carrier identity - * change on the given subscriptionId - * {@link TelephonyManager#ACTION_SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED}. + * change on the given subscriptionId returned by + * {@link TelephonyManager#getSimPreciseCarrierId()}. + * @see TelephonyManager#ACTION_SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED * <p> * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the * precise carrier identity {@link TelephonyManager#getSimPreciseCarrierId()} @@ -3652,7 +3653,6 @@ public final class Telephony { * * @param subscriptionId the subscriptionId to receive updates on * @return the Uri used to observe precise carrier identity changes - * @hide */ public static Uri getPreciseCarrierIdUriForSubscriptionId(int subscriptionId) { return Uri.withAppendedPath(Uri.withAppendedPath(CONTENT_URI, "precise"), @@ -3674,22 +3674,20 @@ public final class Telephony { public static final String CARRIER_ID = "carrier_id"; /** - * A user facing carrier name for precise carrier id. - * @see TelephonyManager#getSimPreciseCarrierIdName() + * A fine-grained carrier id. + * @see TelephonyManager#getSimPreciseCarrierId() * This is not a database column, only used to notify content observers for * {@link #getPreciseCarrierIdUriForSubscriptionId(int)} - * @hide */ - public static final String PRECISE_CARRIER_ID_NAME = "precise_carrier_id_name"; + public static final String PRECISE_CARRIER_ID = "precise_carrier_id"; /** - * A fine-grained carrier id. - * @see TelephonyManager#getSimPreciseCarrierId() + * A user facing carrier name for precise carrier id {@link #PRECISE_CARRIER_ID}. + * @see TelephonyManager#getSimPreciseCarrierIdName() * This is not a database column, only used to notify content observers for * {@link #getPreciseCarrierIdUriForSubscriptionId(int)} - * @hide */ - public static final String PRECISE_CARRIER_ID = "precise_carrier_id"; + public static final String PRECISE_CARRIER_ID_NAME = "precise_carrier_id_name"; /** * A unique parent carrier id. The parent-child @@ -3703,18 +3701,6 @@ public final class Telephony { public static final String PARENT_CARRIER_ID = "parent_carrier_id"; /** - * A unique mno carrier id. mno carrier shares the same {@link All#MCCMNC} as carrier id - * and can be solely identified by {@link All#MCCMNC} only. If there is no such mno - * carrier, then mno carrier id equals to {@link #CARRIER_ID carrier id}. - * - * <p>mno carrier id can be used as fallback id. When the exact carrier id configurations - * are not found, usually fall back to its mno carrier id. - * <P>Type: INTEGER </P> - * @hide - */ - public static final String MNO_CARRIER_ID = "mno_carrier_id"; - - /** * Contains mappings between matching rules with carrier id for all carriers. * @hide */ diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 60eb18cacb88..cfe134fd0ee2 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -68,7 +68,13 @@ public class CarrierConfigManager { * This intent is broadcast by the system when carrier config changes. An int is specified in * {@link #EXTRA_SLOT_INDEX} to indicate the slot index that this is for. An optional int extra * {@link #EXTRA_SUBSCRIPTION_INDEX} is included to indicate the subscription index if a valid - * one is available for the slot index. + * one is available for the slot index. An optional int extra + * {@link TelephonyManager#EXTRA_CARRIER_ID} is included to indicate the carrier id for the + * changed carrier configuration. An optional int extra + * {@link TelephonyManager#EXTRA_PRECISE_CARRIER_ID} is included to indicate the precise + * carrier id for the changed carrier configuration. + * @see TelephonyManager#getSimCarrierId() + * @see TelephonyManager#getSimPreciseCarrierId() */ public static final String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED"; @@ -81,7 +87,6 @@ public class CarrierConfigManager { * Specifies a value that identifies the version of the carrier configuration that is * currently in use. This string is displayed on the UI. * The format of the string is not specified. - * @hide */ public static final String KEY_CARRIER_CONFIG_VERSION_STRING = "carrier_config_version_string"; @@ -403,7 +408,6 @@ public class CarrierConfigManager { * @see SubscriptionManager#getSubscriptionPlans(int) * @see SubscriptionManager#setSubscriptionPlans(int, java.util.List) */ - @SystemApi public static final String KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING = "config_plans_package_override_string"; diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index ea408bf8ff59..1b37bad65d57 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -365,7 +365,6 @@ public final class SmsManager { * * @see #sendTextMessage(String, String, String, PendingIntent, PendingIntent) */ - @SystemApi @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(allOf = { android.Manifest.permission.MODIFY_PHONE_STATE, diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 2c06c4720650..c40eb9ac91e3 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -19,6 +19,7 @@ package android.telephony; import static android.net.NetworkPolicyManager.OVERRIDE_CONGESTED; import static android.net.NetworkPolicyManager.OVERRIDE_UNMETERED; +import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.DurationMillisLong; import android.annotation.NonNull; @@ -52,6 +53,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.telephony.euicc.EuiccManager; import android.telephony.ims.ImsMmTelManager; +import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.Log; @@ -67,6 +69,7 @@ import java.util.List; import java.util.Locale; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; /** * SubscriptionManager is the application interface to SubscriptionController @@ -633,7 +636,6 @@ public class SubscriptionManager { * the user is interested in. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - @SystemApi public static final String ACTION_MANAGE_SUBSCRIPTION_PLANS = "android.telephony.action.MANAGE_SUBSCRIPTION_PLANS"; @@ -653,7 +655,6 @@ public class SubscriptionManager { * {@code android.permission.MANAGE_SUBSCRIPTION_PLANS} permission. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - @SystemApi public static final String ACTION_REFRESH_SUBSCRIPTION_PLANS = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS"; @@ -2059,7 +2060,6 @@ public class SubscriptionManager { * @throws SecurityException if the caller doesn't meet the requirements * outlined above. */ - @SystemApi public @NonNull List<SubscriptionPlan> getSubscriptionPlans(int subId) { try { SubscriptionPlan[] subscriptionPlans = @@ -2091,7 +2091,6 @@ public class SubscriptionManager { * @throws SecurityException if the caller doesn't meet the requirements * outlined above. */ - @SystemApi public void setSubscriptionPlans(int subId, @NonNull List<SubscriptionPlan> plans) { try { getNetworkPolicy().setSubscriptionPlans(subId, @@ -2133,7 +2132,6 @@ public class SubscriptionManager { * @throws SecurityException if the caller doesn't meet the requirements * outlined above. */ - @SystemApi public void setSubscriptionOverrideUnmetered(int subId, boolean overrideUnmetered, @DurationMillisLong long timeoutMillis) { try { @@ -2169,7 +2167,6 @@ public class SubscriptionManager { * @throws SecurityException if the caller doesn't meet the requirements * outlined above. */ - @SystemApi public void setSubscriptionOverrideCongested(int subId, boolean overrideCongested, @DurationMillisLong long timeoutMillis) { try { @@ -2405,16 +2402,21 @@ public class SubscriptionManager { * together, some of them may be invisible to the users, etc. * * Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE} - * permission or can manage all subscriptions in the list, according to their - * acess rules. + * permission or had carrier privilege permission on the subscriptions: + * {@link TelephonyManager#hasCarrierPrivileges(int)} or + * {@link #canManageSubscription(SubscriptionInfo)} + * + * @throws SecurityException if the caller doesn't meet the requirements + * outlined above. * * @param subIdList list of subId that will be in the same group * @return groupUUID a UUID assigned to the subscription group. It returns * null if fails. * */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) - public String setSubscriptionGroup(int[] subIdList) { + public @Nullable String setSubscriptionGroup(@NonNull int[] subIdList) { String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>"; if (VDBG) { logd("[setSubscriptionGroup]+ subIdList:" + Arrays.toString(subIdList)); @@ -2434,6 +2436,80 @@ public class SubscriptionManager { } /** + * Remove a list of subscriptions from their subscription group. + * See {@link #setSubscriptionGroup(int[])} for more details. + * + * Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE} + * permission or had carrier privilege permission on the subscriptions: + * {@link TelephonyManager#hasCarrierPrivileges(int)} or + * {@link #canManageSubscription(SubscriptionInfo)} + * + * @throws SecurityException if the caller doesn't meet the requirements + * outlined above. + * + * @param subIdList list of subId that need removing from their groups. + * @return whether the operation succeeds. + * + */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public boolean removeSubscriptionsFromGroup(@NonNull int[] subIdList) { + String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>"; + if (VDBG) { + logd("[removeSubscriptionsFromGroup]+ subIdList:" + Arrays.toString(subIdList)); + } + + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + return iSub.removeSubscriptionsFromGroup(subIdList, pkgForDebug); + } + } catch (RemoteException ex) { + // ignore it + } + + return false; + } + + /** + * Get subscriptionInfo list of subscriptions that are in the same group of given subId. + * See {@link #setSubscriptionGroup(int[])} for more details. + * + * Caller will either have {@link android.Manifest.permission#READ_PHONE_STATE} + * permission or had carrier privilege permission on the subscription. + * {@link TelephonyManager#hasCarrierPrivileges(int)} + * + * @throws SecurityException if the caller doesn't meet the requirements + * outlined above. + * + * @param subId of which list of subInfo from the same group will be returned. + * @return list of subscriptionInfo that belong to the same group, including the given + * subscription itself. It will return null if the subscription doesn't exist or it + * doesn't belong to any group. + * + */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @RequiresPermission(Manifest.permission.READ_PHONE_STATE) + public @Nullable List<SubscriptionInfo> getSubscriptionsInGroup(int subId) { + String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>"; + if (VDBG) { + logd("[getSubscriptionsInGroup]+ subId:" + subId); + } + + List<SubscriptionInfo> result = null; + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + result = iSub.getSubscriptionsInGroup(subId, pkgForDebug); + } + } catch (RemoteException ex) { + // ignore it + } + + return result; + } + + /** * Set metered by simInfo index * * @param isMetered whether it’s a metered subscription. @@ -2448,6 +2524,42 @@ public class SubscriptionManager { (iSub)-> iSub.setMetered(isMetered, subId)); } + /** + * Whether system UI should hide a subscription. If it's a bundled opportunistic + * subscription, it shouldn't show up in anywhere in Settings app, dialer app, + * or status bar. + * + * @param info the subscriptionInfo to check against. + * @return true if this subscription should be hidden. + * + * @hide + */ + public static boolean shouldHideSubscription(SubscriptionInfo info) { + return (info != null && !TextUtils.isEmpty(info.getGroupUuid()) && info.isOpportunistic()); + } + + /** + * Return a list of subscriptions that are available and visible to the user. + * Used by Settings app to show a list of subscriptions for user to pick. + * + * <p> + * Permissions android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE is required + * for getSelectableSubscriptionInfoList to be invoked. + * @return list of user selectable subscriptions. + * + * @hide + */ + public @Nullable List<SubscriptionInfo> getSelectableSubscriptionInfoList() { + List<SubscriptionInfo> availableList = getAvailableSubscriptionInfoList(); + if (availableList == null) { + return null; + } else { + return getAvailableSubscriptionInfoList().stream() + .filter(subInfo -> !shouldHideSubscription(subInfo)) + .collect(Collectors.toList()); + } + } + private interface CallISubMethodHelper { int callMethod(ISub iSub) throws RemoteException; } diff --git a/telephony/java/android/telephony/SubscriptionPlan.java b/telephony/java/android/telephony/SubscriptionPlan.java index e8bbe42e834e..d67169ccd284 100644 --- a/telephony/java/android/telephony/SubscriptionPlan.java +++ b/telephony/java/android/telephony/SubscriptionPlan.java @@ -45,7 +45,6 @@ import java.util.Objects; * @see SubscriptionManager#setSubscriptionPlans(int, java.util.List) * @see SubscriptionManager#getSubscriptionPlans(int) */ -@SystemApi public final class SubscriptionPlan implements Parcelable { /** {@hide} */ @IntDef(prefix = "LIMIT_BEHAVIOR_", value = { diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 422e66de7e0b..c0250907f7cd 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -1217,81 +1217,79 @@ public class TelephonyManager { "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED"; /** + * An int extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which indicates + * the updated carrier id returned by {@link TelephonyManager#getSimCarrierId()}. + * <p>Will be {@link TelephonyManager#UNKNOWN_CARRIER_ID} if the subscription is unavailable or + * the carrier cannot be identified. + */ + public static final String EXTRA_CARRIER_ID = "android.telephony.extra.CARRIER_ID"; + + /** + * An string extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which + * indicates the updated carrier name of the current subscription. + * @see TelephonyManager#getSimCarrierIdName() + * <p>Carrier name is a user-facing name of the carrier id {@link #EXTRA_CARRIER_ID}, + * usually the brand name of the subsidiary (e.g. T-Mobile). + */ + public static final String EXTRA_CARRIER_NAME = "android.telephony.extra.CARRIER_NAME"; + + /** * Broadcast Action: The subscription precise carrier identity has changed. - * Similar like {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED}, this intent will be sent - * on the event of {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED}. However, its possible - * that precise carrier identity changes while - * {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} remains the same e.g, the same - * subscription switches to different IMSI could potentially change its precise carrier id. + * The precise carrier id can be used to further differentiate a carrier by different + * networks, by prepaid v.s.postpaid or even by 4G v.s.3G plan. Each carrier has a unique + * carrier id returned by {@link #getSimCarrierId()} but could have multiple precise carrier id. + * e.g, {@link #getSimCarrierId()} will always return Tracfone (id 2022) for a Tracfone SIM, + * while {@link #getSimPreciseCarrierId()} can return Tracfone AT&T or Tracfone T-Mobile based + * on the current subscription IMSI. For carriers without any fine-grained ids, precise carrier + * id is same as carrier id. + * + * <p>Similar like {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED}, this intent will be + * sent on the event of {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} while its also + * possible to be sent without {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} when + * precise carrier id changes with the same carrier id. + * e.g, the same subscription switches to different IMSI could potentially change its + * precise carrier id while carrier id remains the same. + * @see #getSimPreciseCarrierId() + * @see #getSimCarrierId() * * The intent will have the following extra values: * <ul> * <li>{@link #EXTRA_PRECISE_CARRIER_ID} The up-to-date precise carrier id of the * current subscription. * </li> - * <li>{@link #EXTRA_PRECISE_CARRIER_NAME} The up-to-date carrier name of the current - * subscription. + * <li>{@link #EXTRA_PRECISE_CARRIER_NAME} The up-to-date name of the precise carrier id. * </li> * <li>{@link #EXTRA_SUBSCRIPTION_ID} The subscription id associated with the changed carrier * identity. * </li> * </ul> * <p class="note">This is a protected intent that can only be sent by the system. - * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED"; /** - * An int extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which indicates - * the updated carrier id {@link TelephonyManager#getSimCarrierId()} of - * the current subscription. - * <p>Will be {@link TelephonyManager#UNKNOWN_CARRIER_ID} if the subscription is unavailable or - * the carrier cannot be identified. - */ - public static final String EXTRA_CARRIER_ID = "android.telephony.extra.CARRIER_ID"; - - /** - * An int extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which indicates - * the updated mno carrier id of the current subscription. - * <p>Will be {@link TelephonyManager#UNKNOWN_CARRIER_ID} if the subscription is unavailable or - * the carrier cannot be identified. - * - *@hide - */ - public static final String EXTRA_MNO_CARRIER_ID = "android.telephony.extra.MNO_CARRIER_ID"; - - /** - * An string extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which - * indicates the updated carrier name of the current subscription. - * {@see TelephonyManager#getSimCarrierIdName()} - * <p>Carrier name is a user-facing name of the carrier id {@link #EXTRA_CARRIER_ID}, - * usually the brand name of the subsidiary (e.g. T-Mobile). - */ - public static final String EXTRA_CARRIER_NAME = "android.telephony.extra.CARRIER_NAME"; - - /** * An int extra used with {@link #ACTION_SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED} which - * indicates the updated precise carrier id {@link TelephonyManager#getSimPreciseCarrierId()} of - * the current subscription. Note, its possible precise carrier id changes while - * {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} remains the same e.g, when - * subscription switch to different IMSI. + * indicates the updated precise carrier id returned by + * {@link TelephonyManager#getSimPreciseCarrierId()}. Note, its possible precise carrier id + * changes while {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} remains the same + * e.g, when subscription switch to different IMSIs. * <p>Will be {@link TelephonyManager#UNKNOWN_CARRIER_ID} if the subscription is unavailable or * the carrier cannot be identified. - * @hide */ public static final String EXTRA_PRECISE_CARRIER_ID = "android.telephony.extra.PRECISE_CARRIER_ID"; /** * An string extra used with {@link #ACTION_SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED} which - * indicates the updated precise carrier name of the current subscription. - * {@see TelephonyManager#getSimPreciseCarrierIdName()} - * <p>it's a user-facing name of the precise carrier id {@link #EXTRA_PRECISE_CARRIER_ID}, - * @hide + * indicates the updated precise carrier name returned by + * {@link TelephonyManager#getSimPreciseCarrierIdName()}. + * <p>it's a user-facing name of the precise carrier id {@link #EXTRA_PRECISE_CARRIER_ID}, e.g, + * Tracfone-AT&T. */ - public static final String EXTRA_PRECISE_CARRIER_NAME = "android.telephony.extra.CARRIER_NAME"; + public static final String EXTRA_PRECISE_CARRIER_NAME = + "android.telephony.extra.PRECISE_CARRIER_NAME"; /** * An int extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} to indicate the @@ -6632,7 +6630,7 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) { - return telephony.getCarrierPrivilegeStatus(mSubId) == + return telephony.getCarrierPrivilegeStatus(subId) == CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; } } catch (RemoteException ex) { @@ -8518,7 +8516,7 @@ public class TelephonyManager { /** * Returns carrier id name of the current subscription. - * <p>Carrier id name is a user-facing name of carrier id + * <p>Carrier id name is a user-facing name of carrier id returned by * {@link #getSimCarrierId()}, usually the brand name of the subsidiary * (e.g. T-Mobile). Each carrier could configure multiple {@link #getSimOperatorName() SPN} but * should have a single carrier name. Carrier name is not a canonical identity, @@ -8528,7 +8526,7 @@ public class TelephonyManager { * @return Carrier name of the current subscription. Return {@code null} if the subscription is * unavailable or the carrier cannot be identified. */ - public CharSequence getSimCarrierIdName() { + public @Nullable CharSequence getSimCarrierIdName() { try { ITelephony service = getITelephony(); if (service != null) { @@ -8545,10 +8543,10 @@ public class TelephonyManager { * * <p>The precise carrier id can be used to further differentiate a carrier by different * networks, by prepaid v.s.postpaid or even by 4G v.s.3G plan. Each carrier has a unique - * carrier id {@link #getSimCarrierId()} but can have multiple precise carrier id. e.g, - * {@link #getSimCarrierId()} will always return Tracfone (id 2022) for a Tracfone SIM, while - * {@link #getSimPreciseCarrierId()} can return Tracfone AT&T or Tracfone T-Mobile based on the - * current subscription IMSI. + * carrier id returned by {@link #getSimCarrierId()} but could have multiple precise carrier id. + * e.g, {@link #getSimCarrierId()} will always return Tracfone (id 2022) for a Tracfone SIM, + * while {@link #getSimPreciseCarrierId()} can return Tracfone AT&T or Tracfone T-Mobile based + * on the current subscription IMSI. * * <p>For carriers without any fine-grained carrier ids, return {@link #getSimCarrierId()} * <p>Precise carrier ids are defined in the same way as carrier id @@ -8558,8 +8556,6 @@ public class TelephonyManager { * @return Returns fine-grained carrier id of the current subscription. * Return {@link #UNKNOWN_CARRIER_ID} if the subscription is unavailable or the carrier cannot * be identified. - * - * @hide */ public int getSimPreciseCarrierId() { try { @@ -8575,16 +8571,14 @@ public class TelephonyManager { /** * Similar like {@link #getSimCarrierIdName()}, returns user-facing name of the - * precise carrier id {@link #getSimPreciseCarrierId()} + * precise carrier id returned by {@link #getSimPreciseCarrierId()}. * * <p>The returned name is unlocalized. * * @return user-facing name of the subscription precise carrier id. Return {@code null} if the * subscription is unavailable or the carrier cannot be identified. - * - * @hide */ - public CharSequence getSimPreciseCarrierIdName() { + public @Nullable CharSequence getSimPreciseCarrierIdName() { try { ITelephony service = getITelephony(); if (service != null) { @@ -8597,43 +8591,54 @@ public class TelephonyManager { } /** - * Return a list of certs in hex string from loaded carrier privileges access rules. + * Returns carrier id based on sim MCCMNC (returned by {@link #getSimOperator()}) only. + * This is used for fallback when configurations/logic for exact carrier id + * {@link #getSimCarrierId()} are not found. * - * @return a list of certificate in hex string. return {@code null} if there is no certs - * or privilege rules are not loaded yet. + * Android carrier id table <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/carrier_list.textpb">here</a> + * can be updated out-of-band, its possible a MVNO (Mobile Virtual Network Operator) carrier + * was not fully recognized and assigned to its MNO (Mobile Network Operator) carrier id + * by default. After carrier id table update, a new carrier id was assigned. If apps don't + * take the update with the new id, it might be helpful to always fallback by using carrier + * id based on MCCMNC if there is no match. * - * <p>Requires Permission: - * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} - * @hide + * @return matching carrier id from sim MCCMNC. Return {@link #UNKNOWN_CARRIER_ID} if the + * subscription is unavailable or the carrier cannot be identified. */ - @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - public List<String> getCertsFromCarrierPrivilegeAccessRules() { + public int getCarrierIdFromSimMccMnc() { try { ITelephony service = getITelephony(); if (service != null) { - return service.getCertsFromCarrierPrivilegeAccessRules(getSubId()); + return service.getCarrierIdFromMccMnc(getSlotIndex(), getSimOperator(), true); } } catch (RemoteException ex) { // This could happen if binder process crashes. } - return null; + return UNKNOWN_CARRIER_ID; } - /** - * Returns MNO carrier id of the current subscription’s MCCMNC. - * <p>MNO carrier id can be solely identified by subscription mccmnc. This is mainly used - * for MNO fallback when exact carrier id {@link #getSimCarrierId()} - * configurations are not found. - * - * @return MNO carrier id of the current subscription. Return the value same as carrier id - * {@link #getSimCarrierId()}, if MNO carrier id cannot be identified. - * @hide - */ - public int getSimMNOCarrierId() { + /** + * Returns carrier id based on MCCMNC (returned by {@link #getSimOperator()}) only. This is + * used for fallback when configurations/logic for exact carrier id {@link #getSimCarrierId()} + * are not found. + * + * Android carrier id table <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/carrier_list.textpb">here</a> + * can be updated out-of-band, its possible a MVNO (Mobile Virtual Network Operator) carrier + * was not fully recognized and assigned to its MNO (Mobile Network Operator) carrier id + * by default. After carrier id table update, a new carrier id was assigned. If apps don't + * take the update with the new id, it might be helpful to always fallback by using carrier + * id based on MCCMNC if there is no match. + * + * @return matching carrier id from passing MCCMNC. Return {@link #UNKNOWN_CARRIER_ID} if the + * subscription is unavailable or the carrier cannot be identified. + * @hide + */ + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public int getCarrierIdFromMccMnc(String mccmnc) { try { ITelephony service = getITelephony(); if (service != null) { - return service.getSubscriptionMNOCarrierId(getSubId()); + return service.getCarrierIdFromMccMnc(getSlotIndex(), mccmnc, false); } } catch (RemoteException ex) { // This could happen if binder process crashes. @@ -8641,24 +8646,27 @@ public class TelephonyManager { return UNKNOWN_CARRIER_ID; } - /** - * Returns carrier id based on MCCMNC only. This is for fallback when exact carrier id - * {@link #getSimCarrierId()} configurations are not found - * - * @return matching carrier id from passing mccmnc. - * @hide - */ - @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - public int getCarrierIdFromMccMnc(String mccmnc) { + /** + * Return a list of certs in hex string from loaded carrier privileges access rules. + * + * @return a list of certificate in hex string. return {@code null} if there is no certs + * or privilege rules are not loaded yet. + * + * <p>Requires Permission: + * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} + * @hide + */ + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public List<String> getCertsFromCarrierPrivilegeAccessRules() { try { ITelephony service = getITelephony(); if (service != null) { - return service.getCarrierIdFromMccMnc(getSlotIndex(), mccmnc); + return service.getCertsFromCarrierPrivilegeAccessRules(getSubId()); } } catch (RemoteException ex) { // This could happen if binder process crashes. } - return UNKNOWN_CARRIER_ID; + return null; } /** diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index a1afc0892ba0..8d148c36f3e7 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -969,7 +969,7 @@ public class ApnSetting implements Parcelable { */ public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("[ApnSettingV5] ") + sb.append("[ApnSettingV6] ") .append(mEntryName) .append(", ").append(mId) .append(", ").append(mOperatorNumeric) @@ -996,6 +996,7 @@ public class ApnSetting implements Parcelable { sb.append(", ").append(mPermanentFailed); sb.append(", ").append(mNetworkTypeBitmask); sb.append(", ").append(mApnSetId); + sb.append(", ").append(mCarrierId); return sb.toString(); } diff --git a/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java index 4af31b5e5346..bef11425b470 100644 --- a/telephony/java/android/telephony/data/DataServiceCallback.java +++ b/telephony/java/android/telephony/data/DataServiceCallback.java @@ -125,7 +125,6 @@ public class DataServiceCallback { * * @param result The result code. Must be one of the {@link ResultCode}. */ - @SystemApi public void onSetDataProfileComplete(@ResultCode int result) { IDataServiceCallback callback = mCallback.get(); if (callback != null) { diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl index f9db4b0afd12..65d1a920a324 100755 --- a/telephony/java/com/android/internal/telephony/ISub.aidl +++ b/telephony/java/com/android/internal/telephony/ISub.aidl @@ -210,6 +210,10 @@ interface ISub { */ List<SubscriptionInfo> getOpportunisticSubscriptions(String callingPackage); + boolean removeSubscriptionsFromGroup(in int[] subIdList, String callingPackage); + + List<SubscriptionInfo> getSubscriptionsInGroup(int subId, String callingPackage); + int getSlotIndex(int subId); int[] getSubId(int slotIndex); diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 88b9302afacb..b12e7cc3ec6f 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -1337,18 +1337,6 @@ interface ITelephony { String getSubscriptionCarrierName(int subId); /** - * Returns MNO carrier id of the current subscription’s MCCMNC. - * <p>MNO carrier id can be solely identified by subscription mccmnc. This is mainly used - * for MNO fallback when exact carrier id {@link #getSimCarrierId()} - * configurations are not found. - * - * @return MNO carrier id of the current subscription. Return the value same as carrier id - * {@link #getSimCarrierId()}, if MNO carrier id cannot be identified. - * @hide - */ - int getSubscriptionMNOCarrierId(int subId); - - /** * Returns fine-grained carrier id of the current subscription. * * <p>The precise carrier id can be used to further differentiate a carrier by different @@ -1383,10 +1371,13 @@ interface ITelephony { * Returns carrier id based on MCCMNC only. This will return a MNO carrier id used for fallback * check when exact carrier id {@link #getSimCarrierId()} configurations are not found * + * @param isSubscriptionMccMnc. If {@true} it means this is a query for subscription mccmnc + * {@false} otherwise. + * * @return carrier id from passing mccmnc. * @hide */ - int getCarrierIdFromMccMnc(int slotIndex, String mccmnc); + int getCarrierIdFromMccMnc(int slotIndex, String mccmnc, boolean isSubscriptionMccMnc); /** * Action set from carrier signalling broadcast receivers to enable/disable metered apns diff --git a/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java b/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java index be74a6d162ae..7a5e7325ad22 100644 --- a/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java +++ b/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java @@ -92,11 +92,11 @@ public class UsageStatsDatabasePerfTest { event.mPackage = "fake.package.name" + pkg; event.mClass = event.mPackage + ".class1"; event.mTimeStamp = 1; - event.mEventType = UsageEvents.Event.MOVE_TO_FOREGROUND; + event.mEventType = UsageEvents.Event.ACTIVITY_RESUMED; for (int evt = 0; evt < eventsPerPackage; evt++) { intervalStats.events.insert(event); intervalStats.update(event.mPackage, event.mClass, event.mTimeStamp, - event.mEventType); + event.mEventType, 1); } } } diff --git a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java index 3480e96b3547..53afa26796ea 100644 --- a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java +++ b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java @@ -21,13 +21,14 @@ import android.app.usage.UsageStatsManager; import android.content.Context; import android.os.Bundle; import android.os.Handler; -import androidx.collection.CircularArray; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; +import androidx.collection.CircularArray; + public class UsageLogActivity extends ListActivity implements Runnable { private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14; @@ -155,10 +156,10 @@ public class UsageLogActivity extends ListActivity implements Runnable { private String eventToString(int eventType) { switch (eventType) { - case UsageEvents.Event.MOVE_TO_FOREGROUND: + case UsageEvents.Event.ACTIVITY_RESUMED: return "Foreground"; - case UsageEvents.Event.MOVE_TO_BACKGROUND: + case UsageEvents.Event.ACTIVITY_PAUSED: return "Background"; case UsageEvents.Event.CONFIGURATION_CHANGE: diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/java/android/net/NetworkCapabilitiesTest.java index 50aef1d24faf..84f735985b0d 100644 --- a/tests/net/java/android/net/NetworkCapabilitiesTest.java +++ b/tests/net/java/android/net/NetworkCapabilitiesTest.java @@ -474,7 +474,7 @@ public class NetworkCapabilitiesTest { new StringNetworkSpecifier("specs")); try { nc2.addTransportType(TRANSPORT_WIFI); - fail("Cannot set NetworkSpecifier on a NetworkCapability with multiple transports!"); + fail("Cannot set a second TransportType of a network which has a NetworkSpecifier!"); } catch (IllegalStateException expected) { // empty } @@ -500,16 +500,23 @@ public class NetworkCapabilitiesTest { // empty }); NetworkCapabilities nc2 = new NetworkCapabilities(); + // new TransportInfo so that object is not #equals to nc1's TransportInfo (that's where + // combine fails) nc2.setTransportInfo(new TransportInfo() { // empty }); try { nc1.combineCapabilities(nc2); - fail("Should not be able to combine NetworkCaabilities which contain TransportInfos"); + fail("Should not be able to combine NetworkCabilities which contain TransportInfos"); } catch (IllegalStateException expected) { // empty } + + // verify that can combine with identical TransportInfo objects + NetworkCapabilities nc3 = new NetworkCapabilities(); + nc3.setTransportInfo(nc1.getTransportInfo()); + nc1.combineCapabilities(nc3); } private void assertEqualsThroughMarshalling(NetworkCapabilities netCap) { diff --git a/tools/aapt2/configuration/ConfigurationParser_test.cpp b/tools/aapt2/configuration/ConfigurationParser_test.cpp index 3a71e836aa38..2ef8b999a192 100644 --- a/tools/aapt2/configuration/ConfigurationParser_test.cpp +++ b/tools/aapt2/configuration/ConfigurationParser_test.cpp @@ -230,7 +230,7 @@ TEST_F(ConfigurationParserTest, ValidateFile) { test::ParseConfigOrDie("fr"), test::ParseConfigOrDie("de"))); ASSERT_TRUE(a1.android_sdk); ASSERT_TRUE(a1.android_sdk.value().min_sdk_version); - EXPECT_EQ(a1.android_sdk.value().min_sdk_version, 19l); + EXPECT_EQ(a1.android_sdk.value().min_sdk_version, 19L); EXPECT_THAT(a1.textures, SizeIs(1ul)); EXPECT_THAT(a1.features, SizeIs(1ul)); @@ -250,7 +250,7 @@ TEST_F(ConfigurationParserTest, ValidateFile) { test::ParseConfigOrDie("fr-rCA"))); ASSERT_TRUE(a2.android_sdk); ASSERT_TRUE(a2.android_sdk.value().min_sdk_version); - EXPECT_EQ(a2.android_sdk.value().min_sdk_version, 19l); + EXPECT_EQ(a2.android_sdk.value().min_sdk_version, 19L); EXPECT_THAT(a2.textures, SizeIs(1ul)); EXPECT_THAT(a2.features, SizeIs(1ul)); } diff --git a/tools/localedata/extract_icu_data.py b/tools/localedata/extract_icu_data.py index 9dceba2163eb..6b4c34677d96 100755 --- a/tools/localedata/extract_icu_data.py +++ b/tools/localedata/extract_icu_data.py @@ -155,7 +155,7 @@ def dump_representative_locales(representative_locales): print print 'std::unordered_set<uint64_t> REPRESENTATIVE_LOCALES({' for locale in sorted(representative_locales): - print ' 0x%08Xllu, // %s' % ( + print ' 0x%08XLLU, // %s' % ( pack_to_uint64(locale), locale) print '});' diff --git a/tools/processors/view_inspector/OWNERS b/tools/processors/view_inspector/OWNERS new file mode 100644 index 000000000000..0473f54e57ca --- /dev/null +++ b/tools/processors/view_inspector/OWNERS @@ -0,0 +1,3 @@ +alanv@google.com +ashleyrose@google.com +aurimas@google.com
\ No newline at end of file diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java index f0b0ff6b979f..579745d2aaef 100644 --- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java +++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java @@ -18,16 +18,20 @@ package android.processor.view.inspector; import com.squareup.javapoet.ClassName; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; /** * Model of an inspectable class derived from annotations. * - * This class does not use any {javax.lang.model} objects to facilitate building models for testing - * {@link InspectionCompanionGenerator}. + * This class does not use any {@code javax.lang.model} objects to facilitate building models for + * testing {@link InspectionCompanionGenerator}. */ public final class InspectableClassModel { private final ClassName mClassName; + private final Map<String, Property> mPropertyMap; private Optional<String> mNodeName = Optional.empty(); /** @@ -35,6 +39,7 @@ public final class InspectableClassModel { */ public InspectableClassModel(ClassName className) { mClassName = className; + mPropertyMap = new HashMap<>(); } public ClassName getClassName() { @@ -48,4 +53,148 @@ public final class InspectableClassModel { public void setNodeName(Optional<String> nodeName) { mNodeName = nodeName; } + + /** + * Add a property to the model, replacing an existing property of the same name. + * + * @param property The property to add or replace + */ + public void putProperty(Property property) { + mPropertyMap.put(property.getName(), property); + } + + /** + * Get a property by name. + * + * @param name The name of the property + * @return The property or an empty optional + */ + public Optional<Property> getProperty(String name) { + return Optional.of(mPropertyMap.get(name)); + } + + /** + * Get all the properties defined on this model. + * + * @return An un-ordered collection of properties + */ + public Collection<Property> getAllProperties() { + return mPropertyMap.values(); + } + + /** + * Model an inspectable property + */ + public static final class Property { + private final String mName; + private String mGetter; + private Type mType; + private boolean mAttributeIdInferrableFromR = true; + private int mAttributeId = 0; + + public Property(String name) { + mName = name; + } + + public int getAttributeId() { + return mAttributeId; + } + + /** + * Set the attribute ID, and mark the attribute ID as non-inferrable. + * + * @param attributeId The attribute ID for this property + */ + public void setAttributeId(int attributeId) { + mAttributeIdInferrableFromR = false; + mAttributeId = attributeId; + } + + public boolean isAttributeIdInferrableFromR() { + return mAttributeIdInferrableFromR; + } + + public void setAttributeIdInferrableFromR(boolean attributeIdInferrableFromR) { + mAttributeIdInferrableFromR = attributeIdInferrableFromR; + } + + public String getName() { + return mName; + } + + public String getGetter() { + return mGetter; + } + + public void setGetter(String getter) { + mGetter = getter; + } + + public Type getType() { + return mType; + } + + public void setType(Type type) { + mType = type; + } + + public enum Type { + /** Primitive or boxed {@code boolean} */ + BOOLEAN, + + /** Primitive or boxed {@code byte} */ + BYTE, + + /** Primitive or boxed {@code char} */ + CHAR, + + /** Primitive or boxed {@code double} */ + DOUBLE, + + /** Primitive or boxed {@code float} */ + FLOAT, + + /** Primitive or boxed {@code int} */ + INT, + + /** Primitive or boxed {@code long} */ + LONG, + + /** Primitive or boxed {@code short} */ + SHORT, + + /** Any other object */ + OBJECT, + + /** + * A color object or packed color {@code int} or {@code long}. + * + * @see android.graphics.Color + * @see android.annotation.ColorInt + * @see android.annotation.ColorLong + */ + COLOR, + + /** + * An {@code int} packed with a gravity specification + * + * @see android.view.Gravity + */ + GRAVITY, + + /** + * An enumeration packed into an {@code int}. + * + * @see android.view.inspector.IntEnumMapping + */ + INT_ENUM, + + /** + * Non-exclusive or partially-exclusive flags packed into an {@code int}. + * + * @see android.view.inspector.IntFlagMapping + */ + INT_FLAG + } + } } diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java index fe0153d7f9af..3b85dbb77d5c 100644 --- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java +++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java @@ -16,13 +16,23 @@ package android.processor.view.inspector; +import android.processor.view.inspector.InspectableClassModel.Property; + import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.CodeBlock; +import com.squareup.javapoet.FieldSpec; import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.NameAllocator; import com.squareup.javapoet.ParameterizedTypeName; +import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; import java.io.IOException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.NoSuchElementException; import java.util.Optional; import javax.annotation.processing.Filer; @@ -36,10 +46,62 @@ public final class InspectionCompanionGenerator { private final Class mRequestingClass; /** + * The class name for {@code R.java}. + */ + private static final ClassName R_CLASS_NAME = ClassName.get("android", "R"); + + /** + * The class name of {@link android.content.res.ResourceId}. + */ + private static final ClassName RESOURCE_ID_CLASS_NAME = ClassName.get( + "android.content.res", "ResourceId"); + + /** + * The class name of {@link android.view.inspector.InspectionCompanion}. + */ + private static final ClassName INSPECTION_COMPANION = ClassName.get( + "android.view.inspector", "InspectionCompanion"); + + /** + * The class name of {@link android.view.inspector.PropertyMapper}. + */ + private static final ClassName PROPERTY_MAPPER = ClassName.get( + "android.view.inspector", "PropertyMapper"); + + /** + * The class name of {@link android.view.inspector.PropertyReader}. + */ + private static final ClassName PROPERTY_READER = ClassName.get( + "android.view.inspector", "PropertyReader"); + + /** + * The {@code mPropertiesMapped} field. + */ + private static final FieldSpec M_PROPERTIES_MAPPED = FieldSpec + .builder(TypeName.BOOLEAN, "mPropertiesMapped", Modifier.PRIVATE) + .initializer("false") + .addJavadoc( + "Set by {@link #mapProperties($T)} once properties have been mapped.\n", + PROPERTY_MAPPER) + .build(); + + /** + * The suffix of the generated class name after the class's binary name. + */ + private static final String GENERATED_CLASS_SUFFIX = "$$InspectionCompanion"; + + /** + * The null resource ID. + * + * @see android.content.res.ResourceId#ID_NULL + */ + private static final int NO_ID = 0; + + /** * @param filer A filer to write the generated source to * @param requestingClass A class object representing the class that invoked the generator */ - public InspectionCompanionGenerator(final Filer filer, final Class requestingClass) { + public InspectionCompanionGenerator(Filer filer, Class requestingClass) { mFiler = filer; mRequestingClass = requestingClass; } @@ -77,17 +139,24 @@ public final class InspectionCompanionGenerator { * @return A TypeSpec of the inspection companion */ private TypeSpec generateTypeSpec(InspectableClassModel model) { + final List<PropertyIdField> propertyIdFields = generatePropertyIdFields(model); + TypeSpec.Builder builder = TypeSpec .classBuilder(generateClassName(model)) .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addSuperinterface(ParameterizedTypeName.get( - ClassName.get("android.view.inspector", "InspectionCompanion"), - model.getClassName())) + INSPECTION_COMPANION, model.getClassName())) .addJavadoc("Inspection companion for {@link $T}.\n\n", model.getClassName()) .addJavadoc("Generated by {@link $T}\n", getClass()) .addJavadoc("on behalf of {@link $T}.\n", mRequestingClass) - .addMethod(generateMapProperties(model)) - .addMethod(generateReadProperties(model)); + .addField(M_PROPERTIES_MAPPED); + + for (PropertyIdField propertyIdField : propertyIdFields) { + builder.addField(propertyIdField.mFieldSpec); + } + + builder.addMethod(generateMapProperties(propertyIdFields)) + .addMethod(generateReadProperties(model, propertyIdFields)); generateGetNodeName(model).ifPresent(builder::addMethod); @@ -95,6 +164,42 @@ public final class InspectionCompanionGenerator { } /** + * Build a list of {@link PropertyIdField}'s for a model. + * + * To insure idempotency of the generated code, this method sorts the list of properties + * alphabetically by name. + * + * A {@link NameAllocator} is used to ensure that the field names are valid Java identifiers, + * and it prevents overlaps in names by suffixing them as needed. + * + * @param model The model to get properties from + * @return A list of properties and fields + */ + private List<PropertyIdField> generatePropertyIdFields(InspectableClassModel model) { + final NameAllocator nameAllocator = new NameAllocator(); + final List<Property> sortedProperties = new ArrayList<>(model.getAllProperties()); + final List<PropertyIdField> propertyIdFields = new ArrayList<>(sortedProperties.size()); + + sortedProperties.sort(Comparator.comparing(Property::getName)); + + for (Property property : sortedProperties) { + // Format a property to a member field name like "someProperty" -> "mSomePropertyId" + final String memberName = String.format( + "m%s%sId", + property.getName().substring(0, 1).toUpperCase(), + property.getName().substring(1)); + final FieldSpec fieldSpec = FieldSpec + .builder(TypeName.INT, nameAllocator.newName(memberName), Modifier.PRIVATE) + .addJavadoc("Property ID of {@code $L}.\n", property.getName()) + .build(); + + propertyIdFields.add(new PropertyIdField(fieldSpec, property)); + } + + return propertyIdFields; + } + + /** * Generate a method definition for * {@link android.view.inspector.InspectionCompanion#getNodeName()}, if needed. * @@ -119,21 +224,19 @@ public final class InspectionCompanionGenerator { * {@link android.view.inspector.InspectionCompanion#mapProperties( * android.view.inspector.PropertyMapper)}. * - * TODO: implement - * - * @param model The model to generate from + * @param propertyIdFields A list of properties to map to ID fields * @return The method definition */ - private MethodSpec generateMapProperties(InspectableClassModel model) { - final ClassName propertyMapper = ClassName.get( - "android.view.inspector", "PropertyMapper"); - - return MethodSpec.methodBuilder("mapProperties") + private MethodSpec generateMapProperties(List<PropertyIdField> propertyIdFields) { + final MethodSpec.Builder builder = MethodSpec.methodBuilder("mapProperties") .addAnnotation(Override.class) .addModifiers(Modifier.PUBLIC) - .addParameter(propertyMapper, "propertyMapper") - // TODO: add method body - .build(); + .addParameter(PROPERTY_MAPPER, "propertyMapper"); + + propertyIdFields.forEach(p -> builder.addStatement(generatePropertyMapperInvocation(p))); + builder.addStatement("$N = true", M_PROPERTIES_MAPPED); + + return builder.build(); } /** @@ -141,21 +244,91 @@ public final class InspectionCompanionGenerator { * {@link android.view.inspector.InspectionCompanion#readProperties( * Object, android.view.inspector.PropertyReader)}. * - * TODO: implement - * * @param model The model to generate from + * @param propertyIdFields A list of properties and ID fields to read from * @return The method definition */ - private MethodSpec generateReadProperties(InspectableClassModel model) { - final ClassName propertyReader = ClassName.get( - "android.view.inspector", "PropertyReader"); - - return MethodSpec.methodBuilder("readProperties") + private MethodSpec generateReadProperties( + InspectableClassModel model, + List<PropertyIdField> propertyIdFields) { + final MethodSpec.Builder builder = MethodSpec.methodBuilder("readProperties") .addAnnotation(Override.class) .addModifiers(Modifier.PUBLIC) .addParameter(model.getClassName(), "inspectable") - .addParameter(propertyReader, "propertyReader") - // TODO: add method body + .addParameter(PROPERTY_READER, "propertyReader") + .addCode(generatePropertyMapInitializationCheck()); + + for (PropertyIdField propertyIdField : propertyIdFields) { + builder.addStatement( + "propertyReader.read$L($N, inspectable.$L())", + methodSuffixForPropertyType(propertyIdField.mProperty.getType()), + propertyIdField.mFieldSpec, + propertyIdField.mProperty.getGetter()); + } + + return builder.build(); + } + + /** + * Generate a statement maps a property with a {@link android.view.inspector.PropertyMapper}. + * + * @param propertyIdField The property model and ID field to generate from + * @return A statement that invokes property mapper method + */ + private CodeBlock generatePropertyMapperInvocation(PropertyIdField propertyIdField) { + final CodeBlock.Builder builder = CodeBlock.builder(); + final Property property = propertyIdField.mProperty; + final FieldSpec fieldSpec = propertyIdField.mFieldSpec; + + builder.add( + "$N = propertyMapper.map$L($S,$W", + fieldSpec, + methodSuffixForPropertyType(property.getType()), + property.getName()); + + if (property.isAttributeIdInferrableFromR()) { + builder.add("$T.attr.$L", R_CLASS_NAME, property.getName()); + } else { + if (property.getAttributeId() == NO_ID) { + builder.add("$T.ID_NULL", RESOURCE_ID_CLASS_NAME); + } else { + builder.add("$L", String.format("0x%08x", property.getAttributeId())); + } + } + + switch (property.getType()) { + case INT_ENUM: + throw new RuntimeException("IntEnumMapping generation not implemented"); + case INT_FLAG: + throw new RuntimeException("IntFlagMapping generation not implemented"); + default: + builder.add(")"); + break; + } + + return builder.build(); + } + + /** + * Generate a check that throws + * {@link android.view.inspector.InspectionCompanion.UninitializedPropertyMapException} + * if the properties haven't been initialized. + * + * <pre> + * if (!mPropertiesMapped) { + * throw new InspectionCompanion.UninitializedPropertyMapException(); + * } + * </pre> + * + * @return A codeblock containing the property map initialization check + */ + private CodeBlock generatePropertyMapInitializationCheck() { + return CodeBlock.builder() + .beginControlFlow("if (!$N)", M_PROPERTIES_MAPPED) + .addStatement( + "throw new $T()", + INSPECTION_COMPANION.nestedClass("UninitializedPropertyMapException")) + .endControlFlow() .build(); } @@ -163,19 +336,71 @@ public final class InspectionCompanionGenerator { * Generate the final class name for the inspection companion from the model's class name. * * The generated class is added to the same package as the source class. If the class in the - * model is a nested class, the nested class names are joined with {"$"}. The suffix - * {"$$InspectionCompanion"} is always added the the generated name. E.g.: For modeled class - * {com.example.Outer.Inner}, the generated class name will be - * {com.example.Outer$Inner$$InspectionCompanion}. + * model is a nested class, the nested class names are joined with {@code "$"}. The suffix + * {@code "$$InspectionCompanion"} is always added the the generated name. E.g.: For modeled + * class {@code com.example.Outer.Inner}, the generated class name will be + * {@code com.example.Outer$Inner$$InspectionCompanion}. * * @param model The model to generate from * @return A class name for the generated inspection companion class */ - private ClassName generateClassName(final InspectableClassModel model) { + private static ClassName generateClassName(InspectableClassModel model) { final ClassName className = model.getClassName(); return ClassName.get( className.packageName(), - String.join("$", className.simpleNames()) + "$$InspectionCompanion"); + String.join("$", className.simpleNames()) + GENERATED_CLASS_SUFFIX); + } + + /** + * Get the suffix for a {@code map} or {@code read} method for a property type. + * + * @param type The requested property type + * @return A method suffix + */ + private static String methodSuffixForPropertyType(Property.Type type) { + switch (type) { + case BOOLEAN: + return "Boolean"; + case BYTE: + return "Byte"; + case CHAR: + return "Char"; + case DOUBLE: + return "Double"; + case FLOAT: + return "Float"; + case INT: + return "Int"; + case LONG: + return "Long"; + case SHORT: + return "Short"; + case OBJECT: + return "Object"; + case COLOR: + return "Color"; + case GRAVITY: + return "Gravity"; + case INT_ENUM: + return "IntEnum"; + case INT_FLAG: + return "IntFlag"; + default: + throw new NoSuchElementException(String.format("No such property type, %s", type)); + } + } + + /** + * Value class that holds a {@link Property} and a {@link FieldSpec} for that property. + */ + private static final class PropertyIdField { + private final FieldSpec mFieldSpec; + private final Property mProperty; + + private PropertyIdField(FieldSpec fieldSpec, Property property) { + mFieldSpec = fieldSpec; + mProperty = property; + } } } diff --git a/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java b/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java index c02b0bdba1cf..f639719800f6 100644 --- a/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java +++ b/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java @@ -16,6 +16,8 @@ package android.processor.view.inspector; +import android.processor.view.inspector.InspectableClassModel.Property; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; import static junit.framework.TestCase.fail; @@ -61,6 +63,54 @@ public class InspectionCompanionGeneratorTest { assertGeneratedFileEquals("NestedClass"); } + @Test + public void testSimpleProperties() { + addProperty("boolean", Property.Type.BOOLEAN, "getBoolean"); + addProperty("byte", Property.Type.BYTE, "getByte"); + addProperty("char", Property.Type.CHAR, "getChar"); + addProperty("double", Property.Type.DOUBLE, "getDouble"); + addProperty("float", Property.Type.FLOAT, "getFloat"); + addProperty("int", Property.Type.INT, "getInt"); + addProperty("long", Property.Type.LONG, "getLong"); + addProperty("short", Property.Type.SHORT, "getShort"); + + addProperty("object", Property.Type.OBJECT, "getObject"); + addProperty("color", Property.Type.COLOR, "getColor"); + addProperty("gravity", Property.Type.GRAVITY, "getGravity"); + + assertGeneratedFileEquals("SimpleProperties"); + } + + @Test + public void testNoAttributeId() { + final Property property = new Property("noAttributeProperty"); + property.setType(Property.Type.INT); + property.setGetter("getNoAttributeProperty"); + property.setAttributeIdInferrableFromR(false); + mModel.putProperty(property); + + assertGeneratedFileEquals("NoAttributeId"); + } + + @Test + public void testSuppliedAttributeId() { + final Property property = new Property("suppliedAttributeProperty"); + property.setType(Property.Type.INT); + property.setGetter("getSuppliedAttributeProperty"); + property.setAttributeId(0xdecafbad); + mModel.putProperty(property); + + assertGeneratedFileEquals("SuppliedAttributeId"); + } + + private Property addProperty(String name, Property.Type type, String getter) { + final Property property = new Property(name); + property.setType(type); + property.setGetter(getter); + mModel.putProperty(property); + return property; + } + private void assertGeneratedFileEquals(String fileName) { assertEquals( loadTextResource(String.format(RESOURCE_PATH_TEMPLATE, fileName)), diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt index e5fb6a2129f5..2fc242c6cf4c 100644 --- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt +++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt @@ -12,11 +12,20 @@ import java.lang.Override; * on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}. */ public final class Outer$Inner$$InspectionCompanion implements InspectionCompanion<Outer.Inner> { + /** + * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped. + */ + private boolean mPropertiesMapped = false; + @Override public void mapProperties(PropertyMapper propertyMapper) { + mPropertiesMapped = true; } @Override public void readProperties(Outer.Inner inspectable, PropertyReader propertyReader) { + if (!mPropertiesMapped) { + throw new InspectionCompanion.UninitializedPropertyMapException(); + } } } diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt new file mode 100644 index 000000000000..277e84065fb7 --- /dev/null +++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt @@ -0,0 +1,39 @@ +package com.android.inspectable; + +import android.content.res.ResourceId; +import android.view.inspector.InspectionCompanion; +import android.view.inspector.PropertyMapper; +import android.view.inspector.PropertyReader; +import java.lang.Override; + +/** + * Inspection companion for {@link TestInspectable}. + * + * Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator} + * on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}. + */ +public final class TestInspectable$$InspectionCompanion implements InspectionCompanion<TestInspectable> { + /** + * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped. + */ + private boolean mPropertiesMapped = false; + + /** + * Property ID of {@code noAttributeProperty}. + */ + private int mNoAttributePropertyId; + + @Override + public void mapProperties(PropertyMapper propertyMapper) { + mNoAttributePropertyId = propertyMapper.mapInt("noAttributeProperty", ResourceId.ID_NULL); + mPropertiesMapped = true; + } + + @Override + public void readProperties(TestInspectable inspectable, PropertyReader propertyReader) { + if (!mPropertiesMapped) { + throw new InspectionCompanion.UninitializedPropertyMapException(); + } + propertyReader.readInt(mNoAttributePropertyId, inspectable.getNoAttributeProperty()); + } +} diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt index a334f50bbdf5..11425482ce94 100644 --- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt +++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt @@ -13,12 +13,21 @@ import java.lang.String; * on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}. */ public final class TestInspectable$$InspectionCompanion implements InspectionCompanion<TestInspectable> { + /** + * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped. + */ + private boolean mPropertiesMapped = false; + @Override public void mapProperties(PropertyMapper propertyMapper) { + mPropertiesMapped = true; } @Override public void readProperties(TestInspectable inspectable, PropertyReader propertyReader) { + if (!mPropertiesMapped) { + throw new InspectionCompanion.UninitializedPropertyMapException(); + } } @Override diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt new file mode 100644 index 000000000000..57eb08041131 --- /dev/null +++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt @@ -0,0 +1,109 @@ +package com.android.inspectable; + +import android.R; +import android.view.inspector.InspectionCompanion; +import android.view.inspector.PropertyMapper; +import android.view.inspector.PropertyReader; +import java.lang.Override; + +/** + * Inspection companion for {@link TestInspectable}. + * + * Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator} + * on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}. + */ +public final class TestInspectable$$InspectionCompanion implements InspectionCompanion<TestInspectable> { + /** + * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped. + */ + private boolean mPropertiesMapped = false; + + /** + * Property ID of {@code boolean}. + */ + private int mBooleanId; + + /** + * Property ID of {@code byte}. + */ + private int mByteId; + + /** + * Property ID of {@code char}. + */ + private int mCharId; + + /** + * Property ID of {@code color}. + */ + private int mColorId; + + /** + * Property ID of {@code double}. + */ + private int mDoubleId; + + /** + * Property ID of {@code float}. + */ + private int mFloatId; + + /** + * Property ID of {@code gravity}. + */ + private int mGravityId; + + /** + * Property ID of {@code int}. + */ + private int mIntId; + + /** + * Property ID of {@code long}. + */ + private int mLongId; + + /** + * Property ID of {@code object}. + */ + private int mObjectId; + + /** + * Property ID of {@code short}. + */ + private int mShortId; + + @Override + public void mapProperties(PropertyMapper propertyMapper) { + mBooleanId = propertyMapper.mapBoolean("boolean", R.attr.boolean); + mByteId = propertyMapper.mapByte("byte", R.attr.byte); + mCharId = propertyMapper.mapChar("char", R.attr.char); + mColorId = propertyMapper.mapColor("color", R.attr.color); + mDoubleId = propertyMapper.mapDouble("double", R.attr.double); + mFloatId = propertyMapper.mapFloat("float", R.attr.float); + mGravityId = propertyMapper.mapGravity("gravity", R.attr.gravity); + mIntId = propertyMapper.mapInt("int", R.attr.int); + mLongId = propertyMapper.mapLong("long", R.attr.long); + mObjectId = propertyMapper.mapObject("object", R.attr.object); + mShortId = propertyMapper.mapShort("short", R.attr.short); + mPropertiesMapped = true; + } + + @Override + public void readProperties(TestInspectable inspectable, PropertyReader propertyReader) { + if (!mPropertiesMapped) { + throw new InspectionCompanion.UninitializedPropertyMapException(); + } + propertyReader.readBoolean(mBooleanId, inspectable.getBoolean()); + propertyReader.readByte(mByteId, inspectable.getByte()); + propertyReader.readChar(mCharId, inspectable.getChar()); + propertyReader.readColor(mColorId, inspectable.getColor()); + propertyReader.readDouble(mDoubleId, inspectable.getDouble()); + propertyReader.readFloat(mFloatId, inspectable.getFloat()); + propertyReader.readGravity(mGravityId, inspectable.getGravity()); + propertyReader.readInt(mIntId, inspectable.getInt()); + propertyReader.readLong(mLongId, inspectable.getLong()); + propertyReader.readObject(mObjectId, inspectable.getObject()); + propertyReader.readShort(mShortId, inspectable.getShort()); + } +} diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt new file mode 100644 index 000000000000..6b6ce2157481 --- /dev/null +++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt @@ -0,0 +1,39 @@ +package com.android.inspectable; + +import android.view.inspector.InspectionCompanion; +import android.view.inspector.PropertyMapper; +import android.view.inspector.PropertyReader; +import java.lang.Override; + +/** + * Inspection companion for {@link TestInspectable}. + * + * Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator} + * on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}. + */ +public final class TestInspectable$$InspectionCompanion implements InspectionCompanion<TestInspectable> { + /** + * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped. + */ + private boolean mPropertiesMapped = false; + + /** + * Property ID of {@code suppliedAttributeProperty}. + */ + private int mSuppliedAttributePropertyId; + + @Override + public void mapProperties(PropertyMapper propertyMapper) { + mSuppliedAttributePropertyId = propertyMapper.mapInt("suppliedAttributeProperty", + 0xdecafbad); + mPropertiesMapped = true; + } + + @Override + public void readProperties(TestInspectable inspectable, PropertyReader propertyReader) { + if (!mPropertiesMapped) { + throw new InspectionCompanion.UninitializedPropertyMapException(); + } + propertyReader.readInt(mSuppliedAttributePropertyId, inspectable.getSuppliedAttributeProperty()); + } +} diff --git a/tools/signedconfig/debug_key.pem b/tools/signedconfig/debug_key.pem new file mode 100644 index 000000000000..0af577bf81e1 --- /dev/null +++ b/tools/signedconfig/debug_key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIEfgtO+KPOoqJqTnqkDDKkAcOzyvtovsUO/ShLE6y4XRoAoGCCqGSM49 +AwEHoUQDQgAEaAn2XVifsLTHg616nTsOMVmlhBoECGbTEBTKKvdd2hO60pj1pnU8 +SMkhYfaNxZuKgw9LNvOwlFwStboIYeZ3lQ== +-----END EC PRIVATE KEY----- diff --git a/tools/signedconfig/debug_public.pem b/tools/signedconfig/debug_public.pem new file mode 100644 index 000000000000..f61f81322b94 --- /dev/null +++ b/tools/signedconfig/debug_public.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaAn2XVifsLTHg616nTsOMVmlhBoE +CGbTEBTKKvdd2hO60pj1pnU8SMkhYfaNxZuKgw9LNvOwlFwStboIYeZ3lQ== +-----END PUBLIC KEY----- diff --git a/tools/signedconfig/debug_sign.sh b/tools/signedconfig/debug_sign.sh new file mode 100755 index 000000000000..28e54289f8f8 --- /dev/null +++ b/tools/signedconfig/debug_sign.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# Script to sign data with the debug keys. Outputs base64 for embedding into +# APK metadata. + +openssl dgst -sha256 -sign $(dirname $0)/debug_key.pem $1 | base64 -w 0 +echo diff --git a/tools/signedconfig/gen_priv_key.sh b/tools/signedconfig/gen_priv_key.sh new file mode 100755 index 000000000000..834c86bc8c12 --- /dev/null +++ b/tools/signedconfig/gen_priv_key.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# This script acts as a record of how the debug key was generated. There should +# be no need to run it again. + +openssl ecparam -name prime256v1 -genkey -noout -out debug_key.pem +openssl ec -in debug_key.pem -pubout -out debug_public.pem diff --git a/tools/signedconfig/verify_b64.sh b/tools/signedconfig/verify_b64.sh new file mode 100755 index 000000000000..8e1f58ce7b45 --- /dev/null +++ b/tools/signedconfig/verify_b64.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# Script to verify signatures, with both signature & data given in b64 +# Args: +# 1. data (base64 encoded) +# 2. signature (base64 encoded) +# The arg values can be taken from the debug log for SignedConfigService when verbose logging is +# enabled. + +openssl dgst -sha256 -verify $(dirname $0)/debug_public.pem -signature <(echo $2 | base64 -d) <(echo $1 | base64 -d) diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index c6acd026bd39..21d6b94fba24 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -193,5 +193,7 @@ interface IWifiManager int addNetworkSuggestions(in List<WifiNetworkSuggestion> networkSuggestions, in String packageName); int removeNetworkSuggestions(in List<WifiNetworkSuggestion> networkSuggestions, in String packageName); + + String[] getFactoryMacAddresses(); } diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index cad6d2997bfb..57c97eaf1f10 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -2062,7 +2062,6 @@ public class WifiManager { /** * @return true if this adapter supports Device-to-AP RTT */ - @SystemApi public boolean isDeviceToApRttSupported() { return isFeatureSupported(WIFI_FEATURE_D2AP_RTT); } @@ -4435,4 +4434,19 @@ public class WifiManager { public boolean isOweSupported() { return isFeatureSupported(WIFI_FEATURE_OWE); } + + /** + * Gets the factory Wi-Fi MAC addresses. + * @return Array of String representing Wi-Fi MAC addresses sorted lexically or an empty Array + * if failed. + * @hide + */ + @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) + public String[] getFactoryMacAddresses() { + try { + return mService.getFactoryMacAddresses(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/wifi/java/com/android/server/wifi/AbstractWifiService.java b/wifi/java/com/android/server/wifi/AbstractWifiService.java index 0f4e3a8ba20f..36f66aa81661 100644 --- a/wifi/java/com/android/server/wifi/AbstractWifiService.java +++ b/wifi/java/com/android/server/wifi/AbstractWifiService.java @@ -452,4 +452,9 @@ public abstract class AbstractWifiService extends IWifiManager.Stub { List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName) { throw new UnsupportedOperationException(); } + + @Override + public String[] getFactoryMacAddresses() { + throw new UnsupportedOperationException(); + } } diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java index 13c8c9ea7ead..1001b100cb3b 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -29,6 +29,7 @@ import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING; import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -88,6 +89,7 @@ public class WifiManagerTest { private static final int TEST_UID = 14553; private static final String TEST_PACKAGE_NAME = "TestPackage"; private static final String TEST_COUNTRY_CODE = "US"; + private static final String[] TEST_MAC_ADDRESSES = {"da:a1:19:0:0:0"}; @Mock Context mContext; @Mock @@ -1320,4 +1322,15 @@ i * Verify that a call to cancel WPS immediately returns a failure. assertEquals(WifiManager.NETWORK_SUGGESTIONS_MAX_PER_APP, mWifiManager.getMaxNumberOfNetworkSuggestionsPerApp()); } + + /** + * Verify getting the factory MAC address. + * @throws Exception + */ + @Test + public void testGetFactoryMacAddress() throws Exception { + when(mWifiService.getFactoryMacAddresses()).thenReturn(TEST_MAC_ADDRESSES); + assertArrayEquals(TEST_MAC_ADDRESSES, mWifiManager.getFactoryMacAddresses()); + verify(mWifiService).getFactoryMacAddresses(); + } } |