diff options
192 files changed, 4507 insertions, 2114 deletions
diff --git a/Android.bp b/Android.bp index 4e7aa5f82d91..e8f35611e74b 100644 --- a/Android.bp +++ b/Android.bp @@ -636,7 +636,7 @@ java_defaults { "wifi/java/android/net/wifi/ISoftApCallback.aidl", "wifi/java/android/net/wifi/ITrafficStateCallback.aidl", "wifi/java/android/net/wifi/IWifiManager.aidl", - "wifi/java/android/net/wifi/IWifiUsabilityStatsListener.aidl", + "wifi/java/android/net/wifi/IOnWifiUsabilityStatsListener.aidl", "wifi/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl", "wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl", "wifi/java/android/net/wifi/aware/IWifiAwareMacAddressProvider.aidl", diff --git a/api/current.txt b/api/current.txt index 5b68eb579a79..8e0c75e85a99 100644 --- a/api/current.txt +++ b/api/current.txt @@ -130,7 +130,7 @@ package android { field public static final String REQUEST_DELETE_PACKAGES = "android.permission.REQUEST_DELETE_PACKAGES"; field public static final String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"; field public static final String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES"; - field public static final String REQUEST_SCREEN_LOCK_COMPLEXITY = "android.permission.REQUEST_SCREEN_LOCK_COMPLEXITY"; + field public static final String REQUEST_PASSWORD_COMPLEXITY = "android.permission.REQUEST_PASSWORD_COMPLEXITY"; field @Deprecated public static final String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES"; field public static final String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE"; field public static final String SEND_SMS = "android.permission.SEND_SMS"; @@ -6509,9 +6509,9 @@ package android.app.admin { public class DelegatedAdminReceiver extends android.content.BroadcastReceiver { ctor public DelegatedAdminReceiver(); - method public String onChoosePrivateKeyAlias(android.content.Context, android.content.Intent, int, android.net.Uri, String); - method public void onNetworkLogsAvailable(android.content.Context, android.content.Intent, long, int); - method public void onReceive(android.content.Context, android.content.Intent); + method @Nullable public String onChoosePrivateKeyAlias(@NonNull android.content.Context, @NonNull android.content.Intent, int, @Nullable android.net.Uri, @Nullable String); + method public void onNetworkLogsAvailable(@NonNull android.content.Context, @NonNull android.content.Intent, long, @IntRange(from=1) int); + method public final void onReceive(@NonNull android.content.Context, @NonNull android.content.Intent); } public final class DeviceAdminInfo implements android.os.Parcelable { @@ -6544,38 +6544,38 @@ package android.app.admin { public class DeviceAdminReceiver extends android.content.BroadcastReceiver { ctor public DeviceAdminReceiver(); - method public android.app.admin.DevicePolicyManager getManager(android.content.Context); - method public android.content.ComponentName getWho(android.content.Context); - method public void onBugreportFailed(android.content.Context, android.content.Intent, int); - method public void onBugreportShared(android.content.Context, android.content.Intent, String); - method public void onBugreportSharingDeclined(android.content.Context, android.content.Intent); - method public String onChoosePrivateKeyAlias(android.content.Context, android.content.Intent, int, android.net.Uri, String); - method public CharSequence onDisableRequested(android.content.Context, android.content.Intent); - method public void onDisabled(android.content.Context, android.content.Intent); - method public void onEnabled(android.content.Context, android.content.Intent); - method public void onLockTaskModeEntering(android.content.Context, android.content.Intent, String); - method public void onLockTaskModeExiting(android.content.Context, android.content.Intent); - method public void onNetworkLogsAvailable(android.content.Context, android.content.Intent, long, int); - method @Deprecated public void onPasswordChanged(android.content.Context, android.content.Intent); - method public void onPasswordChanged(android.content.Context, android.content.Intent, android.os.UserHandle); - method @Deprecated public void onPasswordExpiring(android.content.Context, android.content.Intent); - method public void onPasswordExpiring(android.content.Context, android.content.Intent, android.os.UserHandle); - method @Deprecated public void onPasswordFailed(android.content.Context, android.content.Intent); - method public void onPasswordFailed(android.content.Context, android.content.Intent, android.os.UserHandle); - method @Deprecated public void onPasswordSucceeded(android.content.Context, android.content.Intent); - method public void onPasswordSucceeded(android.content.Context, android.content.Intent, android.os.UserHandle); - method public void onProfileProvisioningComplete(android.content.Context, android.content.Intent); - method @Deprecated public void onReadyForUserInitialization(android.content.Context, android.content.Intent); - method public void onReceive(android.content.Context, android.content.Intent); - method public void onSecurityLogsAvailable(android.content.Context, android.content.Intent); - method public void onSystemUpdatePending(android.content.Context, android.content.Intent, long); - method public void onTransferAffiliatedProfileOwnershipComplete(android.content.Context, android.os.UserHandle); + method @NonNull public android.app.admin.DevicePolicyManager getManager(@NonNull android.content.Context); + method @NonNull public android.content.ComponentName getWho(@NonNull android.content.Context); + method public void onBugreportFailed(@NonNull android.content.Context, @NonNull android.content.Intent, int); + method public void onBugreportShared(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull String); + method public void onBugreportSharingDeclined(@NonNull android.content.Context, @NonNull android.content.Intent); + method @Nullable public String onChoosePrivateKeyAlias(@NonNull android.content.Context, @NonNull android.content.Intent, int, @Nullable android.net.Uri, @Nullable String); + method @Nullable public CharSequence onDisableRequested(@NonNull android.content.Context, @NonNull android.content.Intent); + method public void onDisabled(@NonNull android.content.Context, @NonNull android.content.Intent); + method public void onEnabled(@NonNull android.content.Context, @NonNull android.content.Intent); + method public void onLockTaskModeEntering(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull String); + method public void onLockTaskModeExiting(@NonNull android.content.Context, @NonNull android.content.Intent); + method public void onNetworkLogsAvailable(@NonNull android.content.Context, @NonNull android.content.Intent, long, @IntRange(from=1) int); + method @Deprecated public void onPasswordChanged(@NonNull android.content.Context, @NonNull android.content.Intent); + method public void onPasswordChanged(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull android.os.UserHandle); + method @Deprecated public void onPasswordExpiring(@NonNull android.content.Context, @NonNull android.content.Intent); + method public void onPasswordExpiring(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull android.os.UserHandle); + method @Deprecated public void onPasswordFailed(@NonNull android.content.Context, @NonNull android.content.Intent); + method public void onPasswordFailed(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull android.os.UserHandle); + method @Deprecated public void onPasswordSucceeded(@NonNull android.content.Context, @NonNull android.content.Intent); + method public void onPasswordSucceeded(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull android.os.UserHandle); + method public void onProfileProvisioningComplete(@NonNull android.content.Context, @NonNull android.content.Intent); + method @Deprecated public void onReadyForUserInitialization(@NonNull android.content.Context, @NonNull android.content.Intent); + method public void onReceive(@NonNull android.content.Context, @NonNull android.content.Intent); + method public void onSecurityLogsAvailable(@NonNull android.content.Context, @NonNull android.content.Intent); + method public void onSystemUpdatePending(@NonNull android.content.Context, @NonNull android.content.Intent, long); + method public void onTransferAffiliatedProfileOwnershipComplete(@NonNull android.content.Context, @NonNull android.os.UserHandle); method public void onTransferOwnershipComplete(@NonNull android.content.Context, @Nullable android.os.PersistableBundle); - method public void onUserAdded(android.content.Context, android.content.Intent, @NonNull android.os.UserHandle); - method public void onUserRemoved(android.content.Context, android.content.Intent, @NonNull android.os.UserHandle); - method public void onUserStarted(android.content.Context, android.content.Intent, @NonNull android.os.UserHandle); - method public void onUserStopped(android.content.Context, android.content.Intent, @NonNull android.os.UserHandle); - method public void onUserSwitched(android.content.Context, android.content.Intent, @NonNull android.os.UserHandle); + method public void onUserAdded(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull android.os.UserHandle); + method public void onUserRemoved(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull android.os.UserHandle); + method public void onUserStarted(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull android.os.UserHandle); + method public void onUserStopped(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull android.os.UserHandle); + method public void onUserSwitched(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull android.os.UserHandle); field public static final String ACTION_CHOOSE_PRIVATE_KEY_ALIAS = "android.app.action.CHOOSE_PRIVATE_KEY_ALIAS"; field public static final String ACTION_DEVICE_ADMIN_DISABLED = "android.app.action.DEVICE_ADMIN_DISABLED"; field public static final String ACTION_DEVICE_ADMIN_DISABLE_REQUESTED = "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED"; @@ -6656,7 +6656,7 @@ package android.app.admin { method @Nullable public CharSequence getOrganizationName(@NonNull android.content.ComponentName); method public java.util.List<android.telephony.data.ApnSetting> getOverrideApns(@NonNull android.content.ComponentName); method @NonNull public android.app.admin.DevicePolicyManager getParentProfileInstance(@NonNull android.content.ComponentName); - method @RequiresPermission(android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY) public int getPasswordComplexity(); + method @RequiresPermission(android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY) public int getPasswordComplexity(); method public long getPasswordExpiration(@Nullable android.content.ComponentName); method public long getPasswordExpirationTimeout(@Nullable android.content.ComponentName); method public int getPasswordHistoryLength(@Nullable android.content.ComponentName); @@ -6851,7 +6851,7 @@ package android.app.admin { field public static final String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION"; field public static final String EXTRA_DELEGATION_SCOPES = "android.app.extra.DELEGATION_SCOPES"; field public static final String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN"; - field @RequiresPermission(android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY) public static final String EXTRA_PASSWORD_COMPLEXITY = "android.app.extra.PASSWORD_COMPLEXITY"; + field @RequiresPermission(android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY) public static final String EXTRA_PASSWORD_COMPLEXITY = "android.app.extra.PASSWORD_COMPLEXITY"; field public static final String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE"; field public static final String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE"; field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME"; @@ -6949,7 +6949,7 @@ package android.app.admin { field public static final int PRIVATE_DNS_MODE_UNKNOWN = 0; // 0x0 field public static final int PRIVATE_DNS_SET_ERROR_FAILURE_SETTING = 2; // 0x2 field public static final int PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING = 1; // 0x1 - field public static final int PRIVATE_DNS_SET_SUCCESS = 0; // 0x0 + field public static final int PRIVATE_DNS_SET_NO_ERROR = 0; // 0x0 field public static final int PROVISIONING_MODE_FULLY_MANAGED_DEVICE = 1; // 0x1 field public static final int PROVISIONING_MODE_MANAGED_PROFILE = 2; // 0x2 field public static final int PROVISIONING_MODE_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE = 3; // 0x3 @@ -7966,9 +7966,9 @@ package android.bluetooth { method public boolean isMultipleAdvertisementSupported(); method public boolean isOffloadedFilteringSupported(); method public boolean isOffloadedScanBatchingSupported(); - method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingInsecureL2capChannel() throws java.io.IOException; + method @RequiresPermission(android.Manifest.permission.BLUETOOTH) @NonNull public android.bluetooth.BluetoothServerSocket listenUsingInsecureL2capChannel() throws java.io.IOException; method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException; - method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingL2capChannel() throws java.io.IOException; + method @RequiresPermission(android.Manifest.permission.BLUETOOTH) @NonNull public android.bluetooth.BluetoothServerSocket listenUsingL2capChannel() throws java.io.IOException; method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException; method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setName(String); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean startDiscovery(); @@ -8336,9 +8336,9 @@ package android.bluetooth { method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int); method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int, android.os.Handler); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean createBond(); - method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createInsecureL2capChannel(int) throws java.io.IOException; + method @RequiresPermission(android.Manifest.permission.BLUETOOTH) @NonNull public android.bluetooth.BluetoothSocket createInsecureL2capChannel(int) throws java.io.IOException; method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException; - method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createL2capChannel(int) throws java.io.IOException; + method @RequiresPermission(android.Manifest.permission.BLUETOOTH) @NonNull public android.bluetooth.BluetoothSocket createL2capChannel(int) throws java.io.IOException; method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException; method public int describeContents(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean fetchUuidsWithSdp(); @@ -11271,11 +11271,11 @@ package android.content.pm { method public boolean shouldHideFromSuggestions(@NonNull String, @NonNull android.os.UserHandle); method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle); method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle); - method public void startPackageInstallerSessionDetailsActivity(android.content.pm.PackageInstaller.SessionInfo, android.graphics.Rect, android.os.Bundle); + method public void startPackageInstallerSessionDetailsActivity(@NonNull android.content.pm.PackageInstaller.SessionInfo, @Nullable android.graphics.Rect, @Nullable android.os.Bundle); method public void startShortcut(@NonNull String, @NonNull String, @Nullable android.graphics.Rect, @Nullable android.os.Bundle, @NonNull android.os.UserHandle); method public void startShortcut(@NonNull android.content.pm.ShortcutInfo, @Nullable android.graphics.Rect, @Nullable android.os.Bundle); method public void unregisterCallback(android.content.pm.LauncherApps.Callback); - method public void unregisterPackageInstallerSessionCallback(android.content.pm.PackageInstaller.SessionCallback); + method public void unregisterPackageInstallerSessionCallback(@NonNull android.content.pm.PackageInstaller.SessionCallback); field public static final String ACTION_CONFIRM_PIN_APPWIDGET = "android.content.pm.action.CONFIRM_PIN_APPWIDGET"; field public static final String ACTION_CONFIRM_PIN_SHORTCUT = "android.content.pm.action.CONFIRM_PIN_SHORTCUT"; field public static final String EXTRA_PIN_ITEM_REQUEST = "android.content.pm.extra.PIN_ITEM_REQUEST"; @@ -11465,7 +11465,7 @@ package android.content.pm { method public long getSize(); method public int getStagedSessionErrorCode(); method @NonNull public String getStagedSessionErrorMessage(); - method public android.os.UserHandle getUser(); + method @NonNull public android.os.UserHandle getUser(); method public boolean isActive(); method public boolean isMultiPackage(); method public boolean isSealed(); @@ -11945,6 +11945,7 @@ package android.content.pm { field public static final int FOREGROUND_SERVICE_TYPE_LOCATION = 8; // 0x8 field public static final int FOREGROUND_SERVICE_TYPE_MANIFEST = -1; // 0xffffffff field public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK = 2; // 0x2 + field public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION = 32; // 0x20 field public static final int FOREGROUND_SERVICE_TYPE_NONE = 0; // 0x0 field public static final int FOREGROUND_SERVICE_TYPE_PHONE_CALL = 4; // 0x4 field public int flags; @@ -14430,6 +14431,7 @@ package android.graphics { method @ColorInt public int getColor(); method public android.graphics.ColorFilter getColorFilter(); method @ColorLong public long getColorLong(); + method public int getEndHyphenEdit(); method public boolean getFillPath(android.graphics.Path, android.graphics.Path); method public int getFlags(); method public String getFontFeatureSettings(); @@ -14440,7 +14442,6 @@ package android.graphics { method public float getFontSpacing(); method public String getFontVariationSettings(); method public int getHinting(); - method public int getHyphenEdit(); method public float getLetterSpacing(); method public android.graphics.MaskFilter getMaskFilter(); method public int getOffsetForAdvance(char[], int, int, int, int, boolean, float); @@ -14454,6 +14455,7 @@ package android.graphics { method public float getShadowLayerDx(); method public float getShadowLayerDy(); method public float getShadowLayerRadius(); + method public int getStartHyphenEdit(); method @Px public float getStrikeThruPosition(); method @Px public float getStrikeThruThickness(); method public android.graphics.Paint.Cap getStrokeCap(); @@ -14509,13 +14511,13 @@ package android.graphics { method public android.graphics.ColorFilter setColorFilter(android.graphics.ColorFilter); method public void setDither(boolean); method public void setElegantTextHeight(boolean); + method public void setEndHyphenEdit(int); method public void setFakeBoldText(boolean); method public void setFilterBitmap(boolean); method public void setFlags(int); method public void setFontFeatureSettings(String); method public boolean setFontVariationSettings(String); method public void setHinting(int); - method public void setHyphenEdit(int); method public void setLetterSpacing(float); method public void setLinearText(boolean); method public android.graphics.MaskFilter setMaskFilter(android.graphics.MaskFilter); @@ -14523,6 +14525,7 @@ package android.graphics { method public android.graphics.Shader setShader(android.graphics.Shader); method public void setShadowLayer(float, float, float, @ColorInt int); method public void setShadowLayer(float, float, float, @ColorLong long); + method public void setStartHyphenEdit(int); method public void setStrikeThruText(boolean); method public void setStrokeCap(android.graphics.Paint.Cap); method public void setStrokeJoin(android.graphics.Paint.Join); @@ -14549,11 +14552,21 @@ package android.graphics { field public static final int DEV_KERN_TEXT_FLAG = 256; // 0x100 field public static final int DITHER_FLAG = 4; // 0x4 field public static final int EMBEDDED_BITMAP_TEXT_FLAG = 1024; // 0x400 + field public static final int END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN = 3; // 0x3 + field public static final int END_HYPHEN_EDIT_INSERT_HYPHEN = 2; // 0x2 + field public static final int END_HYPHEN_EDIT_INSERT_MAQAF = 4; // 0x4 + field public static final int END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN = 5; // 0x5 + field public static final int END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN = 6; // 0x6 + field public static final int END_HYPHEN_EDIT_NO_EDIT = 0; // 0x0 + field public static final int END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN = 1; // 0x1 field public static final int FAKE_BOLD_TEXT_FLAG = 32; // 0x20 field public static final int FILTER_BITMAP_FLAG = 2; // 0x2 field public static final int HINTING_OFF = 0; // 0x0 field public static final int HINTING_ON = 1; // 0x1 field public static final int LINEAR_TEXT_FLAG = 64; // 0x40 + field public static final int START_HYPHEN_EDIT_INSERT_HYPHEN = 1; // 0x1 + field public static final int START_HYPHEN_EDIT_INSERT_ZWJ = 2; // 0x2 + field public static final int START_HYPHEN_EDIT_NO_EDIT = 0; // 0x0 field public static final int STRIKE_THRU_TEXT_FLAG = 16; // 0x10 field public static final int SUBPIXEL_TEXT_FLAG = 128; // 0x80 field public static final int UNDERLINE_TEXT_FLAG = 8; // 0x8 @@ -15927,12 +15940,13 @@ package android.graphics.text { } public static class LineBreaker.Result { + method public int getEndLineHyphenEdit(int); method @Px public float getLineAscent(@IntRange(from=0) int); method @IntRange(from=0) public int getLineBreakOffset(@IntRange(from=0) int); method @IntRange(from=0) public int getLineCount(); method @Px public float getLineDescent(@IntRange(from=0) int); - method public int getLineHyphenEdit(int); method @Px public float getLineWidth(@IntRange(from=0) int); + method public int getStartLineHyphenEdit(int); method public boolean hasLineTab(int); } @@ -24739,6 +24753,10 @@ package android.media { public final class MediaDrm implements java.lang.AutoCloseable { ctor public MediaDrm(@NonNull java.util.UUID) throws android.media.UnsupportedSchemeException; + method public void clearOnEventListener(); + method public void clearOnExpirationUpdateListener(); + method public void clearOnKeyStatusChangeListener(); + method public void clearOnSessionLostStateListener(); method public void close(); method public void closeSession(@NonNull byte[]); method @android.media.MediaDrm.HdcpLevel public int getConnectedHdcpLevel(); @@ -24775,9 +24793,14 @@ package android.media { method public void removeSecureStop(@NonNull byte[]); method public void restoreKeys(@NonNull byte[], @NonNull byte[]); method public void setOnEventListener(@Nullable android.media.MediaDrm.OnEventListener); + method public void setOnEventListener(@Nullable android.media.MediaDrm.OnEventListener, @Nullable android.os.Handler); + method public void setOnEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaDrm.OnEventListener); method public void setOnExpirationUpdateListener(@Nullable android.media.MediaDrm.OnExpirationUpdateListener, @Nullable android.os.Handler); + method public void setOnExpirationUpdateListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaDrm.OnExpirationUpdateListener); method public void setOnKeyStatusChangeListener(@Nullable android.media.MediaDrm.OnKeyStatusChangeListener, @Nullable android.os.Handler); + method public void setOnKeyStatusChangeListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaDrm.OnKeyStatusChangeListener); method public void setOnSessionLostStateListener(@Nullable android.media.MediaDrm.OnSessionLostStateListener, @Nullable android.os.Handler); + method public void setOnSessionLostStateListener(@NonNull java.util.concurrent.Executor, @Nullable android.media.MediaDrm.OnSessionLostStateListener); method public void setPropertyByteArray(@NonNull String, @NonNull byte[]); method public void setPropertyString(@NonNull String, @NonNull String); field @Deprecated public static final int EVENT_KEY_EXPIRED = 3; // 0x3 @@ -26398,7 +26421,7 @@ package android.media { public final class Session2Token implements android.os.Parcelable { ctor public Session2Token(@NonNull android.content.Context, @NonNull android.content.ComponentName); method public int describeContents(); - method @Nullable public android.os.Bundle getExtras(); + method @NonNull public android.os.Bundle getExtras(); method @NonNull public String getPackageName(); method @Nullable public String getServiceName(); method public int getType(); @@ -36845,7 +36868,7 @@ package android.provider { field public static final String CALENDAR_LOCATION = "calendar_location"; field public static final android.net.Uri CONTENT_URI; field public static final String DEFAULT_SORT_ORDER = "calendar_displayName"; - field public static final android.net.Uri ENTERPRISE_CONTENT_URI; + field @NonNull public static final android.net.Uri ENTERPRISE_CONTENT_URI; field public static final String NAME = "name"; } @@ -36874,7 +36897,7 @@ package android.provider { public static final class CalendarContract.Events implements android.provider.BaseColumns android.provider.CalendarContract.CalendarColumns android.provider.CalendarContract.EventsColumns android.provider.CalendarContract.SyncColumns { field public static final android.net.Uri CONTENT_EXCEPTION_URI; field public static final android.net.Uri CONTENT_URI; - field public static final android.net.Uri ENTERPRISE_CONTENT_URI; + field @NonNull public static final android.net.Uri ENTERPRISE_CONTENT_URI; } protected static interface CalendarContract.EventsColumns { @@ -36966,10 +36989,10 @@ package android.provider { field public static final String END = "end"; field public static final String END_DAY = "endDay"; field public static final String END_MINUTE = "endMinute"; - field public static final android.net.Uri ENTERPRISE_CONTENT_BY_DAY_URI; - field public static final android.net.Uri ENTERPRISE_CONTENT_SEARCH_BY_DAY_URI; - field public static final android.net.Uri ENTERPRISE_CONTENT_SEARCH_URI; - field public static final android.net.Uri ENTERPRISE_CONTENT_URI; + field @NonNull public static final android.net.Uri ENTERPRISE_CONTENT_BY_DAY_URI; + field @NonNull public static final android.net.Uri ENTERPRISE_CONTENT_SEARCH_BY_DAY_URI; + field @NonNull public static final android.net.Uri ENTERPRISE_CONTENT_SEARCH_URI; + field @NonNull public static final android.net.Uri ENTERPRISE_CONTENT_URI; field public static final String EVENT_ID = "event_id"; field public static final String START_DAY = "startDay"; field public static final String START_MINUTE = "startMinute"; @@ -45441,26 +45464,26 @@ package android.telephony.data { public static class ApnSetting.Builder { ctor public ApnSetting.Builder(); method public android.telephony.data.ApnSetting build(); - method public android.telephony.data.ApnSetting.Builder setApnName(String); - method public android.telephony.data.ApnSetting.Builder setApnTypeBitmask(int); - method public android.telephony.data.ApnSetting.Builder setAuthType(int); - method public android.telephony.data.ApnSetting.Builder setCarrierEnabled(boolean); + method @NonNull public android.telephony.data.ApnSetting.Builder setApnName(String); + method @NonNull public android.telephony.data.ApnSetting.Builder setApnTypeBitmask(int); + method @NonNull public android.telephony.data.ApnSetting.Builder setAuthType(int); + method @NonNull public android.telephony.data.ApnSetting.Builder setCarrierEnabled(boolean); method @NonNull public android.telephony.data.ApnSetting.Builder setCarrierId(int); - method public android.telephony.data.ApnSetting.Builder setEntryName(String); + method @NonNull public android.telephony.data.ApnSetting.Builder setEntryName(String); method @Deprecated public android.telephony.data.ApnSetting.Builder setMmsProxyAddress(java.net.InetAddress); - method public android.telephony.data.ApnSetting.Builder setMmsProxyAddress(String); - method public android.telephony.data.ApnSetting.Builder setMmsProxyPort(int); - method public android.telephony.data.ApnSetting.Builder setMmsc(android.net.Uri); - method public android.telephony.data.ApnSetting.Builder setMvnoType(int); - method public android.telephony.data.ApnSetting.Builder setNetworkTypeBitmask(int); - method public android.telephony.data.ApnSetting.Builder setOperatorNumeric(String); - method public android.telephony.data.ApnSetting.Builder setPassword(String); - method public android.telephony.data.ApnSetting.Builder setProtocol(int); + method @NonNull public android.telephony.data.ApnSetting.Builder setMmsProxyAddress(String); + method @NonNull public android.telephony.data.ApnSetting.Builder setMmsProxyPort(int); + method @NonNull public android.telephony.data.ApnSetting.Builder setMmsc(android.net.Uri); + method @NonNull public android.telephony.data.ApnSetting.Builder setMvnoType(int); + method @NonNull public android.telephony.data.ApnSetting.Builder setNetworkTypeBitmask(int); + method @NonNull public android.telephony.data.ApnSetting.Builder setOperatorNumeric(String); + method @NonNull public android.telephony.data.ApnSetting.Builder setPassword(String); + method @NonNull public android.telephony.data.ApnSetting.Builder setProtocol(int); method @Deprecated public android.telephony.data.ApnSetting.Builder setProxyAddress(java.net.InetAddress); - method public android.telephony.data.ApnSetting.Builder setProxyAddress(String); - method public android.telephony.data.ApnSetting.Builder setProxyPort(int); - method public android.telephony.data.ApnSetting.Builder setRoamingProtocol(int); - method public android.telephony.data.ApnSetting.Builder setUser(String); + method @NonNull public android.telephony.data.ApnSetting.Builder setProxyAddress(String); + method @NonNull public android.telephony.data.ApnSetting.Builder setProxyPort(int); + method @NonNull public android.telephony.data.ApnSetting.Builder setRoamingProtocol(int); + method @NonNull public android.telephony.data.ApnSetting.Builder setUser(String); } } @@ -46003,22 +46026,6 @@ package android.text { method public void handleTag(boolean, String, android.text.Editable, org.xml.sax.XMLReader); } - public class Hyphenator { - method public static int packHyphenEdit(int, int); - method public static int unpackEndHyphenEdit(int); - method public static int unpackStartHyphenEdit(int); - field public static final int END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN = 3; // 0x3 - field public static final int END_HYPHEN_EDIT_INSERT_HYPHEN = 2; // 0x2 - field public static final int END_HYPHEN_EDIT_INSERT_MAQAF = 4; // 0x4 - field public static final int END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN = 5; // 0x5 - field public static final int END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN = 6; // 0x6 - field public static final int END_HYPHEN_EDIT_NO_EDIT = 0; // 0x0 - field public static final int END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN = 1; // 0x1 - field public static final int START_HYPHEN_EDIT_INSERT_HYPHEN = 1; // 0x1 - field public static final int START_HYPHEN_EDIT_INSERT_ZWJ = 2; // 0x2 - field public static final int START_HYPHEN_EDIT_NO_EDIT = 0; // 0x0 - } - public interface InputFilter { method public CharSequence filter(CharSequence, int, int, android.text.Spanned, int, int); } diff --git a/api/system-current.txt b/api/system-current.txt index bd7b92a539b3..921a6bf2f272 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -546,10 +546,10 @@ package android.app { public class NotificationManager { method @Nullable public android.content.ComponentName getAllowedNotificationAssistant(); - method @Nullable public android.content.ComponentName getAllowedNotificationAssistantForUser(android.os.UserHandle); + method @Nullable public android.content.ComponentName getAllowedNotificationAssistantForUser(@NonNull android.os.UserHandle); method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName); - method public void setNotificationAssistantAccessGranted(android.content.ComponentName, boolean); - method public void setNotificationAssistantAccessGrantedForUser(android.content.ComponentName, android.os.UserHandle, boolean); + method public void setNotificationAssistantAccessGranted(@Nullable android.content.ComponentName, boolean); + method public void setNotificationAssistantAccessGrantedForUser(@Nullable android.content.ComponentName, @NonNull android.os.UserHandle, boolean); } public final class StatsManager { @@ -1836,10 +1836,8 @@ package android.content.rollback { public final class RollbackManager { method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender); - method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String); method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks(); method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks(); - method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void reloadPersistedData(); field public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS"; field public static final String EXTRA_STATUS_MESSAGE = "android.content.rollback.extra.STATUS_MESSAGE"; field public static final int STATUS_FAILURE = 1; // 0x1 @@ -3489,6 +3487,7 @@ package android.media { method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setVolumeIndexForAttributes(@NonNull android.media.AudioAttributes, int, int); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicyAsync(@NonNull android.media.audiopolicy.AudioPolicy); method public void unregisterVolumeGroupCallback(@NonNull android.media.AudioManager.VolumeGroupCallback); field public static final int AUDIOFOCUS_FLAG_DELAY_OK = 1; // 0x1 @@ -4066,7 +4065,7 @@ package android.net { } public static interface ConnectivityManager.OnTetheringEntitlementResultListener { - method public void onEntitlementResult(int); + method public void onTetheringEntitlementResult(int); } public abstract static class ConnectivityManager.OnTetheringEventCallback { @@ -4737,13 +4736,13 @@ package android.net.wifi { } public class WifiManager { - method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void addWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.WifiUsabilityStatsListener); + method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void addOnWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener); method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void connect(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener); method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void connect(int, @Nullable android.net.wifi.WifiManager.ActionListener); method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void disable(int, @Nullable android.net.wifi.WifiManager.ActionListener); method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void forget(int, @Nullable android.net.wifi.WifiManager.ActionListener); method @NonNull @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.util.Pair<android.net.wifi.WifiConfiguration,java.util.Map<java.lang.Integer,java.util.List<android.net.wifi.ScanResult>>>> getAllMatchingWifiConfigs(@NonNull java.util.List<android.net.wifi.ScanResult>); - method @NonNull @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,java.util.List<android.net.wifi.ScanResult>> getMatchingOsuProviders(java.util.List<android.net.wifi.ScanResult>); + method @NonNull @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,java.util.List<android.net.wifi.ScanResult>> getMatchingOsuProviders(@Nullable java.util.List<android.net.wifi.ScanResult>); method @NonNull @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,android.net.wifi.hotspot2.PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(@NonNull java.util.Set<android.net.wifi.hotspot2.OsuProvider>); method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks(); method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration(); @@ -4752,7 +4751,7 @@ package android.net.wifi { method public boolean isPortableHotspotSupported(); method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isWifiApEnabled(); method public boolean isWifiScannerSupported(); - method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void removeWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.WifiUsabilityStatsListener); + method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener); method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener); method @RequiresPermission("android.permission.WIFI_SET_DEVICE_MOBILITY_STATE") public void setDeviceMobilityState(int); method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration); @@ -4797,8 +4796,8 @@ package android.net.wifi { method public void onSuccess(); } - public static interface WifiManager.WifiUsabilityStatsListener { - method public void onStatsUpdated(int, boolean, android.net.wifi.WifiUsabilityStatsEntry); + public static interface WifiManager.OnWifiUsabilityStatsListener { + method public void onWifiUsabilityStats(int, boolean, @NonNull android.net.wifi.WifiUsabilityStatsEntry); } public class WifiNetworkConnectionStatistics implements android.os.Parcelable { @@ -4933,35 +4932,35 @@ package android.net.wifi { public final class WifiUsabilityStatsEntry implements android.os.Parcelable { method public int describeContents(); + method public int getLinkSpeedMbps(); + method public int getProbeElapsedTimeSinceLastUpdateMillis(); + method public int getProbeMcsRateSinceLastUpdate(); + method public int getProbeStatusSinceLastUpdate(); + method public int getRssi(); + method public int getRxLinkSpeedMbps(); + method public long getTimeStampMillis(); + method public long getTotalBackgroundScanTimeMillis(); + method public long getTotalBeaconRx(); + method public long getTotalCcaBusyFreqTimeMillis(); + method public long getTotalHotspot2ScanTimeMillis(); + method public long getTotalNanScanTimeMillis(); + method public long getTotalPnoScanTimeMillis(); + method public long getTotalRadioOnFreqTimeMillis(); + method public long getTotalRadioOnTimeMillis(); + method public long getTotalRadioRxTimeMillis(); + method public long getTotalRadioTxTimeMillis(); + method public long getTotalRoamScanTimeMillis(); + method public long getTotalRxSuccess(); + method public long getTotalScanTimeMillis(); + method public long getTotalTxBad(); + method public long getTotalTxRetries(); + method public long getTotalTxSuccess(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiUsabilityStatsEntry> CREATOR; field public static final int PROBE_STATUS_FAILURE = 3; // 0x3 field public static final int PROBE_STATUS_NO_PROBE = 1; // 0x1 field public static final int PROBE_STATUS_SUCCESS = 2; // 0x2 field public static final int PROBE_STATUS_UNKNOWN = 0; // 0x0 - field public final int linkSpeedMbps; - field public final int probeElapsedTimeMsSinceLastUpdate; - field public final int probeMcsRateSinceLastUpdate; - field public final int probeStatusSinceLastUpdate; - field public final int rssi; - field public final int rxLinkSpeedMbps; - field public final long timeStampMs; - field public final long totalBackgroundScanTimeMs; - field public final long totalBeaconRx; - field public final long totalCcaBusyFreqTimeMs; - field public final long totalHotspot2ScanTimeMs; - field public final long totalNanScanTimeMs; - field public final long totalPnoScanTimeMs; - field public final long totalRadioOnFreqTimeMs; - field public final long totalRadioOnTimeMs; - field public final long totalRadioRxTimeMs; - field public final long totalRadioTxTimeMs; - field public final long totalRoamScanTimeMs; - field public final long totalRxSuccess; - field public final long totalScanTimeMs; - field public final long totalTxBad; - field public final long totalTxRetries; - field public final long totalTxSuccess; } } @@ -5210,7 +5209,7 @@ package android.os { } public static class Build.VERSION { - field public static final String PREVIEW_SDK_FINGERPRINT; + field @NonNull public static final String PREVIEW_SDK_FINGERPRINT; } public final class ConfigUpdate { @@ -5862,6 +5861,7 @@ package android.provider { field public static final String NAMESPACE_AUTOFILL = "autofill"; field public static final String NAMESPACE_CONNECTIVITY = "connectivity"; field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture"; + field public static final String NAMESPACE_DEX_BOOT = "dex_boot"; field public static final String NAMESPACE_GAME_DRIVER = "game_driver"; field public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot"; field public static final String NAMESPACE_MEDIA_NATIVE = "media_native"; @@ -5877,12 +5877,6 @@ package android.provider { field public static final String SERVICE_ENABLED = "service_enabled"; } - public static interface DeviceConfig.DexBoot { - field public static final String NAMESPACE = "dex_boot"; - field public static final String PRIV_APPS_OOB_ENABLED = "priv_apps_oob_enabled"; - field public static final String PRIV_APPS_OOB_WHITELIST = "priv_apps_oob_whitelist"; - } - public static interface DeviceConfig.IntelligenceAttention { field public static final String ATTENTION_ENABLED = "attention_enabled"; field public static final String ATTENTION_SETTINGS = "attention_settings"; @@ -8064,6 +8058,10 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoiceActivationState(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmi(String); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmiForSubscriber(int, String); + method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean iccCloseLogicalChannelBySlot(int, int); + method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannelBySlot(int, @Nullable String, int); + method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduBasicChannelBySlot(int, int, int, int, int, int, @Nullable String); + method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, @Nullable String); method public boolean isDataConnectivityPossible(); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle(); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook(); @@ -8099,7 +8097,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean switchSlots(int[]); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void toggleRadioOnOff(); method public void updateServiceLocation(); - field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_DEBUG_EVENT = "android.telephony.action.DEBUG_EVENT"; + field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_ANOMALY_REPORTED = "android.telephony.action.ANOMALY_REPORTED"; field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED"; field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED"; field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED"; @@ -8107,8 +8105,8 @@ package android.telephony { field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1 field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0 field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff - field public static final String EXTRA_DEBUG_EVENT_DESCRIPTION = "android.telephony.extra.DEBUG_EVENT_DESCRIPTION"; - field public static final String EXTRA_DEBUG_EVENT_ID = "android.telephony.extra.DEBUG_EVENT_ID"; + field public static final String EXTRA_ANOMALY_DESCRIPTION = "android.telephony.extra.ANOMALY_DESCRIPTION"; + field public static final String EXTRA_ANOMALY_ID = "android.telephony.extra.ANOMALY_ID"; field public static final String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE"; field public static final String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL"; field public static final String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING"; diff --git a/api/test-current.txt b/api/test-current.txt index 46e061b740e6..29137438384e 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -11,8 +11,10 @@ package android { field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS"; field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES"; field public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS"; + field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS"; field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS"; field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS"; + field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG"; field public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE"; field public static final String WRITE_OBB = "android.permission.WRITE_OBB"; } @@ -596,6 +598,7 @@ package android.content { method public int getUserId(); method public void setAutofillOptions(@Nullable android.content.AutofillOptions); method public void setContentCaptureOptions(@Nullable android.content.ContentCaptureOptions); + field public static final String ROLLBACK_SERVICE = "rollback"; } public class ContextWrapper extends android.content.Context { @@ -603,6 +606,7 @@ package android.content { } public class Intent implements java.lang.Cloneable android.os.Parcelable { + field public static final String ACTION_ROLLBACK_COMMITTED = "android.intent.action.ROLLBACK_COMMITTED"; field public static final String EXTRA_ROLE_NAME = "android.intent.extra.ROLE_NAME"; } @@ -626,6 +630,12 @@ package android.content.pm { ctor public LauncherApps(android.content.Context); } + public static class PackageInstaller.SessionParams implements android.os.Parcelable { + method public void setEnableRollback(boolean); + method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setInstallAsApex(); + method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setStaged(); + } + public abstract class PackageManager { method public abstract boolean arePermissionsIndividuallyControlled(); method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract String getDefaultBrowserPackageNameAsUser(int); @@ -686,6 +696,44 @@ package android.content.res { } +package android.content.rollback { + + public final class PackageRollbackInfo implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public String getPackageName(); + method @NonNull public android.content.pm.VersionedPackage getVersionRolledBackFrom(); + method @NonNull public android.content.pm.VersionedPackage getVersionRolledBackTo(); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.content.rollback.PackageRollbackInfo> CREATOR; + } + + public final class RollbackInfo implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public java.util.List<android.content.pm.VersionedPackage> getCausePackages(); + method public int getCommittedSessionId(); + method @NonNull public java.util.List<android.content.rollback.PackageRollbackInfo> getPackages(); + method public int getRollbackId(); + method public boolean isStaged(); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.content.rollback.RollbackInfo> CREATOR; + } + + public final class RollbackManager { + method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender); + method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String); + method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks(); + method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks(); + method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void reloadPersistedData(); + field public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS"; + field public static final String EXTRA_STATUS_MESSAGE = "android.content.rollback.extra.STATUS_MESSAGE"; + field public static final int STATUS_FAILURE = 1; // 0x1 + field public static final int STATUS_FAILURE_INSTALL = 3; // 0x3 + field public static final int STATUS_FAILURE_ROLLBACK_UNAVAILABLE = 2; // 0x2 + field public static final int STATUS_SUCCESS = 0; // 0x0 + } + +} + package android.database.sqlite { public class SQLiteCompatibilityWalFlags { @@ -2015,8 +2063,8 @@ package android.provider { method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getString(String, String, String); method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener); method public static void removeOnPropertyChangedListener(@NonNull android.provider.DeviceConfig.OnPropertyChangedListener); - method @RequiresPermission("android.permission.WRITE_DEVICE_CONFIG") public static void resetToDefaults(int, @Nullable String); - method @RequiresPermission("android.permission.WRITE_DEVICE_CONFIG") public static boolean setProperty(String, String, String, boolean); + method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String); + method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(String, String, String, boolean); field public static final String NAMESPACE_AUTOFILL = "autofill"; field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture"; } @@ -2044,6 +2092,13 @@ package android.provider { method @Nullable public String getString(@NonNull String, @Nullable String); } + public static interface DeviceConfig.Rollback { + field public static final String BOOT_NAMESPACE = "rollback_boot"; + field public static final String ENABLE_ROLLBACK_TIMEOUT = "enable_rollback_timeout"; + field public static final String NAMESPACE = "rollback"; + field public static final String ROLLBACK_LIFETIME_IN_MILLIS = "rollback_lifetime_in_millis"; + } + public final class MediaStore { method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static void deleteContributedMedia(android.content.Context, String, android.os.UserHandle) throws java.io.IOException; method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static long getContributedMediaSize(android.content.Context, String, android.os.UserHandle) throws java.io.IOException; diff --git a/cmds/bootanimation/bootanim.rc b/cmds/bootanimation/bootanim.rc index 3666d6af29f5..469c9646a4aa 100644 --- a/cmds/bootanimation/bootanim.rc +++ b/cmds/bootanimation/bootanim.rc @@ -2,9 +2,6 @@ service bootanim /system/bin/bootanimation class core animation user graphics group graphics audio - # bootanimation depends on libandroidicu in the Runtime APEX. - # TODO(b/124939955): Remove this dependency on libandroidicu - updatable disabled oneshot writepid /dev/stune/top-app/tasks diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index 7298da6f6835..ce07d6d12f72 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -219,6 +219,7 @@ cc_test { "tests/anomaly/AnomalyTracker_test.cpp", "tests/ConfigManager_test.cpp", "tests/external/puller_util_test.cpp", + "tests/external/GpuStatsPuller_test.cpp", "tests/external/IncidentReportArgs_test.cpp", "tests/external/StatsPuller_test.cpp", "tests/indexed_priority_queue_test.cpp", diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index b812c8001003..69372cd379ea 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -249,6 +249,7 @@ message Atom { TouchGestureClassified touch_gesture_classified = 177; HiddenApiUsed hidden_api_used = 178 [(allow_from_any_uid) = true]; StyleUIChanged style_ui_changed = 179; + PrivacyIndicatorsInteracted privacy_indicators_interacted = 180; } // Pulled events will start at field 10000. @@ -3395,6 +3396,32 @@ message HiddenApiUsed { optional bool access_denied = 4; } +/** + * Logs user interaction with the Privacy Indicators added in Q. In particular: + * - When user sees privacy chip + * - When user clicks privacy chip + * - How does the user exit the Privacy Dialog + * Logged from: + * packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt + * packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java + */ +message PrivacyIndicatorsInteracted { + + enum Type { + UNKNOWN = 0; + CHIP_VIEWED = 1; + CHIP_CLICKED = 2; + DIALOG_PRIVACY_SETTINGS = 3; + DIALOG_DISMISS = 4; + DIALOG_LINE_ITEM = 5; + } + + optional Type type = 1 [(state_field_option).option = EXCLUSIVE]; + + // Used if the type is LINE_ITEM + optional string package_name = 2; +} + ////////////////////////////////////////////////////////////////////// // Pulled atoms below this line // ////////////////////////////////////////////////////////////////////// @@ -5732,7 +5759,7 @@ message TimeZoneDataInfo { optional string tzdb_version = 1; } -/* +/** * Logs the GPU stats global health information. * * Logged from: @@ -5764,22 +5791,34 @@ message GpuStatsGlobalInfo { optional int64 vk_loading_failure_count = 8; } -/* +/** + * GPU driver loading time info. + */ +message GpuDriverLoadingTime { + // List of all the driver loading times for this app. The list size is + // capped at 50. + repeated int64 driver_loading_time = 1; +} + +/** * Logs the GPU stats per app health information. * * Logged from: * frameworks/native/services/gpuservice/gpustats/ */ message GpuStatsAppInfo { - // Package name of the application that loads the gpu driver. + // Package name of the application that loads the gpu driver. Total number + // of different packages is capped at 100. optional string app_package_name = 1; // Version code of the gpu driver this app loads. optional int64 driver_version_code = 2; - // List of all the gl driver loading times for this app. - repeated int64 gl_driver_loading_time = 3; + // gl driver loading time info. + optional GpuDriverLoadingTime gl_driver_loading_time = 3 + [(android.os.statsd.log_mode) = MODE_BYTES]; - // List of all the Vulkan driver laoding times for this app. - repeated int64 vk_driver_loading_time = 4; + // Vulkan driver loading time info. + optional GpuDriverLoadingTime vk_driver_loading_time = 4 + [(android.os.statsd.log_mode) = MODE_BYTES]; } diff --git a/cmds/statsd/src/external/GpuStatsPuller.cpp b/cmds/statsd/src/external/GpuStatsPuller.cpp index 844580321719..130bd85d56c6 100644 --- a/cmds/statsd/src/external/GpuStatsPuller.cpp +++ b/cmds/statsd/src/external/GpuStatsPuller.cpp @@ -70,6 +70,30 @@ static bool pullGpuStatsGlobalInfo(const sp<IGpuService>& gpuService, return true; } +static bool pullGpuStatsAppInfo(const sp<IGpuService>& gpuService, + std::vector<std::shared_ptr<LogEvent>>* data) { + std::vector<GpuStatsAppInfo> stats; + status_t status = gpuService->getGpuStatsAppInfo(&stats); + if (status != OK) { + return false; + } + + data->clear(); + data->reserve(stats.size()); + for (const auto& info : stats) { + std::shared_ptr<LogEvent> event = make_shared<LogEvent>( + android::util::GPU_STATS_APP_INFO, getWallClockNs(), getElapsedRealtimeNs()); + if (!event->write(info.appPackageName)) return false; + if (!event->write((int64_t)info.driverVersionCode)) return false; + if (!event->write(int64VectorToProtoByteString(info.glDriverLoadingTime))) return false; + if (!event->write(int64VectorToProtoByteString(info.vkDriverLoadingTime))) return false; + event->init(); + data->emplace_back(event); + } + + return true; +} + bool GpuStatsPuller::PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) { const sp<IGpuService> gpuService = getGpuService(); if (!gpuService) { @@ -79,6 +103,8 @@ bool GpuStatsPuller::PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) switch (mTagId) { case android::util::GPU_STATS_GLOBAL_INFO: return pullGpuStatsGlobalInfo(gpuService, data); + case android::util::GPU_STATS_APP_INFO: + return pullGpuStatsAppInfo(gpuService, data); default: break; } @@ -86,6 +112,35 @@ bool GpuStatsPuller::PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) return false; } +static std::string protoOutputStreamToByteString(ProtoOutputStream& proto) { + if (!proto.size()) return ""; + + std::string byteString; + auto iter = proto.data(); + while (iter.readBuffer() != nullptr) { + const size_t toRead = iter.currentToRead(); + byteString.append((char*)iter.readBuffer(), toRead); + iter.rp()->move(toRead); + } + + if (byteString.size() != proto.size()) return ""; + + return byteString; +} + +std::string int64VectorToProtoByteString(const std::vector<int64_t>& value) { + if (value.empty()) return ""; + + ProtoOutputStream proto; + for (const auto& ele : value) { + proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED | + 1 /* field id */, + (long long)ele); + } + + return protoOutputStreamToByteString(proto); +} + } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/src/external/GpuStatsPuller.h b/cmds/statsd/src/external/GpuStatsPuller.h index 4c7a4d604252..2da199c51e0f 100644 --- a/cmds/statsd/src/external/GpuStatsPuller.h +++ b/cmds/statsd/src/external/GpuStatsPuller.h @@ -31,6 +31,12 @@ public: bool PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) override; }; +// convert a int64_t vector into a byte string for proto message like: +// message RepeatedInt64Wrapper { +// repeated int64 value = 1; +// } +std::string int64VectorToProtoByteString(const std::vector<int64_t>& value); + } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index 924704ba6db5..4f872727cdfd 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -244,6 +244,9 @@ std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { // GpuStatsGlobalInfo {android::util::GPU_STATS_GLOBAL_INFO, {.puller = new GpuStatsPuller(android::util::GPU_STATS_GLOBAL_INFO)}}, + // GpuStatsAppInfo + {android::util::GPU_STATS_APP_INFO, + {.puller = new GpuStatsPuller(android::util::GPU_STATS_APP_INFO)}}, }; StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) { diff --git a/cmds/statsd/tests/external/GpuStatsPuller_test.cpp b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp new file mode 100644 index 000000000000..8625487d1aca --- /dev/null +++ b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp @@ -0,0 +1,152 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#undef LOG_TAG +#define LOG_TAG "GpuStatsPuller_test" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include <graphicsenv/GpuStatsInfo.h> +#include <log/log.h> + +#include "src/external/GpuStatsPuller.h" + +#ifdef __ANDROID__ + +namespace android { +namespace os { +namespace statsd { + +// clang-format off +static const std::string DRIVER_PACKAGE_NAME = "TEST_DRIVER"; +static const std::string DRIVER_VERSION_NAME = "TEST_DRIVER_VERSION"; +static const std::string APP_PACKAGE_NAME = "TEST_APP"; +static const int64_t TIMESTAMP_WALLCLOCK = 111; +static const int64_t TIMESTAMP_ELAPSED = 222; +static const int64_t DRIVER_VERSION_CODE = 333; +static const int64_t DRIVER_BUILD_TIME = 444; +static const int64_t GL_LOADING_COUNT = 3; +static const int64_t GL_LOADING_FAILURE_COUNT = 1; +static const int64_t VK_LOADING_COUNT = 4; +static const int64_t VK_LOADING_FAILURE_COUNT = 0; +static const int64_t GL_DRIVER_LOADING_TIME_0 = 555; +static const int64_t GL_DRIVER_LOADING_TIME_1 = 666; +static const int64_t VK_DRIVER_LOADING_TIME_0 = 777; +static const int64_t VK_DRIVER_LOADING_TIME_1 = 888; +static const int64_t VK_DRIVER_LOADING_TIME_2 = 999; +static const size_t NUMBER_OF_VALUES_GLOBAL = 8; +static const size_t NUMBER_OF_VALUES_APP = 4; +// clang-format on + +class MockGpuStatsPuller : public GpuStatsPuller { +public: + MockGpuStatsPuller(const int tagId, vector<std::shared_ptr<LogEvent>>* data) + : GpuStatsPuller(tagId), mData(data){}; + +private: + bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override { + *data = *mData; + return true; + } + + vector<std::shared_ptr<LogEvent>>* mData; +}; + +class GpuStatsPuller_test : public ::testing::Test { +public: + GpuStatsPuller_test() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); + } + + ~GpuStatsPuller_test() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); + } +}; + +TEST_F(GpuStatsPuller_test, PullGpuStatsGlobalInfo) { + vector<std::shared_ptr<LogEvent>> inData, outData; + std::shared_ptr<LogEvent> event = make_shared<LogEvent>(android::util::GPU_STATS_GLOBAL_INFO, + TIMESTAMP_WALLCLOCK, TIMESTAMP_ELAPSED); + EXPECT_TRUE(event->write(DRIVER_PACKAGE_NAME)); + EXPECT_TRUE(event->write(DRIVER_VERSION_NAME)); + EXPECT_TRUE(event->write(DRIVER_VERSION_CODE)); + EXPECT_TRUE(event->write(DRIVER_BUILD_TIME)); + EXPECT_TRUE(event->write(GL_LOADING_COUNT)); + EXPECT_TRUE(event->write(GL_LOADING_FAILURE_COUNT)); + EXPECT_TRUE(event->write(VK_LOADING_COUNT)); + EXPECT_TRUE(event->write(VK_LOADING_FAILURE_COUNT)); + event->init(); + inData.emplace_back(event); + MockGpuStatsPuller mockPuller(android::util::GPU_STATS_GLOBAL_INFO, &inData); + mockPuller.ForceClearCache(); + mockPuller.Pull(&outData); + + ASSERT_EQ(1, outData.size()); + EXPECT_EQ(android::util::GPU_STATS_GLOBAL_INFO, outData[0]->GetTagId()); + ASSERT_EQ(NUMBER_OF_VALUES_GLOBAL, outData[0]->size()); + EXPECT_EQ(DRIVER_PACKAGE_NAME, outData[0]->getValues()[0].mValue.str_value); + EXPECT_EQ(DRIVER_VERSION_NAME, outData[0]->getValues()[1].mValue.str_value); + EXPECT_EQ(DRIVER_VERSION_CODE, outData[0]->getValues()[2].mValue.long_value); + EXPECT_EQ(DRIVER_BUILD_TIME, outData[0]->getValues()[3].mValue.long_value); + EXPECT_EQ(GL_LOADING_COUNT, outData[0]->getValues()[4].mValue.long_value); + EXPECT_EQ(GL_LOADING_FAILURE_COUNT, outData[0]->getValues()[5].mValue.long_value); + EXPECT_EQ(VK_LOADING_COUNT, outData[0]->getValues()[6].mValue.long_value); + EXPECT_EQ(VK_LOADING_FAILURE_COUNT, outData[0]->getValues()[7].mValue.long_value); +} + +TEST_F(GpuStatsPuller_test, PullGpuStatsAppInfo) { + vector<std::shared_ptr<LogEvent>> inData, outData; + std::shared_ptr<LogEvent> event = make_shared<LogEvent>(android::util::GPU_STATS_APP_INFO, + TIMESTAMP_WALLCLOCK, TIMESTAMP_ELAPSED); + EXPECT_TRUE(event->write(APP_PACKAGE_NAME)); + EXPECT_TRUE(event->write(DRIVER_VERSION_CODE)); + std::vector<int64_t> glDriverLoadingTime; + glDriverLoadingTime.emplace_back(GL_DRIVER_LOADING_TIME_0); + glDriverLoadingTime.emplace_back(GL_DRIVER_LOADING_TIME_1); + std::vector<int64_t> vkDriverLoadingTime; + vkDriverLoadingTime.emplace_back(VK_DRIVER_LOADING_TIME_0); + vkDriverLoadingTime.emplace_back(VK_DRIVER_LOADING_TIME_1); + vkDriverLoadingTime.emplace_back(VK_DRIVER_LOADING_TIME_2); + EXPECT_TRUE(event->write(int64VectorToProtoByteString(glDriverLoadingTime))); + EXPECT_TRUE(event->write(int64VectorToProtoByteString(vkDriverLoadingTime))); + event->init(); + inData.emplace_back(event); + MockGpuStatsPuller mockPuller(android::util::GPU_STATS_APP_INFO, &inData); + mockPuller.ForceClearCache(); + mockPuller.Pull(&outData); + + ASSERT_EQ(1, outData.size()); + EXPECT_EQ(android::util::GPU_STATS_APP_INFO, outData[0]->GetTagId()); + ASSERT_EQ(NUMBER_OF_VALUES_APP, outData[0]->size()); + EXPECT_EQ(APP_PACKAGE_NAME, outData[0]->getValues()[0].mValue.str_value); + EXPECT_EQ(DRIVER_VERSION_CODE, outData[0]->getValues()[1].mValue.long_value); + EXPECT_EQ(int64VectorToProtoByteString(glDriverLoadingTime), + outData[0]->getValues()[2].mValue.str_value); + EXPECT_EQ(int64VectorToProtoByteString(vkDriverLoadingTime), + outData[0]->getValues()[3].mValue.str_value); +} + +} // namespace statsd +} // namespace os +} // namespace android +#else +GTEST_LOG_(INFO) << "This test does nothing.\n"; +#endif diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 56bf8fa8ffce..694f6b061375 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -139,6 +139,8 @@ import com.android.internal.app.ToolbarActionBar; import com.android.internal.app.WindowDecorActionBar; import com.android.internal.policy.PhoneWindow; +import dalvik.system.VMRuntime; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.annotation.Retention; @@ -2491,6 +2493,7 @@ public class Activity extends ContextThemeWrapper try { ActivityTaskManager.getService().reportActivityFullyDrawn( mToken, mRestoredFromBundle); + VMRuntime.getRuntime().notifyStartupCompleted(); } catch (RemoteException e) { } } diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java index da45054cbe51..08cad04401e9 100644 --- a/core/java/android/app/AppOpsManagerInternal.java +++ b/core/java/android/app/AppOpsManagerInternal.java @@ -16,6 +16,7 @@ package android.app; +import android.annotation.NonNull; import android.util.SparseIntArray; import com.android.internal.util.function.QuadFunction; @@ -96,4 +97,18 @@ public abstract class AppOpsManagerInternal { * @param uid The uid */ public abstract void setAllPkgModesToDefault(int code, int uid); + + /** + * Get the (raw) mode of an app-op. + * + * <p>Does <u>not</u> verify that package belongs to uid. The caller needs to do that. + * + * @param code The code of the op + * @param uid The uid of the package the op belongs to + * @param packageName The package the op belongs to + * + * @return The mode of the op + */ + public abstract @AppOpsManager.Mode int checkOperationUnchecked(int code, int uid, + @NonNull String packageName); } diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index ed7aa4a097eb..204fb6aeb529 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -1277,7 +1277,8 @@ public class NotificationManager { * @hide */ @SystemApi - public void setNotificationAssistantAccessGranted(ComponentName assistant, boolean granted) { + public void setNotificationAssistantAccessGranted(@Nullable ComponentName assistant, + boolean granted) { INotificationManager service = getService(); try { service.setNotificationAssistantAccessGranted(assistant, granted); @@ -1296,8 +1297,8 @@ public class NotificationManager { * @hide */ @SystemApi - public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant, - UserHandle user, boolean granted) { + public void setNotificationAssistantAccessGrantedForUser(@Nullable ComponentName assistant, + @NonNull UserHandle user, boolean granted) { INotificationManager service = getService(); try { service.setNotificationAssistantAccessGrantedForUser(assistant, user.getIdentifier(), @@ -1319,7 +1320,8 @@ public class NotificationManager { /** @hide */ @SystemApi - public @Nullable ComponentName getAllowedNotificationAssistantForUser(UserHandle user) { + public @Nullable ComponentName getAllowedNotificationAssistantForUser( + @NonNull UserHandle user) { INotificationManager service = getService(); try { return service.getAllowedNotificationAssistantForUser(user.getIdentifier()); diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 2d9fbf974397..35658fbcb989 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -1091,6 +1091,16 @@ public class ResourcesManager { */ @UnsupportedAppUsage public void appendLibAssetForMainAssetPath(String assetPath, String libAsset) { + appendLibAssetsForMainAssetPath(assetPath, new String[] { libAsset }); + } + + /** + * Appends the library asset paths to any ResourcesImpl object that contains the main + * assetPath. + * @param assetPath The main asset path for which to add the library asset path. + * @param libAssets The library asset paths to add. + */ + public void appendLibAssetsForMainAssetPath(String assetPath, String[] libAssets) { synchronized (this) { // Record which ResourcesImpl need updating // (and what ResourcesKey they should update to). @@ -1102,15 +1112,13 @@ public class ResourcesManager { final WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i); final ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null; if (impl != null && Objects.equals(key.mResDir, assetPath)) { - if (!ArrayUtils.contains(key.mLibDirs, libAsset)) { - final int newLibAssetCount = 1 + - (key.mLibDirs != null ? key.mLibDirs.length : 0); - final String[] newLibAssets = new String[newLibAssetCount]; - if (key.mLibDirs != null) { - System.arraycopy(key.mLibDirs, 0, newLibAssets, 0, key.mLibDirs.length); - } - newLibAssets[newLibAssetCount - 1] = libAsset; + String[] newLibAssets = key.mLibDirs; + for (String libAsset : libAssets) { + newLibAssets = + ArrayUtils.appendElement(String.class, newLibAssets, libAsset); + } + if (newLibAssets != key.mLibDirs) { updatedResourceKeys.put(impl, new ResourcesKey( key.mResDir, key.mSplitResDirs, diff --git a/core/java/android/app/admin/DelegatedAdminReceiver.java b/core/java/android/app/admin/DelegatedAdminReceiver.java index 960538251c5f..f66de8d238ed 100644 --- a/core/java/android/app/admin/DelegatedAdminReceiver.java +++ b/core/java/android/app/admin/DelegatedAdminReceiver.java @@ -24,6 +24,9 @@ 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.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; @@ -63,20 +66,21 @@ public class DelegatedAdminReceiver extends BroadcastReceiver { * * <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 DeviceAdminReceiver#ACTION_CHOOSE_PRIVATE_KEY_ALIAS} - * in the receiver's manifest in order to receive this callback. + * declare an intent filter for {@link DeviceAdminReceiver#ACTION_CHOOSE_PRIVATE_KEY_ALIAS} + * in the receiver's manifest in order to receive this callback. The default implementation + * simply throws {@link UnsupportedOperationException}. * * @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 uid The uid of the app 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; + public @Nullable String onChoosePrivateKeyAlias(@NonNull Context context, + @NonNull Intent intent, int uid, @Nullable Uri uri, @Nullable String alias) { + throw new UnsupportedOperationException("onChoosePrivateKeyAlias should be implemented"); } /** @@ -91,8 +95,9 @@ public class DelegatedAdminReceiver extends BroadcastReceiver { * * <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 DeviceAdminReceiver#ACTION_NETWORK_LOGS_AVAILABLE} in the - * receiver's manifest in order to receive this callback. + * declare an intent filter for {@link DeviceAdminReceiver#ACTION_NETWORK_LOGS_AVAILABLE} in the + * receiver's manifest in order to receive this callback. The default implementation + * simply throws {@link UnsupportedOperationException}. * * @param context The running context as per {@link #onReceive}. * @param intent The received intent as per {@link #onReceive}. @@ -100,8 +105,9 @@ public class DelegatedAdminReceiver extends BroadcastReceiver { * @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) { + public void onNetworkLogsAvailable(@NonNull Context context, @NonNull Intent intent, + long batchToken, @IntRange(from = 1) int networkLogsCount) { + throw new UnsupportedOperationException("onNetworkLogsAvailable should be implemented"); } /** @@ -109,7 +115,7 @@ public class DelegatedAdminReceiver extends BroadcastReceiver { * this method; implement the convenience callbacks for each action instead. */ @Override - public void onReceive(Context context, Intent intent) { + public final void onReceive(@NonNull Context context, @NonNull Intent intent) { String action = intent.getAction(); if (ACTION_CHOOSE_PRIVATE_KEY_ALIAS.equals(action)) { diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java index 5a7124e1fdc6..4771fd8a00b6 100644 --- a/core/java/android/app/admin/DeviceAdminReceiver.java +++ b/core/java/android/app/admin/DeviceAdminReceiver.java @@ -19,6 +19,7 @@ package android.app.admin; import android.accounts.AccountManager; import android.annotation.BroadcastBehavior; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; @@ -515,7 +516,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * Retrieve the DevicePolicyManager interface for this administrator to work * with the system. */ - public DevicePolicyManager getManager(Context context) { + public @NonNull DevicePolicyManager getManager(@NonNull Context context) { if (mManager != null) { return mManager; } @@ -529,7 +530,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * use in {@link DevicePolicyManager} APIs that require the administrator to * identify itself. */ - public ComponentName getWho(Context context) { + public @NonNull ComponentName getWho(@NonNull Context context) { if (mWho != null) { return mWho; } @@ -550,7 +551,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @param context The running context as per {@link #onReceive}. * @param intent The received intent as per {@link #onReceive}. */ - public void onEnabled(Context context, Intent intent) { + public void onEnabled(@NonNull Context context, @NonNull Intent intent) { } /** @@ -564,7 +565,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @return Return the warning message to display to the user before * being disabled; if null is returned, no message is displayed. */ - public CharSequence onDisableRequested(Context context, Intent intent) { + public @Nullable CharSequence onDisableRequested(@NonNull Context context, + @NonNull Intent intent) { return null; } @@ -576,7 +578,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @param context The running context as per {@link #onReceive}. * @param intent The received intent as per {@link #onReceive}. */ - public void onDisabled(Context context, Intent intent) { + public void onDisabled(@NonNull Context context, @NonNull Intent intent) { } /** @@ -591,7 +593,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * {@link #onPasswordChanged(Context, Intent, UserHandle)} instead. */ @Deprecated - public void onPasswordChanged(Context context, Intent intent) { + public void onPasswordChanged(@NonNull Context context, @NonNull Intent intent) { } /** @@ -605,7 +607,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * user is the current profile or a parent user, check for equality with * {@link Process#myUserHandle}. */ - public void onPasswordChanged(Context context, Intent intent, UserHandle user) { + public void onPasswordChanged(@NonNull Context context, @NonNull Intent intent, + @NonNull UserHandle user) { onPasswordChanged(context, intent); } @@ -621,7 +624,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * {@link #onPasswordFailed(Context, Intent, UserHandle)} instead. */ @Deprecated - public void onPasswordFailed(Context context, Intent intent) { + public void onPasswordFailed(@NonNull Context context, @NonNull Intent intent) { } /** @@ -635,7 +638,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * user is the current profile or a parent user, check for equality with * {@link Process#myUserHandle}. */ - public void onPasswordFailed(Context context, Intent intent, UserHandle user) { + public void onPasswordFailed(@NonNull Context context, @NonNull Intent intent, + @NonNull UserHandle user) { onPasswordFailed(context, intent); } @@ -651,7 +655,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * {@link #onPasswordSucceeded(Context, Intent, UserHandle)} instead. */ @Deprecated - public void onPasswordSucceeded(Context context, Intent intent) { + public void onPasswordSucceeded(@NonNull Context context, @NonNull Intent intent) { } /** @@ -665,7 +669,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * user is the current profile or a parent user, check for equality with * {@link Process#myUserHandle}. */ - public void onPasswordSucceeded(Context context, Intent intent, UserHandle user) { + public void onPasswordSucceeded(@NonNull Context context, @NonNull Intent intent, + @NonNull UserHandle user) { onPasswordSucceeded(context, intent); } @@ -691,7 +696,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * {@link #onPasswordExpiring(Context, Intent, UserHandle)} instead. */ @Deprecated - public void onPasswordExpiring(Context context, Intent intent) { + public void onPasswordExpiring(@NonNull Context context, @NonNull Intent intent) { } /** @@ -715,7 +720,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * user is the current profile or a parent user, check for equality with * {@link Process#myUserHandle}. */ - public void onPasswordExpiring(Context context, Intent intent, UserHandle user) { + public void onPasswordExpiring(@NonNull Context context, @NonNull Intent intent, + @NonNull UserHandle user) { onPasswordExpiring(context, intent); } @@ -746,7 +752,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @param context The running context as per {@link #onReceive}. * @param intent The received intent as per {@link #onReceive}. */ - public void onProfileProvisioningComplete(Context context, Intent intent) { + public void onProfileProvisioningComplete(@NonNull Context context, @NonNull Intent intent) { } /** @@ -758,7 +764,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @deprecated Do not use */ @Deprecated - public void onReadyForUserInitialization(Context context, Intent intent) { + public void onReadyForUserInitialization(@NonNull Context context, @NonNull Intent intent) { } /** @@ -766,9 +772,10 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * * @param context The running context as per {@link #onReceive}. * @param intent The received intent as per {@link #onReceive}. - * @param pkg If entering, the authorized package using lock task mode, otherwise null. + * @param pkg The authorized package using lock task mode. */ - public void onLockTaskModeEntering(Context context, Intent intent, String pkg) { + public void onLockTaskModeEntering(@NonNull Context context, @NonNull Intent intent, + @NonNull String pkg) { } /** @@ -777,7 +784,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @param context The running context as per {@link #onReceive}. * @param intent The received intent as per {@link #onReceive}. */ - public void onLockTaskModeExiting(Context context, Intent intent) { + public void onLockTaskModeExiting(@NonNull Context context, @NonNull Intent intent) { } /** @@ -787,14 +794,14 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * * @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 uid The uid of the app 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) { + public @Nullable String onChoosePrivateKeyAlias(@NonNull Context context, + @NonNull Intent intent, int uid, @Nullable Uri uri, @Nullable String alias) { return null; } @@ -818,7 +825,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * the current pending update was first available. -1 if no pending update is available. * @see DevicePolicyManager#getPendingSystemUpdate */ - public void onSystemUpdatePending(Context context, Intent intent, long receivedTime) { + public void onSystemUpdatePending(@NonNull Context context, @NonNull Intent intent, + long receivedTime) { } /** @@ -830,7 +838,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @param intent The received intent as per {@link #onReceive}. * @see DevicePolicyManager#requestBugreport */ - public void onBugreportSharingDeclined(Context context, Intent intent) { + public void onBugreportSharingDeclined(@NonNull Context context, @NonNull Intent intent) { } /** @@ -845,7 +853,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @param bugreportHash SHA-256 hash of the bugreport file. * @see DevicePolicyManager#requestBugreport */ - public void onBugreportShared(Context context, Intent intent, String bugreportHash) { + public void onBugreportShared(@NonNull Context context, @NonNull Intent intent, + @NonNull String bugreportHash) { } /** @@ -860,7 +869,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * or {@link #BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE} * @see DevicePolicyManager#requestBugreport */ - public void onBugreportFailed(Context context, Intent intent, + public void onBugreportFailed(@NonNull Context context, @NonNull Intent intent, @BugreportFailureCode int failureCode) { } @@ -879,7 +888,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @param intent The received intent as per {@link #onReceive}. * @see DevicePolicyManager#retrieveSecurityLogs(ComponentName) */ - public void onSecurityLogsAvailable(Context context, Intent intent) { + public void onSecurityLogsAvailable(@NonNull Context context, @NonNull Intent intent) { } /** @@ -900,8 +909,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @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) { + public void onNetworkLogsAvailable(@NonNull Context context, @NonNull Intent intent, + long batchToken, @IntRange(from = 1) int networkLogsCount) { } /** @@ -913,7 +922,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @param intent The received intent as per {@link #onReceive}. * @param newUser The {@link UserHandle} of the user that has just been added. */ - public void onUserAdded(Context context, Intent intent, @NonNull UserHandle newUser) { + public void onUserAdded(@NonNull Context context, @NonNull Intent intent, + @NonNull UserHandle newUser) { } /** @@ -925,7 +935,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @param intent The received intent as per {@link #onReceive}. * @param removedUser The {@link UserHandle} of the user that has just been removed. */ - public void onUserRemoved(Context context, Intent intent, @NonNull UserHandle removedUser) { + public void onUserRemoved(@NonNull Context context, @NonNull Intent intent, + @NonNull UserHandle removedUser) { } /** @@ -937,7 +948,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @param intent The received intent as per {@link #onReceive}. * @param startedUser The {@link UserHandle} of the user that has just been started. */ - public void onUserStarted(Context context, Intent intent, @NonNull UserHandle startedUser) { + public void onUserStarted(@NonNull Context context, @NonNull Intent intent, + @NonNull UserHandle startedUser) { } /** @@ -949,7 +961,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @param intent The received intent as per {@link #onReceive}. * @param stoppedUser The {@link UserHandle} of the user that has just been stopped. */ - public void onUserStopped(Context context, Intent intent, @NonNull UserHandle stoppedUser) { + public void onUserStopped(@NonNull Context context, @NonNull Intent intent, + @NonNull UserHandle stoppedUser) { } /** @@ -961,7 +974,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @param intent The received intent as per {@link #onReceive}. * @param switchedUser The {@link UserHandle} of the user that has just been switched to. */ - public void onUserSwitched(Context context, Intent intent, @NonNull UserHandle switchedUser) { + public void onUserSwitched(@NonNull Context context, @NonNull Intent intent, + @NonNull UserHandle switchedUser) { } /** @@ -995,7 +1009,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @param user the {@link UserHandle} of the affiliated user * @see DevicePolicyManager#transferOwnership(ComponentName, ComponentName, PersistableBundle) */ - public void onTransferAffiliatedProfileOwnershipComplete(Context context, UserHandle user) { + public void onTransferAffiliatedProfileOwnershipComplete(@NonNull Context context, + @NonNull UserHandle user) { } /** @@ -1004,7 +1019,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * convenience callbacks for each action. */ @Override - public void onReceive(Context context, Intent intent) { + public void onReceive(@NonNull Context context, @NonNull Intent intent) { String action = intent.getAction(); if (ACTION_PASSWORD_CHANGED.equals(action)) { diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 7cdd227162b2..f8ccb13b6b53 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1377,7 +1377,7 @@ public class DevicePolicyManager { * complexity, and use this activity with extra {@link #EXTRA_PASSWORD_COMPLEXITY} to suggest * to users how complex the app wants the new screen lock to be. Note that both {@link * #getPasswordComplexity()} and the extra {@link #EXTRA_PASSWORD_COMPLEXITY} require the - * calling app to have the permission {@link permission#REQUEST_SCREEN_LOCK_COMPLEXITY}. + * calling app to have the permission {@link permission#REQUEST_PASSWORD_COMPLEXITY}. * * <p>If the intent is launched from within a managed profile with a profile * owner built against {@link android.os.Build.VERSION_CODES#M} or before, @@ -1405,7 +1405,7 @@ public class DevicePolicyManager { * * <p>If an invalid value is used, it will be treated as {@link #PASSWORD_COMPLEXITY_NONE}. */ - @RequiresPermission(android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY) + @RequiresPermission(android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY) public static final String EXTRA_PASSWORD_COMPLEXITY = "android.app.extra.PASSWORD_COMPLEXITY"; @@ -2187,7 +2187,7 @@ public class DevicePolicyManager { * {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME} then it implies the supplied host is valid * and reachable. */ - public static final int PRIVATE_DNS_SET_SUCCESS = 0; + public static final int PRIVATE_DNS_SET_NO_ERROR = 0; /** * If the {@code privateDnsHost} provided was of a valid hostname but that host was found @@ -2204,7 +2204,7 @@ public class DevicePolicyManager { * @hide */ @IntDef(prefix = {"PRIVATE_DNS_SET_"}, value = { - PRIVATE_DNS_SET_SUCCESS, + PRIVATE_DNS_SET_NO_ERROR, PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING, PRIVATE_DNS_SET_ERROR_FAILURE_SETTING }) @@ -3331,27 +3331,48 @@ public class DevicePolicyManager { } /** - * Determine whether the current password the user has set is sufficient to meet the policy - * requirements (e.g. quality, minimum length) that have been requested by the admins of this - * user and its participating profiles. Restrictions on profiles that have a separate challenge - * are not taken into account. The user must be unlocked in order to perform the check. - * <p> - * On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the - * password is always treated as empty - i.e. this method will always return false on such - * devices, provided any password requirements were set. - * <p> - * The calling device admin must have requested - * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has - * not, a security exception will be thrown. - * <p> - * This method can be called on the {@link DevicePolicyManager} instance returned by + * Determines whether the calling user's current password meets policy requirements + * (e.g. quality, minimum length). The user must be unlocked to perform this check. + * + * <p>Policy requirements which affect this check can be set by admins of the user, but also + * by the admin of a managed profile associated with the calling user (when the managed profile + * doesn't have a separate work challenge). When a managed profile has a separate work + * challenge, its policy requirements only affect the managed profile. + * + * <p>Depending on the user, this method checks the policy requirement against one of the + * following passwords: + * <ul> + * <li>For the primary user or secondary users: the personal keyguard password. + * <li>For managed profiles: a work challenge if set, otherwise the parent user's personal + * keyguard password. + * <ul/> + * In other words, it's always checking the requirement against the password that is protecting + * the calling user. + * + * <p>Note that this method considers all policy requirements targeting the password in + * question. For example a profile owner might set a requirement on the parent profile i.e. + * personal keyguard but not on the profile itself. When the device has a weak personal keyguard + * password and no separate work challenge, calling this method will return {@code false} + * despite the profile owner not setting a policy on the profile itself. This is because the + * profile's current password is the personal keyguard password, and it does not meet all policy + * requirements. + * + * <p>Device admins must request {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} before + * calling this method. Note, this policy type is deprecated for device admins in Android 9.0 + * (API level 28) or higher. + * + * <p>This method can be called on the {@link DevicePolicyManager} instance returned by * {@link #getParentProfileInstance(ComponentName)} in order to determine if the password set on * the parent profile is sufficient. * - * @return Returns true if the password meets the current requirements, else false. - * @throws SecurityException if the calling application does not own an active administrator - * that uses {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} - * @throws IllegalStateException if the user is not unlocked. + * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the + * password is always treated as empty - i.e. this method will always return false on such + * devices, provided any password requirements were set. + * + * @return {@code true} if the password meets the policy requirements, {@code false} otherwise + * @throws SecurityException if the calling application isn't an active admin that uses + * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} + * @throws IllegalStateException if the user isn't unlocked */ public boolean isActivePasswordSufficient() { if (mService != null) { @@ -3377,10 +3398,10 @@ public class DevicePolicyManager { * * @throws IllegalStateException if the user is not unlocked. * @throws SecurityException if the calling application does not have the permission - * {@link permission#REQUEST_SCREEN_LOCK_COMPLEXITY} + * {@link permission#REQUEST_PASSWORD_COMPLEXITY} */ @PasswordComplexity - @RequiresPermission(android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY) + @RequiresPermission(android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY) public int getPasswordComplexity() { throwIfParentInstance("getPasswordComplexity"); if (mService == null) { @@ -10457,7 +10478,7 @@ public class DevicePolicyManager { * * @param admin which {@link DeviceAdminReceiver} this request is associated with. * - * @return {@code PRIVATE_DNS_SET_SUCCESS} if the mode was set successfully, or + * @return {@code PRIVATE_DNS_SET_NO_ERROR} if the mode was set successfully, or * {@code PRIVATE_DNS_SET_ERROR_FAILURE_SETTING} if it could not be set. * * @throws SecurityException if the caller is not the device owner. @@ -10493,7 +10514,7 @@ public class DevicePolicyManager { * @param admin which {@link DeviceAdminReceiver} this request is associated with. * @param privateDnsHost The hostname of a server that implements DNS over TLS (RFC7858). * - * @return {@code PRIVATE_DNS_SET_SUCCESS} if the mode was set successfully, + * @return {@code PRIVATE_DNS_SET_NO_ERROR} if the mode was set successfully, * {@code PRIVATE_DNS_SET_ERROR_FAILURE_SETTING} if it could not be set or * {@code PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING} if the specified host does not * implement RFC7858. diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl index 62b24e9995e8..83c1d611226d 100644 --- a/core/java/android/app/usage/IUsageStatsManager.aidl +++ b/core/java/android/app/usage/IUsageStatsManager.aidl @@ -60,7 +60,7 @@ interface IUsageStatsManager { in PendingIntent sessionEndCallbackIntent, String callingPackage); void unregisterUsageSessionObserver(int sessionObserverId, String callingPackage); void registerAppUsageLimitObserver(int observerId, in String[] packages, long timeLimitMs, - long timeRemainingMs, in PendingIntent callback, String callingPackage); + long timeUsedMs, in PendingIntent callback, String callingPackage); void unregisterAppUsageLimitObserver(int observerId, String callingPackage); void reportUsageStart(in IBinder activity, String token, String callingPackage); void reportPastUsageStart(in IBinder activity, String token, long timeAgoMs, diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index cee6b87fd3f1..e47ec22310aa 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -747,7 +747,7 @@ public final class UsageStatsManager { */ @Deprecated @UnsupportedAppUsage - // STOPSHIP b/126917290: remove this method once ag/6591106 is merged and it's not being used. + // STOPSHIP b/126917290: remove this method once b/126926550 is fixed. public void registerAppUsageLimitObserver(int observerId, @NonNull String[] observedEntities, long timeLimit, @NonNull TimeUnit timeUnit, @Nullable PendingIntent callbackIntent) { final Duration timeLimitDuration = Duration.ofMillis(timeUnit.toMillis(timeLimit)); @@ -782,16 +782,17 @@ public final class UsageStatsManager { * null and must include at least one package or token. * @param timeLimit The total time the set of apps can be in the foreground before the * {@code callbackIntent} is delivered. Must be at least one minute. - * @param timeRemaining The remaining time the set of apps can be in the foreground before the - * {@code callbackIntent} is delivered. Must be greater than - * {@code timeLimit}. Note: a limit of 0 can be set to indicate that the - * user has already exhausted the limit for a group, in which case, - * the given {@code callbackIntent} will be ignored. + * @param timeUsed The time that has already been used by the set of apps in + * {@code observedEntities}. Note: a time used equal to or greater than + * {@code timeLimit} can be set to indicate that the user has already exhausted + * the limit for a group, in which case, the given {@code callbackIntent} will + * be ignored. * @param callbackIntent The PendingIntent that will be dispatched when the usage limit is * exceeded by the group of apps. The delivered Intent will also contain * the extras {@link #EXTRA_OBSERVER_ID}, {@link #EXTRA_TIME_LIMIT} and * {@link #EXTRA_TIME_USED}. Cannot be {@code null} unless the observer is - * being registered with a {@code timeRemaining} of 0. + * being registered with a {@code timeUsed} equal to or greater than + * {@code timeLimit}. * @throws SecurityException if the caller doesn't have both SUSPEND_APPS and OBSERVE_APP_USAGE * permissions. * @hide @@ -801,11 +802,11 @@ public final class UsageStatsManager { android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int observerId, @NonNull String[] observedEntities, - @NonNull Duration timeLimit, @NonNull Duration timeRemaining, + @NonNull Duration timeLimit, @NonNull Duration timeUsed, @Nullable PendingIntent callbackIntent) { try { mService.registerAppUsageLimitObserver(observerId, observedEntities, - timeLimit.toMillis(), timeRemaining.toMillis(), callbackIntent, + timeLimit.toMillis(), timeUsed.toMillis(), callbackIntent, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index ab8c196edccd..b8a741ab2b72 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -19,6 +19,7 @@ package android.bluetooth; import android.Manifest; import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; @@ -3057,7 +3058,7 @@ public final class BluetoothAdapter { * permissions, or unable to start this CoC */ @RequiresPermission(Manifest.permission.BLUETOOTH) - public BluetoothServerSocket listenUsingL2capChannel() + public @NonNull BluetoothServerSocket listenUsingL2capChannel() throws IOException { BluetoothServerSocket socket = new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, true, true, @@ -3115,7 +3116,7 @@ public final class BluetoothAdapter { * permissions, or unable to start this CoC */ @RequiresPermission(Manifest.permission.BLUETOOTH) - public BluetoothServerSocket listenUsingInsecureL2capChannel() + public @NonNull BluetoothServerSocket listenUsingInsecureL2capChannel() throws IOException { BluetoothServerSocket socket = new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, false, false, diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index f71841563a63..fa2c9f8a52ae 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -17,6 +17,7 @@ package android.bluetooth; import android.Manifest; +import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; @@ -2182,7 +2183,7 @@ public final class BluetoothDevice implements Parcelable { * permissions */ @RequiresPermission(Manifest.permission.BLUETOOTH) - public BluetoothSocket createL2capChannel(int psm) throws IOException { + public @NonNull BluetoothSocket createL2capChannel(int psm) throws IOException { if (!isBluetoothEnabled()) { Log.e(TAG, "createL2capChannel: Bluetooth is not enabled"); throw new IOException(); @@ -2221,7 +2222,7 @@ public final class BluetoothDevice implements Parcelable { * permissions */ @RequiresPermission(Manifest.permission.BLUETOOTH) - public BluetoothSocket createInsecureL2capChannel(int psm) throws IOException { + public @NonNull BluetoothSocket createInsecureL2capChannel(int psm) throws IOException { if (!isBluetoothEnabled()) { Log.e(TAG, "createInsecureL2capChannel: Bluetooth is not enabled"); throw new IOException(); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index f896274ed8b3..0c76f3f049a8 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4089,7 +4089,7 @@ public abstract class Context { * @see #getSystemService(String) * @hide */ - @SystemApi + @SystemApi @TestApi public static final String ROLLBACK_SERVICE = "rollback"; /** diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 0715572c03c0..a2d3f6af2564 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2441,7 +2441,7 @@ public class Intent implements Parcelable, Cloneable { * * @hide */ - @SystemApi + @SystemApi @TestApi @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_ROLLBACK_COMMITTED = "android.intent.action.ROLLBACK_COMMITTED"; diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index 0cc5f3931487..2a19763321f2 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -585,8 +585,8 @@ public class LauncherApps { * @param sourceBounds The Rect containing the source bounds of the clicked icon * @param opts Options to pass to startActivity */ - public void startPackageInstallerSessionDetailsActivity(SessionInfo sessionInfo, - Rect sourceBounds, Bundle opts) { + public void startPackageInstallerSessionDetailsActivity(@NonNull SessionInfo sessionInfo, + @Nullable Rect sourceBounds, @Nullable Bundle opts) { try { mService.startSessionDetailsActivityAsUser(mContext.getIApplicationThread(), mContext.getPackageName(), sessionInfo, sourceBounds, opts, @@ -1503,7 +1503,7 @@ public class LauncherApps { * @param callback The callback to unregister. * @see #registerPackageInstallerSessionCallback(Executor, SessionCallback) */ - public void unregisterPackageInstallerSessionCallback(SessionCallback callback) { + public void unregisterPackageInstallerSessionCallback(@NonNull SessionCallback callback) { synchronized (mDelegates) { for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) { final SessionCallbackDelegate delegate = i.next(); diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 7b4dd195ded9..33b9c724de21 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -24,6 +24,7 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.AppGlobals; @@ -1465,7 +1466,7 @@ public class PackageInstaller { * @param enable set to {@code true} to enable, {@code false} to disable * @hide */ - @SystemApi + @SystemApi @TestApi public void setEnableRollback(boolean enable) { if (enable) { installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK; @@ -1591,7 +1592,7 @@ public class PackageInstaller { * * {@hide} */ - @SystemApi + @SystemApi @TestApi @RequiresPermission(Manifest.permission.INSTALL_PACKAGES) public void setStaged() { this.isStaged = true; @@ -1602,7 +1603,7 @@ public class PackageInstaller { * * {@hide} */ - @SystemApi + @SystemApi @TestApi @RequiresPermission(Manifest.permission.INSTALL_PACKAGES) public void setInstallAsApex() { installFlags |= PackageManager.INSTALL_APEX; @@ -1833,7 +1834,7 @@ public class PackageInstaller { /** * Return the user associated with this session. */ - public UserHandle getUser() { + public @NonNull UserHandle getUser() { return new UserHandle(userId); } diff --git a/core/java/android/content/pm/PackageList.java b/core/java/android/content/pm/PackageList.java index cfd99abc6283..f78175868860 100644 --- a/core/java/android/content/pm/PackageList.java +++ b/core/java/android/content/pm/PackageList.java @@ -45,16 +45,16 @@ public class PackageList implements PackageListObserver, AutoCloseable { } @Override - public void onPackageAdded(String packageName) { + public void onPackageAdded(String packageName, int uid) { if (mWrappedObserver != null) { - mWrappedObserver.onPackageAdded(packageName); + mWrappedObserver.onPackageAdded(packageName, uid); } } @Override - public void onPackageRemoved(String packageName) { + public void onPackageRemoved(String packageName, int uid) { if (mWrappedObserver != null) { - mWrappedObserver.onPackageRemoved(packageName); + mWrappedObserver.onPackageRemoved(packageName, uid); } } diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index 2c1842c70db9..0ef765693c49 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -78,9 +78,9 @@ public abstract class PackageManagerInternal { /** Observer called whenever the list of packages changes */ public interface PackageListObserver { /** A package was added to the system. */ - void onPackageAdded(@NonNull String packageName); + void onPackageAdded(@NonNull String packageName, int uid); /** A package was removed from the system. */ - void onPackageRemoved(@NonNull String packageName); + void onPackageRemoved(@NonNull String packageName, int uid); } /** Interface to override permission checks via composition */ diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 89c069026065..ec4213405f39 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -1618,7 +1618,7 @@ public class PackageParser { } final AttributeSet attrs = parser; - return parseApkLite(apkPath, parser, attrs, signingDetails, flags); + return parseApkLite(apkPath, parser, attrs, signingDetails); } catch (XmlPullParserException | IOException | RuntimeException e) { Slog.w(TAG, "Failed to parse " + apkPath, e); @@ -1705,7 +1705,7 @@ public class PackageParser { } private static ApkLite parseApkLite(String codePath, XmlPullParser parser, AttributeSet attrs, - SigningDetails signingDetails, int flags) + SigningDetails signingDetails) throws IOException, XmlPullParserException, PackageParserException { final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs); @@ -1713,12 +1713,11 @@ public class PackageParser { int versionCode = 0; int versionCodeMajor = 0; int revisionCode = 0; - int targetSdkVersion = 0; boolean coreApp = false; boolean debuggable = false; boolean multiArch = false; boolean use32bitAbi = false; - Boolean extractNativeLibsProvided = null; + boolean extractNativeLibs = true; boolean isolatedSplits = false; boolean isFeatureSplit = false; boolean isSplitRequired = false; @@ -1783,8 +1782,7 @@ public class PackageParser { use32bitAbi = attrs.getAttributeBooleanValue(i, false); } if ("extractNativeLibs".equals(attr)) { - extractNativeLibsProvided = Boolean.valueOf( - attrs.getAttributeBooleanValue(i, true)); + extractNativeLibs = attrs.getAttributeBooleanValue(i, true); } if ("useEmbeddedDex".equals(attr)) { useEmbeddedDex = attrs.getAttributeBooleanValue(i, false); @@ -1802,52 +1800,9 @@ public class PackageParser { PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, "<uses-split> tag requires 'android:name' attribute"); } - } else if (TAG_USES_SDK.equals(parser.getName())) { - final String[] errorMsg = new String[1]; - Pair<Integer, Integer> versions = deriveSdkVersions(new AbstractVersionsAccessor() { - @Override public String getMinSdkVersionCode() { - return getAttributeAsString("minSdkVersion"); - } - - @Override public int getMinSdkVersion() { - return getAttributeAsInt("minSdkVersion"); - } - - @Override public String getTargetSdkVersionCode() { - return getAttributeAsString("targetSdkVersion"); - } - - @Override public int getTargetSdkVersion() { - return getAttributeAsInt("targetSdkVersion"); - } - - private String getAttributeAsString(String name) { - return attrs.getAttributeValue(ANDROID_RESOURCES, name); - } - - private int getAttributeAsInt(String name) { - try { - return attrs.getAttributeIntValue(ANDROID_RESOURCES, name, -1); - } catch (NumberFormatException e) { - return -1; - } - } - }, flags, errorMsg); - - if (versions == null) { - throw new PackageParserException( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, errorMsg[0]); - } - - targetSdkVersion = versions.second; } } - // TODO: flip the default based on targetSdkVersion when possible. See b/128335904. - final boolean extractNativeLibsDefault = true; - final boolean extractNativeLibs = (extractNativeLibsProvided != null) - ? extractNativeLibsProvided : extractNativeLibsDefault; - return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit, configForSplit, usesSplitName, isSplitRequired, versionCode, versionCodeMajor, revisionCode, installLocation, verifiers, signingDetails, coreApp, debuggable, @@ -2253,60 +2208,64 @@ public class PackageParser { } else if (tagName.equals(TAG_USES_SDK)) { if (SDK_VERSION > 0) { - sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdk); - final TypedArray saFinal = sa; - Pair<Integer, Integer> versions = deriveSdkVersions( - new AbstractVersionsAccessor() { - @Override public String getMinSdkVersionCode() { - return getAttributeAsString( - R.styleable.AndroidManifestUsesSdk_minSdkVersion); - } - - @Override public int getMinSdkVersion() { - return getAttributeAsInt( - R.styleable.AndroidManifestUsesSdk_minSdkVersion); - } - - @Override public String getTargetSdkVersionCode() { - return getAttributeAsString( - R.styleable.AndroidManifestUsesSdk_targetSdkVersion); - } - - @Override public int getTargetSdkVersion() { - return getAttributeAsInt( - R.styleable.AndroidManifestUsesSdk_targetSdkVersion); - } - - private String getAttributeAsString(int index) { - TypedValue val = saFinal.peekValue(index); - if (val != null && val.type == TypedValue.TYPE_STRING - && val.string != null) { - return val.string.toString(); - } - return null; - } - - private int getAttributeAsInt(int index) { - TypedValue val = saFinal.peekValue(index); - if (val != null && val.type != TypedValue.TYPE_STRING) { - // If it's not a string, it's an integer. - return val.data; - } - return -1; - } - }, flags, outError); - - if (versions == null) { + sa = res.obtainAttributes(parser, + com.android.internal.R.styleable.AndroidManifestUsesSdk); + + int minVers = 1; + String minCode = null; + int targetVers = 0; + String targetCode = null; + + TypedValue val = sa.peekValue( + com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion); + if (val != null) { + if (val.type == TypedValue.TYPE_STRING && val.string != null) { + minCode = val.string.toString(); + } else { + // If it's not a string, it's an integer. + minVers = val.data; + } + } + + val = sa.peekValue( + com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion); + if (val != null) { + if (val.type == TypedValue.TYPE_STRING && val.string != null) { + targetCode = val.string.toString(); + if (minCode == null) { + minCode = targetCode; + } + } else { + // If it's not a string, it's an integer. + targetVers = val.data; + } + } else { + targetVers = minVers; + targetCode = minCode; + } + + sa.recycle(); + + final int minSdkVersion = PackageParser.computeMinSdkVersion(minVers, minCode, + SDK_VERSION, SDK_CODENAMES, outError); + if (minSdkVersion < 0) { mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; return null; } - pkg.applicationInfo.minSdkVersion = versions.first; - pkg.applicationInfo.targetSdkVersion = versions.second; + final int targetSdkVersion = PackageParser.computeTargetSdkVersion(targetVers, + targetCode, SDK_CODENAMES, outError); + if (targetSdkVersion < 0) { + mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; + return null; + } - sa.recycle(); + pkg.applicationInfo.minSdkVersion = minSdkVersion; + pkg.applicationInfo.targetSdkVersion = targetSdkVersion; } + XmlUtils.skipCurrentTag(parser); + } else if (tagName.equals(TAG_SUPPORT_SCREENS)) { sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifestSupportsScreens); @@ -2717,66 +2676,6 @@ public class PackageParser { return -1; } - private interface AbstractVersionsAccessor { - /** Returns minimum SDK version code string, or null if absent. */ - String getMinSdkVersionCode(); - - /** Returns minimum SDK version code, or -1 if absent. */ - int getMinSdkVersion(); - - /** Returns target SDK version code string, or null if absent. */ - String getTargetSdkVersionCode(); - - /** Returns target SDK version code, or -1 if absent. */ - int getTargetSdkVersion(); - } - - private static @Nullable Pair<Integer, Integer> deriveSdkVersions( - @NonNull AbstractVersionsAccessor accessor, int flags, String[] outError) { - int minVers = 1; - String minCode = null; - int targetVers = 0; - String targetCode = null; - - String code = accessor.getMinSdkVersionCode(); - int version = accessor.getMinSdkVersion(); - // Check integer first since code is almost never a null string (e.g. "28"). - if (version >= 0) { - minVers = version; - } else if (code != null) { - minCode = code; - } - - code = accessor.getTargetSdkVersionCode(); - version = accessor.getTargetSdkVersion(); - // Check integer first since code is almost never a null string (e.g. "28"). - if (version >= 0) { - targetVers = version; - } else if (code != null) { - targetCode = code; - if (minCode == null) { - minCode = targetCode; - } - } else { - targetVers = minVers; - targetCode = minCode; - } - - final int minSdkVersion = computeMinSdkVersion(minVers, minCode, - SDK_VERSION, SDK_CODENAMES, outError); - if (minSdkVersion < 0) { - return null; - } - - final int targetSdkVersion = computeTargetSdkVersion(targetVers, - targetCode, SDK_CODENAMES, outError); - if (targetSdkVersion < 0) { - return null; - } - - return Pair.create(minSdkVersion, targetSdkVersion); - } - /** * Computes the minSdkVersion to use at runtime. If the package is not * compatible with this platform, populates {@code outError[0]} with an @@ -3719,7 +3618,6 @@ public class PackageParser { ai.flags |= ApplicationInfo.FLAG_MULTIARCH; } - // TODO: flip the default based on targetSdkVersion when possible. See b/128335904. if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_extractNativeLibs, true)) { diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java index cd40c95b5737..00507e1548a6 100644 --- a/core/java/android/content/pm/ServiceInfo.java +++ b/core/java/android/content/pm/ServiceInfo.java @@ -140,6 +140,13 @@ public class ServiceInfo extends ComponentInfo public static final int FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE = 1 << 4; /** + * Constant corresponding to {@code mediaProjection} in + * the {@link android.R.attr#foregroundServiceType} attribute. + * Managing a media projection session, e.g for screen recording or taking screenshots. + */ + public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION = 1 << 5; + + /** * A special value indicates to use all types set in manifest file. */ public static final int FOREGROUND_SERVICE_TYPE_MANIFEST = -1; @@ -158,6 +165,7 @@ public class ServiceInfo extends ComponentInfo FOREGROUND_SERVICE_TYPE_PHONE_CALL, FOREGROUND_SERVICE_TYPE_LOCATION, FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE, + FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION, }) @Retention(RetentionPolicy.SOURCE) public @interface ForegroundServiceType {} diff --git a/core/java/android/content/rollback/PackageRollbackInfo.java b/core/java/android/content/rollback/PackageRollbackInfo.java index c0414fcdf5c5..201475130753 100644 --- a/core/java/android/content/rollback/PackageRollbackInfo.java +++ b/core/java/android/content/rollback/PackageRollbackInfo.java @@ -18,6 +18,7 @@ package android.content.rollback; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.content.pm.VersionedPackage; import android.os.Parcel; import android.os.Parcelable; @@ -31,7 +32,7 @@ import java.util.ArrayList; * * @hide */ -@SystemApi +@SystemApi @TestApi public final class PackageRollbackInfo implements Parcelable { private final VersionedPackage mVersionRolledBackFrom; @@ -211,7 +212,7 @@ public final class PackageRollbackInfo implements Parcelable { out.writeBoolean(mIsApex); } - public static final @android.annotation.NonNull Parcelable.Creator<PackageRollbackInfo> CREATOR = + public static final @NonNull Parcelable.Creator<PackageRollbackInfo> CREATOR = new Parcelable.Creator<PackageRollbackInfo>() { public PackageRollbackInfo createFromParcel(Parcel in) { return new PackageRollbackInfo(in); diff --git a/core/java/android/content/rollback/RollbackInfo.java b/core/java/android/content/rollback/RollbackInfo.java index a363718a8b1d..c09cfd54866c 100644 --- a/core/java/android/content/rollback/RollbackInfo.java +++ b/core/java/android/content/rollback/RollbackInfo.java @@ -18,6 +18,7 @@ package android.content.rollback; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.content.pm.VersionedPackage; import android.os.Parcel; import android.os.Parcelable; @@ -30,7 +31,7 @@ import java.util.List; * * @hide */ -@SystemApi +@SystemApi @TestApi public final class RollbackInfo implements Parcelable { /** diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java index 4e8c254138de..9038b033c3c0 100644 --- a/core/java/android/content/rollback/RollbackManager.java +++ b/core/java/android/content/rollback/RollbackManager.java @@ -16,16 +16,20 @@ package android.content.rollback; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; import android.content.Context; import android.content.IntentSender; import android.content.pm.ParceledListSlice; import android.content.pm.VersionedPackage; import android.os.RemoteException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.List; /** @@ -38,7 +42,7 @@ import java.util.List; * @see PackageInstaller.SessionParams#setEnableRollback() * @hide */ -@SystemApi +@SystemApi @TestApi @SystemService(Context.ROLLBACK_SERVICE) public final class RollbackManager { private final String mCallerPackageName; @@ -112,6 +116,20 @@ public final class RollbackManager { "android.content.rollback.extra.STATUS_MESSAGE"; /** + * Status result of committing a rollback. + * + * @hide + */ + @IntDef(prefix = "STATUS_", value = { + STATUS_SUCCESS, + STATUS_FAILURE, + STATUS_FAILURE_ROLLBACK_UNAVAILABLE, + STATUS_FAILURE_INSTALL, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Status {}; + + /** * The rollback was successfully committed. */ public static final int STATUS_SUCCESS = 0; @@ -175,8 +193,11 @@ public final class RollbackManager { * * @throws SecurityException if the caller does not have the * MANAGE_ROLLBACKS permission. + * + * @hide */ @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) + @TestApi public void reloadPersistedData() { try { mBinder.reloadPersistedData(); @@ -194,8 +215,11 @@ public final class RollbackManager { * @param packageName the name of the package to expire data for. * @throws SecurityException if the caller does not have the * MANAGE_ROLLBACKS permission. + * + * @hide */ @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) + @TestApi public void expireRollbackForPackage(@NonNull String packageName) { try { mBinder.expireRollbackForPackage(packageName); diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 234014327150..d5d25c5c869b 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -680,7 +680,7 @@ public final class CameraManager { } /** - * Notify registered clients about a change in the camera access priorities. + * Called whenever camera access priorities change. * * <p>Notification that camera access priorities have changed and the camera may * now be openable. An application that was previously denied camera access due to diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 3f8410f0cc7f..2a357ff2bcbb 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -2805,7 +2805,7 @@ public class ConnectivityManager { * {@link #TETHER_ERROR_PROVISION_FAILED}, or * {@link #TETHER_ERROR_ENTITLEMENT_UNKONWN}. */ - void onEntitlementResult(@EntitlementResultCode int resultCode); + void onTetheringEntitlementResult(@EntitlementResultCode int resultCode); } /** @@ -2855,7 +2855,7 @@ public class ConnectivityManager { protected void onReceiveResult(int resultCode, Bundle resultData) { Binder.withCleanCallingIdentity(() -> executor.execute(() -> { - listener.onEntitlementResult(resultCode); + listener.onTetheringEntitlementResult(resultCode); })); } }; diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java index 45860b3858ce..95d66bb87064 100644 --- a/core/java/android/net/SSLCertificateSocketFactory.java +++ b/core/java/android/net/SSLCertificateSocketFactory.java @@ -62,7 +62,7 @@ import javax.net.ssl.X509TrustManager; * * The handshake timeout does not apply to actual TCP socket connection. * If you want a connection timeout as well, use {@link #createSocket()} - * and {@link Socket#connect(SocketAddress, int)}, after which you + * and {@link Socket#connect(java.net.SocketAddress, int)}, after which you * must verify the identity of the server you are connected to. * * <p class="caution"><b>Most {@link SSLSocketFactory} implementations do not @@ -211,14 +211,14 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { } /** - * Verify the hostname of the certificate used by the other end of a - * connected socket. You MUST call this if you did not supply a hostname - * to {@link #createSocket()}. It is harmless to call this method - * redundantly if the hostname has already been verified. + * Verify the hostname of the certificate used by the other end of a connected socket using the + * {@link HostnameVerifier} obtained from {@code + * HttpsURLConnection.getDefaultHostnameVerifier()}. You MUST call this if you did not supply a + * hostname to {@link #createSocket()}. It is harmless to call this method redundantly if the + * hostname has already been verified. * - * <p>Wildcard certificates are allowed to verify any matching hostname, - * so "foo.bar.example.com" is verified if the peer has a certificate - * for "*.example.com". + * <p>Wildcard certificates are allowed to verify any matching hostname, so + * "foo.bar.example.com" is verified if the peer has a certificate for "*.example.com". * * @param socket An SSL socket which has been connected to a server * @param hostname The expected hostname of the remote server @@ -483,7 +483,8 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { * {@inheritDoc} * * <p>By default, this method returns a <i>connected</i> socket and verifies the peer's - * certificate hostname after connecting; if this instance was created with + * certificate hostname after connecting using the {@link HostnameVerifier} obtained from + * {@code HttpsURLConnection.getDefaultHostnameVerifier()}; if this instance was created with * {@link #getInsecure(int, SSLSessionCache)}, it returns a socket that is <i>not connected</i> * instead. */ @@ -562,7 +563,8 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { * {@inheritDoc} * * <p>By default, this method returns a <i>connected</i> socket and verifies the peer's - * certificate hostname after connecting; if this instance was created with + * certificate hostname after connecting using the {@link HostnameVerifier} obtained from + * {@code HttpsURLConnection.getDefaultHostnameVerifier()}; if this instance was created with * {@link #getInsecure(int, SSLSessionCache)}, it returns a socket that is <i>not connected</i> * instead. */ @@ -585,7 +587,8 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { * {@inheritDoc} * * <p>By default, this method returns a <i>connected</i> socket and verifies the peer's - * certificate hostname after connecting; if this instance was created with + * certificate hostname after connecting using the {@link HostnameVerifier} obtained from + * {@code HttpsURLConnection.getDefaultHostnameVerifier()}; if this instance was created with * {@link #getInsecure(int, SSLSessionCache)}, it returns a socket that is <i>not connected</i> * instead. */ diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 0425c6234a04..0de4ddca0494 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -306,7 +306,7 @@ public class Build { * @hide */ @SystemApi - public static final String PREVIEW_SDK_FINGERPRINT = SystemProperties.get( + @NonNull public static final String PREVIEW_SDK_FINGERPRINT = SystemProperties.get( "ro.build.version.preview_sdk_fingerprint", "REL"); /** diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index 60f4f06c9617..ff551d46fb2a 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -120,10 +120,6 @@ public class ZygoteProcess { mUsapPoolSecondarySocketAddress = new LocalSocketAddress(Zygote.USAP_POOL_SECONDARY_SOCKET_NAME, LocalSocketAddress.Namespace.RESERVED); - - if (fetchUsapPoolEnabledProp()) { - informZygotesOfUsapPoolStatus(); - } } public ZygoteProcess(LocalSocketAddress primarySocketAddress, @@ -179,14 +175,18 @@ public class ZygoteProcess { * address * @throws IOException */ - public static ZygoteState connect(LocalSocketAddress zygoteSocketAddress, - LocalSocketAddress usapSocketAddress) + public static ZygoteState connect(@NonNull LocalSocketAddress zygoteSocketAddress, + @Nullable LocalSocketAddress usapSocketAddress) throws IOException { DataInputStream zygoteInputStream = null; BufferedWriter zygoteOutputWriter = null; final LocalSocket zygoteSessionSocket = new LocalSocket(); + if (zygoteSocketAddress == null) { + throw new IllegalArgumentException("zygoteSocketAddress can't be null"); + } + try { zygoteSessionSocket.connect(zygoteSocketAddress); zygoteInputStream = new DataInputStream(zygoteSessionSocket.getInputStream()); @@ -678,12 +678,15 @@ public class ZygoteProcess { return origVal != mUsapPoolEnabled; } + private boolean mIsFirstPropCheck = true; private long mLastPropCheckTimestamp = 0; private boolean fetchUsapPoolEnabledPropWithMinInterval() { final long currentTimestamp = SystemClock.elapsedRealtime(); - if (currentTimestamp - mLastPropCheckTimestamp >= Zygote.PROPERTY_CHECK_INTERVAL) { + if (mIsFirstPropCheck + || (currentTimestamp - mLastPropCheckTimestamp >= Zygote.PROPERTY_CHECK_INTERVAL)) { + mIsFirstPropCheck = false; mLastPropCheckTimestamp = currentTimestamp; return fetchUsapPoolEnabledProp(); } @@ -919,11 +922,13 @@ public class ZygoteProcess { return primaryZygoteState; } - // The primary zygote didn't match. Try the secondary. - attemptConnectionToSecondaryZygote(); + if (mZygoteSecondarySocketAddress != null) { + // The primary zygote didn't match. Try the secondary. + attemptConnectionToSecondaryZygote(); - if (secondaryZygoteState.matches(abi)) { - return secondaryZygoteState; + if (secondaryZygoteState.matches(abi)) { + return secondaryZygoteState; + } } } catch (IOException ioe) { throw new ZygoteStartFailedEx("Error connecting to zygote", ioe); @@ -1071,22 +1076,24 @@ public class ZygoteProcess { return; } - try { - attemptConnectionToSecondaryZygote(); - + if (mZygoteSecondarySocketAddress != null) { try { - secondaryZygoteState.mZygoteOutputWriter.write(command); - secondaryZygoteState.mZygoteOutputWriter.flush(); - - // Wait for the secondary Zygote to finish its work. - secondaryZygoteState.mZygoteInputStream.readInt(); + attemptConnectionToSecondaryZygote(); + + try { + secondaryZygoteState.mZygoteOutputWriter.write(command); + secondaryZygoteState.mZygoteOutputWriter.flush(); + + // Wait for the secondary Zygote to finish its work. + secondaryZygoteState.mZygoteInputStream.readInt(); + } catch (IOException ioe) { + throw new IllegalStateException( + "USAP pool state change cause an irrecoverable error", + ioe); + } } catch (IOException ioe) { - throw new IllegalStateException( - "USAP pool state change cause an irrecoverable error", - ioe); + // No secondary zygote present. This is expected on some devices. } - } catch (IOException ioe) { - // No secondary zygote present. This is expected on some devices. } // Wait for the response from the primary zygote here so the primary/secondary zygotes diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java index 5d34aa65937d..fa244e480e11 100644 --- a/core/java/android/provider/CalendarContract.java +++ b/core/java/android/provider/CalendarContract.java @@ -766,15 +766,13 @@ 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 managed profile. Appending a - * calendar id using {@link ContentUris#withAppendedId(Uri, long)} will - * specify a single calendar. + * The content:// style URL for querying Calendars table in the managed profile. Appending + * a calendar id using {@link ContentUris#withAppendedId(Uri, long)} specifies + * a single calendar. * * <p>The following columns are allowed to be queried via this uri: * <ul> * <li>{@link #_ID}</li> - * <li>{@link #NAME}</li> - * <li>{@link #CALENDAR_DISPLAY_NAME}</li> * <li>{@link #CALENDAR_COLOR}</li> * <li>{@link #VISIBLE}</li> * <li>{@link #CALENDAR_LOCATION}</li> @@ -782,18 +780,22 @@ public final class CalendarContract { * <li>{@link #IS_PRIMARY}</li> * </ul> * - * <p>{@link IllegalArgumentException} will be thrown if there exist columns in the + * <p>{@link IllegalArgumentException} is thrown if there exists columns in the * 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 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 + * <p>This uri returns an empty cursor if the calling user is not a parent profile + * of a managed profile, or the managed profile is disabled, or cross-profile calendar is + * disabled in Settings, or this uri is queried from a package that is not allowed by + * the profile owner of the managed profile via * {@link DevicePolicyManager#setCrossProfileCalendarPackages(ComponentName, Set)}. * + * <p>Apps can register a {@link android.database.ContentObserver} for this URI to listen + * to changes. + * * @see DevicePolicyManager#getCrossProfileCalendarPackages(ComponentName) * @see Settings.Secure#CROSS_PROFILE_CALENDAR_ENABLED */ + @NonNull public static final Uri ENTERPRISE_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/enterprise/calendars"); @@ -1747,8 +1749,7 @@ public final class CalendarContract { /** * 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. + * event id using {@link ContentUris#withAppendedId(Uri, long)} specifies a single event. * * <p>The following columns are allowed to be queried via this uri: * <ul> @@ -1767,26 +1768,33 @@ public final class CalendarContract { * <li>{@link #AVAILABILITY}</li> * <li>{@link #RRULE}</li> * <li>{@link #RDATE}</li> + * <li>{@link #LAST_DATE}</li> * <li>{@link #EXRULE}</li> * <li>{@link #EXDATE}</li> - * <li>{@link #CALENDAR_DISPLAY_NAME}</li> + * <li>{@link #SELF_ATTENDEE_STATUS}</li> + * <li>{@link #DISPLAY_COLOR}</li> * <li>{@link #CALENDAR_COLOR}</li> * <li>{@link #VISIBLE}</li> * <li>{@link #CALENDAR_TIME_ZONE}</li> + * <li>{@link #IS_PRIMARY}</li> * </ul> * - * <p>{@link IllegalArgumentException} will be thrown if there exist columns in the + * <p>{@link IllegalArgumentException} is thrown if there exists columns in the * 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 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 + * <p>This uri returns an empty cursor if the calling user is not a parent profile + * of a managed profile, or the managed profile is disabled, or cross-profile calendar is + * disabled in Settings, or this uri is queried from a package that is not allowed by + * the profile owner of the managed profile via * {@link DevicePolicyManager#setCrossProfileCalendarPackages(ComponentName, Set)}. * + * <p>Apps can register a {@link android.database.ContentObserver} for this URI to listen + * to changes. + * * @see DevicePolicyManager#getCrossProfileCalendarPackages(ComponentName) * @see Settings.Secure#CROSS_PROFILE_CALENDAR_ENABLED */ + @NonNull public static final Uri ENTERPRISE_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/enterprise/events"); @@ -1974,7 +1982,7 @@ public final class CalendarContract { * 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 + * <p>The following columns plus the columns that are allowed by * {@link Events#ENTERPRISE_CONTENT_URI} are allowed to be queried via this uri: * <ul> * <li>{@link #_ID}</li> @@ -1987,18 +1995,19 @@ public final class CalendarContract { * <li>{@link #END_MINUTE}</li> * </ul> * - * <p>{@link IllegalArgumentException} will be thrown if there exist columns in the + * <p>{@link IllegalArgumentException} is thrown if there exists columns in the * 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 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 managed profile via + * <p>This uri returns an empty cursor if the calling user is not a parent profile + * of a managed profile, or the managed profile is disabled, or cross-profile calendar is + * disabled in Settings, or this uri is queried from a package that is not allowed by + * the profile owner of the managed profile via * {@link DevicePolicyManager#setCrossProfileCalendarPackages(ComponentName, Set)}. * * @see DevicePolicyManager#getCrossProfileCalendarPackages(ComponentName) * @see Settings.Secure#CROSS_PROFILE_CALENDAR_ENABLED */ + @NonNull public static final Uri ENTERPRISE_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/enterprise/instances/when"); @@ -2007,6 +2016,7 @@ public final class CalendarContract { * Day in the managed profile. It supports similar semantics as {@link #CONTENT_BY_DAY_URI} * and performs similar checks as {@link #ENTERPRISE_CONTENT_URI}. */ + @NonNull public static final Uri ENTERPRISE_CONTENT_BY_DAY_URI = Uri.parse("content://" + AUTHORITY + "/enterprise/instances/whenbyday"); @@ -2015,6 +2025,7 @@ public final class CalendarContract { * term in the managed profile. It supports similar semantics as {@link #CONTENT_SEARCH_URI} * and performs similar checks as {@link #ENTERPRISE_CONTENT_URI}. */ + @NonNull public static final Uri ENTERPRISE_CONTENT_SEARCH_URI = Uri.parse("content://" + AUTHORITY + "/enterprise/instances/search"); @@ -2024,6 +2035,7 @@ public final class CalendarContract { * {@link #CONTENT_SEARCH_BY_DAY_URI} and performs similar checks as * {@link #ENTERPRISE_CONTENT_URI}. */ + @NonNull public static final Uri ENTERPRISE_CONTENT_SEARCH_BY_DAY_URI = Uri.parse("content://" + AUTHORITY + "/enterprise/instances/searchbyday"); diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index e4593e55a2c6..17fc10878099 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -105,6 +105,14 @@ public final class DeviceConfig { public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture"; /** + * Namespace for how dex runs. The feature requires a reboot to reach a clean state. + * + * @hide + */ + @SystemApi + public static final String NAMESPACE_DEX_BOOT = "dex_boot"; + + /** * Namespace for all Game Driver features. * * @hide @@ -290,18 +298,6 @@ public final class DeviceConfig { } /** - * Namespace for how dex runs. The feature may requires reboot to a clean state. - * - * @hide - */ - @SystemApi - public interface DexBoot { - String NAMESPACE = "dex_boot"; - String PRIV_APPS_OOB_ENABLED = "priv_apps_oob_enabled"; - String PRIV_APPS_OOB_WHITELIST = "priv_apps_oob_whitelist"; - } - - /** * Namespace for {@link AttentionManagerService} related features. * * @hide @@ -322,7 +318,7 @@ public final class DeviceConfig { * * @hide */ - @SystemApi + @SystemApi @TestApi public interface Rollback { /** diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java index e931826d2455..281447419943 100644 --- a/core/java/android/provider/FontsContract.java +++ b/core/java/android/provider/FontsContract.java @@ -34,7 +34,6 @@ import android.graphics.fonts.FontFamily; import android.graphics.fonts.FontStyle; import android.graphics.fonts.FontVariationAxis; import android.net.Uri; -import android.os.Build.VERSION_CODES; import android.os.CancellationSignal; import android.os.Handler; import android.os.HandlerThread; @@ -642,25 +641,35 @@ public class FontsContract { continue; } try { - final Font font = new Font.Builder(buffer) + Font font = null; + try { + font = new Font.Builder(buffer) .setWeight(fontInfo.getWeight()) .setSlant(fontInfo.isItalic() ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT) .setTtcIndex(fontInfo.getTtcIndex()) .setFontVariationSettings(fontInfo.getAxes()) .build(); + } catch (IllegalArgumentException e) { + // The exception happens if the unsupported font is passed. We suppress this + // exception and just ignore this font here since there is no way of + // resolving this issue by users during inflating layout. + Log.w(TAG, "Ignoring font file since failed to create font object." + + " The font file is not supported on this platform."); + continue; + } if (familyBuilder == null) { familyBuilder = new FontFamily.Builder(font); } else { try { familyBuilder.addFont(font); } catch (IllegalArgumentException e) { - if (context.getApplicationInfo().targetSdkVersion <= VERSION_CODES.P) { - // Surpress the IllegalArgumentException for keeping the backward - // compatibility. - continue; - } - throw e; + // The exception happens if the same style font is added to the family. + // We suppress this exception and just ignore this font here since there is + // no way of resolving this issue by users during inflating layout. + Log.w(TAG, + "Ignoring font file since the same style font is already added."); + continue; } } } catch (IOException e) { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 4836e6c0cba7..b437435902df 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5590,6 +5590,15 @@ public final class Settings { private static final Validator ALLOW_MOCK_LOCATION_VALIDATOR = BOOLEAN_VALIDATOR; /** + * Setting to indicate that on device captions are enabled. + * + * @hide + */ + public static final String ODI_CAPTIONS_ENABLED = "odi_captions_enabled"; + + private static final Validator ODI_CAPTIONS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR; + + /** * On Android 8.0 (API level 26) and higher versions of the platform, * a 64-bit number (expressed as a hexadecimal string), unique to * each combination of app-signing key, user, and device. @@ -8950,6 +8959,7 @@ public final class Settings { VALIDATORS.put(SILENCE_TIMER_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR); VALIDATORS.put(SILENCE_CALL_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR); VALIDATORS.put(SILENCE_NOTIFICATION_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR); + VALIDATORS.put(ODI_CAPTIONS_ENABLED, ODI_CAPTIONS_ENABLED_VALIDATOR); } /** diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java index c928da103557..32982f9df15d 100644 --- a/core/java/android/text/DynamicLayout.java +++ b/core/java/android/text/DynamicLayout.java @@ -674,7 +674,8 @@ public class DynamicLayout extends Layout { objects[0] = reflowed.getLineDirections(i); final int end = (i == n - 1) ? where + after : reflowed.getLineStart(i + 1); - ints[HYPHEN] = reflowed.getHyphen(i) & HYPHEN_MASK; + ints[HYPHEN] = StaticLayout.packHyphenEdit( + reflowed.getStartHyphenEdit(i), reflowed.getEndHyphenEdit(i)); ints[MAY_PROTRUDE_FROM_TOP_OR_BOTTOM] |= contentMayProtrudeFromLineTopOrBottom(text, start, end) ? MAY_PROTRUDE_FROM_TOP_OR_BOTTOM_MASK : 0; @@ -1056,8 +1057,16 @@ public class DynamicLayout extends Layout { * @hide */ @Override - public int getHyphen(int line) { - return mInts.getValue(line, HYPHEN) & HYPHEN_MASK; + public @Paint.StartHyphenEdit int getStartHyphenEdit(int line) { + return StaticLayout.unpackStartHyphenEdit(mInts.getValue(line, HYPHEN) & HYPHEN_MASK); + } + + /** + * @hide + */ + @Override + public @Paint.EndHyphenEdit int getEndHyphenEdit(int line) { + return StaticLayout.unpackEndHyphenEdit(mInts.getValue(line, HYPHEN) & HYPHEN_MASK); } private boolean getContentMayProtrudeFromTopOrBottom(int line) { diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java index e4200ac0bc6c..6f0628ad38e6 100644 --- a/core/java/android/text/Hyphenator.java +++ b/core/java/android/text/Hyphenator.java @@ -16,142 +16,15 @@ package android.text; -import android.annotation.IntDef; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - /** - * Provides constants and pack/unpack methods for the HyphenEdit. - * - * Hyphenator provides constant values for start of line and end of line modification. - * For example, by passing {@link #END_HYPHEN_EDIT_INSERT_HYPHEN} like as follows, HYPHEN(U+2010) - * character is appended at the end of line. + * Does the native Hyphenator initialization. * - * <pre> - * <code> - * Paint paint = new Paint(); - * paint.setHyphenEdit(Hyphenator.packHyphenEdit( - * Hyphenator.START_HYPHEN_EDIT_NO_EDIT, - * Hyphenator.END_HYPHEN_EDIT_INSERT_HYPHEN)); - * paint.measureText("abc", 0, 3); // Returns the width of "abc‐" - * Canvas.drawText("abc", 0, 3, 0f, 0f, paint); // Draws "abc‐" - * </code> - * </pre> - * - * @see android.graphics.Paint#setHyphenEdit(int) + * @hide */ public class Hyphenator { private Hyphenator() {} - /** @hide */ - @IntDef(prefix = { "START_HYPHEN_EDIT_" }, value = { - START_HYPHEN_EDIT_NO_EDIT, - START_HYPHEN_EDIT_INSERT_HYPHEN, - START_HYPHEN_EDIT_INSERT_ZWJ - }) - @Retention(RetentionPolicy.SOURCE) - public @interface StartHyphenEdit {} - - /** - * An integer representing the starting of the line has no modification for hyphenation. - */ - public static final int START_HYPHEN_EDIT_NO_EDIT = 0x00; - - /** - * An integer representing the starting of the line has normal hyphen character (U+002D). - */ - public static final int START_HYPHEN_EDIT_INSERT_HYPHEN = 0x01; - - /** - * An integer representing the starting of the line has Zero-Width-Joiner (U+200D). - */ - public static final int START_HYPHEN_EDIT_INSERT_ZWJ = 0x02; - - /** @hide */ - @IntDef(prefix = { "END_HYPHEN_EDIT_" }, value = { - END_HYPHEN_EDIT_NO_EDIT, - END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN, - END_HYPHEN_EDIT_INSERT_HYPHEN, - END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN, - END_HYPHEN_EDIT_INSERT_MAQAF, - END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN, - END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN - }) - @Retention(RetentionPolicy.SOURCE) - public @interface EndHyphenEdit {} - - /** - * An integer representing the end of the line has no modification for hyphenation. - */ - public static final int END_HYPHEN_EDIT_NO_EDIT = 0x00; - - /** - * An integer representing the character at the end of the line is replaced with hyphen - * character (U+002D). - */ - public static final int END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN = 0x01; - - /** - * An integer representing the end of the line has normal hyphen character (U+002D). - */ - public static final int END_HYPHEN_EDIT_INSERT_HYPHEN = 0x02; - - /** - * An integer representing the end of the line has Armentian hyphen (U+058A). - */ - public static final int END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN = 0x03; - - /** - * An integer representing the end of the line has maqaf (Hebrew hyphen, U+05BE). - */ - public static final int END_HYPHEN_EDIT_INSERT_MAQAF = 0x04; - - /** - * An integer representing the end of the line has Canadian Syllabics hyphen (U+1400). - */ - public static final int END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN = 0x05; - - /** - * An integer representing the end of the line has Zero-Width-Joiner (U+200D) followed by normal - * hyphen character (U+002D). - */ - public static final int END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN = 0x06; - - // Following three constants are used for packing start hyphen edit and end hyphen edit into - // single integer. Following encodings must be the same as the minikin's one. - // See frameworks/minikin/include/Hyphenator.h for more details. - private static final int END_HYPHEN_EDIT_MASK = 0x07; // 0b00111 - private static final int START_HYPHEN_EDIT_MASK = 0x18; // 0b11000 - private static final int START_HYPHEN_EDIT_SHIFT = 0x03; - - /** - * Extract start hyphen edit from packed value. - */ - public static @StartHyphenEdit int unpackStartHyphenEdit(int hyphenEdit) { - return (hyphenEdit & START_HYPHEN_EDIT_MASK) >> START_HYPHEN_EDIT_SHIFT; - } - - /** - * Extract end hyphen edit from packed value. - */ - public static @EndHyphenEdit int unpackEndHyphenEdit(int hyphenEdit) { - return hyphenEdit & END_HYPHEN_EDIT_MASK; - } - - /** - * Pack the start hyphen edit and end hyphen edit into single integer. - */ - public static int packHyphenEdit(@StartHyphenEdit int startHyphenEdit, - @EndHyphenEdit int endHyphenEdit) { - return ((startHyphenEdit << START_HYPHEN_EDIT_SHIFT) & START_HYPHEN_EDIT_MASK) - | (endHyphenEdit & END_HYPHEN_EDIT_MASK); - } - - - /** - * @hide - */ + // This method is called from Zygote. public static void init() { nInit(); } diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index 2d5f3bf8c862..fb6dc228e786 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -437,7 +437,8 @@ public abstract class Layout { previousLineEnd = getLineStart(lineNum + 1); final boolean justify = isJustificationRequired(lineNum); int end = getLineVisibleEnd(lineNum, start, previousLineEnd); - paint.setHyphenEdit(getHyphen(lineNum)); + paint.setStartHyphenEdit(getStartHyphenEdit(lineNum)); + paint.setEndHyphenEdit(getEndHyphenEdit(lineNum)); int ltop = previousLineBottom; int lbottom = getLineTop(lineNum + 1); @@ -910,12 +911,21 @@ public abstract class Layout { public abstract int getBottomPadding(); /** - * Returns the hyphen edit for a line. + * Returns the start hyphen edit for a line. * * @hide */ - public int getHyphen(int line) { - return 0; + public @Paint.StartHyphenEdit int getStartHyphenEdit(int line) { + return Paint.START_HYPHEN_EDIT_NO_EDIT; + } + + /** + * Returns the end hyphen edit for a line. + * + * @hide + */ + public @Paint.EndHyphenEdit int getEndHyphenEdit(int line) { + return Paint.END_HYPHEN_EDIT_NO_EDIT; } /** @@ -1418,7 +1428,8 @@ public abstract class Layout { final TextLine tl = TextLine.obtain(); final TextPaint paint = mWorkPaint; paint.set(mPaint); - paint.setHyphenEdit(getHyphen(line)); + paint.setStartHyphenEdit(getStartHyphenEdit(line)); + paint.setEndHyphenEdit(getEndHyphenEdit(line)); tl.set(paint, mText, start, end, dir, directions, hasTabs, tabStops, getEllipsisStart(line), getEllipsisStart(line) + getEllipsisCount(line)); if (isJustificationRequired(line)) { @@ -1447,7 +1458,8 @@ public abstract class Layout { final TextLine tl = TextLine.obtain(); final TextPaint paint = mWorkPaint; paint.set(mPaint); - paint.setHyphenEdit(getHyphen(line)); + paint.setStartHyphenEdit(getStartHyphenEdit(line)); + paint.setEndHyphenEdit(getEndHyphenEdit(line)); tl.set(paint, mText, start, end, dir, directions, hasTabs, tabStops, getEllipsisStart(line), getEllipsisStart(line) + getEllipsisCount(line)); if (isJustificationRequired(line)) { diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index defe2cefc1f7..9fefc83056ac 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -779,7 +779,8 @@ public class StaticLayout extends Layout { ascents[i] = res.getLineAscent(i); descents[i] = res.getLineDescent(i); hasTabs[i] = res.hasLineTab(i); - hyphenEdits[i] = res.getLineHyphenEdit(i); + hyphenEdits[i] = + packHyphenEdit(res.getStartLineHyphenEdit(i), res.getEndLineHyphenEdit(i)); } final int remainingLineCount = mMaximumVisibleLineCount - mLineCount; @@ -1258,20 +1259,42 @@ public class StaticLayout extends Layout { return mBottomPadding; } + // To store into single int field, pack the pair of start and end hyphen edit. + static int packHyphenEdit( + @Paint.StartHyphenEdit int start, @Paint.EndHyphenEdit int end) { + return start << START_HYPHEN_BITS_SHIFT | end; + } + + static int unpackStartHyphenEdit(int packedHyphenEdit) { + return (packedHyphenEdit & START_HYPHEN_MASK) >> START_HYPHEN_BITS_SHIFT; + } + + static int unpackEndHyphenEdit(int packedHyphenEdit) { + return packedHyphenEdit & END_HYPHEN_MASK; + } + /** - * Returns the packed hyphen edit value for this line. + * Returns the start hyphen edit value for this line. * - * You can extract start hyphen edit and end hyphen edit by using - * {@link Hyphenator#unpackStartHyphenEdit(int)} and - * {@link Hyphenator#unpackEndHyphenEdit(int)}. + * @param lineNumber a line number + * @return A start hyphen edit value. + * @hide + */ + @Override + public @Paint.StartHyphenEdit int getStartHyphenEdit(int lineNumber) { + return unpackStartHyphenEdit(mLines[mColumns * lineNumber + HYPHEN] & HYPHEN_MASK); + } + + /** + * Returns the packed hyphen edit value for this line. * * @param lineNumber a line number - * @return A packed hyphen edit value. + * @return An end hyphen edit value. * @hide */ @Override - public int getHyphen(int lineNumber) { - return mLines[mColumns * lineNumber + HYPHEN] & HYPHEN_MASK; + public @Paint.EndHyphenEdit int getEndHyphenEdit(int lineNumber) { + return unpackEndHyphenEdit(mLines[mColumns * lineNumber + HYPHEN] & HYPHEN_MASK); } /** @@ -1395,6 +1418,9 @@ public class StaticLayout extends Layout { private static final int DIR_SHIFT = 30; private static final int TAB_MASK = 0x20000000; private static final int HYPHEN_MASK = 0xFF; + private static final int START_HYPHEN_BITS_SHIFT = 3; + private static final int START_HYPHEN_MASK = 0x18; // 0b11000 + private static final int END_HYPHEN_MASK = 0x7; // 0b00111 private static final int TAB_INCREMENT = 20; // same as Layout, but that's private diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index 915a18e59226..86651060a394 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -1012,19 +1012,14 @@ public class TextLine { return runIsRtl ? -ret : ret; } - private int adjustHyphenEdit(int start, int limit, int packedHyphenEdit) { - int result = packedHyphenEdit; - // Only draw hyphens on first or last run in line. Disable them otherwise. - if (start > 0) { // not the first run - result = Hyphenator.packHyphenEdit(Hyphenator.START_HYPHEN_EDIT_NO_EDIT, - Hyphenator.unpackEndHyphenEdit(packedHyphenEdit)); - } - if (limit < mLen) { // not the last run - result = Hyphenator.packHyphenEdit(Hyphenator.unpackStartHyphenEdit(packedHyphenEdit), - Hyphenator.END_HYPHEN_EDIT_NO_EDIT); - result &= ~Paint.HYPHENEDIT_MASK_END_OF_LINE; - } - return result; + private int adjustStartHyphenEdit(int start, @Paint.StartHyphenEdit int startHyphenEdit) { + // Only draw hyphens on first in line. Disable them otherwise. + return start > 0 ? Paint.START_HYPHEN_EDIT_NO_EDIT : startHyphenEdit; + } + + private int adjustEndHyphenEdit(int limit, @Paint.EndHyphenEdit int endHyphenEdit) { + // Only draw hyphens on last run in line. Disable them otherwise. + return limit < mLen ? Paint.END_HYPHEN_EDIT_NO_EDIT : endHyphenEdit; } private static final class DecorationInfo { @@ -1115,7 +1110,8 @@ public class TextLine { if (!needsSpanMeasurement) { final TextPaint wp = mWorkPaint; wp.set(mPaint); - wp.setHyphenEdit(adjustHyphenEdit(start, limit, wp.getHyphenEdit())); + wp.setStartHyphenEdit(adjustStartHyphenEdit(start, wp.getStartHyphenEdit())); + wp.setEndHyphenEdit(adjustEndHyphenEdit(limit, wp.getEndHyphenEdit())); return handleText(wp, start, limit, start, limit, runIsRtl, c, x, top, y, bottom, fmi, needWidth, measureLimit, null); } @@ -1193,8 +1189,10 @@ public class TextLine { // The style of the present chunk of text is substantially different from the // style of the previous chunk. We need to handle the active piece of text // and restart with the present chunk. - activePaint.setHyphenEdit(adjustHyphenEdit( - activeStart, activeEnd, mPaint.getHyphenEdit())); + activePaint.setStartHyphenEdit( + adjustStartHyphenEdit(activeStart, mPaint.getStartHyphenEdit())); + activePaint.setEndHyphenEdit( + adjustEndHyphenEdit(activeEnd, mPaint.getEndHyphenEdit())); x += handleText(activePaint, activeStart, activeEnd, i, inext, runIsRtl, c, x, top, y, bottom, fmi, needWidth || activeEnd < measureLimit, Math.min(activeEnd, mlimit), mDecorations); @@ -1218,8 +1216,10 @@ public class TextLine { } } // Handle the final piece of text. - activePaint.setHyphenEdit(adjustHyphenEdit( - activeStart, activeEnd, mPaint.getHyphenEdit())); + activePaint.setStartHyphenEdit( + adjustStartHyphenEdit(activeStart, mPaint.getStartHyphenEdit())); + activePaint.setEndHyphenEdit( + adjustEndHyphenEdit(activeEnd, mPaint.getEndHyphenEdit())); x += handleText(activePaint, activeStart, activeEnd, i, inext, runIsRtl, c, x, top, y, bottom, fmi, needWidth || activeEnd < measureLimit, Math.min(activeEnd, mlimit), mDecorations); @@ -1323,7 +1323,8 @@ public class TextLine { && lp.getTextSkewX() == rp.getTextSkewX() && lp.getLetterSpacing() == rp.getLetterSpacing() && lp.getWordSpacing() == rp.getWordSpacing() - && lp.getHyphenEdit() == rp.getHyphenEdit() + && lp.getStartHyphenEdit() == rp.getStartHyphenEdit() + && lp.getEndHyphenEdit() == rp.getEndHyphenEdit() && lp.bgColor == rp.bgColor && lp.baselineShift == rp.baselineShift && lp.linkColor == rp.linkColor diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java index e2af6f5ed102..436cb4ff7072 100644 --- a/core/java/android/util/ArrayMap.java +++ b/core/java/android/util/ArrayMap.java @@ -16,12 +16,12 @@ package android.util; +import libcore.util.EmptyArray; + import android.annotation.UnsupportedAppUsage; import com.android.internal.util.ArrayUtils; -import libcore.util.EmptyArray; - import java.util.Collection; import java.util.ConcurrentModificationException; import java.util.Map; @@ -453,10 +453,6 @@ public final class ArrayMap<K, V> implements Map<K, V> { * @return Returns the key stored at the given index. */ public K keyAt(int index) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } return (K)mArray[index << 1]; } @@ -466,10 +462,6 @@ public final class ArrayMap<K, V> implements Map<K, V> { * @return Returns the value stored at the given index. */ public V valueAt(int index) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } return (V)mArray[(index << 1) + 1]; } @@ -480,10 +472,6 @@ public final class ArrayMap<K, V> implements Map<K, V> { * @return Returns the previous value at the given index. */ public V setValueAt(int index, V value) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } index = (index << 1) + 1; V old = (V)mArray[index]; mArray[index] = value; @@ -677,11 +665,6 @@ public final class ArrayMap<K, V> implements Map<K, V> { * @return Returns the value that was stored at this index. */ public V removeAt(int index) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } - final Object old = mArray[(index << 1) + 1]; final int osize = mSize; final int nsize; diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index 7747a55e3e12..aee1d6a18a80 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -51,7 +51,6 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put("settings_network_and_internet_v2", "true"); DEFAULT_FLAGS.put("settings_slice_injection", "true"); DEFAULT_FLAGS.put("settings_systemui_theme", "true"); - DEFAULT_FLAGS.put("settings_wifi_mac_randomization", "true"); DEFAULT_FLAGS.put("settings_mainline_module", "false"); DEFAULT_FLAGS.put("settings_dynamic_android", "false"); DEFAULT_FLAGS.put(SEAMLESS_TRANSFER, "false"); @@ -60,6 +59,7 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false"); DEFAULT_FLAGS.put(GLOBAL_ACTIONS_GRID_ENABLED, "true"); DEFAULT_FLAGS.put(GLOBAL_ACTIONS_PANEL_ENABLED, "true"); + DEFAULT_FLAGS.put("settings_wifi_details_saved_screen", "false"); } /** diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java index e4de7045721b..cf49803a7225 100644 --- a/core/java/android/util/LongSparseArray.java +++ b/core/java/android/util/LongSparseArray.java @@ -21,6 +21,9 @@ import com.android.internal.util.GrowingArrayUtils; import libcore.util.EmptyArray; +import java.util.Arrays; +import java.util.Objects; + /** * SparseArray mapping longs to Objects. Unlike a normal array of Objects, * there can be gaps in the indices. It is intended to be more memory efficient @@ -144,10 +147,6 @@ public class LongSparseArray<E> implements Cloneable { * Removes the mapping at the specified index. */ public void removeAt(int index) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } if (mValues[index] != DELETED) { mValues[index] = DELETED; mGarbage = true; @@ -237,10 +236,6 @@ public class LongSparseArray<E> implements Cloneable { * key.</p> */ public long keyAt(int index) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } if (mGarbage) { gc(); } @@ -261,10 +256,6 @@ public class LongSparseArray<E> implements Cloneable { */ @SuppressWarnings("unchecked") public E valueAt(int index) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } if (mGarbage) { gc(); } @@ -278,10 +269,6 @@ public class LongSparseArray<E> implements Cloneable { * LongSparseArray stores. */ public void setValueAt(int index, E value) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } if (mGarbage) { gc(); } diff --git a/core/java/android/util/LongSparseLongArray.java b/core/java/android/util/LongSparseLongArray.java index f167f009a942..8dcdb4026246 100644 --- a/core/java/android/util/LongSparseLongArray.java +++ b/core/java/android/util/LongSparseLongArray.java @@ -16,13 +16,14 @@ package android.util; -import android.annotation.UnsupportedAppUsage; - import com.android.internal.util.ArrayUtils; import com.android.internal.util.GrowingArrayUtils; +import android.annotation.UnsupportedAppUsage; import libcore.util.EmptyArray; +import java.util.Arrays; + /** * Map of {@code long} to {@code long}. Unlike a normal array of longs, there * can be gaps in the indices. It is intended to be more memory efficient than using a @@ -172,10 +173,6 @@ public class LongSparseLongArray implements Cloneable { * key.</p> */ public long keyAt(int index) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } return mKeys[index]; } @@ -191,10 +188,6 @@ public class LongSparseLongArray implements Cloneable { * associated with the largest key.</p> */ public long valueAt(int index) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } return mValues[index]; } diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java index 67dfb02a0b95..89ea2d35fc2f 100644 --- a/core/java/android/util/SparseArray.java +++ b/core/java/android/util/SparseArray.java @@ -16,11 +16,10 @@ package android.util; -import android.annotation.UnsupportedAppUsage; - import com.android.internal.util.ArrayUtils; import com.android.internal.util.GrowingArrayUtils; +import android.annotation.UnsupportedAppUsage; import libcore.util.EmptyArray; /** @@ -172,10 +171,6 @@ public class SparseArray<E> implements Cloneable { * the behavior is undefined.</p> */ public void removeAt(int index) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } if (mValues[index] != DELETED) { mValues[index] = DELETED; mGarbage = true; @@ -284,10 +279,6 @@ public class SparseArray<E> implements Cloneable { * the behavior is undefined.</p> */ public int keyAt(int index) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } if (mGarbage) { gc(); } @@ -311,10 +302,6 @@ public class SparseArray<E> implements Cloneable { */ @SuppressWarnings("unchecked") public E valueAt(int index) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } if (mGarbage) { gc(); } @@ -330,10 +317,6 @@ public class SparseArray<E> implements Cloneable { * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined.</p> */ public void setValueAt(int index, E value) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } if (mGarbage) { gc(); } diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java index 03fa1c996027..d4c40954bdd1 100644 --- a/core/java/android/util/SparseBooleanArray.java +++ b/core/java/android/util/SparseBooleanArray.java @@ -16,11 +16,10 @@ package android.util; -import android.annotation.UnsupportedAppUsage; - import com.android.internal.util.ArrayUtils; import com.android.internal.util.GrowingArrayUtils; +import android.annotation.UnsupportedAppUsage; import libcore.util.EmptyArray; /** @@ -168,10 +167,6 @@ public class SparseBooleanArray implements Cloneable { * key.</p> */ public int keyAt(int index) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } return mKeys[index]; } @@ -187,10 +182,6 @@ public class SparseBooleanArray implements Cloneable { * associated with the largest key.</p> */ public boolean valueAt(int index) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } return mValues[index]; } @@ -198,19 +189,11 @@ public class SparseBooleanArray implements Cloneable { * Directly set the value at a particular index. */ public void setValueAt(int index, boolean value) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } mValues[index] = value; } /** @hide */ public void setKeyAt(int index, int key) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } mKeys[index] = key; } diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java index c68dc4edcfb7..9e6bad1d9ae0 100644 --- a/core/java/android/util/SparseIntArray.java +++ b/core/java/android/util/SparseIntArray.java @@ -16,15 +16,14 @@ package android.util; -import android.annotation.UnsupportedAppUsage; - import com.android.internal.util.ArrayUtils; import com.android.internal.util.GrowingArrayUtils; -import libcore.util.EmptyArray; - import java.util.Arrays; +import android.annotation.UnsupportedAppUsage; +import libcore.util.EmptyArray; + /** * SparseIntArrays map integers to integers. Unlike a normal array of integers, * there can be gaps in the indices. It is intended to be more memory efficient @@ -172,10 +171,6 @@ public class SparseIntArray implements Cloneable { * key.</p> */ public int keyAt(int index) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } return mKeys[index]; } @@ -191,10 +186,6 @@ public class SparseIntArray implements Cloneable { * associated with the largest key.</p> */ public int valueAt(int index) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } return mValues[index]; } @@ -202,10 +193,6 @@ public class SparseIntArray implements Cloneable { * Directly set the value at a particular index. */ public void setValueAt(int index, int value) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } mValues[index] = value; } diff --git a/core/java/android/util/SparseLongArray.java b/core/java/android/util/SparseLongArray.java index 37a92024f374..81db2b7ff715 100644 --- a/core/java/android/util/SparseLongArray.java +++ b/core/java/android/util/SparseLongArray.java @@ -182,10 +182,6 @@ public class SparseLongArray implements Cloneable { * key.</p> */ public int keyAt(int index) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } return mKeys[index]; } @@ -201,10 +197,6 @@ public class SparseLongArray implements Cloneable { * associated with the largest key.</p> */ public long valueAt(int index) { - if (index >= mSize) { - // The array might be slightly bigger than mSize, in which case, indexing won't fail. - throw new ArrayIndexOutOfBoundsException(index); - } return mValues[index]; } diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 998ad2a237ea..cd075bf65e4a 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -63,6 +63,7 @@ import libcore.util.NativeAllocationRegistry; import java.io.Closeable; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.Objects; /** * Handle to an on-screen Surface managed by the system compositor. The SurfaceControl is @@ -196,6 +197,9 @@ public final class SurfaceControl implements Parcelable { private static native boolean nativeGetProtectedContentSupport(); private static native void nativeSetMetadata(long transactionObj, int key, Parcel data); private static native void nativeSyncInputWindows(long transactionObj); + private static native boolean nativeGetDisplayBrightnessSupport(IBinder displayToken); + private static native boolean nativeSetDisplayBrightness(IBinder displayToken, + float brightness); private final CloseGuard mCloseGuard = CloseGuard.get(); private String mName; @@ -1961,6 +1965,47 @@ public final class SurfaceControl implements Parcelable { } /** + * Returns whether brightness operations are supported on a display. + * + * @param displayToken + * The token for the display. + * + * @return Whether brightness operations are supported on the display. + * + * @hide + */ + public static boolean getDisplayBrightnessSupport(IBinder displayToken) { + return nativeGetDisplayBrightnessSupport(displayToken); + } + + /** + * Sets the brightness of a display. + * + * @param displayToken + * The token for the display whose brightness is set. + * @param brightness + * A number between 0.0f (minimum brightness) and 1.0f (maximum brightness), or -1.0f to + * turn the backlight off. + * + * @return Whether the method succeeded or not. + * + * @throws IllegalArgumentException if: + * - displayToken is null; + * - brightness is NaN or greater than 1.0f. + * + * @hide + */ + public static boolean setDisplayBrightness(IBinder displayToken, float brightness) { + Objects.requireNonNull(displayToken); + if (Float.isNaN(brightness) || brightness > 1.0f + || (brightness < 0.0f && brightness != -1.0f)) { + throw new IllegalArgumentException("brightness must be a number between 0.0f and 1.0f," + + " or -1 to turn the backlight off."); + } + return nativeSetDisplayBrightness(displayToken, brightness); + } + + /** * An atomic set of changes to a set of SurfaceControl. */ public static class Transaction implements Closeable { diff --git a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java index efdc968909ee..ddbff7bc915f 100644 --- a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java +++ b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java @@ -18,9 +18,11 @@ package android.view.textclassifier; import android.annotation.Nullable; import android.app.Person; +import android.app.RemoteAction; import android.content.Context; import android.text.TextUtils; import android.util.ArrayMap; +import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; @@ -118,12 +120,60 @@ public final class ActionsSuggestionsHelper { @Nullable public static LabeledIntent.TitleChooser createTitleChooser(String actionType) { if (ConversationAction.TYPE_OPEN_URL.equals(actionType)) { - return (labeledIntent, resolveInfo) -> resolveInfo.handleAllWebDataURI - ? labeledIntent.titleWithEntity : labeledIntent.titleWithoutEntity; + return (labeledIntent, resolveInfo) -> { + if (resolveInfo.handleAllWebDataURI) { + return labeledIntent.titleWithEntity; + } + if ("android".equals(resolveInfo.activityInfo.packageName)) { + return labeledIntent.titleWithEntity; + } + return labeledIntent.titleWithoutEntity; + }; } return null; } + /** + * Returns a list of {@link ConversationAction}s that have 0 duplicates. Two actions are + * duplicates if they may look the same to users. This function assumes every + * ConversationActions with a non-null RemoteAction also have a non-null intent in the extras. + */ + public static List<ConversationAction> removeActionsWithDuplicates( + List<ConversationAction> conversationActions) { + // Ideally, we should compare title and icon here, but comparing icon is expensive and thus + // we use the component name of the target handler as the heuristic. + Map<Pair<String, String>, Integer> counter = new ArrayMap<>(); + for (ConversationAction conversationAction : conversationActions) { + Pair<String, String> representation = getRepresentation(conversationAction); + if (representation == null) { + continue; + } + Integer existingCount = counter.getOrDefault(representation, 0); + counter.put(representation, existingCount + 1); + } + List<ConversationAction> result = new ArrayList<>(); + for (ConversationAction conversationAction : conversationActions) { + Pair<String, String> representation = getRepresentation(conversationAction); + if (representation == null || counter.getOrDefault(representation, 0) == 1) { + result.add(conversationAction); + } + } + return result; + } + + @Nullable + private static Pair<String, String> getRepresentation( + ConversationAction conversationAction) { + RemoteAction remoteAction = conversationAction.getAction(); + if (remoteAction == null) { + return null; + } + return new Pair<>( + conversationAction.getAction().getTitle().toString(), + ExtrasUtils.getActionIntent( + conversationAction.getExtras()).getComponent().getPackageName()); + } + private static final class PersonEncoder { private final Map<Person, Integer> mMapping = new ArrayMap<>(); private int mNextUserId = FIRST_NON_LOCAL_USER; diff --git a/core/java/android/view/textclassifier/ExtrasUtils.java b/core/java/android/view/textclassifier/ExtrasUtils.java index 2ad17a84a64e..df548ae5329d 100644 --- a/core/java/android/view/textclassifier/ExtrasUtils.java +++ b/core/java/android/view/textclassifier/ExtrasUtils.java @@ -29,6 +29,7 @@ import java.util.ArrayList; */ public final class ExtrasUtils { + private static final String ACTION_INTENT = "action-intent"; private static final String ACTIONS_INTENTS = "actions-intents"; private static final String FOREIGN_LANGUAGE = "foreign-language"; private static final String ENTITY_TYPE = "entity-type"; @@ -77,6 +78,22 @@ public final class ExtrasUtils { } /** + * Stores {@code actionIntents} information in TextClassifier response object's extras + * {@code container}. + */ + public static void putActionIntent(Bundle container, @Nullable Intent actionIntent) { + container.putParcelable(ACTION_INTENT, actionIntent); + } + + /** + * Returns {@code actionIntent} information contained in a TextClassifier response object. + */ + @Nullable + public static Intent getActionIntent(Bundle container) { + return container.getParcelable(ACTION_INTENT); + } + + /** * Returns {@code actionIntents} information contained in the TextClassification object. */ @Nullable diff --git a/core/java/android/view/textclassifier/LabeledIntent.java b/core/java/android/view/textclassifier/LabeledIntent.java index 7544dc1b58b1..d2897b2e8d3d 100644 --- a/core/java/android/view/textclassifier/LabeledIntent.java +++ b/core/java/android/view/textclassifier/LabeledIntent.java @@ -91,15 +91,22 @@ public final class LabeledIntent { Context context, @Nullable TitleChooser titleChooser) { final PackageManager pm = context.getPackageManager(); final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0); - final String packageName = resolveInfo != null && resolveInfo.activityInfo != null - ? resolveInfo.activityInfo.packageName : null; - Icon icon = null; + + if (resolveInfo == null || resolveInfo.activityInfo == null) { + Log.w(TAG, "resolveInfo or activityInfo is null"); + return null; + } + final String packageName = resolveInfo.activityInfo.packageName; + final String className = resolveInfo.activityInfo.name; + if (packageName == null || className == null) { + Log.w(TAG, "packageName or className is null"); + return null; + } Intent resolvedIntent = new Intent(intent); + resolvedIntent.setComponent(new ComponentName(packageName, className)); boolean shouldShowIcon = false; - if (packageName != null && !"android".equals(packageName)) { - // There is a default activity handling the intent. - resolvedIntent.setComponent( - new ComponentName(packageName, resolveInfo.activityInfo.name)); + Icon icon = null; + if (!"android".equals(packageName)) { if (resolveInfo.activityInfo.getIconResource() != 0) { icon = Icon.createWithResource( packageName, resolveInfo.activityInfo.getIconResource()); @@ -113,9 +120,6 @@ public final class LabeledIntent { } final PendingIntent pendingIntent = TextClassification.createPendingIntent(context, resolvedIntent, requestCode); - if (pendingIntent == null) { - return null; - } if (titleChooser == null) { titleChooser = DEFAULT_TITLE_CHOOSER; } @@ -150,6 +154,7 @@ public final class LabeledIntent { public interface TitleChooser { /** * Picks a title from a {@link LabeledIntent} by looking into resolved info. + * {@code resolveInfo} is guaranteed to have a non-null {@code activityInfo}. */ @Nullable CharSequence chooseTitle(LabeledIntent labeledIntent, ResolveInfo resolveInfo); diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java index 034da01e1de1..a275f0f515c9 100644 --- a/core/java/android/view/textclassifier/TextClassification.java +++ b/core/java/android/view/textclassifier/TextClassification.java @@ -25,8 +25,6 @@ import android.app.PendingIntent; import android.app.RemoteAction; import android.content.Context; import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.graphics.BitmapFactory; import android.graphics.drawable.AdaptiveIconDrawable; @@ -304,53 +302,10 @@ public final class TextClassification implements Parcelable { * @throws IllegalArgumentException if context or intent is null * @hide */ - @Nullable public static PendingIntent createPendingIntent( @NonNull final Context context, @NonNull final Intent intent, int requestCode) { - final int flags = PendingIntent.FLAG_UPDATE_CURRENT; - switch (getIntentType(intent, context)) { - case IntentType.ACTIVITY: - return PendingIntent.getActivity(context, requestCode, intent, flags); - case IntentType.SERVICE: - return PendingIntent.getService(context, requestCode, intent, flags); - default: - return null; - } - } - - @IntentType - private static int getIntentType(@NonNull Intent intent, @NonNull Context context) { - Preconditions.checkArgument(context != null); - Preconditions.checkArgument(intent != null); - - final ResolveInfo activityRI = context.getPackageManager().resolveActivity(intent, 0); - if (activityRI != null) { - if (context.getPackageName().equals(activityRI.activityInfo.packageName)) { - return IntentType.ACTIVITY; - } - final boolean exported = activityRI.activityInfo.exported; - if (exported && hasPermission(context, activityRI.activityInfo.permission)) { - return IntentType.ACTIVITY; - } - } - - final ResolveInfo serviceRI = context.getPackageManager().resolveService(intent, 0); - if (serviceRI != null) { - if (context.getPackageName().equals(serviceRI.serviceInfo.packageName)) { - return IntentType.SERVICE; - } - final boolean exported = serviceRI.serviceInfo.exported; - if (exported && hasPermission(context, serviceRI.serviceInfo.permission)) { - return IntentType.SERVICE; - } - } - - return IntentType.UNSUPPORTED; - } - - private static boolean hasPermission(@NonNull Context context, @NonNull String permission) { - return permission == null - || context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED; + return PendingIntent.getActivity( + context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT); } /** diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java index 632328be973e..35cd678dedbb 100644 --- a/core/java/android/view/textclassifier/TextClassifierImpl.java +++ b/core/java/android/view/textclassifier/TextClassifierImpl.java @@ -84,12 +84,17 @@ public final class TextClassifierImpl implements TextClassifier { private final GenerateLinksLogger mGenerateLinksLogger; private final Object mLock = new Object(); + @GuardedBy("mLock") // Do not access outside this lock. private ModelFileManager.ModelFile mAnnotatorModelInUse; @GuardedBy("mLock") // Do not access outside this lock. private AnnotatorModel mAnnotatorImpl; + + @GuardedBy("mLock") // Do not access outside this lock. + private ModelFileManager.ModelFile mLangIdModelInUse; @GuardedBy("mLock") // Do not access outside this lock. private LangIdModel mLangIdImpl; + @GuardedBy("mLock") // Do not access outside this lock. private ModelFileManager.ModelFile mActionModelInUse; @GuardedBy("mLock") // Do not access outside this lock. @@ -403,6 +408,12 @@ public final class TextClassifierImpl implements TextClassifier { return mFallback.suggestConversationActions(request); } + /** + * Returns the {@link ConversationAction} result, with a non-null extras. + * <p> + * Whenever the RemoteAction is non-null, you can expect its corresponding intent + * with a non-null component name is in the extras. + */ private ConversationActions createConversationActionResult( ConversationActions.Request request, ActionsSuggestionsModel.ActionSuggestion[] nativeSuggestions) { @@ -419,6 +430,7 @@ public final class TextClassifierImpl implements TextClassifier { } List<LabeledIntent> labeledIntents = mTemplateIntentFactory.create(nativeSuggestion.getRemoteActionTemplates()); + Bundle extras = new Bundle(); RemoteAction remoteAction = null; // Given that we only support implicit intent here, we should expect there is just one // intent for each action type. @@ -428,6 +440,7 @@ public final class TextClassifierImpl implements TextClassifier { LabeledIntent.Result result = labeledIntents.get(0).resolve(mContext, titleChooser); if (result != null) { remoteAction = result.remoteAction; + ExtrasUtils.putActionIntent(extras, result.resolvedIntent); } } conversationActions.add( @@ -435,8 +448,11 @@ public final class TextClassifierImpl implements TextClassifier { .setConfidenceScore(nativeSuggestion.getScore()) .setTextReply(nativeSuggestion.getResponseText()) .setAction(remoteAction) + .setExtras(extras) .build()); } + conversationActions = + ActionsSuggestionsHelper.removeActionsWithDuplicates(conversationActions); String resultId = ActionsSuggestionsHelper.createResultId( mContext, request.getConversation(), @@ -504,17 +520,19 @@ public final class TextClassifierImpl implements TextClassifier { private LangIdModel getLangIdImpl() throws FileNotFoundException { synchronized (mLock) { - if (mLangIdImpl == null) { - final ModelFileManager.ModelFile bestModel = - mLangIdModelFileManager.findBestModelFile(null); - if (bestModel == null) { - throw new FileNotFoundException("No LangID model is found"); - } + final ModelFileManager.ModelFile bestModel = + mLangIdModelFileManager.findBestModelFile(null); + if (bestModel == null) { + throw new FileNotFoundException("No LangID model is found"); + } + if (mLangIdImpl == null || !Objects.equals(mLangIdModelInUse, bestModel)) { + Log.d(DEFAULT_LOG_TAG, "Loading " + bestModel); final ParcelFileDescriptor pfd = ParcelFileDescriptor.open( new File(bestModel.getPath()), ParcelFileDescriptor.MODE_READ_ONLY); try { if (pfd != null) { mLangIdImpl = new LangIdModel(pfd.getFd()); + mLangIdModelInUse = bestModel; } } finally { maybeCloseAndLogError(pfd); @@ -527,13 +545,14 @@ public final class TextClassifierImpl implements TextClassifier { @Nullable private ActionsSuggestionsModel getActionsImpl() throws FileNotFoundException { synchronized (mLock) { - if (mActionsImpl == null) { - // TODO: Use LangID to determine the locale we should use here? - final ModelFileManager.ModelFile bestModel = - mActionsModelFileManager.findBestModelFile(LocaleList.getDefault()); - if (bestModel == null) { - return null; - } + // TODO: Use LangID to determine the locale we should use here? + final ModelFileManager.ModelFile bestModel = + mActionsModelFileManager.findBestModelFile(LocaleList.getDefault()); + if (bestModel == null) { + return null; + } + if (mActionsImpl == null || !Objects.equals(mActionModelInUse, bestModel)) { + Log.d(DEFAULT_LOG_TAG, "Loading " + bestModel); final ParcelFileDescriptor pfd = ParcelFileDescriptor.open( new File(bestModel.getPath()), ParcelFileDescriptor.MODE_READ_ONLY); try { diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java index 3d3d94198448..f5657dff538f 100644 --- a/core/java/android/webkit/WebViewDelegate.java +++ b/core/java/android/webkit/WebViewDelegate.java @@ -209,19 +209,17 @@ public final class WebViewDelegate { * Adds the WebView asset path to {@link android.content.res.AssetManager}. */ public void addWebViewAssetPath(Context context) { - final String newAssetPath = WebViewFactory.getLoadedPackageInfo().applicationInfo.sourceDir; - + final String[] newAssetPaths = + WebViewFactory.getLoadedPackageInfo().applicationInfo.getAllApkPaths(); final ApplicationInfo appInfo = context.getApplicationInfo(); - final String[] libs = appInfo.sharedLibraryFiles; - if (!ArrayUtils.contains(libs, newAssetPath)) { - // Build the new library asset path list. - final int newLibAssetsCount = 1 + (libs != null ? libs.length : 0); - final String[] newLibAssets = new String[newLibAssetsCount]; - if (libs != null) { - System.arraycopy(libs, 0, newLibAssets, 0, libs.length); - } - newLibAssets[newLibAssetsCount - 1] = newAssetPath; + // Build the new library asset path list. + String[] newLibAssets = appInfo.sharedLibraryFiles; + for (String newAssetPath : newAssetPaths) { + newLibAssets = ArrayUtils.appendElement(String.class, newLibAssets, newAssetPath); + } + + if (newLibAssets != appInfo.sharedLibraryFiles) { // Update the ApplicationInfo object with the new list. // We know this will persist and future Resources created via ResourcesManager // will include the shared library because this ApplicationInfo comes from the @@ -230,8 +228,8 @@ public final class WebViewDelegate { appInfo.sharedLibraryFiles = newLibAssets; // Update existing Resources with the WebView library. - ResourcesManager.getInstance().appendLibAssetForMainAssetPath( - appInfo.getBaseResourcePath(), newAssetPath); + ResourcesManager.getInstance().appendLibAssetsForMainAssetPath( + appInfo.getBaseResourcePath(), newAssetPaths); } } diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java index 6d88530f29d9..528a6a84c630 100644 --- a/core/java/android/webkit/WebViewFactory.java +++ b/core/java/android/webkit/WebViewFactory.java @@ -448,8 +448,7 @@ public final class WebViewFactory { Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()"); try { - initialApplication.getAssets().addAssetPathAsSharedLibrary( - webViewContext.getApplicationInfo().sourceDir); + new WebViewDelegate().addWebViewAssetPath(initialApplication); ClassLoader clazzLoader = webViewContext.getClassLoader(); Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()"); diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java index 8ee31e212cbf..37bed6538a26 100644 --- a/core/java/android/widget/RelativeLayout.java +++ b/core/java/android/widget/RelativeLayout.java @@ -35,6 +35,9 @@ import android.view.ViewGroup; import android.view.ViewHierarchyEncoder; import android.view.accessibility.AccessibilityEvent; import android.view.inspector.InspectableProperty; +import android.view.inspector.InspectionCompanion; +import android.view.inspector.PropertyMapper; +import android.view.inspector.PropertyReader; import android.widget.RemoteViews.RemoteView; import com.android.internal.R; @@ -1286,7 +1289,6 @@ public class RelativeLayout extends ViewGroup { * the anchor's visibility is GONE. */ @ViewDebug.ExportedProperty(category = "layout") - @InspectableProperty(name = "layout_alignWithParentIfMissing") public boolean alignWithParent; public LayoutParams(Context c, AttributeSet attrs) { @@ -1723,6 +1725,146 @@ public class RelativeLayout extends ViewGroup { super.encodeProperties(encoder); encoder.addProperty("layout:alignWithParent", alignWithParent); } + + /** @hide */ + public static final class InspectionCompanion + implements android.view.inspector.InspectionCompanion<LayoutParams> { + private boolean mPropertiesMapped; + + private int mAboveId; + private int mAlignBaselineId; + private int mAlignBottomId; + private int mAlignEndId; + private int mAlignLeftId; + private int mAlignParentBottomId; + private int mAlignParentEndId; + private int mAlignParentLeftId; + private int mAlignParentRightId; + private int mAlignParentStartId; + private int mAlignParentTopId; + private int mAlignRightId; + private int mAlignStartId; + private int mAlignTopId; + private int mAlignWithParentIfMissingId; + private int mBelowId; + private int mCenterHorizontalId; + private int mCenterInParentId; + private int mCenterVerticalId; + private int mToEndOfId; + private int mToLeftOfId; + private int mToRightOfId; + private int mToStartOfId; + + @Override + public void mapProperties(@NonNull PropertyMapper propertyMapper) { + mPropertiesMapped = true; + + mAboveId = propertyMapper.mapResourceId("layout_above", R.attr.layout_above); + + mAlignBaselineId = propertyMapper.mapResourceId( + "layout_alignBaseline", R.attr.layout_alignBaseline); + + mAlignBottomId = propertyMapper.mapResourceId( + "layout_alignBottom", R.attr.layout_alignBottom); + + mAlignEndId = propertyMapper.mapResourceId( + "layout_alignEnd", R.attr.layout_alignEnd); + + mAlignLeftId = propertyMapper.mapResourceId( + "layout_alignLeft", R.attr.layout_alignLeft); + + mAlignParentBottomId = propertyMapper.mapBoolean( + "layout_alignParentBottom", R.attr.layout_alignParentBottom); + + mAlignParentEndId = propertyMapper.mapBoolean( + "layout_alignParentEnd", R.attr.layout_alignParentEnd); + + mAlignParentLeftId = propertyMapper.mapBoolean( + "layout_alignParentLeft", R.attr.layout_alignParentLeft); + + mAlignParentRightId = propertyMapper.mapBoolean( + "layout_alignParentRight", R.attr.layout_alignParentRight); + + mAlignParentStartId = propertyMapper.mapBoolean( + "layout_alignParentStart", R.attr.layout_alignParentStart); + + mAlignParentTopId = propertyMapper.mapBoolean( + "layout_alignParentTop", R.attr.layout_alignParentTop); + + mAlignRightId = propertyMapper.mapResourceId( + "layout_alignRight", R.attr.layout_alignRight); + + mAlignStartId = propertyMapper.mapResourceId( + "layout_alignStart", R.attr.layout_alignStart); + + mAlignTopId = propertyMapper.mapResourceId( + "layout_alignTop", R.attr.layout_alignTop); + + mAlignWithParentIfMissingId = propertyMapper.mapBoolean( + "layout_alignWithParentIfMissing", + R.attr.layout_alignWithParentIfMissing); + + mBelowId = propertyMapper.mapResourceId("layout_below", R.attr.layout_below); + + mCenterHorizontalId = propertyMapper.mapBoolean( + "layout_centerHorizontal", R.attr.layout_centerHorizontal); + + mCenterInParentId = propertyMapper.mapBoolean( + "layout_centerInParent", R.attr.layout_centerInParent); + + mCenterVerticalId = propertyMapper.mapBoolean( + "layout_centerVertical", R.attr.layout_centerVertical); + + mToEndOfId = propertyMapper.mapResourceId( + "layout_toEndOf", R.attr.layout_toEndOf); + + mToLeftOfId = propertyMapper.mapResourceId( + "layout_toLeftOf", R.attr.layout_toLeftOf); + + mToRightOfId = propertyMapper.mapResourceId( + "layout_toRightOf", R.attr.layout_toRightOf); + + mToStartOfId = propertyMapper.mapResourceId( + "layout_toStartOf", R.attr.layout_toStartOf); + } + + @Override + public void readProperties( + @NonNull LayoutParams node, + @NonNull PropertyReader propertyReader + ) { + if (!mPropertiesMapped) { + throw new UninitializedPropertyMapException(); + } + + final int[] rules = node.getRules(); + + propertyReader.readResourceId(mAboveId, rules[ABOVE]); + propertyReader.readResourceId(mAlignBaselineId, rules[ALIGN_BASELINE]); + propertyReader.readResourceId(mAlignBottomId, rules[ALIGN_BOTTOM]); + propertyReader.readResourceId(mAlignEndId, rules[ALIGN_END]); + propertyReader.readResourceId(mAlignLeftId, rules[ALIGN_LEFT]); + propertyReader.readBoolean( + mAlignParentBottomId, rules[ALIGN_PARENT_BOTTOM] == TRUE); + propertyReader.readBoolean(mAlignParentEndId, rules[ALIGN_PARENT_END] == TRUE); + propertyReader.readBoolean(mAlignParentLeftId, rules[ALIGN_PARENT_LEFT] == TRUE); + propertyReader.readBoolean(mAlignParentRightId, rules[ALIGN_PARENT_RIGHT] == TRUE); + propertyReader.readBoolean(mAlignParentStartId, rules[ALIGN_PARENT_START] == TRUE); + propertyReader.readBoolean(mAlignParentTopId, rules[ALIGN_PARENT_TOP] == TRUE); + propertyReader.readResourceId(mAlignRightId, rules[ALIGN_RIGHT]); + propertyReader.readResourceId(mAlignStartId, rules[ALIGN_START]); + propertyReader.readResourceId(mAlignTopId, rules[ALIGN_TOP]); + propertyReader.readBoolean(mAlignWithParentIfMissingId, node.alignWithParent); + propertyReader.readResourceId(mBelowId, rules[BELOW]); + propertyReader.readBoolean(mCenterHorizontalId, rules[CENTER_HORIZONTAL] == TRUE); + propertyReader.readBoolean(mCenterInParentId, rules[CENTER_IN_PARENT] == TRUE); + propertyReader.readBoolean(mCenterVerticalId, rules[CENTER_VERTICAL] == TRUE); + propertyReader.readResourceId(mToEndOfId, rules[END_OF]); + propertyReader.readResourceId(mToLeftOfId, rules[LEFT_OF]); + propertyReader.readResourceId(mToRightOfId, rules[RIGHT_OF]); + propertyReader.readResourceId(mToStartOfId, rules[START_OF]); + } + } } private static class DependencyGraph { diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java index 65953172818e..4aff912104f5 100644 --- a/core/java/com/android/internal/os/ZygoteServer.java +++ b/core/java/com/android/internal/os/ZygoteServer.java @@ -277,17 +277,31 @@ class ZygoteServer { Integer.parseInt(usapPoolRefillThresholdPropString), mUsapPoolSizeMax); } + + // Sanity check + + if (mUsapPoolSizeMin >= mUsapPoolSizeMax) { + Log.w(TAG, "The max size of the USAP pool must be greater than the minimum size." + + " Restoring default values."); + + mUsapPoolSizeMax = Integer.parseInt(USAP_POOL_SIZE_MAX_DEFAULT); + mUsapPoolSizeMin = Integer.parseInt(USAP_POOL_SIZE_MIN_DEFAULT); + mUsapPoolRefillThreshold = mUsapPoolSizeMax / 2; + } } } + private boolean mIsFirstPropertyCheck = true; private long mLastPropCheckTimestamp = 0; private void fetchUsapPoolPolicyPropsWithMinInterval() { final long currentTimestamp = SystemClock.elapsedRealtime(); - if (currentTimestamp - mLastPropCheckTimestamp >= Zygote.PROPERTY_CHECK_INTERVAL) { - fetchUsapPoolPolicyProps(); + if (mIsFirstPropertyCheck + || (currentTimestamp - mLastPropCheckTimestamp >= Zygote.PROPERTY_CHECK_INTERVAL)) { + mIsFirstPropertyCheck = false; mLastPropCheckTimestamp = currentTimestamp; + fetchUsapPoolPolicyProps(); } } @@ -304,6 +318,9 @@ class ZygoteServer { Runnable fillUsapPool(int[] sessionSocketRawFDs) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Zygote:FillUsapPool"); + // Ensure that the pool properties have been fetched. + fetchUsapPoolPolicyPropsWithMinInterval(); + int usapPoolCount = Zygote.getUsapPoolCount(); int numUsapsToSpawn = mUsapPoolSizeMax - usapPoolCount; diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index 85f11595346f..cd7346eb0215 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -923,14 +923,24 @@ namespace PaintGlue { paint->setWordSpacing(wordSpacing); } - static jint getHyphenEdit(jlong paintHandle, jint hyphen) { + static jint getStartHyphenEdit(jlong paintHandle, jint hyphen) { Paint* paint = reinterpret_cast<Paint*>(paintHandle); - return paint->getHyphenEdit(); + return static_cast<jint>(paint->getStartHyphenEdit()); } - static void setHyphenEdit(jlong paintHandle, jint hyphen) { + static jint getEndHyphenEdit(jlong paintHandle, jint hyphen) { Paint* paint = reinterpret_cast<Paint*>(paintHandle); - paint->setHyphenEdit((uint32_t)hyphen); + return static_cast<jint>(paint->getEndHyphenEdit()); + } + + static void setStartHyphenEdit(jlong paintHandle, jint hyphen) { + Paint* paint = reinterpret_cast<Paint*>(paintHandle); + paint->setStartHyphenEdit((uint32_t)hyphen); + } + + static void setEndHyphenEdit(jlong paintHandle, jint hyphen) { + Paint* paint = reinterpret_cast<Paint*>(paintHandle); + paint->setEndHyphenEdit((uint32_t)hyphen); } static jfloat ascent(jlong paintHandle) { @@ -1105,8 +1115,10 @@ static const JNINativeMethod methods[] = { {"nSetLetterSpacing","(JF)V", (void*) PaintGlue::setLetterSpacing}, {"nGetWordSpacing","(J)F", (void*) PaintGlue::getWordSpacing}, {"nSetWordSpacing","(JF)V", (void*) PaintGlue::setWordSpacing}, - {"nGetHyphenEdit", "(J)I", (void*) PaintGlue::getHyphenEdit}, - {"nSetHyphenEdit", "(JI)V", (void*) PaintGlue::setHyphenEdit}, + {"nGetStartHyphenEdit", "(J)I", (void*) PaintGlue::getStartHyphenEdit}, + {"nGetEndHyphenEdit", "(J)I", (void*) PaintGlue::getEndHyphenEdit}, + {"nSetStartHyphenEdit", "(JI)V", (void*) PaintGlue::setStartHyphenEdit}, + {"nSetEndHyphenEdit", "(JI)V", (void*) PaintGlue::setEndHyphenEdit}, {"nAscent","(J)F", (void*) PaintGlue::ascent}, {"nDescent","(J)F", (void*) PaintGlue::descent}, {"nGetUnderlinePosition","(J)F", (void*) PaintGlue::getUnderlinePosition}, diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 89d908b31aa0..4a6c72bda283 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -1164,6 +1164,25 @@ static void nativeWriteToParcel(JNIEnv* env, jclass clazz, } } +static jboolean nativeGetDisplayBrightnessSupport(JNIEnv* env, jclass clazz, + jobject displayTokenObject) { + sp<IBinder> displayToken(ibinderForJavaObject(env, displayTokenObject)); + if (displayToken == nullptr) { + return JNI_FALSE; + } + return static_cast<jboolean>(SurfaceComposerClient::getDisplayBrightnessSupport(displayToken)); +} + +static jboolean nativeSetDisplayBrightness(JNIEnv* env, jclass clazz, jobject displayTokenObject, + jfloat brightness) { + sp<IBinder> displayToken(ibinderForJavaObject(env, displayTokenObject)); + if (displayToken == nullptr) { + return JNI_FALSE; + } + status_t error = SurfaceComposerClient::setDisplayBrightness(displayToken, brightness); + return error == OK ? JNI_TRUE : JNI_FALSE; +} + // ---------------------------------------------------------------------------- static const JNINativeMethod sSurfaceControlMethods[] = { @@ -1308,7 +1327,11 @@ static const JNINativeMethod sSurfaceControlMethods[] = { {"nativeSetGeometry", "(JJLandroid/graphics/Rect;Landroid/graphics/Rect;J)V", (void*)nativeSetGeometry }, {"nativeSyncInputWindows", "(J)V", - (void*)nativeSyncInputWindows } + (void*)nativeSyncInputWindows }, + {"nativeGetDisplayBrightnessSupport", "(Landroid/os/IBinder;)Z", + (void*)nativeGetDisplayBrightnessSupport }, + {"nativeSetDisplayBrightness", "(Landroid/os/IBinder;F)Z", + (void*)nativeSetDisplayBrightness }, }; int register_android_view_SurfaceControl(JNIEnv* env) diff --git a/core/proto/android/server/connectivity/data_stall_event.proto b/core/proto/android/server/connectivity/data_stall_event.proto index 21717d886266..a82326f67d74 100644 --- a/core/proto/android/server/connectivity/data_stall_event.proto +++ b/core/proto/android/server/connectivity/data_stall_event.proto @@ -25,6 +25,7 @@ enum ProbeResult { VALID = 1; INVALID = 2; PORTAL = 3; + PARTIAL = 4; } enum ApBand { @@ -86,4 +87,4 @@ message DnsEvent { repeated int32 dns_return_code = 1; // Indicate the timestamp of the dns event. repeated int64 dns_time = 2; -}
\ No newline at end of file +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index d176260a9896..ea300aa170ee 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2152,9 +2152,9 @@ screen lock to a certain complexity level. <p>Protection level: normal --> - <permission android:name="android.permission.REQUEST_SCREEN_LOCK_COMPLEXITY" - android:label="@string/permlab_requestScreenLockComplexity" - android:description="@string/permdesc_requestScreenLockComplexity" + <permission android:name="android.permission.REQUEST_PASSWORD_COMPLEXITY" + android:label="@string/permlab_requestPasswordComplexity" + android:description="@string/permdesc_requestPasswordComplexity" android:protectionLevel="normal" /> <!-- ================================== --> @@ -2524,7 +2524,7 @@ <permission android:name="android.permission.WRITE_GSERVICES" android:protectionLevel="signature|privileged" /> - <!-- @SystemApi @hide Allows an application to modify config settings. + <!-- @SystemApi @TestApi @hide Allows an application to modify config settings. <p>Not for use by third-party applications. --> <permission android:name="android.permission.WRITE_DEVICE_CONFIG" android:protectionLevel="signature|configurator"/> @@ -3917,7 +3917,7 @@ <permission android:name="android.permission.PACKAGE_ROLLBACK_AGENT" android:protectionLevel="signature" /> - <!-- @SystemApi @hide Allows managing apk level rollbacks. --> + <!-- @SystemApi @TestApi @hide Allows managing apk level rollbacks. --> <permission android:name="android.permission.MANAGE_ROLLBACKS" android:protectionLevel="signature|verifier" /> diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index fc7b4cf05b56..dbea13ec7539 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1473,6 +1473,9 @@ <flag name="location" value="0x08" /> <!-- Auto, bluetooth, TV or other devices connection, monitoring and interaction. --> <flag name="connectedDevice" value="0x10" /> + <!-- Managing a media projection session, e.g, for screen recording or taking + screenshots.--> + <flag name="mediaProjection" value="0x20" /> </attr> @@ -1993,7 +1996,9 @@ {@link #AndroidManifestApplication application} tag. --> <declare-styleable name="AndroidManifestUsesPackage" parent="AndroidManifestApplication"> <!-- Required type of association with the package, for example "android.package.ad_service" - if it provides an advertising service. --> + if it provides an advertising service. This should use the standard scoped naming + convention as used for other things such as package names, based on the Java naming + convention. --> <attr name="packageType" format="string" /> <!-- Required name of the package you use. --> <attr name="name" /> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index bfb6d247e0dd..dce144a64266 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3513,6 +3513,12 @@ --> <string name="config_defaultAttentionService" translatable="false"></string> + <!-- The component name for the system-wide captions service. + This service must be trusted, as it controls part of the UI of the volume bar. + Example: "com.android.captions/.SystemCaptionsService" + --> + <string name="config_defaultSystemCaptionsService" translatable="false"></string> + <!-- The package name for the incident report approver app. This app is usually PermissionController or an app that replaces it. When a bugreport or incident report with EXPLICT-level sharing flags is going to be diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index f7b27f0c4d07..a69655aa555c 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1406,9 +1406,9 @@ 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_requestScreenLockComplexity">request screen lock complexity</string> + <string name="permlab_requestPasswordComplexity">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_requestScreenLockComplexity">Allows the app to learn the screen + <string name="permdesc_requestPasswordComplexity">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 diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 69def5b70f07..36b48bbb3d56 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3382,6 +3382,7 @@ <java-symbol type="string" name="config_defaultAppPredictionService" /> <java-symbol type="string" name="config_defaultContentSuggestionsService" /> <java-symbol type="string" name="config_defaultAttentionService" /> + <java-symbol type="string" name="config_defaultSystemCaptionsService" /> <java-symbol type="string" name="notification_channel_foreground_service" /> <java-symbol type="string" name="foreground_service_app_in_background" /> diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 43f8db1a32e5..7322a5445e86 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -655,6 +655,7 @@ public class SettingsBackupTest { Settings.Secure.NIGHT_DISPLAY_ACTIVATED, Settings.Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED, + Settings.Secure.ODI_CAPTIONS_ENABLED, Settings.Secure.PACKAGE_VERIFIER_STATE, Settings.Secure.PACKAGE_VERIFIER_USER_CONSENT, Settings.Secure.PARENTAL_CONTROL_LAST_UPDATE, diff --git a/core/tests/coretests/src/android/text/StaticLayoutTest.java b/core/tests/coretests/src/android/text/StaticLayoutTest.java index b1c896ec2ce4..0ebf03fab966 100644 --- a/core/tests/coretests/src/android/text/StaticLayoutTest.java +++ b/core/tests/coretests/src/android/text/StaticLayoutTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import android.graphics.Canvas; +import android.graphics.Paint; import android.graphics.Paint.FontMetricsInt; import android.os.LocaleList; import android.platform.test.annotations.Presubmit; @@ -799,11 +800,13 @@ public class StaticLayoutTest { @Test public void testLayoutDoesntModifyPaint() { final TextPaint paint = new TextPaint(); - paint.setHyphenEdit(31); + paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_INSERT_HYPHEN); + paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_INSERT_HYPHEN); final StaticLayout layout = StaticLayout.Builder.obtain("", 0, 0, paint, 100).build(); final Canvas canvas = new Canvas(); layout.drawText(canvas, 0, 0); - assertEquals(31, paint.getHyphenEdit()); + assertEquals(Paint.START_HYPHEN_EDIT_INSERT_HYPHEN, paint.getStartHyphenEdit()); + assertEquals(Paint.END_HYPHEN_EDIT_INSERT_HYPHEN, paint.getEndHyphenEdit()); } @Test diff --git a/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java b/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java index 5022e305ecc2..f4409534250b 100644 --- a/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java @@ -21,8 +21,15 @@ import static android.view.textclassifier.ConversationActions.Message.PERSON_USE import static com.google.common.truth.Truth.assertThat; +import android.app.PendingIntent; import android.app.Person; +import android.app.RemoteAction; +import android.content.ComponentName; +import android.content.Intent; +import android.graphics.drawable.Icon; +import android.os.Bundle; +import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -36,6 +43,7 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.Locale; import java.util.function.Function; @@ -129,6 +137,73 @@ public class ActionsSuggestionsHelperTest { assertNativeMessage(conversationMessages[2], thirdMessage.getText(), 1, 2000); } + @Test + public void testDeduplicateActions() { + Bundle phoneExtras = new Bundle(); + Intent phoneIntent = new Intent(); + phoneIntent.setComponent(new ComponentName("phone", "intent")); + ExtrasUtils.putActionIntent(phoneExtras, phoneIntent); + + Bundle anotherPhoneExtras = new Bundle(); + Intent anotherPhoneIntent = new Intent(); + anotherPhoneIntent.setComponent(new ComponentName("phone", "another.intent")); + ExtrasUtils.putActionIntent(anotherPhoneExtras, anotherPhoneIntent); + + Bundle urlExtras = new Bundle(); + Intent urlIntent = new Intent(); + urlIntent.setComponent(new ComponentName("url", "intent")); + ExtrasUtils.putActionIntent(urlExtras, urlIntent); + + PendingIntent pendingIntent = PendingIntent.getActivity( + InstrumentationRegistry.getTargetContext(), + 0, + phoneIntent, + 0); + Icon icon = Icon.createWithData(new byte[0], 0, 0); + ConversationAction action = + new ConversationAction.Builder(ConversationAction.TYPE_CALL_PHONE) + .setAction(new RemoteAction(icon, "label", "1", pendingIntent)) + .setExtras(phoneExtras) + .build(); + ConversationAction actionWithSameLabel = + new ConversationAction.Builder(ConversationAction.TYPE_CALL_PHONE) + .setAction(new RemoteAction( + icon, "label", "2", pendingIntent)) + .setExtras(phoneExtras) + .build(); + ConversationAction actionWithSamePackageButDifferentClass = + new ConversationAction.Builder(ConversationAction.TYPE_CALL_PHONE) + .setAction(new RemoteAction( + icon, "label", "3", pendingIntent)) + .setExtras(anotherPhoneExtras) + .build(); + ConversationAction actionWithDifferentLabel = + new ConversationAction.Builder(ConversationAction.TYPE_CALL_PHONE) + .setAction(new RemoteAction( + icon, "another_label", "4", pendingIntent)) + .setExtras(phoneExtras) + .build(); + ConversationAction actionWithDifferentPackage = + new ConversationAction.Builder(ConversationAction.TYPE_OPEN_URL) + .setAction(new RemoteAction(icon, "label", "5", pendingIntent)) + .setExtras(urlExtras) + .build(); + ConversationAction actionWithoutRemoteAction = + new ConversationAction.Builder(ConversationAction.TYPE_CREATE_REMINDER) + .build(); + + List<ConversationAction> conversationActions = + ActionsSuggestionsHelper.removeActionsWithDuplicates( + Arrays.asList(action, actionWithSameLabel, + actionWithSamePackageButDifferentClass, actionWithDifferentLabel, + actionWithDifferentPackage, actionWithoutRemoteAction)); + + assertThat(conversationActions).hasSize(3); + assertThat(conversationActions.get(0).getAction().getContentDescription()).isEqualTo("4"); + assertThat(conversationActions.get(1).getAction().getContentDescription()).isEqualTo("5"); + assertThat(conversationActions.get(2).getAction()).isNull(); + } + private ZonedDateTime createZonedDateTimeFromMsUtc(long msUtc) { return ZonedDateTime.ofInstant(Instant.ofEpochMilli(msUtc), ZoneId.of("UTC")); } diff --git a/core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java b/core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java index e4e9cde5e977..6520c8f740f4 100644 --- a/core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java @@ -132,7 +132,6 @@ public final class LabeledIntentTest { assertThat(intent.getComponent()).isNotNull(); } - @Test public void resolve_missingTitle() { assertThrows( @@ -146,4 +145,19 @@ public final class LabeledIntentTest { REQUEST_CODE )); } + + @Test + public void resolve_noIntentHandler() { + Intent intent = new Intent("some.thing.does.not.exist"); + LabeledIntent labeledIntent = new LabeledIntent( + TITLE_WITHOUT_ENTITY, + null, + DESCRIPTION, + intent, + REQUEST_CODE); + + LabeledIntent.Result result = labeledIntent.resolve(mContext, null); + + assertThat(result).isNull(); + } } diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java index d2d03e565522..bcaf6631c97f 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertTrue; import android.app.RemoteAction; import android.content.Context; import android.content.Intent; +import android.net.Uri; import android.os.Bundle; import android.os.LocaleList; import android.text.Spannable; @@ -32,6 +33,8 @@ import android.text.SpannableString; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; +import com.google.common.truth.Truth; + import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.hamcrest.Matcher; @@ -403,7 +406,6 @@ public class TextClassifierTest { ConversationActions conversationActions = mClassifier.suggestConversationActions(request); assertTrue(conversationActions.getConversationActions().size() > 0); - assertTrue(conversationActions.getConversationActions().size() == 1); for (ConversationAction conversationAction : conversationActions.getConversationActions()) { assertThat(conversationAction, @@ -438,6 +440,34 @@ public class TextClassifierTest { } } + @Test + public void testSuggestConversationActions_openUrl() { + if (isTextClassifierDisabled()) return; + ConversationActions.Message message = + new ConversationActions.Message.Builder( + ConversationActions.Message.PERSON_USER_OTHERS) + .setText("Check this out: https://www.android.com") + .build(); + TextClassifier.EntityConfig typeConfig = + new TextClassifier.EntityConfig.Builder().includeTypesFromTextClassifier(false) + .setIncludedTypes( + Collections.singletonList(ConversationAction.TYPE_OPEN_URL)) + .build(); + ConversationActions.Request request = + new ConversationActions.Request.Builder(Collections.singletonList(message)) + .setMaxSuggestions(1) + .setTypeConfig(typeConfig) + .build(); + + ConversationActions conversationActions = mClassifier.suggestConversationActions(request); + Truth.assertThat(conversationActions.getConversationActions()).hasSize(1); + ConversationAction conversationAction = conversationActions.getConversationActions().get(0); + Truth.assertThat(conversationAction.getType()).isEqualTo(ConversationAction.TYPE_OPEN_URL); + Intent actionIntent = ExtrasUtils.getActionIntent(conversationAction.getExtras()); + Truth.assertThat(actionIntent.getAction()).isEqualTo(Intent.ACTION_VIEW); + Truth.assertThat(actionIntent.getData()).isEqualTo(Uri.parse("https://www.android.com")); + } + private boolean isTextClassifierDisabled() { return mClassifier == null || mClassifier == TextClassifier.NO_OP; diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java index 585360fdd2f3..0617caf57308 100644 --- a/core/tests/coretests/src/android/widget/TextViewTest.java +++ b/core/tests/coretests/src/android/widget/TextViewTest.java @@ -209,7 +209,8 @@ public class TextViewTest { int lineCount = layout.getLineCount(); boolean hyphenationHappend = false; for (int i = 0; i < lineCount; ++i) { - if (layout.getHyphen(i) == 0) { + if (layout.getStartHyphenEdit(i) == Paint.START_HYPHEN_EDIT_NO_EDIT + && layout.getEndHyphenEdit(i) == Paint.END_HYPHEN_EDIT_NO_EDIT) { continue; // Hyphantion does not happen. } hyphenationHappend = true; diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 9eeb43b579bc..452f7c93f8aa 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -364,19 +364,79 @@ public class Paint { */ private static final int CURSOR_OPT_MAX_VALUE = CURSOR_AT; + /** @hide */ + @IntDef(prefix = { "START_HYPHEN_EDIT_" }, value = { + START_HYPHEN_EDIT_NO_EDIT, + START_HYPHEN_EDIT_INSERT_HYPHEN, + START_HYPHEN_EDIT_INSERT_ZWJ + }) + @Retention(RetentionPolicy.SOURCE) + public @interface StartHyphenEdit {} + /** - * Mask for hyphen edits that happen at the end of a line. Keep in sync with the definition in - * Minikin's Hyphenator.h. - * @hide + * An integer representing the starting of the line has no modification for hyphenation. */ - public static final int HYPHENEDIT_MASK_END_OF_LINE = 0x07; + public static final int START_HYPHEN_EDIT_NO_EDIT = 0x00; /** - * Mask for hyphen edits that happen at the start of a line. Keep in sync with the definition in - * Minikin's Hyphenator.h. - * @hide + * An integer representing the starting of the line has normal hyphen character (U+002D). + */ + public static final int START_HYPHEN_EDIT_INSERT_HYPHEN = 0x01; + + /** + * An integer representing the starting of the line has Zero-Width-Joiner (U+200D). + */ + public static final int START_HYPHEN_EDIT_INSERT_ZWJ = 0x02; + + /** @hide */ + @IntDef(prefix = { "END_HYPHEN_EDIT_" }, value = { + END_HYPHEN_EDIT_NO_EDIT, + END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN, + END_HYPHEN_EDIT_INSERT_HYPHEN, + END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN, + END_HYPHEN_EDIT_INSERT_MAQAF, + END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN, + END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN + }) + @Retention(RetentionPolicy.SOURCE) + public @interface EndHyphenEdit {} + + /** + * An integer representing the end of the line has no modification for hyphenation. + */ + public static final int END_HYPHEN_EDIT_NO_EDIT = 0x00; + + /** + * An integer representing the character at the end of the line is replaced with hyphen + * character (U+002D). + */ + public static final int END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN = 0x01; + + /** + * An integer representing the end of the line has normal hyphen character (U+002D). + */ + public static final int END_HYPHEN_EDIT_INSERT_HYPHEN = 0x02; + + /** + * An integer representing the end of the line has Armentian hyphen (U+058A). + */ + public static final int END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN = 0x03; + + /** + * An integer representing the end of the line has maqaf (Hebrew hyphen, U+05BE). */ - public static final int HYPHENEDIT_MASK_START_OF_LINE = 0x03 << 3; + public static final int END_HYPHEN_EDIT_INSERT_MAQAF = 0x04; + + /** + * An integer representing the end of the line has Canadian Syllabics hyphen (U+1400). + */ + public static final int END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN = 0x05; + + /** + * An integer representing the end of the line has Zero-Width-Joiner (U+200D) followed by normal + * hyphen character (U+002D). + */ + public static final int END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN = 0x06; /** * The Style specifies if the primitive being drawn is filled, stroked, or @@ -1873,54 +1933,80 @@ public class Paint { } /** - * Get the current value of packed hyphen edit. + * Get the current value of start hyphen edit. + * + * The default value is 0 which is equivalent to {@link #START_HYPHEN_EDIT_NO_EDIT}. * - * You can extract start hyphen edit and end hyphen edit by using - * {@link android.text.Hyphenator#unpackStartHyphenEdit(int)} and - * {@link android.text.Hyphenator#unpackEndHyphenEdit(int)}. + * @return the current starting hyphen edit value + * @see #setStartHyphenEdit(int) + */ + public @StartHyphenEdit int getStartHyphenEdit() { + return nGetStartHyphenEdit(mNativePaint); + } + + /** + * Get the current value of end hyphen edit. * - * The default value is 0 which is equivalent to packed value of - * {@link android.text.Hyphenator#START_HYPHEN_EDIT_NO_EDIT} and - * {@link android.text.Hyphenator#END_HYPHEN_EDIT_NO_EDIT}. + * The default value is 0 which is equivalent to {@link #END_HYPHEN_EDIT_NO_EDIT}. * - * @return the current hyphen edit value - * @see #setHyphenEdit(int) + * @return the current starting hyphen edit value + * @see #setStartHyphenEdit(int) */ - public int getHyphenEdit() { - return nGetHyphenEdit(mNativePaint); + public @EndHyphenEdit int getEndHyphenEdit() { + return nGetEndHyphenEdit(mNativePaint); } /** - * Set a packed hyphen edit on the paint. + * Set a start hyphen edit on the paint. * - * By setting hyphen edit, the measurement and drawing is performed with modifying hyphenation - * at the start of line and end of line. For example, by passing - * {@link android.text.Hyphenator#END_HYPHEN_EDIT_INSERT_HYPHEN} like as follows, HYPHEN(U+2010) + * By setting start hyphen edit, the measurement and drawing is performed with modifying + * hyphenation at the start of line. For example, by passing + * {@link #START_HYPHEN_EDIT_INSERT_HYPHEN} like as follows, HYPHEN(U+2010) + * character is appended at the start of line. + * + * <pre> + * <code> + * Paint paint = new Paint(); + * paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_INSERT_HYPHEN); + * paint.measureText("abc", 0, 3); // Returns the width of "‐abc" + * Canvas.drawText("abc", 0, 3, 0f, 0f, paint); // Draws "‐abc" + * </code> + * </pre> + * + * The default value is 0 which is equivalent to + * {@link #START_HYPHEN_EDIT_NO_EDIT}. + * + * @param startHyphen a start hyphen edit value. + * @see #getStartHyphenEdit() + */ + public void setStartHyphenEdit(@StartHyphenEdit int startHyphen) { + nSetStartHyphenEdit(mNativePaint, startHyphen); + } + + /** + * Set a end hyphen edit on the paint. + * + * By setting end hyphen edit, the measurement and drawing is performed with modifying + * hyphenation at the end of line. For example, by passing + * {@link #END_HYPHEN_EDIT_INSERT_HYPHEN} like as follows, HYPHEN(U+2010) * character is appended at the end of line. * * <pre> * <code> * Paint paint = new Paint(); - * paint.setHyphenEdit(Hyphenator.packHyphenEdit( - * Hyphenator.START_HYPHEN_EDIT_NO_EDIT, - * Hyphenator.END_HYPHEN_EDIT_INSERT_HYPHEN)); + * paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_INSERT_HYPHEN); * paint.measureText("abc", 0, 3); // Returns the width of "abc‐" * Canvas.drawText("abc", 0, 3, 0f, 0f, paint); // Draws "abc‐" * </code> * </pre> * - * You can pack start hyphen edit and end hyphen edit by - * {@link android.text.Hyphenator#packHyphenEdit(int,int)} + * The default value is 0 which is equivalent to {@link #END_HYPHEN_EDIT_NO_EDIT}. * - * The default value is 0 which is equivalent to packed value of - * {@link android.text.Hyphenator#START_HYPHEN_EDIT_NO_EDIT} and - * {@link android.text.Hyphenator#END_HYPHEN_EDIT_NO_EDIT}. - * - * @param hyphen a packed hyphen edit value. - * @see #getHyphenEdit() + * @param endHyphen a end hyphen edit value. + * @see #getEndHyphenEdit() */ - public void setHyphenEdit(int hyphen) { - nSetHyphenEdit(mNativePaint, hyphen); + public void setEndHyphenEdit(@EndHyphenEdit int endHyphen) { + nSetEndHyphenEdit(mNativePaint, endHyphen); } /** @@ -3063,9 +3149,13 @@ public class Paint { @CriticalNative private static native void nSetWordSpacing(long paintPtr, float wordSpacing); @CriticalNative - private static native int nGetHyphenEdit(long paintPtr); + private static native int nGetStartHyphenEdit(long paintPtr); + @CriticalNative + private static native int nGetEndHyphenEdit(long paintPtr); + @CriticalNative + private static native void nSetStartHyphenEdit(long paintPtr, int hyphen); @CriticalNative - private static native void nSetHyphenEdit(long paintPtr, int hyphen); + private static native void nSetEndHyphenEdit(long paintPtr, int hyphen); @CriticalNative private static native void nSetStrokeMiter(long paintPtr, float miter); @CriticalNative diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 95187149b985..86f658b4a48e 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -33,12 +33,12 @@ import android.graphics.fonts.FontStyle; import android.graphics.fonts.FontVariationAxis; import android.graphics.fonts.SystemFonts; import android.os.Build; -import android.os.Build.VERSION_CODES; import android.os.ParcelFileDescriptor; import android.provider.FontRequest; import android.provider.FontsContract; import android.text.FontConfig; import android.util.Base64; +import android.util.Log; import android.util.LongSparseArray; import android.util.LruCache; import android.util.SparseArray; @@ -48,7 +48,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import dalvik.annotation.optimization.CriticalNative; -import dalvik.system.VMRuntime; import libcore.util.NativeAllocationRegistry; @@ -262,18 +261,29 @@ public class Typeface { ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT); } + Font font = null; + try { + font = fontBuilder.build(); + } catch (IllegalArgumentException e) { + // The exception happens if the unsupported font is passed. We suppress this + // exception and just ignore this font here since there is no way of + // resolving this issue by users during inflating layout. + Log.w(TAG, "Ignoring font file since failed to create font object." + + " The font file is not supported on this platform."); + continue; + } if (familyBuilder == null) { - familyBuilder = new FontFamily.Builder(fontBuilder.build()); + familyBuilder = new FontFamily.Builder(font); } else { try { - familyBuilder.addFont(fontBuilder.build()); + familyBuilder.addFont(font); } catch (IllegalArgumentException e) { - if (VMRuntime.getRuntime().getTargetSdkVersion() <= VERSION_CODES.P) { - // Surpress the IllegalArgumentException for keeping the backward - // compatibility. - continue; - } - throw e; + // The exception happens if the same style is added to the family. + // We suppress this exception and just ignore this font here since there is + // no way of resolving this issue by users during inflating layout. + Log.w(TAG, + "Ignoring font file since the same style font is already added."); + continue; } } } diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java index f715f43344d3..f92802f5b574 100644 --- a/graphics/java/android/graphics/fonts/Font.java +++ b/graphics/java/android/graphics/fonts/Font.java @@ -354,6 +354,10 @@ public final class Font { /** * Creates the font based on the configured values. + * + * If the font is not supported by the platform, this function will fail with + * {@link IllegalArgumentException}. + * * @return the Font object */ public @Nullable Font build() throws IOException { diff --git a/graphics/java/android/graphics/text/LineBreaker.java b/graphics/java/android/graphics/text/LineBreaker.java index 046bbcffb76a..9cabf1ce185d 100644 --- a/graphics/java/android/graphics/text/LineBreaker.java +++ b/graphics/java/android/graphics/text/LineBreaker.java @@ -342,8 +342,12 @@ public class LineBreaker { */ public static class Result { // Following two contstant must be synced with minikin's line breaker. + // TODO(nona): Remove these constatns by introducing native methods. private static final int TAB_MASK = 0x20000000; private static final int HYPHEN_MASK = 0xFF; + private static final int START_HYPHEN_MASK = 0x18; // 0b11000 + private static final int END_HYPHEN_MASK = 0x7; // 0b00111 + private static final int START_HYPHEN_BITS_SHIFT = 3; private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( Result.class.getClassLoader(), nGetReleaseResultFunc(), 32); @@ -414,17 +418,29 @@ public class LineBreaker { } /** - * Returns a packed hyphen edit for the line. + * Returns a start hyphen edit for the line. * * @param lineIndex an index of the line. - * @return a packed hyphen edit for the line. + * @return a start hyphen edit for the line. * - * @see android.text.Hyphenator#unpackStartHyphenEdit(int) - * @see android.text.Hyphenator#unpackEndHyphenEdit(int) - * @see android.text.Hyphenator#packHyphenEdit(int,int) + * @see android.graphics.Paint#setStartHyphenEdit + * @see android.graphics.Paint#getStartHyphenEdit */ - public int getLineHyphenEdit(int lineIndex) { - return (nGetLineFlag(mPtr, lineIndex) & HYPHEN_MASK); + public int getStartLineHyphenEdit(int lineIndex) { + return (nGetLineFlag(mPtr, lineIndex) & START_HYPHEN_MASK) >> START_HYPHEN_BITS_SHIFT; + } + + /** + * Returns an end hyphen edit for the line. + * + * @param lineIndex an index of the line. + * @return an end hyphen edit for the line. + * + * @see android.graphics.Paint#setEndHyphenEdit + * @see android.graphics.Paint#getEndHyphenEdit + */ + public int getEndLineHyphenEdit(int lineIndex) { + return nGetLineFlag(mPtr, lineIndex) & END_HYPHEN_MASK; } } diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp index 733f8e415270..5f6b53ac767f 100644 --- a/libs/hwui/hwui/MinikinUtils.cpp +++ b/libs/hwui/hwui/MinikinUtils.cpp @@ -58,9 +58,8 @@ minikin::Layout MinikinUtils::doLayout(const Paint* paint, minikin::Bidi bidiFla const minikin::U16StringPiece textBuf(buf, bufSize); const minikin::Range range(start, start + count); const minikin::Range contextRange(contextStart, contextStart + contextCount); - const minikin::HyphenEdit hyphenEdit = static_cast<minikin::HyphenEdit>(paint->getHyphenEdit()); - const minikin::StartHyphenEdit startHyphen = minikin::startHyphenEdit(hyphenEdit); - const minikin::EndHyphenEdit endHyphen = minikin::endHyphenEdit(hyphenEdit); + const minikin::StartHyphenEdit startHyphen = paint->getStartHyphenEdit(); + const minikin::EndHyphenEdit endHyphen = paint->getEndHyphenEdit(); if (mt == nullptr) { return minikin::Layout(textBuf.substr(contextRange), range - contextStart, bidiFlags, @@ -76,9 +75,8 @@ float MinikinUtils::measureText(const Paint* paint, minikin::Bidi bidiFlags, minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface); const minikin::U16StringPiece textBuf(buf, bufSize); const minikin::Range range(start, start + count); - const minikin::HyphenEdit hyphenEdit = static_cast<minikin::HyphenEdit>(paint->getHyphenEdit()); - const minikin::StartHyphenEdit startHyphen = minikin::startHyphenEdit(hyphenEdit); - const minikin::EndHyphenEdit endHyphen = minikin::endHyphenEdit(hyphenEdit); + const minikin::StartHyphenEdit startHyphen = paint->getStartHyphenEdit(); + const minikin::EndHyphenEdit endHyphen = paint->getEndHyphenEdit(); return minikin::Layout::measureText(textBuf, range, bidiFlags, minikinPaint, startHyphen, endHyphen, advances); diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h index 601b3c23cc1f..9b2fa9df1e8f 100644 --- a/libs/hwui/hwui/Paint.h +++ b/libs/hwui/hwui/Paint.h @@ -27,6 +27,7 @@ #include <minikin/FontFamily.h> #include <minikin/FamilyVariant.h> +#include <minikin/Hyphenator.h> namespace android { @@ -89,9 +90,25 @@ public: minikin::FamilyVariant getFamilyVariant() const { return mFamilyVariant; } - void setHyphenEdit(uint32_t hyphen) { mHyphenEdit = hyphen; } + void setStartHyphenEdit(uint32_t startHyphen) { + mHyphenEdit = minikin::packHyphenEdit( + static_cast<minikin::StartHyphenEdit>(startHyphen), + minikin::endHyphenEdit(mHyphenEdit)); + } + + void setEndHyphenEdit(uint32_t endHyphen) { + mHyphenEdit = minikin::packHyphenEdit( + minikin::startHyphenEdit(mHyphenEdit), + static_cast<minikin::EndHyphenEdit>(endHyphen)); + } - uint32_t getHyphenEdit() const { return mHyphenEdit; } + minikin::StartHyphenEdit getStartHyphenEdit() const { + return minikin::startHyphenEdit(mHyphenEdit); + } + + minikin::EndHyphenEdit getEndHyphenEdit() const { + return minikin::endHyphenEdit(mHyphenEdit); + } void setAndroidTypeface(Typeface* typeface) { mTypeface = typeface; } diff --git a/libs/hwui/surfacetexture/ImageConsumer.cpp b/libs/hwui/surfacetexture/ImageConsumer.cpp index 624c29058014..077a8f73b0da 100644 --- a/libs/hwui/surfacetexture/ImageConsumer.cpp +++ b/libs/hwui/surfacetexture/ImageConsumer.cpp @@ -23,6 +23,7 @@ #include "renderthread/RenderThread.h" #include "renderthread/VulkanManager.h" #include "utils/Color.h" +#include <GrAHardwareBufferUtils.h> // Macro for including the SurfaceTexture name in log messages #define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__) @@ -30,31 +31,67 @@ namespace android { void ImageConsumer::onFreeBufferLocked(int slotIndex) { - mImageSlots[slotIndex].mImage.reset(); + mImageSlots[slotIndex].clear(); } void ImageConsumer::onAcquireBufferLocked(BufferItem* item) { // If item->mGraphicBuffer is not null, this buffer has not been acquired // before, so any prior SkImage is created with a stale buffer. This resets the stale SkImage. if (item->mGraphicBuffer != nullptr) { - mImageSlots[item->mSlot].mImage.reset(); + mImageSlots[item->mSlot].clear(); } } void ImageConsumer::onReleaseBufferLocked(int buf) { - mImageSlots[buf].mEglFence = EGL_NO_SYNC_KHR; + mImageSlots[buf].eglFence() = EGL_NO_SYNC_KHR; } void ImageConsumer::ImageSlot::createIfNeeded(sp<GraphicBuffer> graphicBuffer, - android_dataspace dataspace, bool forceCreate) { + android_dataspace dataspace, bool forceCreate, + GrContext* context) { if (!mImage.get() || dataspace != mDataspace || forceCreate) { - mImage = graphicBuffer.get() - ? SkImage::MakeFromAHardwareBuffer( - reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()), - kPremul_SkAlphaType, - uirenderer::DataSpaceToColorSpace(dataspace)) - : nullptr; + if (!graphicBuffer.get()) { + clear(); + return; + } + + if (!mBackendTexture.isValid()) { + clear(); + bool createProtectedImage = + 0 != (graphicBuffer->getUsage() & GraphicBuffer::USAGE_PROTECTED); + GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat( + context, + reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()), + graphicBuffer->getPixelFormat(), + false); + mBackendTexture = GrAHardwareBufferUtils::MakeBackendTexture( + context, + reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()), + graphicBuffer->getWidth(), + graphicBuffer->getHeight(), + &mDeleteProc, + &mDeleteCtx, + createProtectedImage, + backendFormat, + false); + } mDataspace = dataspace; + SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat( + graphicBuffer->getPixelFormat()); + mImage = SkImage::MakeFromTexture(context, + mBackendTexture, + kTopLeft_GrSurfaceOrigin, + colorType, + kPremul_SkAlphaType, + uirenderer::DataSpaceToColorSpace(dataspace)); + } +} + +void ImageConsumer::ImageSlot::clear() { + mImage.reset(); + if (mBackendTexture.isValid()) { + mDeleteProc(mDeleteCtx); + mBackendTexture = {}; } } @@ -71,8 +108,8 @@ sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st, if (slot != BufferItem::INVALID_BUFFER_SLOT) { *queueEmpty = true; mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer, - st.mCurrentDataSpace, false); - return mImageSlots[slot].mImage; + st.mCurrentDataSpace, false, renderState.getRenderThread().getGrContext()); + return mImageSlots[slot].getImage(); } } return nullptr; @@ -104,7 +141,7 @@ sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st, uirenderer::RenderPipelineType::SkiaGL) { auto& eglManager = renderState.getRenderThread().eglManager(); display = eglManager.eglDisplay(); - err = eglManager.createReleaseFence(st.mUseFenceSync, &mImageSlots[slot].mEglFence, + err = eglManager.createReleaseFence(st.mUseFenceSync, &mImageSlots[slot].eglFence(), releaseFence); } else { err = renderState.getRenderThread().vulkanManager().createReleaseFence(releaseFence); @@ -129,7 +166,7 @@ sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st, // Finally release the old buffer. status_t status = st.releaseBufferLocked( st.mCurrentTexture, st.mSlots[st.mCurrentTexture].mGraphicBuffer, display, - mImageSlots[st.mCurrentTexture].mEglFence); + mImageSlots[st.mCurrentTexture].eglFence()); if (status < NO_ERROR) { IMG_LOGE("dequeueImage: failed to release buffer: %s (%d)", strerror(-status), status); err = status; @@ -150,8 +187,9 @@ sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st, st.computeCurrentTransformMatrixLocked(); *queueEmpty = false; - mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer, item.mDataSpace, true); - return mImageSlots[slot].mImage; + mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer, item.mDataSpace, true, + renderState.getRenderThread().getGrContext()); + return mImageSlots[slot].getImage(); } } /* namespace android */ diff --git a/libs/hwui/surfacetexture/ImageConsumer.h b/libs/hwui/surfacetexture/ImageConsumer.h index 5c4190397bc4..eee0a0ac3512 100644 --- a/libs/hwui/surfacetexture/ImageConsumer.h +++ b/libs/hwui/surfacetexture/ImageConsumer.h @@ -25,6 +25,12 @@ #include <cutils/compiler.h> #include <gui/BufferItem.h> #include <system/graphics.h> +#include <GrBackendSurface.h> + +namespace GrAHardwareBufferUtils { +typedef void* DeleteImageCtx; +typedef void (*DeleteImageProc)(DeleteImageCtx); +} namespace android { @@ -67,9 +73,21 @@ private: * ImageSlot contains the information and object references that * ImageConsumer maintains about a BufferQueue buffer slot. */ - struct ImageSlot { + class ImageSlot { + public: ImageSlot() : mDataspace(HAL_DATASPACE_UNKNOWN), mEglFence(EGL_NO_SYNC_KHR) {} + ~ImageSlot() { clear(); } + + void createIfNeeded(sp<GraphicBuffer> graphicBuffer, android_dataspace dataspace, + bool forceCreate, GrContext* context); + void clear(); + + inline EGLSyncKHR& eglFence() { return mEglFence; } + + inline sk_sp<SkImage> getImage() { return mImage; } + + private: // mImage is the SkImage created from mGraphicBuffer. sk_sp<SkImage> mImage; @@ -82,8 +100,11 @@ private: */ EGLSyncKHR mEglFence; - void createIfNeeded(sp<GraphicBuffer> graphicBuffer, android_dataspace dataspace, - bool forceCreate); + GrBackendTexture mBackendTexture; + + GrAHardwareBufferUtils::DeleteImageProc mDeleteProc; + + GrAHardwareBufferUtils::DeleteImageCtx mDeleteCtx; }; /** diff --git a/libs/hwui/surfacetexture/SurfaceTexture.cpp b/libs/hwui/surfacetexture/SurfaceTexture.cpp index da094442684d..a27db6591d6a 100644 --- a/libs/hwui/surfacetexture/SurfaceTexture.cpp +++ b/libs/hwui/surfacetexture/SurfaceTexture.cpp @@ -23,6 +23,7 @@ #include "Matrix.h" #include "SurfaceTexture.h" +#include "ImageConsumer.h" namespace android { @@ -150,7 +151,7 @@ status_t SurfaceTexture::releaseBufferLocked(int buf, sp<GraphicBuffer> graphicB // buffer has reallocated the original buffer slot after this buffer // was acquired. status_t err = ConsumerBase::releaseBufferLocked(buf, graphicBuffer, display, eglFence); - // We could be releasing an EGL buffer, even if not currently attached to a GL context. + // We could be releasing an EGL/Vulkan buffer, even if not currently attached to a GL context. mImageConsumer.onReleaseBufferLocked(buf); mEGLConsumer.onReleaseBufferLocked(buf); return err; @@ -235,6 +236,10 @@ void SurfaceTexture::detachFromView() { if (mOpMode == OpMode::attachedToView) { mOpMode = OpMode::detached; + // Free all EglImage and VkImage before the context is destroyed. + for (int i=0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; i++) { + mImageConsumer.onFreeBufferLocked(i); + } } else { SFT_LOGE("detachFromView: not attached to View"); } diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java index ed74333da895..673b4112d423 100644 --- a/location/java/android/location/Location.java +++ b/location/java/android/location/Location.java @@ -150,7 +150,7 @@ public class Location implements Parcelable { private Bundle mExtras = null; // A bitmask of fields present in this object (see HAS_* constants defined above). - private byte mFieldsMask = 0; + private int mFieldsMask = 0; /** * Construct a new Location with a named provider. @@ -1137,7 +1137,7 @@ public class Location implements Parcelable { l.mTime = in.readLong(); l.mElapsedRealtimeNanos = in.readLong(); l.mElapsedRealtimeUncertaintyNanos = in.readLong(); - l.mFieldsMask = in.readByte(); + l.mFieldsMask = in.readInt(); l.mLatitude = in.readDouble(); l.mLongitude = in.readDouble(); l.mAltitude = in.readDouble(); @@ -1168,7 +1168,7 @@ public class Location implements Parcelable { parcel.writeLong(mTime); parcel.writeLong(mElapsedRealtimeNanos); parcel.writeLong(mElapsedRealtimeUncertaintyNanos); - parcel.writeByte(mFieldsMask); + parcel.writeInt(mFieldsMask); parcel.writeDouble(mLatitude); parcel.writeDouble(mLongitude); parcel.writeDouble(mAltitude); diff --git a/media/apex/java/android/media/MediaSession2.java b/media/apex/java/android/media/MediaSession2.java index 09ac9caf831b..d63de098ecee 100644 --- a/media/apex/java/android/media/MediaSession2.java +++ b/media/apex/java/android/media/MediaSession2.java @@ -511,7 +511,8 @@ public class MediaSession2 implements AutoCloseable { } /** - * Set extras for the session token. + * Set extras for the session token. If null or not set, {@link Session2Token#getExtras()} + * will return {@link Bundle#EMPTY}. * * @return The Builder to allow chaining * @see Session2Token#getExtras() diff --git a/media/apex/java/android/media/Session2Token.java b/media/apex/java/android/media/Session2Token.java index dc970ae1fe1a..d7cb9787cf08 100644 --- a/media/apex/java/android/media/Session2Token.java +++ b/media/apex/java/android/media/Session2Token.java @@ -216,10 +216,11 @@ public final class Session2Token implements Parcelable { /** * @return extras of the token + * @see MediaSession2.Builder#setExtras(Bundle) */ - @Nullable + @NonNull public Bundle getExtras() { - return mExtras; + return mExtras == null ? Bundle.EMPTY : mExtras; } Session2Link getSessionLink() { diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 7783a4d6c869..c11f44600be4 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -3308,6 +3308,7 @@ public class AudioManager { /** * @hide + * Unregisters an {@link AudioPolicy} asynchronously. * @param policy the non-null {@link AudioPolicy} to unregister. */ @SystemApi @@ -3329,6 +3330,27 @@ public class AudioManager { } } + /** + * @hide + * Unregisters an {@link AudioPolicy} synchronously. + * This method also invalidates all {@link AudioRecord} and {@link AudioTrack} objects + * associated with mixes of this policy. + * @param policy the non-null {@link AudioPolicy} to unregister. + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public void unregisterAudioPolicy(@NonNull AudioPolicy policy) { + Preconditions.checkNotNull(policy, "Illegal null AudioPolicy argument"); + final IAudioService service = getService(); + try { + policy.invalidateCaptorsAndInjectors(); + service.unregisterAudioPolicy(policy.cb()); + policy.setRegistration(null); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + //==================================================================== // Notification of playback activity & playback configuration /** diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 02856678879e..95d89bb75b34 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -199,6 +199,8 @@ interface IAudioService { oneway void unregisterAudioPolicyAsync(in IAudioPolicyCallback pcb); + void unregisterAudioPolicy(in IAudioPolicyCallback pcb); + int addMixForPolicy(in AudioPolicyConfig policyConfig, in IAudioPolicyCallback pcb); int removeMixForPolicy(in AudioPolicyConfig policyConfig, in IAudioPolicyCallback pcb); diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java index 9258b85395d6..f5abb2482a7f 100644 --- a/media/java/android/media/MediaDrm.java +++ b/media/java/android/media/MediaDrm.java @@ -16,6 +16,7 @@ package android.media; +import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -24,6 +25,7 @@ import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.Looper; import android.os.Message; import android.os.Parcel; @@ -36,8 +38,13 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; +import java.util.function.Function; /** @@ -131,21 +138,6 @@ public final class MediaDrm implements AutoCloseable { private static final String PERMISSION = android.Manifest.permission.ACCESS_DRM_CERTIFICATES; - private EventHandler mEventHandler; - private EventHandler mKeyStatusChangeHandler; - private EventHandler mExpirationUpdateHandler; - private EventHandler mSessionLostStateHandler; - - private OnEventListener mOnEventListener; - private OnKeyStatusChangeListener mOnKeyStatusChangeListener; - private OnExpirationUpdateListener mOnExpirationUpdateListener; - private OnSessionLostStateListener mOnSessionLostStateListener; - - private final Object mEventLock = new Object(); - private final Object mKeyStatusChangeLock = new Object(); - private final Object mExpirationUpdateLock = new Object(); - private final Object mSessionLostStateLock = new Object(); - private long mNativeContext; /** @@ -227,35 +219,19 @@ public final class MediaDrm implements AutoCloseable { private static final native boolean isCryptoSchemeSupportedNative( @NonNull byte[] uuid, @Nullable String mimeType, @SecurityLevel int securityLevel); - private EventHandler createHandler() { + private Handler createHandler() { Looper looper; - EventHandler handler; + Handler handler; if ((looper = Looper.myLooper()) != null) { - handler = new EventHandler(this, looper); + handler = new Handler(looper); } else if ((looper = Looper.getMainLooper()) != null) { - handler = new EventHandler(this, looper); + handler = new Handler(looper); } else { handler = null; } return handler; } - private EventHandler updateHandler(Handler handler) { - Looper looper; - EventHandler newHandler = null; - if (handler != null) { - looper = handler.getLooper(); - } else { - looper = Looper.myLooper(); - } - if (looper != null) { - if (handler == null || handler.getLooper() != looper) { - newHandler = new EventHandler(this, looper); - } - } - return newHandler; - } - /** * Instantiate a MediaDrm object * @@ -265,11 +241,6 @@ public final class MediaDrm implements AutoCloseable { * specified scheme UUID */ public MediaDrm(@NonNull UUID uuid) throws UnsupportedSchemeException { - mEventHandler = createHandler(); - mKeyStatusChangeHandler = createHandler(); - mExpirationUpdateHandler = createHandler(); - mSessionLostStateHandler = createHandler(); - /* Native setup requires a weak reference to our object. * It's easier to create it here than in C++. */ @@ -368,12 +339,30 @@ public final class MediaDrm implements AutoCloseable { */ public void setOnExpirationUpdateListener( @Nullable OnExpirationUpdateListener listener, @Nullable Handler handler) { - synchronized(mExpirationUpdateLock) { - if (listener != null) { - mExpirationUpdateHandler = updateHandler(handler); - } - mOnExpirationUpdateListener = listener; - } + setListenerWithHandler(EXPIRATION_UPDATE, handler, listener, + this::createOnExpirationUpdateListener); + } + /** + * Register a callback to be invoked when a session expiration update + * occurs. + * + * @see #setOnExpirationUpdateListener(OnExpirationUpdateListener, Handler) + * + * @param executor the executor through which the listener should be invoked + * @param listener the callback that will be run. + */ + public void setOnExpirationUpdateListener( + @NonNull @CallbackExecutor Executor executor, + @NonNull OnExpirationUpdateListener listener) { + setListenerWithExecutor(EXPIRATION_UPDATE, executor, listener, + this::createOnExpirationUpdateListener); + } + + /** + * Clear the {@link OnExpirationUpdateListener}. + */ + public void clearOnExpirationUpdateListener() { + clearGenericListener(EXPIRATION_UPDATE); } /** @@ -407,12 +396,31 @@ public final class MediaDrm implements AutoCloseable { */ public void setOnKeyStatusChangeListener( @Nullable OnKeyStatusChangeListener listener, @Nullable Handler handler) { - synchronized(mKeyStatusChangeLock) { - if (listener != null) { - mKeyStatusChangeHandler = updateHandler(handler); - } - mOnKeyStatusChangeListener = listener; - } + setListenerWithHandler(KEY_STATUS_CHANGE, handler, listener, + this::createOnKeyStatusChangeListener); + } + + /** + * Register a callback to be invoked when the state of keys in a session + * change. + * + * @see #setOnKeyStatusChangeListener(OnKeyStatusChangeListener, Handler) + * + * @param listener the callback that will be run when key status changes. + * @param executor the executor on which the listener should be invoked. + */ + public void setOnKeyStatusChangeListener( + @NonNull @CallbackExecutor Executor executor, + @NonNull OnKeyStatusChangeListener listener) { + setListenerWithExecutor(KEY_STATUS_CHANGE, executor, listener, + this::createOnKeyStatusChangeListener); + } + + /** + * Clear the {@link OnKeyStatusChangeListener}. + */ + public void clearOnKeyStatusChangeListener() { + clearGenericListener(KEY_STATUS_CHANGE); } /** @@ -453,12 +461,31 @@ public final class MediaDrm implements AutoCloseable { */ public void setOnSessionLostStateListener( @Nullable OnSessionLostStateListener listener, @Nullable Handler handler) { - synchronized(mSessionLostStateLock) { - if (listener != null) { - mSessionLostStateHandler = updateHandler(handler); - } - mOnSessionLostStateListener = listener; - } + setListenerWithHandler(SESSION_LOST_STATE, handler, listener, + this::createOnSessionLostStateListener); + } + + /** + * Register a callback to be invoked when session state has been + * lost. + * + * @see #setOnSessionLostStateListener(OnSessionLostStateListener, Handler) + * + * @param listener the callback that will be run. + * @param executor the executor on which the listener should be invoked. + */ + public void setOnSessionLostStateListener( + @NonNull @CallbackExecutor Executor executor, + @Nullable OnSessionLostStateListener listener) { + setListenerWithExecutor(SESSION_LOST_STATE, executor, listener, + this::createOnSessionLostStateListener); + } + + /** + * Clear the {@link OnSessionLostStateListener}. + */ + public void clearOnSessionLostStateListener() { + clearGenericListener(SESSION_LOST_STATE); } /** @@ -552,14 +579,48 @@ public final class MediaDrm implements AutoCloseable { /** * Register a callback to be invoked when an event occurs * + * @see #setOnEventListener(OnEventListener, Handler) + * * @param listener the callback that will be run. Use {@code null} to * stop receiving event callbacks. */ public void setOnEventListener(@Nullable OnEventListener listener) { - synchronized(mEventLock) { - mOnEventListener = listener; - } + setOnEventListener(listener, null); + } + + /** + * Register a callback to be invoked when an event occurs + * + * @param listener the callback that will be run. Use {@code null} to + * stop receiving event callbacks. + * @param handler the handler on which the listener should be invoked, or + * null if the listener should be invoked on the calling thread's looper. + */ + + public void setOnEventListener(@Nullable OnEventListener listener, @Nullable Handler handler) + { + setListenerWithHandler(DRM_EVENT, handler, listener, this::createOnEventListener); + } + + /** + * Register a callback to be invoked when an event occurs + * + * @see #setOnEventListener(OnEventListener) + * + * @param executor the executor through which the listener should be invoked + * @param listener the callback that will be run. + */ + public void setOnEventListener(@NonNull @CallbackExecutor Executor executor, + @NonNull OnEventListener listener) { + setListenerWithExecutor(DRM_EVENT, executor, listener, this::createOnEventListener); + } + + /** + * Clear the {@link OnEventListener}. + */ + public void clearOnEventListener() { + clearGenericListener(DRM_EVENT); } /** @@ -637,99 +698,112 @@ public final class MediaDrm implements AutoCloseable { private static final int KEY_STATUS_CHANGE = 202; private static final int SESSION_LOST_STATE = 203; - private class EventHandler extends Handler - { - private MediaDrm mMediaDrm; + // Use ConcurrentMap to support concurrent read/write to listener settings. + // ListenerWithExecutor is immutable so we shouldn't need further locks. + private final Map<Integer, ListenerWithExecutor> mListenerMap = new ConcurrentHashMap<>(); + + // called by old-style set*Listener APIs using Handlers; listener & handler are Nullable + private <T> void setListenerWithHandler(int what, Handler handler, T listener, + Function<T, Consumer<ListenerArgs>> converter) { + if (listener == null) { + clearGenericListener(what); + } else { + handler = handler == null ? createHandler() : handler; + final HandlerExecutor executor = new HandlerExecutor(handler); + setGenericListener(what, executor, listener, converter); + } + } - public EventHandler(@NonNull MediaDrm md, @NonNull Looper looper) { - super(looper); - mMediaDrm = md; + // called by new-style set*Listener APIs using Executors; listener & executor must be NonNull + private <T> void setListenerWithExecutor(int what, Executor executor, T listener, + Function<T, Consumer<ListenerArgs>> converter) { + if (executor == null || listener == null) { + final String errMsg = String.format("executor %s listener %s", executor, listener); + throw new IllegalArgumentException(errMsg); } + setGenericListener(what, executor, listener, converter); + } - @Override - public void handleMessage(@NonNull Message msg) { - if (mMediaDrm.mNativeContext == 0) { - Log.w(TAG, "MediaDrm went away with unhandled events"); - return; + private <T> void setGenericListener(int what, Executor executor, T listener, + Function<T, Consumer<ListenerArgs>> converter) { + mListenerMap.put(what, new ListenerWithExecutor(executor, converter.apply(listener))); + } + + private void clearGenericListener(int what) { + mListenerMap.remove(what); + } + + private Consumer<ListenerArgs> createOnEventListener(OnEventListener listener) { + return args -> { + byte[] sessionId = args.parcel.createByteArray(); + if (sessionId.length == 0) { + sessionId = null; + } + byte[] data = args.parcel.createByteArray(); + if (data.length == 0) { + data = null; } - switch(msg.what) { - case DRM_EVENT: - synchronized(mEventLock) { - if (mOnEventListener != null) { - if (msg.obj != null && msg.obj instanceof Parcel) { - Parcel parcel = (Parcel)msg.obj; - byte[] sessionId = parcel.createByteArray(); - if (sessionId.length == 0) { - sessionId = null; - } - byte[] data = parcel.createByteArray(); - if (data.length == 0) { - data = null; - } - - Log.i(TAG, "Drm event (" + msg.arg1 + "," + msg.arg2 + ")"); - mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data); - } - } - } - return; + Log.i(TAG, "Drm event (" + args.arg1 + "," + args.arg2 + ")"); + listener.onEvent(this, sessionId, args.arg1, args.arg2, data); + }; + } - case KEY_STATUS_CHANGE: - synchronized(mKeyStatusChangeLock) { - if (mOnKeyStatusChangeListener != null) { - if (msg.obj != null && msg.obj instanceof Parcel) { - Parcel parcel = (Parcel)msg.obj; - byte[] sessionId = parcel.createByteArray(); - if (sessionId.length > 0) { - List<KeyStatus> keyStatusList = keyStatusListFromParcel(parcel); - boolean hasNewUsableKey = (parcel.readInt() != 0); - - Log.i(TAG, "Drm key status changed"); - mOnKeyStatusChangeListener.onKeyStatusChange(mMediaDrm, sessionId, - keyStatusList, hasNewUsableKey); - } - } - } - } - return; + private Consumer<ListenerArgs> createOnKeyStatusChangeListener( + OnKeyStatusChangeListener listener) { + return args -> { + byte[] sessionId = args.parcel.createByteArray(); + if (sessionId.length > 0) { + List<KeyStatus> keyStatusList = keyStatusListFromParcel(args.parcel); + boolean hasNewUsableKey = (args.parcel.readInt() != 0); - case EXPIRATION_UPDATE: - synchronized(mExpirationUpdateLock) { - if (mOnExpirationUpdateListener != null) { - if (msg.obj != null && msg.obj instanceof Parcel) { - Parcel parcel = (Parcel)msg.obj; - byte[] sessionId = parcel.createByteArray(); - if (sessionId.length > 0) { - long expirationTime = parcel.readLong(); - - Log.i(TAG, "Drm key expiration update: " + expirationTime); - mOnExpirationUpdateListener.onExpirationUpdate(mMediaDrm, sessionId, - expirationTime); - } - } - } - } - return; + Log.i(TAG, "Drm key status changed"); + listener.onKeyStatusChange(this, sessionId, keyStatusList, hasNewUsableKey); + } + }; + } - case SESSION_LOST_STATE: - synchronized(mSessionLostStateLock) { - if (mOnSessionLostStateListener != null) { - if (msg.obj != null && msg.obj instanceof Parcel) { - Parcel parcel = (Parcel)msg.obj; - byte[] sessionId = parcel.createByteArray(); - Log.i(TAG, "Drm session lost state event: "); - mOnSessionLostStateListener.onSessionLostState(mMediaDrm, - sessionId); - } - } - } - return; + private Consumer<ListenerArgs> createOnExpirationUpdateListener( + OnExpirationUpdateListener listener) { + return args -> { + byte[] sessionId = args.parcel.createByteArray(); + if (sessionId.length > 0) { + long expirationTime = args.parcel.readLong(); - default: - Log.e(TAG, "Unknown message type " + msg.what); - return; + Log.i(TAG, "Drm key expiration update: " + expirationTime); + listener.onExpirationUpdate(this, sessionId, expirationTime); } + }; + } + + private Consumer<ListenerArgs> createOnSessionLostStateListener( + OnSessionLostStateListener listener) { + return args -> { + byte[] sessionId = args.parcel.createByteArray(); + Log.i(TAG, "Drm session lost state event: "); + listener.onSessionLostState(this, sessionId); + }; + } + + private static class ListenerArgs { + private final Parcel parcel; + private final int arg1; + private final int arg2; + + public ListenerArgs(Parcel parcel, int arg1, int arg2) { + this.parcel = parcel; + this.arg1 = arg1; + this.arg2 = arg2; + } + } + + private static class ListenerWithExecutor { + private final Consumer<ListenerArgs> mConsumer; + private final Executor mExecutor; + + public ListenerWithExecutor(Executor executor, Consumer<ListenerArgs> consumer) { + this.mExecutor = executor; + this.mConsumer = consumer; } } @@ -764,35 +838,22 @@ public final class MediaDrm implements AutoCloseable { } switch (what) { case DRM_EVENT: - synchronized(md.mEventLock) { - if (md.mEventHandler != null) { - Message m = md.mEventHandler.obtainMessage(what, eventType, extra, obj); - md.mEventHandler.sendMessage(m); - } - } - break; case EXPIRATION_UPDATE: - synchronized(md.mExpirationUpdateLock) { - if (md.mExpirationUpdateHandler != null) { - Message m = md.mExpirationUpdateHandler.obtainMessage(what, obj); - md.mExpirationUpdateHandler.sendMessage(m); - } - } - break; case KEY_STATUS_CHANGE: - synchronized(md.mKeyStatusChangeLock) { - if (md.mKeyStatusChangeHandler != null) { - Message m = md.mKeyStatusChangeHandler.obtainMessage(what, obj); - md.mKeyStatusChangeHandler.sendMessage(m); - } - } - break; case SESSION_LOST_STATE: - synchronized(md.mSessionLostStateLock) { - if (md.mSessionLostStateHandler != null) { - Message m = md.mSessionLostStateHandler.obtainMessage(what, obj); - md.mSessionLostStateHandler.sendMessage(m); - } + ListenerWithExecutor listener = md.mListenerMap.get(what); + if (listener != null) { + final Runnable command = () -> { + if (md.mNativeContext == 0) { + Log.w(TAG, "MediaDrm went away with unhandled events"); + return; + } + if (obj != null && obj instanceof Parcel) { + Parcel p = (Parcel)obj; + listener.mConsumer.accept(new ListenerArgs(p, eventType, extra)); + } + }; + listener.mExecutor.execute(command); } break; default: diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java index 5f65d586b730..978583e99971 100644 --- a/media/java/android/media/audiopolicy/AudioPolicy.java +++ b/media/java/android/media/audiopolicy/AudioPolicy.java @@ -43,8 +43,11 @@ import android.os.ServiceManager; import android.util.Log; import android.util.Slog; +import com.android.internal.annotations.GuardedBy; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -74,6 +77,19 @@ public class AudioPolicy { private boolean mIsFocusPolicy; /** + * The list of AudioTrack instances created to inject audio into the associated mixes + * Lazy initialization in {@link #createAudioTrackSource(AudioMix)} + */ + @GuardedBy("mLock") + @Nullable private ArrayList<WeakReference<AudioTrack>> mInjectors; + /** + * The list AudioRecord instances created to capture audio from the associated mixes + * Lazy initialization in {@link #createAudioRecordSink(AudioMix)} + */ + @GuardedBy("mLock") + @Nullable private ArrayList<WeakReference<AudioRecord>> mCaptors; + + /** * 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. */ @@ -606,6 +622,12 @@ public class AudioPolicy { AudioFormat.CHANNEL_IN_STEREO, mix.getFormat().getEncoding()), AudioManager.AUDIO_SESSION_ID_GENERATE ); + synchronized (mLock) { + if (mCaptors == null) { + mCaptors = new ArrayList<>(1); + } + mCaptors.add(new WeakReference<AudioRecord>(ar)); + } return ar; } @@ -638,9 +660,47 @@ public class AudioPolicy { AudioTrack.MODE_STREAM, AudioManager.AUDIO_SESSION_ID_GENERATE ); + synchronized (mLock) { + if (mInjectors == null) { + mInjectors = new ArrayList<>(1); + } + mInjectors.add(new WeakReference<AudioTrack>(at)); + } return at; } + /** + * @hide + */ + public void invalidateCaptorsAndInjectors() { + if (!policyReadyToUse()) { + return; + } + synchronized (mLock) { + if (mInjectors != null) { + for (final WeakReference<AudioTrack> weakTrack : mInjectors) { + final AudioTrack track = weakTrack.get(); + if (track == null) { + break; + } + // TODO: add synchronous versions + track.stop(); + track.flush(); + } + } + if (mCaptors != null) { + for (final WeakReference<AudioRecord> weakRecord : mCaptors) { + final AudioRecord record = weakRecord.get(); + if (record == null) { + break; + } + // TODO: if needed: implement an invalidate method + record.stop(); + } + } + } + } + public int getStatus() { return mStatus; } diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl index e85461f93731..cfcc2946bbdb 100644 --- a/media/java/android/media/session/ISessionManager.aidl +++ b/media/java/android/media/session/ISessionManager.aidl @@ -55,8 +55,8 @@ interface ISessionManager { void addSession2TokensListener(in ISession2TokensListener listener, int userId); void removeSession2TokensListener(in ISession2TokensListener listener); - // This is for the system volume UI only - void setRemoteVolumeController(in IRemoteVolumeController rvc); + void registerRemoteVolumeController(in IRemoteVolumeController rvc); + void unregisterRemoteVolumeController(in IRemoteVolumeController rvc); // For PhoneWindowManager to precheck media keys boolean isGlobalPriorityActive(); diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java index fde4f8837fa5..f530442bf087 100644 --- a/media/java/android/media/session/MediaSessionManager.java +++ b/media/java/android/media/session/MediaSessionManager.java @@ -424,17 +424,33 @@ public final class MediaSessionManager { } /** - * Set the remote volume controller to receive volume updates on. Only for - * use by system UI. + * Set the remote volume controller to receive volume updates on. + * Only for use by System UI and Settings application. * * @param rvc The volume controller to receive updates on. * @hide */ - public void setRemoteVolumeController(IRemoteVolumeController rvc) { + public void registerRemoteVolumeController(IRemoteVolumeController rvc) { try { - mService.setRemoteVolumeController(rvc); + mService.registerRemoteVolumeController(rvc); } catch (RemoteException e) { - Log.e(TAG, "Error in setRemoteVolumeController.", e); + Log.e(TAG, "Error in registerRemoteVolumeController.", e); + } + } + + /** + * Unregisters the remote volume controller which was previously registered with + * {@link #registerRemoteVolumeController(IRemoteVolumeController)}. + * Only for use by System UI and Settings application. + * + * @param rvc The volume controller which was registered. + * @hide + */ + public void unregisterRemoteVolumeController(IRemoteVolumeController rvc) { + try { + mService.unregisterRemoteVolumeController(rvc); + } catch (RemoteException e) { + Log.e(TAG, "Error in unregisterRemoteVolumeController.", e); } } diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java index 0c352043f2a3..3b278b40acea 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java @@ -20,9 +20,11 @@ import android.content.Context; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.ViewMediatorCallback; +import com.android.systemui.car.CarNotificationEntryManager; import com.android.systemui.car.CarNotificationInterruptionStateProvider; import com.android.systemui.statusbar.car.CarFacetButtonController; import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager; +import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.volume.CarVolumeDialogComponent; @@ -54,7 +56,7 @@ public class CarSystemUIFactory extends SystemUIFactory { } public StatusBarKeyguardViewManager createStatusBarKeyguardViewManager(Context context, - ViewMediatorCallback viewMediatorCallback, LockPatternUtils lockPatternUtils) { + ViewMediatorCallback viewMediatorCallback, LockPatternUtils lockPatternUtils) { return new CarStatusBarKeyguardViewManager(context, viewMediatorCallback, lockPatternUtils); } @@ -92,4 +94,12 @@ public class CarSystemUIFactory extends SystemUIFactory { public interface CarDependencyComponent { CarFacetButtonController getCarFacetButtonController(); } + + /** + * Use {@link CarNotificationEntryManager}, which does nothing when adding a notification. + */ + @Singleton + public NotificationEntryManager provideNotificationEntryManager(Context context) { + return new CarNotificationEntryManager(context); + } } diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java new file mode 100644 index 000000000000..6d9c7bafb2b2 --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.car; + +import android.content.Context; +import android.service.notification.NotificationListenerService; +import android.service.notification.StatusBarNotification; + +import com.android.systemui.statusbar.notification.NotificationEntryManager; + +/** + * Car specific notification entry manager that does nothing when adding a notification. + * + * <p> This is because system UI notifications are disabled and we have a different implementation. + * Please see {@link com.android.car.notification}. + */ +public class CarNotificationEntryManager extends NotificationEntryManager { + public CarNotificationEntryManager(Context context) { + super(context); + } + + @Override + public void addNotification( + StatusBarNotification notification, NotificationListenerService.RankingMap ranking) { + } +} diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index bd0e0b846abf..8732524de07d 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -606,4 +606,8 @@ public class CarStatusBar extends StatusBar implements getComponent(NotificationsUI.class).toggleShowingCarNotifications(); } + @Override + public void maybeEscalateHeadsUp() { + // Never send full screen intent in car. + } } diff --git a/packages/NetworkStack/src/android/net/metrics/DataStallStatsUtils.java b/packages/NetworkStack/src/android/net/metrics/DataStallStatsUtils.java index d1ca109036b4..e23f10f243dc 100644 --- a/packages/NetworkStack/src/android/net/metrics/DataStallStatsUtils.java +++ b/packages/NetworkStack/src/android/net/metrics/DataStallStatsUtils.java @@ -48,6 +48,8 @@ public class DataStallStatsUtils { return DataStallEventProto.VALID; } else if (result.isPortal()) { return DataStallEventProto.PORTAL; + } else if (result.isPartialConnectivity()) { + return DataStallEventProto.PARTIAL; } else { return DataStallEventProto.INVALID; } diff --git a/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_chart.xml b/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_chart.xml index b063e13bcc12..814246fc2698 100644 --- a/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_chart.xml +++ b/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_chart.xml @@ -66,7 +66,7 @@ android:id="@+id/bar_chart_details" style="@android:style/Widget.DeviceDefault.Button.Borderless.Colored" android:layout_width="wrap_content" - android:layout_height="48dp" + android:layout_height="wrap_content" android:gravity="center"/> </LinearLayout> diff --git a/packages/SettingsLib/BarChartPreference/res/values/styles.xml b/packages/SettingsLib/BarChartPreference/res/values/styles.xml index 4876cb6e1f28..558792855628 100644 --- a/packages/SettingsLib/BarChartPreference/res/values/styles.xml +++ b/packages/SettingsLib/BarChartPreference/res/values/styles.xml @@ -18,7 +18,7 @@ <resources> <style name="BarViewStyle"> <item name="android:layout_width">0dp</item> - <item name="android:layout_height">226dp</item> + <item name="android:layout_height">250dp</item> <item name="android:layout_weight">1</item> <item name="android:layout_marginStart">8dp</item> <item name="android:layout_marginEnd">8dp</item> diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java index 1003c974deb3..20e0a3b20b8c 100644 --- a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java +++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java @@ -158,6 +158,11 @@ public class BarChartPreference extends Preference { holder.setDividerAllowedAbove(true); holder.setDividerAllowedBelow(true); + // We bind title and details early so that we can preserve the correct height for chart + // view. + bindChartTitleView(holder); + bindChartDetailsView(holder); + // If the state is loading, we just show a blank view. if (mIsLoading) { holder.itemView.setVisibility(View.INVISIBLE); @@ -165,9 +170,6 @@ public class BarChartPreference extends Preference { } holder.itemView.setVisibility(View.VISIBLE); - // We must show title of bar chart. - bindChartTitleView(holder); - final BarViewInfo[] barViewInfos = mBarChartInfo.getBarViewInfos(); // If there is no any bar view, we just show an empty text. if (barViewInfos == null || barViewInfos.length == 0) { @@ -175,8 +177,6 @@ public class BarChartPreference extends Preference { return; } setEmptyViewVisible(holder, false /* visible */); - - bindChartDetailsView(holder); updateBarChart(holder); } diff --git a/packages/SettingsLib/LayoutPreference/res/values/styles.xml b/packages/SettingsLib/LayoutPreference/res/values/styles.xml index 805744baef10..6a2b729ff9eb 100644 --- a/packages/SettingsLib/LayoutPreference/res/values/styles.xml +++ b/packages/SettingsLib/LayoutPreference/res/values/styles.xml @@ -31,12 +31,10 @@ </style> <style name="TextAppearance.EntityHeaderSummary" - parent="@android:style/TextAppearance.Material.Body1"> + parent="@*android:style/TextAppearance.DeviceDefault.Body1"> <item name="android:textAlignment">viewStart</item> <item name="android:textColor">?android:attr/textColorSecondary</item> - <item name="android:gravity">start</item> <item name="android:singleLine">true</item> <item name="android:ellipsize">marquee</item> - <item name="android:textSize">14sp</item> </style> </resources>
\ No newline at end of file diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java b/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java index 4ed115405f57..f6cd971ec4f3 100644 --- a/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java +++ b/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java @@ -95,7 +95,7 @@ public class MediaSessions { mMgr.addOnActiveSessionsChangedListener(mSessionsListener, null, mHandler); mInit = true; postUpdateSessions(); - mMgr.setRemoteVolumeController(mRvc); + mMgr.registerRemoteVolumeController(mRvc); } protected void postUpdateSessions() { @@ -110,6 +110,7 @@ public class MediaSessions { if (D.BUG) Log.d(TAG, "destroy"); mInit = false; mMgr.removeOnActiveSessionsChangedListener(mSessionsListener); + mMgr.unregisterRemoteVolumeController(mRvc); } /** diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index 59fbb720eace..800c4014313f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -307,6 +307,7 @@ public class AccessPoint implements Comparable<AccessPoint> { public AccessPoint(Context context, WifiConfiguration config) { mContext = context; loadConfig(config); + updateKey(); } /** @@ -317,6 +318,7 @@ public class AccessPoint implements Comparable<AccessPoint> { mContext = context; mFqdn = config.getHomeSp().getFqdn(); mProviderFriendlyName = config.getHomeSp().getFriendlyName(); + updateKey(); } /** @@ -355,7 +357,6 @@ public class AccessPoint implements Comparable<AccessPoint> { security = getSecurity(config); networkId = config.networkId; mConfig = config; - updateKey(); } /** Updates {@link #mKey} and should only called upon object creation/initialization. */ @@ -363,6 +364,8 @@ public class AccessPoint implements Comparable<AccessPoint> { // TODO(sghuman): Consolidate Key logic on ScanResultMatchInfo if (isPasspoint()) { mKey = getKey(mConfig); + } else if (isPasspointConfig()) { + mKey = getKey(mFqdn); } else if (isOsuProvider()) { mKey = getKey(mOsuProvider); } else { // Non-Passpoint AP @@ -618,15 +621,22 @@ public class AccessPoint implements Comparable<AccessPoint> { */ public static String getKey(WifiConfiguration config) { if (config.isPasspoint()) { - return new StringBuilder() - .append(KEY_PREFIX_FQDN) - .append(config.FQDN).toString(); + return getKey(config.FQDN); } else { return getKey(removeDoubleQuotes(config.SSID), config.BSSID, getSecurity(config)); } } /** + * Returns the AccessPoint key corresponding to a Passpoint network by its FQDN. + */ + public static String getKey(String fqdn) { + return new StringBuilder() + .append(KEY_PREFIX_FQDN) + .append(fqdn).toString(); + } + + /** * Returns the AccessPoint key corresponding to the OsuProvider. */ public static String getKey(OsuProvider provider) { diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java index 7c367c7280e6..9c8e3f4fe543 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java @@ -1250,6 +1250,14 @@ public class AccessPointTest { AccessPoint passpointAp = new AccessPoint(mContext, spyConfig, mScanResults, null); assertThat(passpointAp.getKey()).isEqualTo(AccessPoint.getKey(spyConfig)); + PasspointConfiguration passpointConfig = new PasspointConfiguration(); + HomeSp homeSp = new HomeSp(); + homeSp.setFqdn("fqdn"); + homeSp.setFriendlyName("Test Provider"); + passpointConfig.setHomeSp(homeSp); + AccessPoint passpointConfigAp = new AccessPoint(mContext, passpointConfig); + assertThat(passpointConfigAp.getKey()).isEqualTo(AccessPoint.getKey("fqdn")); + OsuProvider provider = createOsuProvider(); AccessPoint osuAp = new AccessPoint(mContext, provider, mScanResults); assertThat(osuAp.getKey()).isEqualTo(AccessPoint.getKey(provider)); diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java index 5f4cf033a45a..2b10ccb4ac1a 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java @@ -58,6 +58,10 @@ public interface VolumeDialogController { void userActivity(); void getState(); + boolean areCaptionsEnabled(); + void setCaptionsEnabled(boolean isEnabled); + void getCaptionsComponentState(); + @ProvidesInterface(version = StreamState.VERSION) public static final class StreamState { public static final int VERSION = 1; @@ -186,5 +190,6 @@ public interface VolumeDialogController { void onScreenOff(); void onShowSafetyWarning(int flags); void onAccessibilityModeChanged(Boolean showA11yStream); + void onCaptionComponentStateChanged(Boolean isComponentEnabled); } } diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java index bca353050c46..42600c157387 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java @@ -247,27 +247,6 @@ public interface QSTile { } } - - @ProvidesInterface(version = AirplaneBooleanState.VERSION) - public static class AirplaneBooleanState extends BooleanState { - public static final int VERSION = 1; - public boolean isAirplaneMode; - - @Override - public boolean copyTo(State other) { - final AirplaneBooleanState o = (AirplaneBooleanState) other; - final boolean changed = super.copyTo(other) || o.isAirplaneMode != isAirplaneMode; - o.isAirplaneMode = isAirplaneMode; - return changed; - } - - public State copy() { - AirplaneBooleanState state = new AirplaneBooleanState(); - copyTo(state); - return state; - } - } - @ProvidesInterface(version = SlashState.VERSION) public static class SlashState { public static final int VERSION = 2; diff --git a/packages/SystemUI/res/drawable/circle_blue_40dp.xml b/packages/SystemUI/res/drawable/circle_blue_40dp.xml new file mode 100644 index 000000000000..00d2c52deb9b --- /dev/null +++ b/packages/SystemUI/res/drawable/circle_blue_40dp.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="oval"> + <size android:height="40dp" + android:width="40dp" /> + <solid android:color="#4285f4" /> + <stroke android:color="#f1f3f4" android:width="1dp" /> +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/circle_white_40dp.xml b/packages/SystemUI/res/drawable/circle_white_40dp.xml new file mode 100644 index 000000000000..bcb1640a73fb --- /dev/null +++ b/packages/SystemUI/res/drawable/circle_white_40dp.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="oval"> + <size android:height="40dp" + android:width="40dp" /> + <solid android:color="#ffffff" /> + <stroke android:color="#f1f3f4" android:width="1dp" /> +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_volume_odi_captions.xml b/packages/SystemUI/res/drawable/ic_volume_odi_captions.xml new file mode 100644 index 000000000000..9b907290d0e9 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_volume_odi_captions.xml @@ -0,0 +1,24 @@ +<!-- + Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M20,4C21.1,4 22,4.9 22,6L22,18C22,19.1 21.1,20 20,20L4,20C2.9,20 2,19.1 2,18L2,6C2,4.9 2.9,4 4,4L20,4ZM20,18L20,6L4,6L4,18L20,18ZM6,10L8,10L8,12L6,12L6,10ZM6,14L14,14L14,16L6,16L6,14ZM16,14L18,14L18,16L16,16L16,14ZM10,10L18,10L18,12L10,12L10,10Z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_volume_odi_captions_disabled.xml b/packages/SystemUI/res/drawable/ic_volume_odi_captions_disabled.xml new file mode 100644 index 000000000000..f3d8d3b9c2e2 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_volume_odi_captions_disabled.xml @@ -0,0 +1,24 @@ +<!-- + Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M16.9675,14L18,14L18,15.0275L16.9675,14ZM20,17.0176L20,6L8.9281,6L6.9182,4L20,4C21.1,4 22,4.9 22,6L22,18C22,18.2949 21.9353,18.5755 21.8194,18.8281L20,17.0176ZM12.9478,10L18,10L18,12L14.9576,12L12.9478,10ZM1.2823,0.8824L22.8489,22.4489L21.6337,23.6641L17.9696,20L4,20C2.9,20 2,19.1 2,18L2,6C2,5.4577 2.2188,4.964 2.5724,4.6028L0.0672,2.0975L1.2823,0.8824ZM13.9696,16L6,16L6,14L11.9696,14L8,10.0304L8,12L6,12L6,10L7.9696,10L4,6.0304L4,18L15.9696,18L13.9696,16Z"/> +</vector> diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml index 7e0f3ae3f1fc..725ace403ba3 100644 --- a/packages/SystemUI/res/layout/notification_info.xml +++ b/packages/SystemUI/res/layout/notification_info.xml @@ -220,48 +220,142 @@ asked for it --> android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing" style="@style/TextAppearance.NotificationInfo.Button"/> </LinearLayout> - - </RelativeLayout> <LinearLayout android:id="@+id/interruptiveness_settings" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/notification_guts_button_spacing" - android:layout_marginStart="@dimen/notification_guts_button_side_margin" - android:layout_marginEnd="@dimen/notification_guts_button_side_margin" - android:gravity="center" - android:orientation="horizontal" + android:orientation="vertical" android:visibility="gone"> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="2dp" + android:layout_marginStart="@dimen/notification_guts_button_side_margin" + android:layout_marginEnd="@dimen/notification_guts_button_side_margin" + android:gravity="center" + android:orientation="horizontal"> + <LinearLayout + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:gravity="center_horizontal" + android:orientation="vertical"> + <FrameLayout + android:id="@+id/int_block_wrapper" + android:padding="4dp" + android:layout_width="48dp" + android:layout_height="48dp" + android:gravity="center"> + <ImageButton + android:id="@+id/int_block" + android:background="@drawable/circle_white_40dp" + android:src="@drawable/ic_notification_block" + android:layout_gravity="center" + android:layout_width="40dp" + android:layout_height="40dp" + android:clickable="false" + android:tint="@color/GM2_grey_400" + style="@style/TextAppearance.NotificationInfo.Button"/> + </FrameLayout> + <TextView + android:id="@+id/int_block_label" + android:text="@string/inline_block_button" + android:layout_gravity="center_horizontal" + android:gravity="center" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:ellipsize="end" + android:maxLines="1" + style="@style/TextAppearance.NotificationInfo.ButtonLabel"/> + </LinearLayout> + <LinearLayout + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:gravity="center_horizontal" + android:orientation="vertical"> + <FrameLayout + android:id="@+id/int_silent_wrapper" + android:padding="4dp" + android:layout_width="48dp" + android:layout_height="48dp" + android:gravity="center"> + <ImageButton + android:id="@+id/int_silent" + android:background="@drawable/circle_white_40dp" + android:src="@drawable/ic_notifications_silence" + android:layout_gravity="center" + android:layout_width="40dp" + android:layout_height="40dp" + android:clickable="false" + android:tint="@color/GM2_grey_400" + style="@style/TextAppearance.NotificationInfo.Button"/> + </FrameLayout> + <TextView + android:id="@+id/int_silent_label" + android:text="@string/inline_silent_button_silent" + android:layout_gravity="center_horizontal" + android:gravity="center" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:ellipsize="end" + android:maxLines="1" + style="@style/TextAppearance.NotificationInfo.ButtonLabel"/> + </LinearLayout> + <LinearLayout + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:gravity="center_horizontal" + android:orientation="vertical"> + <FrameLayout + android:id="@+id/int_alert_wrapper" + android:padding="4dp" + android:layout_width="48dp" + android:layout_height="48dp" + android:gravity="center"> + <ImageButton + android:id="@+id/int_alert" + android:background="@drawable/circle_white_40dp" + android:src="@drawable/ic_notifications_alert" + android:layout_gravity="center" + android:layout_width="40dp" + android:layout_height="40dp" + android:clickable="false" + android:tint="@color/GM2_grey_400" + style="@style/TextAppearance.NotificationInfo.Button"/> + </FrameLayout> + <TextView + android:id="@+id/int_alert_label" + android:text="@string/inline_silent_button_alert" + android:layout_gravity="center_horizontal" + android:gravity="center" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:ellipsize="end" + android:maxLines="1" + style="@style/TextAppearance.NotificationInfo.ButtonLabel"/> + </LinearLayout> + </LinearLayout> <TextView - android:id="@+id/int_block" - android:text="@string/inline_block_button" - android:layout_width="0dp" - android:layout_height="match_parent" - android:drawableTop="@drawable/ic_notification_block" - android:drawableTint="?android:attr/colorAccent" - android:layout_weight="1" - style="@style/TextAppearance.NotificationInfo.Button"/> - <TextView - android:id="@+id/int_silent" - android:text="@string/inline_minimize_button" - android:layout_width="0dp" - android:layout_height="match_parent" - android:drawableTop="@drawable/ic_notifications_silence" - android:drawableTint="?android:attr/colorAccent" - android:layout_weight="1" - style="@style/TextAppearance.NotificationInfo.Button"/> + android:id="@+id/hint_text" + android:layout_marginStart="@*android:dimen/notification_content_margin_start" + android:layout_marginEnd="@*android:dimen/notification_content_margin_start" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="@style/TextAppearance.NotificationInfo.HintText" /> <TextView - android:id="@+id/int_alert" - android:text="@string/inline_keep_button" - android:layout_width="0dp" - android:layout_height="match_parent" - android:drawableTop="@drawable/ic_notifications_alert" - android:drawableTint="?android:attr/colorAccent" - android:layout_weight="1" - style="@style/TextAppearance.NotificationInfo.Button"/> + android:id="@+id/done_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="right" + android:paddingRight="24dp" + android:text="@string/inline_done_button" + style="@style/TextAppearance.NotificationInfo.Button" /> </LinearLayout> </LinearLayout> + <com.android.systemui.statusbar.notification.row.NotificationUndoLayout android:id="@+id/confirmation" android:layout_width="match_parent" diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml index ca34c23eca1f..130be89914a8 100644 --- a/packages/SystemUI/res/layout/volume_dialog.xml +++ b/packages/SystemUI/res/layout/volume_dialog.xml @@ -98,5 +98,27 @@ </FrameLayout> </LinearLayout> + <FrameLayout + android:id="@+id/odi_captions" + android:layout_width="@dimen/volume_dialog_caption_size" + android:layout_height="@dimen/volume_dialog_caption_size" + android:layout_marginTop="@dimen/volume_dialog_spacer" + android:translationZ="@dimen/volume_dialog_elevation" + android:layout_gravity="right" + android:clipToPadding="false" + android:visibility="gone" + android:background="@drawable/rounded_bg_full"> + <com.android.keyguard.AlphaOptimizedImageButton + android:id="@+id/odi_captions_icon" + android:src="@drawable/ic_volume_odi_captions_disabled" + style="@style/VolumeButtons" + android:background="@drawable/rounded_ripple" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:tint="@color/accent_tint_color_selector" + android:layout_gravity="center" + android:soundEffectsEnabled="false" /> + </FrameLayout> + </LinearLayout> </FrameLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index c83cb59fa792..b42e5dd33500 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -336,6 +336,8 @@ <dimen name="volume_dialog_ringer_size">64dp</dimen> + <dimen name="volume_dialog_caption_size">64dp</dimen> + <dimen name="volume_dialog_tap_target_size">48dp</dimen> <dimen name="volume_dialog_spacer">4dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 9e9aada07bef..16222f7ebd8d 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1608,7 +1608,7 @@ <string name="inline_silent_button_stay_silent">Stay silent</string> <!-- Notification inline controls: button to make notifications alert the user [CHAR_LIMIT=35] --> - <string name="inline_silent_button_alert">Alert me</string> + <string name="inline_silent_button_alert">Alert</string> <!-- Notification inline controls: button to continue alerting the user when notifications arrive [CHAR_LIMIT=35] --> <string name="inline_silent_button_keep_alerting">Keep alerting</string> @@ -1616,6 +1616,15 @@ <!-- Notification Inline controls: continue receiving notifications prompt, app level --> <string name="inline_keep_showing_app">Keep showing notifications from this app?</string> + <!-- Hint text for block button in the interruptiveness settings [CHAR_LIMIT=NONE]--> + <string name="hint_text_block">Blocked notifications do not appear anywhere or play a sound. You can unblock notifications in settings.</string> + + <!-- Hint text for silent button in the interruptiveness settings [CHAR_LIMIT=NONE]--> + <string name="hint_text_silent">Silent notifications appear in the shade, but do not appear on the lock screen, present a banner, or play a sound.</string> + + <!-- Hint text for alert button in the interruptiveness settings [CHAR_LIMIT=NONE]--> + <string name="hint_text_alert">Alerted notifications appear in the shade, on the lock screen, present a banner, and play a sound.</string> + <!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. --> <string name="notification_unblockable_desc">These notifications can\'t be turned off</string> @@ -2322,9 +2331,6 @@ <!-- Content description for ongoing privacy chip. Use with multiple apps [CHAR LIMIT=NONE]--> <string name="ongoing_privacy_chip_content_multiple_apps">Applications are using your <xliff:g id="types_list" example="camera, location">%s</xliff:g>.</string> - <!-- Ongoing Privacy "Chip" in use text [CHAR LIMIT=10]--> - <string name="ongoing_privacy_chip_in_use">In use:</string> - <!-- Content description for ongoing privacy chip. Use with multiple apps using same app op[CHAR LIMIT=NONE]--> <plurals name="ongoing_privacy_chip_content_multiple_apps_single_op"> <item quantity="one"><xliff:g id="num_apps" example="1">%1$d</xliff:g> application is using your <xliff:g id="type" example="camera">%2$s</xliff:g>.</item> @@ -2359,12 +2365,6 @@ <!-- Text for microphone app op [CHAR LIMIT=20]--> <string name="privacy_type_microphone">microphone</string> - <!-- Text for indicating extra apps using app ops [CHAR LIMIT=NONE] --> - <plurals name="ongoing_privacy_dialog_overflow_text"> - <item quantity="one"><xliff:g id="num_apps" example="1">%d</xliff:g> other app</item> - <item quantity="other"><xliff:g id="num_apps" example="3">%d</xliff:g> other apps</item> - </plurals> - <!-- Text for the quick setting tile for sensor privacy [CHAR LIMIT=30] --> <string name="sensor_privacy_mode">Sensors off</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 4adece9bfb77..0f5df45a0eff 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -444,6 +444,19 @@ <item name="android:alpha">0.54</item> </style> + <style name="TextAppearance.NotificationInfo.ButtonLabel"> + <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item> + <item name="android:textSize">14sp</item> + <item name="android:alpha">0.54</item> + <item name="android:paddingTop">4dp</item> + <item name="android:paddingBottom">16dp</item> + </style> + + <style name="TextAppearance.NotificationInfo.HintText"> + <item name="android:textSize">12sp</item> + <item name="android:alpha">0.54</item> + </style> + <style name="TextAppearance.NotificationInfo.Secondary.Warning"> <item name="android:textColor">?android:attr/colorError</item> </style> diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java index 39a584272585..62b0542bd7fe 100644 --- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java @@ -24,6 +24,8 @@ import static com.android.systemui.util.SysuiLifecycle.viewAttachLifecycle; import static java.lang.annotation.RetentionPolicy.SOURCE; import android.animation.ArgbEvaluator; +import android.animation.LayoutTransition; +import android.animation.ObjectAnimator; import android.annotation.IntDef; import android.app.ActivityManager; import android.content.Context; @@ -141,6 +143,8 @@ public class BatteryMeterView extends LinearLayout implements addOnAttachStateChangeListener( new DisableStateTracker(DISABLE_NONE, DISABLE2_SYSTEM_ICONS)); + setupLayoutTransition(); + mSlotBattery = context.getString( com.android.internal.R.string.status_bar_battery); mBatteryIconView = new ImageView(context); @@ -178,6 +182,21 @@ public class BatteryMeterView extends LinearLayout implements setLayerType(LAYER_TYPE_SOFTWARE, null); } + private void setupLayoutTransition() { + LayoutTransition transition = new LayoutTransition(); + transition.setDuration(200); + + ObjectAnimator appearAnimator = ObjectAnimator.ofFloat(null, "alpha", 0f, 1f); + transition.setAnimator(LayoutTransition.APPEARING, appearAnimator); + transition.setInterpolator(LayoutTransition.APPEARING, Interpolators.ALPHA_IN); + + ObjectAnimator disappearAnimator = ObjectAnimator.ofFloat(null, "alpha", 1f, 0f); + transition.setInterpolator(LayoutTransition.DISAPPEARING, Interpolators.ALPHA_OUT); + transition.setAnimator(LayoutTransition.DISAPPEARING, disappearAnimator); + + setLayoutTransition(transition); + } + public void setForceShowPercent(boolean show) { setPercentShowMode(show ? MODE_ON : MODE_DEFAULT); } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index b2f707f76c10..bc3f48dac769 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -28,6 +28,7 @@ import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.hardware.display.AmbientDisplayConfiguration; +import android.metrics.LogMaker; import android.os.Handler; import android.os.SystemClock; import android.os.UserHandle; @@ -35,7 +36,10 @@ import android.text.format.Formatter; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.Preconditions; +import com.android.systemui.Dependency; import com.android.systemui.dock.DockManager; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.util.Assert; @@ -79,6 +83,7 @@ public class DozeTriggers implements DozeMachine.Part { private long mNotificationPulseTime; private boolean mPulsePending; + private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class); public DozeTriggers(Context context, DozeMachine machine, DozeHost dozeHost, AlarmManager alarmManager, AmbientDisplayConfiguration config, @@ -159,8 +164,15 @@ public class DozeTriggers implements DozeMachine.Part { if (screenX != -1 && screenY != -1) { mDozeHost.onSlpiTap(screenX, screenY); } + // Logs screen wake up reason of either single or double tap. + mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING) + .setType(MetricsEvent.TYPE_UPDATE).setSubtype(pulseReason)); mMachine.wakeUp(); } else if (isPickup) { + // Logs screen wake up reason of lift. + mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING) + .setType(MetricsEvent.TYPE_UPDATE) + .setSubtype(DozeLog.REASON_SENSOR_PICKUP)); mMachine.wakeUp(); } else { mDozeHost.extendPulse(); @@ -298,6 +310,10 @@ public class DozeTriggers implements DozeMachine.Part { continuePulseRequest(reason); } }, !mDozeParameters.getProxCheckBeforePulse() || performedProxCheck, reason); + + // Logs request pulse reason on AOD screen. + mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING) + .setType(MetricsEvent.TYPE_UPDATE).setSubtype(reason)); } private boolean canPulse() { diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt index 84a344648a39..cf170187cdaa 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt @@ -24,6 +24,7 @@ import android.content.res.ColorStateList import android.os.UserHandle import android.provider.Settings import android.util.IconDrawableFactory +import android.util.StatsLog import android.view.Gravity import android.view.LayoutInflater import android.view.View @@ -55,7 +56,13 @@ class OngoingPrivacyDialog constructor( fun createDialog(): Dialog { val builder = AlertDialog.Builder(context).apply { - setPositiveButton(R.string.ongoing_privacy_dialog_ok, null) + setPositiveButton(R.string.ongoing_privacy_dialog_ok, + object : DialogInterface.OnClickListener { + override fun onClick(dialog: DialogInterface?, which: Int) { + StatsLog.write(StatsLog.PRIVACY_INDICATORS_INTERACTED, + StatsLog.PRIVACY_INDICATORS_INTERACTED__TYPE__DIALOG_DISMISS) + } + }) setNeutralButton(R.string.ongoing_privacy_dialog_open_settings, object : DialogInterface.OnClickListener { val intent = Intent(Settings.ACTION_PRIVACY_SETTINGS).putExtra( @@ -63,6 +70,8 @@ class OngoingPrivacyDialog constructor( @Suppress("DEPRECATION") override fun onClick(dialog: DialogInterface?, which: Int) { + StatsLog.write(StatsLog.PRIVACY_INDICATORS_INTERACTED, StatsLog + .PRIVACY_INDICATORS_INTERACTED__TYPE__DIALOG_PRIVACY_SETTINGS) Dependency.get(ActivityStarter::class.java) .postStartActivityDismissingKeyguard(intent, 0) } @@ -136,6 +145,9 @@ class OngoingPrivacyDialog constructor( .putExtra(Intent.EXTRA_PACKAGE_NAME, app.packageName) .putExtra(Intent.EXTRA_USER, UserHandle.getUserHandleForUid(app.uid)) override fun onClick(v: View?) { + StatsLog.write(StatsLog.PRIVACY_INDICATORS_INTERACTED, + StatsLog.PRIVACY_INDICATORS_INTERACTED__TYPE__DIALOG_LINE_ITEM, + app.packageName) Dependency.get(ActivityStarter::class.java) .postStartActivityDismissingKeyguard(intent, 0) dismissDialog?.invoke() diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index b502a952471d..4862b9eddc85 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -41,6 +41,7 @@ import android.text.format.DateUtils; import android.util.AttributeSet; import android.util.Log; import android.util.Pair; +import android.util.StatsLog; import android.view.DisplayCutout; import android.view.View; import android.view.WindowInsets; @@ -156,6 +157,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements } }; private boolean mHasTopCutout = false; + private boolean mPrivacyChipLogged = false; /** * Runnable for automatically fading out the long press tooltip (as if it were animating away). @@ -210,6 +212,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements mPrivacyChip.setOnClickListener(this); mCarrierGroup = findViewById(R.id.carrier_group); + updateResources(); Rect tintArea = new Rect(0, 0, 0, 0); @@ -265,6 +268,13 @@ public class QuickStatusBarHeader extends RelativeLayout implements private void setChipVisibility(boolean chipVisible) { if (chipVisible) { mPrivacyChip.setVisibility(View.VISIBLE); + // Makes sure that the chip is logged as viewed at most once each time QS is opened + // mListening makes sure that the callback didn't return after the user closed QS + if (!mPrivacyChipLogged && mListening) { + mPrivacyChipLogged = true; + StatsLog.write(StatsLog.PRIVACY_INDICATORS_INTERACTED, + StatsLog.PRIVACY_INDICATORS_INTERACTED__TYPE__CHIP_VIEWED); + } } else { mPrivacyChip.setVisibility(View.GONE); } @@ -534,6 +544,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements mAlarmController.removeCallback(this); mPrivacyItemController.removeCallback(mPICCallback); mContext.unregisterReceiver(mRingerReceiver); + mPrivacyChipLogged = false; } } @@ -547,6 +558,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements PrivacyDialogBuilder builder = mPrivacyChip.getBuilder(); if (builder.getAppsAndTypes().size() == 0) return; Handler mUiHandler = new Handler(Looper.getMainLooper()); + StatsLog.write(StatsLog.PRIVACY_INDICATORS_INTERACTED, + StatsLog.PRIVACY_INDICATORS_INTERACTED__TYPE__CHIP_CLICKED); mUiHandler.post(() -> { Dialog mDialog = new OngoingPrivacyDialog(mContext, builder).createDialog(); SystemUIDialog.setShowForAllUsers(mDialog, false); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java index 0b1e9c399410..bdebf79d823b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java @@ -88,7 +88,9 @@ public class CastTile extends QSTileImpl<BooleanState> { @Override public BooleanState newTileState() { - return new BooleanState(); + BooleanState state = new BooleanState(); + state.handlesLongClick = false; + return state; } @Override @@ -116,20 +118,25 @@ public class CastTile extends QSTileImpl<BooleanState> { } @Override + protected void handleLongClick() { + handleClick(); + } + + @Override protected void handleClick() { if (getState().state == Tile.STATE_UNAVAILABLE) { return; } - if (mKeyguard.isSecure() && !mKeyguard.canSkipBouncer()) { - mActivityStarter.postQSRunnableDismissingKeyguard(() -> { - showDetail(true); - }); - return; - } CastDevice activeProjection = getActiveDeviceMediaProjection(); if (activeProjection == null) { - showDetail(true); + if (mKeyguard.isSecure() && !mKeyguard.canSkipBouncer()) { + mActivityStarter.postQSRunnableDismissingKeyguard(() -> { + showDetail(true); + }); + } else { + showDetail(true); + } } else { mController.stopCasting(activeProjection); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java index b7e07f828321..5e6f18e511d9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java @@ -20,14 +20,12 @@ import android.annotation.Nullable; import android.content.ComponentName; import android.content.Intent; import android.os.UserManager; -import android.provider.Settings.Global; import android.service.quicksettings.Tile; import android.widget.Switch; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; -import com.android.systemui.plugins.qs.QSTile.AirplaneBooleanState; -import com.android.systemui.qs.GlobalSetting; +import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.DataSaverController; @@ -36,7 +34,7 @@ import com.android.systemui.statusbar.policy.HotspotController; import javax.inject.Inject; /** Quick settings tile: Hotspot **/ -public class HotspotTile extends QSTileImpl<AirplaneBooleanState> { +public class HotspotTile extends QSTileImpl<BooleanState> { private static final Intent TETHER_SETTINGS = new Intent().setComponent(new ComponentName( "com.android.settings", "com.android.settings.TetherSettings")); @@ -46,7 +44,6 @@ public class HotspotTile extends QSTileImpl<AirplaneBooleanState> { private final DataSaverController mDataSaverController; private final HotspotAndDataSaverCallbacks mCallbacks = new HotspotAndDataSaverCallbacks(); - private final GlobalSetting mAirplaneMode; private boolean mListening; @Inject @@ -55,12 +52,6 @@ public class HotspotTile extends QSTileImpl<AirplaneBooleanState> { super(host); mHotspotController = hotspotController; mDataSaverController = dataSaverController; - mAirplaneMode = new GlobalSetting(mContext, mHandler, Global.AIRPLANE_MODE_ON) { - @Override - protected void handleValueChanged(int value) { - refreshState(); - } - }; mHotspotController.observe(this, mCallbacks); mDataSaverController.observe(this, mCallbacks); } @@ -76,18 +67,12 @@ public class HotspotTile extends QSTileImpl<AirplaneBooleanState> { } @Override - public AirplaneBooleanState newTileState() { - return new AirplaneBooleanState(); - } - - @Override public void handleSetListening(boolean listening) { if (mListening == listening) return; mListening = listening; if (listening) { refreshState(); } - mAirplaneMode.setListening(listening); } @Override @@ -96,10 +81,14 @@ public class HotspotTile extends QSTileImpl<AirplaneBooleanState> { } @Override + public BooleanState newTileState() { + return new BooleanState(); + } + + @Override protected void handleClick() { final boolean isEnabled = mState.value; - if (!isEnabled && - (mAirplaneMode.getValue() != 0 || mDataSaverController.isDataSaverEnabled())) { + if (!isEnabled && mDataSaverController.isDataSaverEnabled()) { return; } // Immediately enter transient enabling state when turning hotspot on. @@ -113,7 +102,7 @@ public class HotspotTile extends QSTileImpl<AirplaneBooleanState> { } @Override - protected void handleUpdateState(AirplaneBooleanState state, Object arg) { + protected void handleUpdateState(BooleanState state, Object arg) { final boolean transientEnabling = arg == ARG_SHOW_TRANSIENT_ENABLING; if (state.slash == null) { state.slash = new SlashState(); @@ -138,7 +127,6 @@ public class HotspotTile extends QSTileImpl<AirplaneBooleanState> { state.icon = mEnabledStatic; state.label = mContext.getString(R.string.quick_settings_hotspot_label); - state.isAirplaneMode = mAirplaneMode.getValue() != 0; state.isTransient = isTransient; state.slash.isSlashed = !state.value && !state.isTransient; if (state.isTransient) { @@ -147,7 +135,7 @@ public class HotspotTile extends QSTileImpl<AirplaneBooleanState> { state.expandedAccessibilityClassName = Switch.class.getName(); state.contentDescription = state.label; - final boolean isTileUnavailable = (state.isAirplaneMode || isDataSaverEnabled); + final boolean isTileUnavailable = isDataSaverEnabled; final boolean isTileActive = (state.value || state.isTransient); if (isTileUnavailable) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java index 37237317fc95..2e4325b2f41f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java @@ -17,7 +17,6 @@ package com.android.systemui.statusbar.notification.row; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; -import static android.app.NotificationManager.IMPORTANCE_HIGH; import static android.app.NotificationManager.IMPORTANCE_LOW; import static android.app.NotificationManager.IMPORTANCE_MIN; import static android.app.NotificationManager.IMPORTANCE_NONE; @@ -38,6 +37,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.graphics.Color; import android.graphics.drawable.Drawable; import android.metrics.LogMaker; import android.os.Handler; @@ -81,10 +81,11 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } public static final int ACTION_NONE = 0; - public static final int ACTION_UNDO = 1; - public static final int ACTION_TOGGLE_SILENT = 2; - public static final int ACTION_BLOCK = 3; - public static final int ACTION_DELIVER_SILENTLY = 4; + static final int ACTION_UNDO = 1; + static final int ACTION_TOGGLE_SILENT = 2; + static final int ACTION_BLOCK = 3; + static final int ACTION_DELIVER_SILENTLY = 4; + private static final int ACTION_ALERT = 5; private INotificationManager mINotificationManager; private PackageManager mPm; @@ -98,6 +99,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G private NotificationChannel mSingleNotificationChannel; private int mStartingChannelImportance; private boolean mWasShownHighPriority; + private int mNotificationBlockState = ACTION_NONE; /** * The last importance level chosen by the user. Null if the user has not chosen an importance * level; non-null once the user takes an action which indicates an explicit preference. @@ -117,7 +119,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G /** Whether this view is being shown as part of the blocking helper. */ private boolean mIsForBlockingHelper; - private boolean mNegativeUserSentiment; /** * String that describes how the user exit or quit out of this view, also used as a counter tag. @@ -126,8 +127,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G private OnClickListener mOnKeepShowing = v -> { mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING; - closeControls(v); if (mIsForBlockingHelper) { + closeControls(v); mMetricsLogger.write(getLogMaker().setCategory( MetricsEvent.NOTIFICATION_BLOCKING_HELPER) .setType(MetricsEvent.TYPE_ACTION) @@ -135,23 +136,36 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } }; - private OnClickListener mOnToggleSilent = v -> { - handleSaveImportance(ACTION_TOGGLE_SILENT, MetricsEvent.BLOCKING_HELPER_CLICK_ALERT_ME); + private OnClickListener mOnAlert = v -> { + mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING; + mChosenImportance = IMPORTANCE_DEFAULT; + updateButtonsAndHelpText(ACTION_ALERT); + }; + + private OnClickListener mOnDismissSettings = v -> { + closeControls(v); }; private OnClickListener mOnDeliverSilently = v -> { handleSaveImportance( ACTION_DELIVER_SILENTLY, MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT); + if (!mIsForBlockingHelper) { + updateButtonsAndHelpText(ACTION_DELIVER_SILENTLY); + } }; private OnClickListener mOnStopOrMinimizeNotifications = v -> { handleSaveImportance(ACTION_BLOCK, MetricsEvent.BLOCKING_HELPER_CLICK_BLOCKED); + if (!mIsForBlockingHelper) { + updateButtonsAndHelpText(ACTION_BLOCK); + } }; private void handleSaveImportance(int action, int metricsSubtype) { Runnable saveImportance = () -> { - swapContent(action, true /* animate */); + saveImportanceAndExitReason(action); if (mIsForBlockingHelper) { + swapContent(action, true /* animate */); mMetricsLogger.write(getLogMaker() .setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER) .setType(MetricsEvent.TYPE_ACTION) @@ -177,6 +191,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } else { mMetricsLogger.write(importanceChangeLogMaker().setType(MetricsEvent.TYPE_DISMISS)); } + saveImportanceAndExitReason(ACTION_UNDO); swapContent(ACTION_UNDO, true /* animate */); }; @@ -252,7 +267,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G mSingleNotificationChannel = notificationChannel; mStartingChannelImportance = mSingleNotificationChannel.getImportance(); mWasShownHighPriority = wasShownHighPriority; - mNegativeUserSentiment = isUserSentimentNegative; mIsNonblockable = isNonblockable; mIsForeground = (mSbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0; @@ -329,14 +343,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G bindGroup(); if (mIsNonblockable) { blockPrompt.setText(R.string.notification_unblockable_desc); - } else { - if (mNegativeUserSentiment) { - blockPrompt.setText(R.string.inline_blocking_helper); - } else if (mIsSingleDefaultChannel || mNumUniqueChannelsInRow > 1) { - blockPrompt.setText(R.string.inline_keep_showing_app); - } else { - blockPrompt.setText(R.string.inline_keep_showing); - } } } @@ -403,6 +409,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } } + @VisibleForTesting void logBlockingHelperCounter(String counterTag) { if (mIsForBlockingHelper) { @@ -454,21 +461,20 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G if (showInterruptivenessSettings) { findViewById(R.id.block_or_minimize).setVisibility(GONE); findViewById(R.id.interruptiveness_settings).setVisibility(VISIBLE); - View block = findViewById(R.id.int_block); - TextView silent = findViewById(R.id.int_silent); - TextView alert = findViewById(R.id.int_alert); - + View done = findViewById(R.id.done_button); + done.setOnClickListener(mOnDismissSettings); + View block = findViewById(R.id.int_block_wrapper); + View silent = findViewById(R.id.int_silent_wrapper); + View alert = findViewById(R.id.int_alert_wrapper); block.setOnClickListener(mOnStopOrMinimizeNotifications); - if (mWasShownHighPriority) { - silent.setOnClickListener(mOnToggleSilent); - silent.setText(R.string.inline_silent_button_silent); - alert.setOnClickListener(mOnKeepShowing); - alert.setText(R.string.inline_silent_button_keep_alerting); + silent.setOnClickListener(mOnDeliverSilently); + alert.setOnClickListener(mOnAlert); + if (mNotificationBlockState != ACTION_NONE) { + updateButtonsAndHelpText(mNotificationBlockState); + } else if (mWasShownHighPriority) { + updateButtonsAndHelpText(ACTION_ALERT); } else { - silent.setOnClickListener(mOnKeepShowing); - silent.setText(R.string.inline_silent_button_stay_silent); - alert.setOnClickListener(mOnToggleSilent); - alert.setText(R.string.inline_silent_button_alert); + updateButtonsAndHelpText(ACTION_DELIVER_SILENTLY); } } else { findViewById(R.id.block_or_minimize).setVisibility(VISIBLE); @@ -515,6 +521,73 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } } + private void updateButtonsAndHelpText(int blockState) { + mNotificationBlockState = blockState; + ImageView block = findViewById(R.id.int_block); + ImageView silent = findViewById(R.id.int_silent); + ImageView alert = findViewById(R.id.int_alert); + TextView hintText = findViewById(R.id.hint_text); + switch (blockState) { + case ACTION_BLOCK: + block.setBackgroundResource(R.drawable.circle_blue_40dp); + block.setColorFilter(Color.WHITE); + silent.setBackgroundResource(R.drawable.circle_white_40dp); + silent.setColorFilter(getResources().getColor(R.color.GM2_grey_400)); + alert.setBackgroundResource(R.drawable.circle_white_40dp); + alert.setColorFilter(getResources().getColor(R.color.GM2_grey_400)); + hintText.setText(R.string.hint_text_block); + break; + case ACTION_DELIVER_SILENTLY: + silent.setBackgroundResource(R.drawable.circle_blue_40dp); + silent.setColorFilter(Color.WHITE); + block.setBackgroundResource(R.drawable.circle_white_40dp); + block.setColorFilter(getResources().getColor(R.color.GM2_grey_400)); + alert.setBackgroundResource(R.drawable.circle_white_40dp); + alert.setColorFilter(getResources().getColor(R.color.GM2_grey_400)); + hintText.setText(R.string.hint_text_silent); + break; + case ACTION_ALERT: + alert.setBackgroundResource(R.drawable.circle_blue_40dp); + alert.setColorFilter(Color.WHITE); + block.setBackgroundResource(R.drawable.circle_white_40dp); + block.setColorFilter(getResources().getColor(R.color.GM2_grey_400)); + silent.setBackgroundResource(R.drawable.circle_white_40dp); + silent.setColorFilter(getResources().getColor(R.color.GM2_grey_400)); + hintText.setText(R.string.hint_text_alert); + break; + } + } + + private void saveImportanceAndExitReason(@NotificationInfoAction int action) { + switch (action) { + case ACTION_UNDO: + mChosenImportance = mStartingChannelImportance; + break; + case ACTION_DELIVER_SILENTLY: + mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY; + mChosenImportance = IMPORTANCE_LOW; + break; + case ACTION_TOGGLE_SILENT: + mExitReason = NotificationCounters.BLOCKING_HELPER_TOGGLE_SILENT; + if (mWasShownHighPriority) { + mChosenImportance = IMPORTANCE_LOW; + } else { + mChosenImportance = IMPORTANCE_DEFAULT; + } + break; + case ACTION_BLOCK: + mExitReason = NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS; + if (mIsForeground) { + mChosenImportance = IMPORTANCE_MIN; + } else { + mChosenImportance = IMPORTANCE_NONE; + } + break; + default: + throw new IllegalArgumentException(); + } + } + private void swapContent(@NotificationInfoAction int action, boolean animate) { if (mExpandAnimation != null) { mExpandAnimation.cancel(); @@ -525,32 +598,25 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G TextView confirmationText = findViewById(R.id.confirmation_text); View header = findViewById(R.id.header); + saveImportanceAndExitReason(action); + switch (action) { case ACTION_UNDO: - mChosenImportance = mStartingChannelImportance; break; case ACTION_DELIVER_SILENTLY: - mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY; - mChosenImportance = IMPORTANCE_LOW; confirmationText.setText(R.string.notification_channel_silenced); break; case ACTION_TOGGLE_SILENT: - mExitReason = NotificationCounters.BLOCKING_HELPER_TOGGLE_SILENT; if (mWasShownHighPriority) { - mChosenImportance = IMPORTANCE_LOW; confirmationText.setText(R.string.notification_channel_silenced); } else { - mChosenImportance = IMPORTANCE_DEFAULT; confirmationText.setText(R.string.notification_channel_unsilenced); } break; case ACTION_BLOCK: - mExitReason = NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS; if (mIsForeground) { - mChosenImportance = IMPORTANCE_MIN; confirmationText.setText(R.string.notification_channel_minimized); } else { - mChosenImportance = IMPORTANCE_NONE; confirmationText.setText(R.string.notification_channel_disabled); } break; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java index 409d60fa6c17..2d54970cdfa8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java @@ -16,203 +16,159 @@ package com.android.systemui.statusbar.phone; +import static android.view.Display.DEFAULT_DISPLAY; + import android.content.Context; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; -import android.graphics.Color; import android.graphics.Rect; import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; import android.provider.Settings; -import android.util.DisplayMetrics; -import android.view.SurfaceControl; +import android.view.CompositionSamplingListener; import android.view.View; -import com.android.systemui.R; +import java.io.PrintWriter; + +/** + * Updates the nav bar tint based on the color of the content behind the nav bar. + */ +public class NavBarTintController implements View.OnAttachStateChangeListener, + View.OnLayoutChangeListener { -public class NavBarTintController { public static final int MIN_COLOR_ADAPT_TRANSITION_TIME = 400; public static final int DEFAULT_COLOR_ADAPT_TRANSITION_TIME = 1700; - private final HandlerThread mColorAdaptHandlerThread = new HandlerThread("ColorExtractThread"); - private Handler mColorAdaptionHandler; - - // Poll time for each iteration to color sample - private static final int COLOR_ADAPTION_TIMEOUT = 300; - // Passing the threshold of this luminance value will make the button black otherwise white private static final float LUMINANCE_THRESHOLD = 0.3f; - // The margin from the bounds of the view to color sample around - private static final int COLOR_SAMPLE_MARGIN = 10; - - private boolean mRunning; - + private final Handler mHandler = new Handler(); private final NavigationBarView mNavigationBarView; private final LightBarTransitionsController mLightBarController; - private final Handler mMainHandler = new Handler(Looper.getMainLooper()); - private final int mBarRadius; - private final int mBarBottom; + + private final CompositionSamplingListener mSamplingListener; + private final Runnable mUpdateSamplingListener = this::updateSamplingListener; + private final Rect mSamplingBounds = new Rect(); + private boolean mSamplingEnabled = false; + private boolean mSamplingListenerRegistered = false; + + private float mLastMediaLuma; + private boolean mUpdateOnNextDraw; public NavBarTintController(NavigationBarView navigationBarView, LightBarTransitionsController lightBarController) { + mSamplingListener = new CompositionSamplingListener( + navigationBarView.getContext().getMainExecutor()) { + @Override + public void onSampleCollected(float medianLuma) { + updateTint(medianLuma); + } + }; mNavigationBarView = navigationBarView; + mNavigationBarView.addOnAttachStateChangeListener(this); + mNavigationBarView.addOnLayoutChangeListener(this); mLightBarController = lightBarController; + } - final Resources res = navigationBarView.getResources(); - mBarRadius = res.getDimensionPixelSize(R.dimen.navigation_handle_radius); - mBarBottom = res.getDimensionPixelSize(R.dimen.navigation_handle_bottom); + void onDraw() { + if (mUpdateOnNextDraw) { + mUpdateOnNextDraw = false; + requestUpdateSamplingListener(); + } } - public void start() { + void start() { if (!isEnabled(mNavigationBarView.getContext())) { return; } - if (mColorAdaptionHandler == null) { - mColorAdaptHandlerThread.start(); - mColorAdaptionHandler = new Handler(mColorAdaptHandlerThread.getLooper()); - } - mColorAdaptionHandler.removeCallbacksAndMessages(null); - mColorAdaptionHandler.post(this::updateTint); - mRunning = true; + mSamplingEnabled = true; + // Defer calling updateSamplingListener since we may have just reinflated prior to this + requestUpdateSamplingListener(); } - public void end() { - if (mColorAdaptionHandler != null) { - mColorAdaptionHandler.removeCallbacksAndMessages(null); - } - mRunning = false; + void stop() { + mSamplingEnabled = false; + requestUpdateSamplingListener(); } - public void stop() { - end(); - if (mColorAdaptionHandler != null) { - mColorAdaptHandlerThread.quitSafely(); - } + @Override + public void onViewAttachedToWindow(View view) { + requestUpdateSamplingListener(); + } + + @Override + public void onViewDetachedFromWindow(View view) { + // Defer calling updateSamplingListener the attach info has not yet been reset + requestUpdateSamplingListener(); } - private void updateTint() { - int[] navPos = new int[2]; - int[] butPos = new int[2]; + @Override + public void onLayoutChange(View v, int left, int top, int right, int bottom, + int oldLeft, int oldTop, int oldRight, int oldBottom) { + mSamplingBounds.setEmpty(); + // TODO: Extend this to 2/3 button layout as well View view = mNavigationBarView.getHomeHandle().getCurrentView(); - if (view == null) { - return; + if (view != null) { + int[] pos = new int[2]; + view.getLocationOnScreen(pos); + final Rect samplingBounds = new Rect(pos[0], pos[1], + pos[0] + view.getWidth(), pos[1] + view.getHeight()); + if (!samplingBounds.equals(mSamplingBounds)) { + mSamplingBounds.set(samplingBounds); + requestUpdateSamplingListener(); + } } + } - // Determine the area of the icon within its view bounds - view.getLocationInSurface(butPos); - final int navWidth = view.getWidth(); - final int navHeight = view.getHeight(); - int viewBottom = butPos[1] + navHeight - mBarBottom; - final Rect viewIconRect = new Rect(butPos[0], viewBottom - mBarRadius * 2, - butPos[0] + navWidth, viewBottom); + private void requestUpdateSamplingListener() { + mHandler.removeCallbacks(mUpdateSamplingListener); + mHandler.post(mUpdateSamplingListener); + } - if (mNavigationBarView.getCurrentView() == null || viewIconRect.isEmpty()) { - scheduleColorAdaption(); - return; + private void updateSamplingListener() { + if (mSamplingListenerRegistered) { + mSamplingListenerRegistered = false; + CompositionSamplingListener.unregister(mSamplingListener); } - mNavigationBarView.getCurrentView().getLocationOnScreen(navPos); - viewIconRect.offset(navPos[0], navPos[1]); - - // Apply a margin area around the button region to sample the colors, crop from screenshot - final Rect cropRect = new Rect(viewIconRect); - cropRect.inset(-COLOR_SAMPLE_MARGIN, -COLOR_SAMPLE_MARGIN); - if (cropRect.isEmpty()) { - scheduleColorAdaption(); - return; - } - - // Determine the size of the home area - Rect homeArea = new Rect(COLOR_SAMPLE_MARGIN, COLOR_SAMPLE_MARGIN, - viewIconRect.width() + COLOR_SAMPLE_MARGIN, - viewIconRect.height() + COLOR_SAMPLE_MARGIN); - - // Get the screenshot around the home button icon to determine the color - DisplayMetrics mDisplayMetrics = new DisplayMetrics(); - mNavigationBarView.getContext().getDisplay().getRealMetrics(mDisplayMetrics); - final Bitmap hardBitmap = SurfaceControl - .screenshot(new Rect(), mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels, - mNavigationBarView.getContext().getDisplay().getRotation()); - if (hardBitmap != null && cropRect.bottom <= hardBitmap.getHeight() - && cropRect.left + cropRect.width() <= hardBitmap.getWidth()) { - final Bitmap cropBitmap = Bitmap.createBitmap(hardBitmap, cropRect.left, cropRect.top, - cropRect.width(), cropRect.height()); - final Bitmap softBitmap = cropBitmap.copy(Config.ARGB_8888, false); - - // Get the luminance value to determine if the home button should be black or white - final int[] pixels = new int[softBitmap.getByteCount() / 4]; - softBitmap.getPixels(pixels, 0, softBitmap.getWidth(), 0, 0, softBitmap.getWidth(), - softBitmap.getHeight()); - float r = 0, g = 0, blue = 0; - - int width = cropRect.width(); - int total = 0; - for (int i = 0; i < pixels.length; i += 4) { - int x = i % width; - int y = i / width; - if (!homeArea.contains(x, y)) { - r += Color.red(pixels[i]); - g += Color.green(pixels[i]); - blue += Color.blue(pixels[i]); - total++; - } - } - - r /= total; - g /= total; - blue /= total; - - r = Math.max(Math.min(r / 255f, 1), 0); - g = Math.max(Math.min(g / 255f, 1), 0); - blue = Math.max(Math.min(blue / 255f, 1), 0); - - if (r <= 0.03928) { - r /= 12.92; - } else { - r = (float) Math.pow((r + 0.055) / 1.055, 2.4); - } - if (g <= 0.03928) { - g /= 12.92; - } else { - g = (float) Math.pow((g + 0.055) / 1.055, 2.4); + if (mSamplingEnabled && !mSamplingBounds.isEmpty() + && mNavigationBarView.isAttachedToWindow()) { + if (!mNavigationBarView.getViewRootImpl().getSurfaceControl().isValid()) { + // The view may still be attached, but the surface backing the window can be + // destroyed, so wait until the next draw to update the listener again + mUpdateOnNextDraw = true; + return; } - if (blue <= 0.03928) { - blue /= 12.92; - } else { - blue = (float) Math.pow((blue + 0.055) / 1.055, 2.4); - } - - if (r * 0.2126 + g * 0.7152 + blue * 0.0722 > LUMINANCE_THRESHOLD) { - // Black - mMainHandler.post( - () -> mLightBarController - .setIconsDark(true /* dark */, true /* animate */)); - } else { - // White - mMainHandler.post( - () -> mLightBarController - .setIconsDark(false /* dark */, true /* animate */)); - } - cropBitmap.recycle(); - hardBitmap.recycle(); + mSamplingListenerRegistered = true; + CompositionSamplingListener.register(mSamplingListener, DEFAULT_DISPLAY, + mNavigationBarView.getViewRootImpl().getSurfaceControl().getHandle(), + mSamplingBounds); } - scheduleColorAdaption(); } - private void scheduleColorAdaption() { - mColorAdaptionHandler.removeCallbacksAndMessages(null); - if (!mRunning || !isEnabled(mNavigationBarView.getContext())) { - return; + private void updateTint(float medianLuma) { + mLastMediaLuma = medianLuma; + if (medianLuma > LUMINANCE_THRESHOLD) { + // Black + mLightBarController.setIconsDark(true /* dark */, true /* animate */); + } else { + // White + mLightBarController.setIconsDark(false /* dark */, true /* animate */); } - mColorAdaptionHandler.postDelayed(this::updateTint, COLOR_ADAPTION_TIMEOUT); + } + + void dump(PrintWriter pw) { + pw.println("NavBarTintController:"); + pw.println(" navBar isAttached: " + mNavigationBarView.isAttachedToWindow()); + pw.println(" navBar isScValid: " + (mNavigationBarView.isAttachedToWindow() + ? mNavigationBarView.getViewRootImpl().getSurfaceControl().isValid() + : "false")); + pw.println(" mSamplingListenerRegistered: " + mSamplingListenerRegistered); + pw.println(" mSamplingBounds: " + mSamplingBounds); + pw.println(" mLastMediaLuma: " + mLastMediaLuma); } public static boolean isEnabled(Context context) { - return Settings.Global.getInt(context.getContentResolver(), - NavigationPrototypeController.NAV_COLOR_ADAPT_ENABLE_SETTING, 0) == 1 - && Settings.Global.getInt(context.getContentResolver(), - NavigationPrototypeController.SHOW_HOME_HANDLE_SETTING, 0) == 1; + return context.getDisplayId() == DEFAULT_DISPLAY + && Settings.Global.getInt(context.getContentResolver(), + NavigationPrototypeController.NAV_COLOR_ADAPT_ENABLE_SETTING, 0) == 1 + && Settings.Global.getInt(context.getContentResolver(), + NavigationPrototypeController.SHOW_HOME_HANDLE_SETTING, 0) == 1; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index b68c7c679d1c..09789019d6ef 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -991,7 +991,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } } else { // Screen off disable it - mNavigationBarView.getColorAdaptionController().end(); + mNavigationBarView.getColorAdaptionController().stop(); } } if (Intent.ACTION_USER_SWITCHED.equals(action)) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index b540fb49af01..a64ff0fce73c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -333,7 +333,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav if (enabled) { mColorAdaptionController.start(); } else { - mColorAdaptionController.end(); + mColorAdaptionController.stop(); } } @@ -486,6 +486,12 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav } } + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + mColorAdaptionController.onDraw(); + } + private void updateNavigationGestures() { if (mGestureHelper instanceof QuickStepController) { final int[] assignedMap = mPrototypeController.getGestureActionMap(); @@ -990,7 +996,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav if (visible) { mColorAdaptionController.start(); } else { - mColorAdaptionController.end(); + mColorAdaptionController.stop(); } } @@ -1244,7 +1250,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { mColorAdaptionController.start(); } else { - mColorAdaptionController.end(); + mColorAdaptionController.stop(); } } @@ -1330,7 +1336,6 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav Dependency.get(PluginManager.class).addPluginListener(this, NavGesture.class, false /* Only one */); setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled()); - mColorAdaptionController.start(); if (mPrototypeController.isEnabled()) { WindowManager wm = (WindowManager) getContext() @@ -1363,7 +1368,6 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav mGestureHelper.destroy(); } mPrototypeController.unregister(); - mColorAdaptionController.stop(); setUpSwipeUpOnboarding(false); for (int i = 0; i < mButtonDispatchers.size(); ++i) { mButtonDispatchers.valueAt(i).onDestroy(); @@ -1454,6 +1458,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav mGestureHelper.dump(pw); } mRecentsOnboarding.dump(pw); + mColorAdaptionController.dump(pw); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java index 0461057bf2e9..d1a225320eb7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java @@ -26,8 +26,10 @@ import android.database.ContentObserver; import android.provider.Settings; import android.util.ArrayMap; import android.util.Log; +import android.view.accessibility.AccessibilityManager; import com.android.internal.logging.MetricsLogger; +import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.statusbar.AlertingNotificationManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -55,9 +57,11 @@ public abstract class HeadsUpManager extends AlertingNotificationManager { protected int mUser; private final ArrayMap<String, Long> mSnoozedPackages; + private final AccessibilityManagerWrapper mAccessibilityMgr; public HeadsUpManager(@NonNull final Context context) { mContext = context; + mAccessibilityMgr = Dependency.get(AccessibilityManagerWrapper.class); Resources resources = context.getResources(); mMinimumDisplayTime = resources.getInteger(R.integer.heads_up_notification_minimum_time); mAutoDismissNotificationDecay = resources.getInteger(R.integer.heads_up_notification_decay); @@ -409,5 +413,22 @@ public abstract class HeadsUpManager extends AlertingNotificationManager { // The actual post time will be just after the heads-up really slided in return super.calculatePostTime() + mTouchAcceptanceDelay; } + + @Override + protected long calculateFinishTime() { + return mPostTime + getRecommendedTimeoutMillis(); + } + + /** + * Get user-preferred or default timeout duration. The larger one will be returned. + * @return milliseconds before auto-dismiss + */ + private int getRecommendedTimeoutMillis() { + return mAccessibilityMgr.getRecommendedTimeoutMillis( + mAutoDismissNotificationDecay, + AccessibilityManager.FLAG_CONTENT_CONTROLS + | AccessibilityManager.FLAG_CONTENT_ICONS + | AccessibilityManager.FLAG_CONTENT_TEXT); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index f79ad71a114f..f4d623770c57 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -21,7 +21,9 @@ import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT; import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE; import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT; +import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE; +import static com.android.internal.telephony.PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM; import static com.android.systemui.Dependency.BG_LOOPER_NAME; import android.content.BroadcastReceiver; @@ -41,6 +43,7 @@ import android.os.Looper; import android.os.PersistableBundle; import android.provider.Settings; import android.telephony.CarrierConfigManager; +import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.SubscriptionInfo; @@ -107,6 +110,16 @@ public class NetworkControllerImpl extends BroadcastReceiver private final CurrentUserTracker mUserTracker; private Config mConfig; + private PhoneStateListener mPhoneStateListener = new PhoneStateListener() { + @Override + public void onActiveDataSubscriptionIdChanged(int subId) { + mActiveMobileDataSubscription = subId; + doUpdateMobileControllers(); + } + }; + + private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + // Subcontrollers. @VisibleForTesting final WifiSignalController mWifiSignalController; @@ -281,6 +294,7 @@ public class NetworkControllerImpl extends BroadcastReceiver mSubscriptionListener = new SubListener(); } mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener); + mPhone.listen(mPhoneStateListener, LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE); // broadcasts IntentFilter filter = new IntentFilter(); @@ -525,6 +539,7 @@ public class NetworkControllerImpl extends BroadcastReceiver @VisibleForTesting void handleConfigurationChanged() { + updateMobileControllers(); for (int i = 0; i < mMobileSignalControllers.size(); i++) { MobileSignalController controller = mMobileSignalControllers.valueAt(i); controller.setConfiguration(mConfig); @@ -539,13 +554,39 @@ public class NetworkControllerImpl extends BroadcastReceiver doUpdateMobileControllers(); } + private void filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions) { + if (subscriptions.size() == MAX_PHONE_COUNT_DUAL_SIM) { + SubscriptionInfo info1 = subscriptions.get(0); + SubscriptionInfo info2 = subscriptions.get(1); + if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) { + // If both subscriptions are primary, show both. + if (!info1.isOpportunistic() && !info2.isOpportunistic()) return; + + // If carrier required, always show signal bar of primary subscription. + // Otherwise, show whichever subscription is currently active for Internet. + boolean alwaysShowPrimary = CarrierConfigManager.getDefaultConfig() + .getBoolean(CarrierConfigManager + .KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN); + if (alwaysShowPrimary) { + subscriptions.remove(info1.isOpportunistic() ? info1 : info2); + } else { + subscriptions.remove(info1.getSubscriptionId() == mActiveMobileDataSubscription + ? info2 : info1); + } + } + } + } + @VisibleForTesting void doUpdateMobileControllers() { List<SubscriptionInfo> subscriptions = mSubscriptionManager - .getActiveSubscriptionInfoList(true); + .getActiveSubscriptionInfoList(false); if (subscriptions == null) { subscriptions = Collections.emptyList(); } + + filterMobileSubscriptionInSameGroup(subscriptions); + // If there have been no relevant changes to any of the subscriptions, we can leave as is. if (hasCorrectMobileControllers(subscriptions)) { // Even if the controllers are correct, make sure we have the right no sims state. diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java index 1596ddbafda0..6e740b8536b3 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/Events.java +++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java @@ -55,6 +55,7 @@ public class Events { public static final int EVENT_RINGER_TOGGLE = 18; // (ringer_mode) public static final int EVENT_SHOW_USB_OVERHEAT_ALARM = 19; // (reason|int) (keyguard|bool) public static final int EVENT_DISMISS_USB_OVERHEAT_ALARM = 20; // (reason|int) (keyguard|bool) + public static final int EVENT_ODI_CAPTIONS_CLICK = 21; private static final String[] EVENT_TAGS = { "show_dialog", @@ -77,7 +78,8 @@ public class Events { "zen_mode_config_changed", "ringer_toggle", "show_usb_overheat_alarm", - "dismiss_usb_overheat_alarm" + "dismiss_usb_overheat_alarm", + "odi_captions_click" }; public static final int DISMISS_REASON_UNKNOWN = 0; @@ -90,6 +92,7 @@ public class Events { public static final int DISMISS_STREAM_GONE = 7; public static final int DISMISS_REASON_OUTPUT_CHOOSER = 8; public static final int DISMISS_REASON_USB_OVERHEAD_ALARM_CHANGED = 9; + public static final int DISMISS_REASON_ODI_CAPTIONS_CLICKED = 10; public static final String[] DISMISS_REASONS = { "unknown", "touch_outside", @@ -100,7 +103,8 @@ public class Events { "done_clicked", "a11y_stream_changed", "output_chooser", - "usb_temperature_below_threshold" + "usb_temperature_below_threshold", + "odi_captions_clicked" }; public static final int SHOW_REASON_UNKNOWN = 0; diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java index 4c16297154f3..9192a25dcd3b 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java @@ -48,6 +48,7 @@ import android.os.Vibrator; import android.provider.Settings; import android.service.notification.Condition; import android.service.notification.ZenModeConfig; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import android.view.accessibility.AccessibilityManager; @@ -270,6 +271,22 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa mWorker.sendEmptyMessage(W.GET_STATE); } + public boolean areCaptionsEnabled() { + int currentValue = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.ODI_CAPTIONS_ENABLED, 0); + return currentValue == 1; + } + + public void setCaptionsEnabled(boolean isEnabled) { + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.ODI_CAPTIONS_ENABLED, isEnabled ? 1 : 0); + } + + public void getCaptionsComponentState() { + if (mDestroyed) return; + mWorker.sendEmptyMessage(W.GET_CAPTIONS_COMPONENT_STATE); + } + public void notifyVisible(boolean visible) { if (mDestroyed) return; mWorker.obtainMessage(W.NOTIFY_VISIBLE, visible ? 1 : 0, 0).sendToTarget(); @@ -365,6 +382,38 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa } } + private void onGetCaptionsComponentStateW() { + try { + String componentNameString = mContext.getString( + com.android.internal.R.string.config_defaultSystemCaptionsService); + if (TextUtils.isEmpty(componentNameString)) { + // component doesn't exist + mCallbacks.onCaptionComponentStateChanged(false); + return; + } + + if (D.BUG) { + Log.i(TAG, String.format( + "isCaptionsServiceEnabled componentNameString=%s", componentNameString)); + } + + ComponentName componentName = ComponentName.unflattenFromString(componentNameString); + if (componentName == null) { + mCallbacks.onCaptionComponentStateChanged(false); + return; + } + + PackageManager packageManager = mContext.getPackageManager(); + mCallbacks.onCaptionComponentStateChanged( + packageManager.getComponentEnabledSetting(componentName) + == PackageManager.COMPONENT_ENABLED_STATE_ENABLED); + } catch (Exception ex) { + Log.e(TAG, + "isCaptionsServiceEnabled failed to check for captions component", ex); + mCallbacks.onCaptionComponentStateChanged(false); + } + } + private void onAccessibilityModeChanged(Boolean showA11yStream) { mCallbacks.onAccessibilityModeChanged(showA11yStream); } @@ -718,6 +767,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa private static final int USER_ACTIVITY = 13; private static final int SHOW_SAFETY_WARNING = 14; private static final int ACCESSIBILITY_MODE_CHANGED = 15; + private static final int GET_CAPTIONS_COMPONENT_STATE = 16; W(Looper looper) { super(looper); @@ -740,8 +790,8 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa case NOTIFY_VISIBLE: onNotifyVisibleW(msg.arg1 != 0); break; case USER_ACTIVITY: onUserActivityW(); break; case SHOW_SAFETY_WARNING: onShowSafetyWarningW(msg.arg1); break; + case GET_CAPTIONS_COMPONENT_STATE: onGetCaptionsComponentStateW(); break; case ACCESSIBILITY_MODE_CHANGED: onAccessibilityModeChanged((Boolean) msg.obj); - } } } @@ -881,6 +931,15 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa }); } } + + @Override + public void onCaptionComponentStateChanged(Boolean isComponentEnabled) { + boolean componentEnabled = isComponentEnabled == null ? false : isComponentEnabled; + for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) { + entry.getValue().post( + () -> entry.getKey().onCaptionComponentStateChanged(componentEnabled)); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index ffd8206ca887..398b30963da7 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -29,6 +29,7 @@ import static android.view.View.ACCESSIBILITY_LIVE_REGION_POLITE; import static android.view.View.GONE; import static android.view.View.VISIBLE; +import static com.android.systemui.volume.Events.DISMISS_REASON_ODI_CAPTIONS_CLICKED; import static com.android.systemui.volume.Events.DISMISS_REASON_SETTINGS_CLICKED; import android.animation.ObjectAnimator; @@ -125,6 +126,8 @@ public class VolumeDialogImpl implements VolumeDialog { private ViewGroup mDialogRowsView; private ViewGroup mRinger; private ImageButton mRingerIcon; + private ViewGroup mODICaptionsView; + private ImageButton mODICaptionsIcon; private View mSettingsView; private ImageButton mSettingsIcon; private FrameLayout mZenIcon; @@ -240,6 +243,10 @@ public class VolumeDialogImpl implements VolumeDialog { mRingerIcon = mRinger.findViewById(R.id.ringer_icon); mZenIcon = mRinger.findViewById(R.id.dnd_icon); } + mODICaptionsView = mDialog.findViewById(R.id.odi_captions); + if (mODICaptionsView != null) { + mODICaptionsIcon = mODICaptionsView.findViewById(R.id.odi_captions_icon); + } mSettingsView = mDialog.findViewById(R.id.settings_container); mSettingsIcon = mDialog.findViewById(R.id.settings); @@ -270,6 +277,7 @@ public class VolumeDialogImpl implements VolumeDialog { updateRowsH(getActiveRow()); initRingerH(); initSettingsH(); + initODICaptionsH(); } protected ViewGroup getDialogView() { @@ -478,6 +486,42 @@ public class VolumeDialogImpl implements VolumeDialog { updateRingerH(); } + private void initODICaptionsH() { + if (mODICaptionsIcon != null) { + mODICaptionsIcon.setOnClickListener(v -> { + onCaptionIconClicked(); + Events.writeEvent(mContext, Events.EVENT_ODI_CAPTIONS_CLICK); + dismissH(DISMISS_REASON_ODI_CAPTIONS_CLICKED); + }); + } + + mController.getCaptionsComponentState(); + } + + private void updateODICaptionsH(boolean isServiceComponentEnabled) { + if (mODICaptionsView != null) { + mODICaptionsView.setVisibility(isServiceComponentEnabled ? VISIBLE : GONE); + } + + if (!isServiceComponentEnabled) return; + + updateCaptionsIcon(); + } + + private void updateCaptionsIcon() { + mHandler.post( + mODICaptionsIcon.setImageResourceAsync( + mController.areCaptionsEnabled() + ? R.drawable.ic_volume_odi_captions + : R.drawable.ic_volume_odi_captions_disabled)); + } + + private void onCaptionIconClicked() { + boolean isEnabled = mController.areCaptionsEnabled(); + mController.setCaptionsEnabled(!isEnabled); + updateCaptionsIcon(); + } + private void incrementManualToggleCount() { ContentResolver cr = mContext.getContentResolver(); int ringerCount = Settings.Secure.getInt(cr, Settings.Secure.MANUAL_RINGER_TOGGLE_COUNT, 0); @@ -558,6 +602,7 @@ public class VolumeDialogImpl implements VolumeDialog { mDialog.show(); Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked()); mController.notifyVisible(true); + mController.getCaptionsComponentState(); } protected void rescheduleTimeoutH() { @@ -1151,6 +1196,11 @@ public class VolumeDialogImpl implements VolumeDialog { } } + + @Override + public void onCaptionComponentStateChanged(Boolean isComponentEnabled) { + updateODICaptionsH(isComponentEnabled); + } }; private final class H extends Handler { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java index 19a73f6c2d5b..fb4fd314d363 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java @@ -341,79 +341,62 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, IMPORTANCE_DEFAULT, true); - final TextView silent = mNotificationInfo.findViewById(R.id.int_silent); + final TextView silent = mNotificationInfo.findViewById(R.id.int_silent_label); assertEquals(VISIBLE, silent.getVisibility()); assertEquals( mContext.getString(R.string.inline_silent_button_silent), silent.getText()); } @Test - public void testBindNotification_SilenceButton_CurrentlySilent() throws Exception { + public void testBindNotification_verifyButtonTexts() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, IMPORTANCE_LOW, false); - final TextView silent = mNotificationInfo.findViewById(R.id.int_silent); + final TextView block = mNotificationInfo.findViewById(R.id.int_block_label); + final TextView alert = mNotificationInfo.findViewById(R.id.int_alert_label); + final TextView silent = mNotificationInfo.findViewById(R.id.int_silent_label); assertEquals(VISIBLE, silent.getVisibility()); + assertEquals(VISIBLE, block.getVisibility()); + assertEquals(VISIBLE, alert.getVisibility()); assertEquals( - mContext.getString(R.string.inline_silent_button_stay_silent), + mContext.getString(R.string.inline_silent_button_silent), silent.getText()); + assertEquals( + mContext.getString(R.string.inline_silent_button_alert), alert.getText()); + assertEquals( + mContext.getString(R.string.inline_block_button), block.getText()); } @Test - public void testBindNotification_AlertButton_CurrentlySilent() throws Exception { + public void testBindNotification_verifyHintTextForSilent() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, IMPORTANCE_LOW, false); - final TextView alert = mNotificationInfo.findViewById(R.id.int_alert); - assertEquals(VISIBLE, alert.getVisibility()); - assertEquals( - mContext.getString(R.string.inline_silent_button_alert), alert.getText()); + TextView hintText = mNotificationInfo.findViewById(R.id.hint_text); + assertEquals(mContext.getString(R.string.hint_text_silent), hintText.getText()); } @Test - public void testBindNotification_UnSilenceButton_currentlyAlerting() throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_DEFAULT); + public void testBindNotification_verifyHintTextForBlock() throws Exception { + mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - IMPORTANCE_DEFAULT, true); - final TextView alert = mNotificationInfo.findViewById(R.id.int_alert); - assertEquals(VISIBLE, alert.getVisibility()); - assertEquals( - mContext.getString(R.string.inline_silent_button_keep_alerting), alert.getText()); + IMPORTANCE_LOW, false); + View blockWrapper = mNotificationInfo.findViewById(R.id.int_block_wrapper); + blockWrapper.performClick(); + TextView hintText = mNotificationInfo.findViewById(R.id.hint_text); + assertEquals(mContext.getString(R.string.hint_text_block), hintText.getText()); } @Test - public void testBindNotification_ChannelImportanceUnspecified_NotifAlerting() throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED); + public void testBindNotification_verifyHintTextForAlert() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, IMPORTANCE_DEFAULT, true); - final TextView silent = mNotificationInfo.findViewById(R.id.int_silent); - final TextView alert = mNotificationInfo.findViewById(R.id.int_alert); - assertEquals(VISIBLE, silent.getVisibility()); - assertEquals(VISIBLE, alert.getVisibility()); - assertEquals( - mContext.getString(R.string.inline_silent_button_silent), silent.getText()); - assertEquals( - mContext.getString(R.string.inline_silent_button_keep_alerting), alert.getText()); - } - - @Test - public void testBindNotification_ChannelImportanceUnspecified_NotifSilent() throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - IMPORTANCE_LOW, false); - final TextView silent = mNotificationInfo.findViewById(R.id.int_silent); - final TextView alert = mNotificationInfo.findViewById(R.id.int_alert); - assertEquals(VISIBLE, silent.getVisibility()); - assertEquals(VISIBLE, alert.getVisibility()); - assertEquals( - mContext.getString(R.string.inline_silent_button_stay_silent), silent.getText()); - assertEquals( - mContext.getString(R.string.inline_silent_button_alert), alert.getText()); + TextView hintText = mNotificationInfo.findViewById(R.id.hint_text); + assertEquals(mContext.getString(R.string.hint_text_alert), hintText.getText()); } @Test @@ -560,16 +543,6 @@ public class NotificationInfoTest extends SysuiTestCase { } @Test - public void testbindNotification_BlockingHelper() throws Exception { - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false, false, - true, true, IMPORTANCE_DEFAULT, true); - final TextView view = mNotificationInfo.findViewById(R.id.block_prompt); - assertEquals(View.VISIBLE, view.getVisibility()); - assertEquals(mContext.getString(R.string.inline_blocking_helper), view.getText()); - } - - @Test public void testbindNotification_UnblockableTextVisibleWhenAppUnblockable() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, @@ -687,8 +660,8 @@ public class NotificationInfoTest extends SysuiTestCase { true, false /* isNonblockable */, IMPORTANCE_DEFAULT, false ); - mNotificationInfo.findViewById(R.id.int_block).performClick(); - waitForUndoButton(); + mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick(); + mNotificationInfo.findViewById(R.id.done_button).performClick(); mNotificationInfo.handleCloseControls(true, false); mTestableLooper.processAllMessages(); @@ -709,8 +682,8 @@ public class NotificationInfoTest extends SysuiTestCase { true, false /* isNonblockable */, IMPORTANCE_DEFAULT, false ); - mNotificationInfo.findViewById(R.id.int_block).performClick(); - waitForUndoButton(); + mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick(); + mNotificationInfo.findViewById(R.id.done_button).performClick(); mNotificationInfo.handleCloseControls(true, false); mTestableLooper.processAllMessages(); @@ -842,7 +815,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - IMPORTANCE_DEFAULT, false); + true, false, IMPORTANCE_DEFAULT, false); mNotificationInfo.findViewById(R.id.block).performClick(); waitForUndoButton(); @@ -861,8 +834,8 @@ public class NotificationInfoTest extends SysuiTestCase { true, false, IMPORTANCE_DEFAULT, false); - mNotificationInfo.findViewById(R.id.int_block).performClick(); - waitForUndoButton(); + mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick(); + mNotificationInfo.findViewById(R.id.done_button).performClick(); mNotificationInfo.handleCloseControls(true, false); ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class); @@ -929,7 +902,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - IMPORTANCE_DEFAULT, false); + true, false, IMPORTANCE_DEFAULT, false); mNotificationInfo.findViewById(R.id.minimize).performClick(); waitForUndoButton(); @@ -944,7 +917,7 @@ public class NotificationInfoTest extends SysuiTestCase { mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE; mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - IMPORTANCE_DEFAULT, false); + true, false, IMPORTANCE_DEFAULT, false); mNotificationInfo.findViewById(R.id.minimize).performClick(); waitForUndoButton(); @@ -1014,63 +987,14 @@ public class NotificationInfoTest extends SysuiTestCase { } @Test - public void testBlockUndoDoesNotBlockNotificationChannel_notBlockingHelper() throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, - null, null, null, - true, false, - IMPORTANCE_DEFAULT, false); - - mNotificationInfo.findViewById(R.id.int_block).performClick(); - waitForUndoButton(); - mNotificationInfo.findViewById(R.id.undo).performClick(); - waitForStopButton(); - // mNotificationInfo.handleCloseControls doesn't get called by this interaction. - - ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class); - verify(mMetricsLogger, times(2)).write(logMakerCaptor.capture()); - assertEquals(MetricsEvent.ACTION_SAVE_IMPORTANCE, - logMakerCaptor.getValue().getCategory()); - assertEquals(MetricsEvent.TYPE_DISMISS, - logMakerCaptor.getValue().getType()); - assertEquals(IMPORTANCE_NONE - IMPORTANCE_LOW, - logMakerCaptor.getValue().getSubtype()); - - - mTestableLooper.processAllMessages(); - verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( - anyString(), eq(TEST_UID), any()); - } - - @Test - public void testMinUndoDoesNotMinNotificationChannel_notBlockingHelper() throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, - null, null, null, true, - true, IMPORTANCE_DEFAULT, false); - - mNotificationInfo.findViewById(R.id.minimize).performClick(); - waitForUndoButton(); - mNotificationInfo.findViewById(R.id.undo).performClick(); - waitForStopButton(); - // mNotificationInfo.handleCloseControls doesn't get called by this code path - - mTestableLooper.processAllMessages(); - verify(mMockINotificationManager, times(0)).updateNotificationChannelForPackage( - anyString(), eq(TEST_UID), any()); - } - - @Test public void testSilenceCallsUpdateNotificationChannel() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_DEFAULT); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, IMPORTANCE_DEFAULT, true); - mNotificationInfo.findViewById(R.id.int_silent).performClick(); - waitForUndoButton(); + mNotificationInfo.findViewById(R.id.int_silent_wrapper).performClick(); + mNotificationInfo.findViewById(R.id.done_button).performClick(); mNotificationInfo.handleCloseControls(true, false); mTestableLooper.processAllMessages(); @@ -1090,8 +1014,8 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, IMPORTANCE_DEFAULT, false); - mNotificationInfo.findViewById(R.id.int_alert).performClick(); - waitForUndoButton(); + mNotificationInfo.findViewById(R.id.int_alert_wrapper).performClick(); + mNotificationInfo.findViewById(R.id.done_button).performClick(); mNotificationInfo.handleCloseControls(true, false); mTestableLooper.processAllMessages(); @@ -1112,8 +1036,8 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, IMPORTANCE_DEFAULT, true); - mNotificationInfo.findViewById(R.id.int_silent).performClick(); - waitForUndoButton(); + mNotificationInfo.findViewById(R.id.int_silent_wrapper).performClick(); + mNotificationInfo.findViewById(R.id.done_button).performClick(); mNotificationInfo.handleCloseControls(true, false); mTestableLooper.processAllMessages(); @@ -1134,8 +1058,8 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, IMPORTANCE_LOW, false); - mNotificationInfo.findViewById(R.id.int_alert).performClick(); - waitForUndoButton(); + mNotificationInfo.findViewById(R.id.int_alert_wrapper).performClick(); + mNotificationInfo.findViewById(R.id.done_button).performClick(); mNotificationInfo.handleCloseControls(true, false); mTestableLooper.processAllMessages(); @@ -1153,7 +1077,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - IMPORTANCE_DEFAULT, false); + true, false, IMPORTANCE_DEFAULT, false); mNotificationInfo.findViewById(R.id.minimize).performClick(); waitForUndoButton(); @@ -1171,8 +1095,8 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, IMPORTANCE_DEFAULT, false); - mNotificationInfo.findViewById(R.id.int_block).performClick(); - waitForUndoButton(); + mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick(); + mNotificationInfo.findViewById(R.id.done_button).performClick(); mNotificationInfo.handleCloseControls(false, false); mTestableLooper.processAllMessages(); @@ -1188,9 +1112,8 @@ public class NotificationInfoTest extends SysuiTestCase { (Runnable saveImportance, StatusBarNotification sbn) -> { }, null, null, true, true, IMPORTANCE_DEFAULT, false); - mNotificationInfo.findViewById(R.id.int_block).performClick(); + mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick(); mTestableLooper.processAllMessages(); - ensureNoUndoButton(); mNotificationInfo.handleCloseControls(true, false); verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( @@ -1207,12 +1130,12 @@ public class NotificationInfoTest extends SysuiTestCase { }, null, null, true, false, IMPORTANCE_DEFAULT, false ); - mNotificationInfo.findViewById(R.id.int_block).performClick(); + mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick(); + mNotificationInfo.findViewById(R.id.done_button).performClick(); mTestableLooper.processAllMessages(); verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel)); - waitForUndoButton(); mNotificationInfo.handleCloseControls(true, false); mTestableLooper.processAllMessages(); @@ -1231,78 +1154,11 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - IMPORTANCE_DEFAULT, false); + true, false, IMPORTANCE_DEFAULT, false); mNotificationInfo.findViewById(R.id.minimize).performClick(); waitForUndoButton(); TextView confirmationText = mNotificationInfo.findViewById(R.id.confirmation_text); assertTrue(confirmationText.getText().toString().contains("minimized")); } - - @Test - public void testUndoText_block() throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - IMPORTANCE_DEFAULT, false); - - mNotificationInfo.findViewById(R.id.int_block).performClick(); - waitForUndoButton(); - TextView confirmationText = mNotificationInfo.findViewById(R.id.confirmation_text); - assertTrue(confirmationText.getText().toString().contains("won't see")); - } - - @Test - public void testUndoText_silence() throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_DEFAULT); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - IMPORTANCE_DEFAULT, true); - - mNotificationInfo.findViewById(R.id.int_silent).performClick(); - waitForUndoButton(); - TextView confirmationText = mNotificationInfo.findViewById(R.id.confirmation_text); - assertEquals(mContext.getString(R.string.notification_channel_silenced), - confirmationText.getText()); - } - - @Test - public void testUndoText_unsilence() throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - IMPORTANCE_DEFAULT, false); - - mNotificationInfo.findViewById(R.id.int_alert).performClick(); - waitForUndoButton(); - TextView confirmationText = mNotificationInfo.findViewById(R.id.confirmation_text); - assertEquals(mContext.getString(R.string.notification_channel_unsilenced), - confirmationText.getText()); - } - - @Test - public void testNoHeaderOnConfirmation() throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - IMPORTANCE_DEFAULT, false); - - mNotificationInfo.findViewById(R.id.int_block).performClick(); - waitForUndoButton(); - assertEquals(GONE, mNotificationInfo.findViewById(R.id.header).getVisibility()); - } - - @Test - public void testHeaderOnUndo() throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - IMPORTANCE_DEFAULT, false); - - mNotificationInfo.findViewById(R.id.int_block).performClick(); - waitForUndoButton(); - mNotificationInfo.findViewById(R.id.undo).performClick(); - waitForStopButton(); - assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility()); - } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java index 7797cb37b397..7bd41584f889 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java @@ -19,8 +19,10 @@ package com.android.systemui.statusbar.phone; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.when; +import android.content.Context; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.View; @@ -31,6 +33,7 @@ import com.android.systemui.statusbar.AlertingNotificationManager; import com.android.systemui.statusbar.AlertingNotificationManagerTest; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import org.junit.Before; import org.junit.Rule; @@ -53,15 +56,29 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest { @Mock private VisualStabilityManager mVSManager; @Mock private StatusBar mBar; + private final class TestableHeadsUpManagerPhone extends HeadsUpManagerPhone { + TestableHeadsUpManagerPhone(Context context, View statusBarWindowView, + NotificationGroupManager groupManager, StatusBar bar, + VisualStabilityManager vsManager) { + super(context, statusBarWindowView, groupManager, bar, vsManager); + mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME; + mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME; + } + } + protected AlertingNotificationManager createAlertingNotificationManager() { return mHeadsUpManager; } @Before public void setUp() { + AccessibilityManagerWrapper mAccessibilityMgr = + mDependency.injectMockDependency(AccessibilityManagerWrapper.class); + when(mAccessibilityMgr.getRecommendedTimeoutMillis(anyInt(), anyInt())) + .thenReturn(TEST_AUTO_DISMISS_TIME); when(mVSManager.isReorderingAllowed()).thenReturn(true); - mHeadsUpManager = new HeadsUpManagerPhone(mContext, mStatusBarWindowView, mGroupManager, - mBar, mVSManager); + mHeadsUpManager = new TestableHeadsUpManagerPhone(mContext, mStatusBarWindowView, + mGroupManager, mBar, mVSManager); super.setUp(); mHeadsUpManager.mHandler = mTestHandler; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java new file mode 100644 index 000000000000..6b83fed64ddf --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy; + +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doReturn; + +import android.content.Context; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.statusbar.AlertingNotificationManager; +import com.android.systemui.statusbar.AlertingNotificationManagerTest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class HeadsUpManagerTest extends AlertingNotificationManagerTest { + private static final int TEST_A11Y_AUTO_DISMISS_TIME = 600; + private static final int TEST_A11Y_TIMEOUT_TIME = 5_000; + + private AccessibilityManagerWrapper mAccessibilityMgr; + private HeadsUpManager mHeadsUpManager; + private boolean mLivesPastNormalTime; + + private final class TestableHeadsUpManager extends HeadsUpManager { + TestableHeadsUpManager(Context context) { + super(context); + mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME; + mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME; + } + } + + protected AlertingNotificationManager createAlertingNotificationManager() { + return mHeadsUpManager; + } + + @Before + public void setUp() { + mAccessibilityMgr = mDependency.injectMockDependency(AccessibilityManagerWrapper.class); + + mHeadsUpManager = new TestableHeadsUpManager(mContext); + super.setUp(); + mHeadsUpManager.mHandler = mTestHandler; + } + + @Test + public void testShowNotification_autoDismissesWithAccessibilityTimeout() { + doReturn(TEST_A11Y_AUTO_DISMISS_TIME).when(mAccessibilityMgr) + .getRecommendedTimeoutMillis(anyInt(), anyInt()); + mHeadsUpManager.showNotification(mEntry); + Runnable pastNormalTimeRunnable = + () -> mLivesPastNormalTime = mHeadsUpManager.isAlerting(mEntry.key); + mTestHandler.postDelayed(pastNormalTimeRunnable, + (TEST_A11Y_AUTO_DISMISS_TIME + TEST_AUTO_DISMISS_TIME) / 2); + mTestHandler.postDelayed(TEST_TIMEOUT_RUNNABLE, TEST_A11Y_TIMEOUT_TIME); + + TestableLooper.get(this).processMessages(2); + + assertFalse("Test timed out", mTimedOut); + assertTrue("Heads up should live long enough", mLivesPastNormalTime); + assertFalse(mHeadsUpManager.isAlerting(mEntry.key)); + } +} + diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto index 9673a84018e4..bc4286356ead 100644 --- a/proto/src/metrics_constants/metrics_constants.proto +++ b/proto/src/metrics_constants/metrics_constants.proto @@ -260,6 +260,18 @@ message MetricsEvent { PREVIOUSLY_VISIBLE = 2; } + // Explanations for notification importance, derived from + // NotificationRecord.mImportanceExplanation. + enum NotificationImportanceExplanation { + IMPORTANCE_EXPLANATION_UNKNOWN = 0; + IMPORTANCE_EXPLANATION_APP = 1; // App-specified channel importance. + IMPORTANCE_EXPLANATION_USER = 2; // User-specified channel importance. + IMPORTANCE_EXPLANATION_ASST = 3; // Notification Assistant override. + IMPORTANCE_EXPLANATION_SYSTEM = 4; // System override. + // Like _APP, but based on pre-channels priority signal. + IMPORTANCE_EXPLANATION_APP_PRE_CHANNELS = 5; + } + // Known visual elements: views or controls. enum View { // Unknown view @@ -7090,6 +7102,21 @@ message MetricsEvent { // Panel for Wifi PANEL_WIFI = 1687; + // Custom tag for NotificationItem. A NotificationImportanceExplanation. + FIELD_NOTIFICATION_IMPORTANCE_EXPLANATION = 1688; + + // Custom tag for NotificationItem. The initial "natural" importance. + FIELD_NOTIFICATION_IMPORTANCE_INITIAL = 1689; + + // Custom tag for NotificationItem. A NotificationImportanceExplanation. + // The source of the "natural" importance, if it was overridden. + FIELD_NOTIFICATION_IMPORTANCE_INITIAL_EXPLANATION = 1690; + + // Custom tag for NotificationItem. The Notification Assistant's + // override of importance. Logged separately only if it was + // overridden by the system. + FIELD_NOTIFICATION_IMPORTANCE_ASST = 1691; + // ---- End Q Constants, all Q constants go above this line ---- // Add new aosp constants above this line. // END OF AOSP CONSTANTS diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto index 9f049cff66e5..0d17f22e2edf 100644 --- a/proto/src/wifi.proto +++ b/proto/src/wifi.proto @@ -1957,7 +1957,7 @@ message WifiUsabilityStatsEntry { optional LinkProbeStatus probe_status_since_last_update = 24; // The elapsed time of the most recent link probe since last stats update; - optional int32 probe_elapsed_time_ms_since_last_update = 25; + optional int32 probe_elapsed_time_since_last_update_ms = 25; // The MCS rate of the most recent link probe since last stats update optional int32 probe_mcs_rate_since_last_update = 26; @@ -2291,13 +2291,13 @@ message HistogramBucketInt32 { optional int32 count = 3; } -// Single entry in a map from int32 => int32 -message MapEntryInt32Int32 { +// Counts occurrences of a int32 key +message Int32Count { // the key optional int32 key = 1; - // the value - optional int32 value = 2; + // the count + optional int32 count = 2; } message LinkProbeStats { @@ -2328,16 +2328,16 @@ message LinkProbeStats { } // Counts the occurrences of RSSI values when a link probe succeeds. - repeated MapEntryInt32Int32 success_rssi_counts = 1; + repeated Int32Count success_rssi_counts = 1; // Counts the occurrences of RSSI values when a link probe fails. - repeated MapEntryInt32Int32 failure_rssi_counts = 2; + repeated Int32Count failure_rssi_counts = 2; // Counts the occurrences of Link Speed values when a link probe succeeds. - repeated MapEntryInt32Int32 success_link_speed_counts = 3; + repeated Int32Count success_link_speed_counts = 3; // Counts the occurrences of Link Speed values when a link probe fails. - repeated MapEntryInt32Int32 failure_link_speed_counts = 4; + repeated Int32Count failure_link_speed_counts = 4; // Histogram for the number of seconds since the last TX success when a link probe succeeds. repeated HistogramBucketInt32 success_seconds_since_last_tx_success_histogram = 5; @@ -2364,7 +2364,7 @@ message NetworkSelectionExperimentDecisions { // same network selection as experiment2. // The keys are the number of network choices, and the values are the number of occurrences of // this number of network choices when exp1 and exp2 make the same network selection. - repeated MapEntryInt32Int32 same_selection_num_choices_counter = 3; + repeated Int32Count same_selection_num_choices_counter = 3; // Counts occurrences of the number of network choices there were when experiment1 makes the // same network selection as experiment2. @@ -2372,7 +2372,7 @@ message NetworkSelectionExperimentDecisions { // this number of network choices when exp1 and exp2 make different network selections. // Note that it is possible for the network selection to be different even when there only exists // a single network choice, since choosing not to connect to that network is a valid choice. - repeated MapEntryInt32Int32 different_selection_num_choices_counter = 4; + repeated Int32Count different_selection_num_choices_counter = 4; } // NetworkRequest API metrics. diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java index 429315782a63..85c82bc009a0 100644 --- a/rs/java/android/renderscript/RenderScript.java +++ b/rs/java/android/renderscript/RenderScript.java @@ -16,12 +16,6 @@ package android.renderscript; -import java.io.File; -import java.lang.reflect.Method; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.concurrent.locks.ReentrantReadWriteLock; - import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.AssetManager; @@ -32,6 +26,12 @@ import android.os.Trace; import android.util.Log; import android.view.Surface; +import java.io.File; +import java.lang.reflect.Method; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.concurrent.locks.ReentrantReadWriteLock; + // TODO: Clean up the whitespace that separates methods in this class. /** @@ -114,8 +114,9 @@ public class RenderScript { Class<?> vm_runtime = Class.forName("dalvik.system.VMRuntime"); Method get_runtime = vm_runtime.getDeclaredMethod("getRuntime"); sRuntime = get_runtime.invoke(null); - registerNativeAllocation = vm_runtime.getDeclaredMethod("registerNativeAllocation", Integer.TYPE); - registerNativeFree = vm_runtime.getDeclaredMethod("registerNativeFree", Integer.TYPE); + registerNativeAllocation = + vm_runtime.getDeclaredMethod("registerNativeAllocation", Long.TYPE); + registerNativeFree = vm_runtime.getDeclaredMethod("registerNativeFree", Long.TYPE); } catch (Exception e) { Log.e(LOG_TAG, "Error loading GC methods: " + e); throw new RSRuntimeException("Error loading GC methods: " + e); diff --git a/services/core/java/com/android/server/BluetoothService.java b/services/core/java/com/android/server/BluetoothService.java index 1bf4e3a563c9..6018f008054c 100644 --- a/services/core/java/com/android/server/BluetoothService.java +++ b/services/core/java/com/android/server/BluetoothService.java @@ -18,15 +18,26 @@ package com.android.server; import android.bluetooth.BluetoothAdapter; import android.content.Context; +import android.os.SystemProperties; class BluetoothService extends SystemService { + private static final String HEADLESS_SYSTEM_USER = "android.car.systemuser.headless"; + private BluetoothManagerService mBluetoothManagerService; + private boolean mInitialized = false; public BluetoothService(Context context) { super(context); mBluetoothManagerService = new BluetoothManagerService(context); } + private void initialize() { + if (!mInitialized) { + mBluetoothManagerService.handleOnBootPhase(); + mInitialized = true; + } + } + @Override public void onStart() { } @@ -36,13 +47,15 @@ class BluetoothService extends SystemService { if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { publishBinderService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE, mBluetoothManagerService); - } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { - mBluetoothManagerService.handleOnBootPhase(); + } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY && + !SystemProperties.getBoolean(HEADLESS_SYSTEM_USER, false)) { + initialize(); } } @Override public void onSwitchUser(int userHandle) { + initialize(); mBluetoothManagerService.handleOnSwitchUser(userHandle); } diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 70733efa68bd..ea23081b8447 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -477,14 +477,22 @@ public final class BroadcastQueue { // when processNextBroadcastLocked() next finds this uid as a receiver identity. if (!r.timeoutExempt) { if (mConstants.SLOW_TIME > 0 && elapsed > mConstants.SLOW_TIME) { - if (DEBUG_BROADCAST_DEFERRAL) { - Slog.i(TAG_BROADCAST, "Broadcast receiver " + (r.nextReceiver - 1) - + " was slow: " + receiver + " br=" + r); - } - if (r.curApp != null) { - mDispatcher.startDeferring(r.curApp.uid); + // Core system packages are exempt from deferral policy + if (!UserHandle.isCore(r.curApp.uid)) { + if (DEBUG_BROADCAST_DEFERRAL) { + Slog.i(TAG_BROADCAST, "Broadcast receiver " + (r.nextReceiver - 1) + + " was slow: " + receiver + " br=" + r); + } + if (r.curApp != null) { + mDispatcher.startDeferring(r.curApp.uid); + } else { + Slog.d(TAG_BROADCAST, "finish receiver curApp is null? " + r); + } } else { - Slog.d(TAG_BROADCAST, "finish receiver curApp is null? " + r); + if (DEBUG_BROADCAST_DEFERRAL) { + Slog.i(TAG_BROADCAST, "Core uid " + r.curApp.uid + + " receiver was slow but not deferring: " + receiver + " br=" + r); + } } } } else { diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index abc1066af046..0387774bb257 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -519,10 +519,10 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN public void setProcess(ProcessRecord _proc) { app = _proc; - if (pendingConnectionGroup > 0) { - app.connectionService = this; - app.connectionGroup = pendingConnectionGroup; - app.connectionImportance = pendingConnectionImportance; + if (pendingConnectionGroup > 0 && _proc != null) { + _proc.connectionService = this; + _proc.connectionGroup = pendingConnectionGroup; + _proc.connectionImportance = pendingConnectionImportance; pendingConnectionGroup = pendingConnectionImportance = 0; } if (ActivityManagerService.TRACK_PROCSTATS_ASSOCIATIONS) { diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 1e406c01f255..676cc336ef8b 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -1547,8 +1547,8 @@ class UserController implements Handler.Callback { } builder.append(" asks to run as user "); builder.append(userId); - builder.append(" but is calling from user "); - builder.append(UserHandle.getUserId(callingUid)); + builder.append(" but is calling from uid "); + UserHandle.formatUid(builder, callingUid); builder.append("; this requires "); builder.append(INTERACT_ACROSS_USERS_FULL); if (allowMode != ALLOW_FULL_ONLY) { diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index ba7288e6d15f..9c26526920a0 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -1742,10 +1742,31 @@ public class AppOpsService extends IAppOpsService.Stub { return checkOperationUnchecked(code, uid, resolvedPackageName, raw); } - private int checkOperationUnchecked(int code, int uid, String packageName, - boolean raw) { + /** + * @see #checkOperationUnchecked(int, int, String, boolean, boolean) + */ + private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName, + boolean raw) { + return checkOperationUnchecked(code, uid, packageName, raw, true); + } + + /** + * Get the mode of an app-op. + * + * @param code The code of the op + * @param uid The uid of the package the op belongs to + * @param packageName The package the op belongs to + * @param raw If the raw state of eval-ed state should be checked. + * @param verify If the code should check the package belongs to the uid + * + * @return The mode of the op + */ + private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName, + boolean raw, boolean verify) { synchronized (this) { - checkPackage(uid, packageName); + if (verify) { + checkPackage(uid, packageName); + } if (isOpRestrictedLocked(uid, code, packageName)) { return AppOpsManager.MODE_IGNORED; } @@ -1756,7 +1777,7 @@ public class AppOpsService extends IAppOpsService.Stub { final int rawMode = uidState.opModes.get(code); return raw ? rawMode : uidState.evalMode(code, rawMode); } - Op op = getOpLocked(code, uid, packageName, false, true, false); + Op op = getOpLocked(code, uid, packageName, false, verify, false); if (op == null) { return AppOpsManager.opToDefaultMode(code); } @@ -2359,7 +2380,7 @@ public class AppOpsService extends IAppOpsService.Stub { throw new IllegalArgumentException("Bad operation #" + op); } - private @NonNull UidState getUidStateLocked(int uid, boolean edit) { + private @Nullable UidState getUidStateLocked(int uid, boolean edit) { UidState uidState = mUidStates.get(uid); if (uidState == null) { if (!edit) { @@ -4535,5 +4556,10 @@ public class AppOpsService extends IAppOpsService.Stub { public void setAllPkgModesToDefault(int code, int uid) { AppOpsService.this.setAllPkgModesToDefault(code, uid); } + + @Override + public @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName) { + return AppOpsService.this.checkOperationUnchecked(code, uid, packageName, true, false); + } } } diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index 41a3c9859f23..cb0bbd9b4088 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -858,11 +858,20 @@ public final class AudioDeviceInventory { if (musicDevice == AudioSystem.DEVICE_NONE) { musicDevice = mDeviceBroker.getDeviceForStream(AudioSystem.STREAM_MUSIC); } - // ignore condition on device being actually used for music when in communication + + // always ignore condition on device being actually used for music when in communication // because music routing is altered in this case. - // also checks whether media routing if affected by a dynamic policy + // also checks whether media routing if affected by a dynamic policy or mirroring if (((device == musicDevice) || mDeviceBroker.isInCommunication()) - && (device == devices) && !mDeviceBroker.hasMediaDynamicPolicy()) { + && (device == devices) && !mDeviceBroker.hasMediaDynamicPolicy() + && ((musicDevice & AudioSystem.DEVICE_OUT_REMOTE_SUBMIX) == 0)) { + if (!AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0 /*not looking in past*/)) { + // no media playback, not a "becoming noisy" situation, otherwise it could cause + // the pausing of some apps that are playing remotely + AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( + "dropping ACTION_AUDIO_BECOMING_NOISY, no media playback")).printLog(TAG)); + return 0; + } mDeviceBroker.postBroadcastBecomingNoisy(); delay = 1000; } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 91d19def1766..100113cbb5a5 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -6387,7 +6387,28 @@ public class AudioService extends IAudioService.Stub return mProjectionService; } - public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) { + /** + * See {@link AudioManager#unregisterAudioPolicyAsync(AudioPolicy)} + * Declared oneway + * @param pcb nullable because on service interface + */ + public void unregisterAudioPolicyAsync(@Nullable IAudioPolicyCallback pcb) { + unregisterAudioPolicy(pcb); + } + + /** + * See {@link AudioManager#unregisterAudioPolicy(AudioPolicy)} + * @param pcb nullable because on service interface + */ + public void unregisterAudioPolicy(@Nullable IAudioPolicyCallback pcb) { + if (pcb == null) { + return; + } + unregisterAudioPolicyInt(pcb); + } + + + private void unregisterAudioPolicyInt(@NonNull IAudioPolicyCallback pcb) { mDynPolicyLogger.log((new AudioEventLogger.StringEvent("unregisterAudioPolicyAsync for " + pcb.asBinder()).printLog(TAG))); synchronized (mAudioPolicies) { diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java index d84a4d2db993..123564eb4fdb 100644 --- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java +++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java @@ -46,13 +46,11 @@ import android.util.Log; import android.util.Slog; import android.util.SparseIntArray; -import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.server.LocalServices; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -84,20 +82,14 @@ public class PermissionMonitor { // Keys are App IDs. Values are true for SYSTEM permission and false for NETWORK permission. private final Map<Integer, Boolean> mApps = new HashMap<>(); - // Keys are App packageNames, Values are app uids. . We need to keep track of this information - // because PackageListObserver#onPackageRemoved does not pass the UID. - @GuardedBy("mPackageNameUidMap") - private final Map<String, Integer> mPackageNameUidMap = new HashMap<>(); - private class PackageListObserver implements PackageManagerInternal.PackageListObserver { @Override - public void onPackageAdded(String packageName) { + public void onPackageAdded(String packageName, int uid) { final PackageInfo app = getPackageInfo(packageName); if (app == null) { Slog.wtf(TAG, "Failed to get information of installed package: " + packageName); return; } - int uid = (app.applicationInfo != null) ? app.applicationInfo.uid : INVALID_UID; if (uid == INVALID_UID) { Slog.wtf(TAG, "Failed to get the uid of installed package: " + packageName + "uid: " + uid); @@ -107,29 +99,21 @@ public class PermissionMonitor { return; } sendPackagePermissionsForUid(uid, - filterPermission(Arrays.asList(app.requestedPermissions))); - synchronized (mPackageNameUidMap) { - mPackageNameUidMap.put(packageName, uid); - } + getNetdPermissionMask(app.requestedPermissions)); } @Override - public void onPackageRemoved(String packageName) { - int uid; - synchronized (mPackageNameUidMap) { - if (!mPackageNameUidMap.containsKey(packageName)) { - return; - } - uid = mPackageNameUidMap.get(packageName); - mPackageNameUidMap.remove(packageName); - } + public void onPackageRemoved(String packageName, int uid) { int permission = 0; + // If there are still packages remain under the same uid, check the permission of the + // remaining packages. We only remove the permission for a given uid when all packages + // for that uid no longer have that permission. String[] packages = mPackageManager.getPackagesForUid(uid); if (packages != null && packages.length > 0) { for (String name : packages) { final PackageInfo app = getPackageInfo(name); if (app != null && app.requestedPermissions != null) { - permission |= filterPermission(Arrays.asList(app.requestedPermissions)); + permission |= getNetdPermissionMask(app.requestedPermissions); } } } @@ -184,12 +168,9 @@ public class PermissionMonitor { //TODO: unify the management of the permissions into one codepath. if (app.requestedPermissions != null) { - int otherNetdPerms = filterPermission(Arrays.asList(app.requestedPermissions)); + int otherNetdPerms = getNetdPermissionMask(app.requestedPermissions); if (otherNetdPerms != 0) { netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms); - synchronized (mPackageNameUidMap) { - mPackageNameUidMap.put(app.applicationInfo.packageName, uid); - } } } } @@ -422,13 +403,15 @@ public class PermissionMonitor { } } - private static int filterPermission(List<String> requestedPermissions) { + private static int getNetdPermissionMask(String[] requestedPermissions) { int permissions = 0; - if (requestedPermissions.contains(INTERNET)) { - permissions |= INetd.PERMISSION_INTERNET; - } - if (requestedPermissions.contains(UPDATE_DEVICE_STATS)) { - permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS; + for (String permissionName : requestedPermissions) { + if (permissionName.equals(INTERNET)) { + permissions |= INetd.PERMISSION_INTERNET; + } + if (permissionName.equals(UPDATE_DEVICE_STATS)) { + permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS; + } } return permissions; } @@ -439,8 +422,6 @@ public class PermissionMonitor { | MATCH_ANY_USER); return app; } catch (NameNotFoundException e) { - // App not found. - loge("NameNotFoundException " + packageName); return null; } } diff --git a/services/core/java/com/android/server/lights/Light.java b/services/core/java/com/android/server/lights/Light.java index b5ec603f5f70..717e3dae479d 100644 --- a/services/core/java/com/android/server/lights/Light.java +++ b/services/core/java/com/android/server/lights/Light.java @@ -16,8 +16,8 @@ package com.android.server.lights; -import android.hardware.light.V2_0.Flash; import android.hardware.light.V2_0.Brightness; +import android.hardware.light.V2_0.Flash; public abstract class Light { public static final int LIGHT_FLASH_NONE = Flash.NONE; @@ -39,8 +39,16 @@ public abstract class Light { */ public static final int BRIGHTNESS_MODE_LOW_PERSISTENCE = Brightness.LOW_PERSISTENCE; + /** + * Set the brightness of a display. + */ public abstract void setBrightness(int brightness); + + /** + * Set the brightness and mode of a display. + */ public abstract void setBrightness(int brightness, int brightnessMode); + public abstract void setColor(int color); public abstract void setFlashing(int color, int mode, int onMS, int offMS); public abstract void pulse(); diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java index a94ed608b9c9..ac906bb23d32 100644 --- a/services/core/java/com/android/server/lights/LightsService.java +++ b/services/core/java/com/android/server/lights/LightsService.java @@ -15,15 +15,18 @@ package com.android.server.lights; -import com.android.server.SystemService; - import android.app.ActivityManager; import android.content.Context; import android.os.Handler; +import android.os.IBinder; import android.os.Message; +import android.os.PowerManager; import android.os.Trace; import android.provider.Settings; import android.util.Slog; +import android.view.SurfaceControl; + +import com.android.server.SystemService; public class LightsService extends SystemService { static final String TAG = "LightsService"; @@ -33,8 +36,25 @@ public class LightsService extends SystemService { private final class LightImpl extends Light { - private LightImpl(int id) { + private final IBinder mDisplayToken; + private final int mSurfaceControlMaximumBrightness; + + private LightImpl(Context context, int id) { mId = id; + mDisplayToken = SurfaceControl.getInternalDisplayToken(); + final boolean brightnessSupport = SurfaceControl.getDisplayBrightnessSupport( + mDisplayToken); + if (DEBUG) { + Slog.d(TAG, "Display brightness support: " + brightnessSupport); + } + int maximumBrightness = 0; + if (brightnessSupport) { + PowerManager pm = context.getSystemService(PowerManager.class); + if (pm != null) { + maximumBrightness = pm.getMaximumScreenBrightnessSetting(); + } + } + mSurfaceControlMaximumBrightness = maximumBrightness; } @Override @@ -51,10 +71,26 @@ public class LightsService extends SystemService { ": brightness=0x" + Integer.toHexString(brightness)); return; } - - int color = brightness & 0x000000ff; - color = 0xff000000 | (color << 16) | (color << 8) | color; - setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode); + // Ideally, we'd like to set the brightness mode through the SF/HWC as well, but + // right now we just fall back to the old path through Lights brightessMode is + // anything but USER or the device shouldBeInLowPersistenceMode(). + if (brightnessMode == BRIGHTNESS_MODE_USER && !shouldBeInLowPersistenceMode() + && mSurfaceControlMaximumBrightness == 255) { + // TODO: the last check should be mSurfaceControlMaximumBrightness != 0; the + // reason we enforce 255 right now is to stay consistent with the old path. In + // the future, the framework should be refactored so that brightness is a float + // between 0.0f and 1.0f, and the actual number of supported brightness levels + // is determined in the device-specific implementation. + if (DEBUG) { + Slog.d(TAG, "Using new setBrightness path!"); + } + SurfaceControl.setDisplayBrightness(mDisplayToken, + (float) brightness / mSurfaceControlMaximumBrightness); + } else { + int color = brightness & 0x000000ff; + color = 0xff000000 | (color << 16) | (color << 8) | color; + setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode); + } } } @@ -172,7 +208,7 @@ public class LightsService extends SystemService { super(context); for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) { - mLights[i] = new LightImpl(i); + mLights[i] = new LightImpl(context, i); } } diff --git a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java index b86328b92869..94f289f2e382 100644 --- a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java @@ -64,6 +64,7 @@ import android.os.IBinder; import android.os.Message; import android.os.PowerManager; import android.os.Process; +import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; @@ -138,9 +139,9 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { private MediaSessionRecord mGlobalPrioritySession; private AudioPlayerStateMonitor mAudioPlayerStateMonitor; - // Used to notify system UI when remote volume was changed. TODO find a - // better way to handle this. - private IRemoteVolumeController mRvc; + // Used to notify System UI and Settings when remote volume was changed. + final RemoteCallbackList<IRemoteVolumeController> mRemoteVolumeControllers = + new RemoteCallbackList<>(); public MediaSessionServiceImpl(Context context) { mContext = context; @@ -281,20 +282,23 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { } /** - * Tells the system UI that volume has changed on an active remote session. + * Tells the System UI and Settings app that volume has changed on an active remote session. */ public void notifyRemoteVolumeChanged(int flags, MediaSessionRecord session) { - synchronized (mLock) { - if (mRvc == null || !session.isActive()) { - return; - } + if (!session.isActive()) { + return; + } + int size = mRemoteVolumeControllers.beginBroadcast(); + MediaSession.Token token = session.getSessionToken(); + for (int i = size - 1; i >= 0; i--) { try { - mRvc.remoteVolumeChanged(session.getSessionToken(), flags); + IRemoteVolumeController cb = mRemoteVolumeControllers.getBroadcastItem(i); + cb.remoteVolumeChanged(token, flags); } catch (Exception e) { - Log.w(TAG, "Error sending volume change to system UI.", e); - mRvc = null; + Log.w(TAG, "Error sending volume change.", e); } } + mRemoteVolumeControllers.finishBroadcast(); } @Override @@ -497,7 +501,7 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { */ private void enforceMediaPermissions(ComponentName compName, int pid, int uid, int resolvedUserId) { - if (isCurrentVolumeController(pid, uid)) return; + if (hasStatusBarServicePermission(pid, uid)) return; if (mContext .checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid) != PackageManager.PERMISSION_GRANTED @@ -507,14 +511,14 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { } } - private boolean isCurrentVolumeController(int pid, int uid) { + private boolean hasStatusBarServicePermission(int pid, int uid) { return mContext.checkPermission(android.Manifest.permission.STATUS_BAR_SERVICE, pid, uid) == PackageManager.PERMISSION_GRANTED; } - private void enforceSystemUiPermission(String action, int pid, int uid) { - if (!isCurrentVolumeController(pid, uid)) { - throw new SecurityException("Only system ui may " + action); + private void enforceStatusBarServicePermission(String action, int pid, int uid) { + if (!hasStatusBarServicePermission(pid, uid)) { + throw new SecurityException("Only System UI and Settings may " + action); } } @@ -638,20 +642,25 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { } private void pushRemoteVolumeUpdateLocked(int userId) { - if (mRvc != null) { + FullUserRecord user = getFullUserRecordLocked(userId); + if (user == null) { + Log.w(TAG, "pushRemoteVolumeUpdateLocked failed. No user with id=" + userId); + return; + } + + int size = mRemoteVolumeControllers.beginBroadcast(); + MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId); + MediaSession.Token token = record == null ? null : record.getSessionToken(); + + for (int i = size - 1; i >= 0; i--) { try { - FullUserRecord user = getFullUserRecordLocked(userId); - if (user == null) { - Log.w(TAG, "pushRemoteVolumeUpdateLocked failed. No user with id=" + userId); - return; - } - MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId); - mRvc.updateRemoteController(record == null ? null : record.getSessionToken()); - } catch (RemoteException e) { - Log.w(TAG, "Error sending default remote volume to sys ui.", e); - mRvc = null; + IRemoteVolumeController cb = mRemoteVolumeControllers.getBroadcastItem(i); + cb.updateRemoteController(token); + } catch (Exception e) { + Log.w(TAG, "Error sending default remote volume.", e); } } + mRemoteVolumeControllers.finishBroadcast(); } void pushSession2TokensChangedLocked(int userId) { @@ -1661,15 +1670,26 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { } @Override - public void setRemoteVolumeController(IRemoteVolumeController rvc) { + public void registerRemoteVolumeController(IRemoteVolumeController rvc) { final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); try { - enforceSystemUiPermission("listen for volume changes", pid, uid); - synchronized (mLock) { - mRvc = rvc; - } + enforceStatusBarServicePermission("listen for volume changes", pid, uid); + mRemoteVolumeControllers.register(rvc); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override + public void unregisterRemoteVolumeController(IRemoteVolumeController rvc) { + final int pid = Binder.getCallingPid(); + final int uid = Binder.getCallingUid(); + final long token = Binder.clearCallingIdentity(); + try { + enforceStatusBarServicePermission("listen for volume changes", pid, uid); + mRemoteVolumeControllers.unregister(rvc); } finally { Binder.restoreCallingIdentity(token); } @@ -1755,8 +1775,8 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { private boolean hasMediaControlPermission(int resolvedUserId, String packageName, int pid, int uid) throws RemoteException { - // Allow API calls from the System UI - if (isCurrentVolumeController(pid, uid)) { + // Allow API calls from the System UI and Settings + if (hasStatusBarServicePermission(pid, uid)) { return true; } diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index 46ce4bf59a50..d9ab13295166 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -149,7 +149,10 @@ public final class NotificationRecord { private int mImportance = IMPORTANCE_UNSPECIFIED; // Field used in global sort key to bypass normal notifications private int mCriticality = CriticalNotificationExtractor.NORMAL; - private CharSequence mImportanceExplanation = null; + // A MetricsEvent.NotificationImportanceExplanation, tracking source of mImportance. + private int mImportanceExplanationCode = MetricsEvent.IMPORTANCE_EXPLANATION_UNKNOWN; + // A MetricsEvent.NotificationImportanceExplanation for initial importance. + private int mInitialImportanceExplanationCode = MetricsEvent.IMPORTANCE_EXPLANATION_UNKNOWN; private int mSuppressedVisualEffects = 0; private String mUserExplanation; @@ -332,14 +335,18 @@ public final class NotificationRecord { private int calculateInitialImportance() { final Notification n = sbn.getNotification(); - int importance = getChannel().getImportance(); - int requestedImportance = IMPORTANCE_DEFAULT; + int importance = getChannel().getImportance(); // Post-channels notifications use this + mInitialImportanceExplanationCode = getChannel().hasUserSetImportance() + ? MetricsEvent.IMPORTANCE_EXPLANATION_USER + : MetricsEvent.IMPORTANCE_EXPLANATION_APP; - // Migrate notification flags to scores + // Migrate notification priority flag to a priority value. if (0 != (n.flags & Notification.FLAG_HIGH_PRIORITY)) { n.priority = Notification.PRIORITY_MAX; } + // Convert priority value to an importance value, used only for pre-channels notifications. + int requestedImportance = IMPORTANCE_DEFAULT; n.priority = NotificationManagerService.clamp(n.priority, Notification.PRIORITY_MIN, Notification.PRIORITY_MAX); switch (n.priority) { @@ -360,10 +367,11 @@ public final class NotificationRecord { stats.requestedImportance = requestedImportance; stats.isNoisy = mSound != null || mVibration != null; + // For pre-channels notifications, apply system overrides and then use requestedImportance + // as importance. if (mPreChannelsNotification && (importance == IMPORTANCE_UNSPECIFIED - || (getChannel().getUserLockedFields() - & USER_LOCKED_IMPORTANCE) == 0)) { + || (!getChannel().hasUserSetImportance()))) { if (!stats.isNoisy && requestedImportance > IMPORTANCE_LOW) { requestedImportance = IMPORTANCE_LOW; } @@ -378,6 +386,8 @@ public final class NotificationRecord { requestedImportance = IMPORTANCE_HIGH; } importance = requestedImportance; + mInitialImportanceExplanationCode = + MetricsEvent.IMPORTANCE_EXPLANATION_APP_PRE_CHANNELS; } stats.naturalImportance = importance; @@ -540,7 +550,7 @@ public final class NotificationRecord { + NotificationListenerService.Ranking.importanceToString(mAssistantImportance)); pw.println(prefix + "mImportance=" + NotificationListenerService.Ranking.importanceToString(mImportance)); - pw.println(prefix + "mImportanceExplanation=" + mImportanceExplanation); + pw.println(prefix + "mImportanceExplanation=" + getImportanceExplanation()); pw.println(prefix + "mIsAppImportanceLocked=" + mIsAppImportanceLocked); pw.println(prefix + "mIntercept=" + mIntercept); pw.println(prefix + "mHidden==" + mHidden); @@ -760,23 +770,23 @@ public final class NotificationRecord { } /** - * Recalculates the importance of the record after fields affecting importance have changed + * Recalculates the importance of the record after fields affecting importance have changed, + * and records an explanation. */ protected void calculateImportance() { mImportance = calculateInitialImportance(); - mImportanceExplanation = "app"; - if (getChannel().hasUserSetImportance()) { - mImportanceExplanation = "user"; - } + mImportanceExplanationCode = mInitialImportanceExplanationCode; + + // Consider Notification Assistant and system overrides to importance. If both, system wins. if (!getChannel().hasUserSetImportance() && mAssistantImportance != IMPORTANCE_UNSPECIFIED && !getChannel().isImportanceLockedByOEM()) { mImportance = mAssistantImportance; - mImportanceExplanation = "asst"; + mImportanceExplanationCode = MetricsEvent.IMPORTANCE_EXPLANATION_ASST; } if (mSystemImportance != IMPORTANCE_UNSPECIFIED) { mImportance = mSystemImportance; - mImportanceExplanation = "system"; + mImportanceExplanationCode = MetricsEvent.IMPORTANCE_EXPLANATION_SYSTEM; } } @@ -785,7 +795,20 @@ public final class NotificationRecord { } public CharSequence getImportanceExplanation() { - return mImportanceExplanation; + switch (mImportanceExplanationCode) { + case MetricsEvent.IMPORTANCE_EXPLANATION_UNKNOWN: + return null; + case MetricsEvent.IMPORTANCE_EXPLANATION_APP: + case MetricsEvent.IMPORTANCE_EXPLANATION_APP_PRE_CHANNELS: + return "app"; + case MetricsEvent.IMPORTANCE_EXPLANATION_USER: + return "user"; + case MetricsEvent.IMPORTANCE_EXPLANATION_ASST: + return "asst"; + case MetricsEvent.IMPORTANCE_EXPLANATION_SYSTEM: + return "system"; + } + return null; } public boolean setIntercepted(boolean intercept) { @@ -1242,14 +1265,37 @@ public final class NotificationRecord { } public LogMaker getLogMaker(long now) { - return sbn.getLogMaker() - .clearTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX) + LogMaker lm = sbn.getLogMaker() .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE, mImportance) .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS, getLifespanMs(now)) .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS, getFreshnessMs(now)) .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS, getExposureMs(now)) .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_INTERRUPTION_MILLIS, getInterruptionMs(now)); + // Record results of the calculateImportance() calculation if available. + if (mImportanceExplanationCode != MetricsEvent.IMPORTANCE_EXPLANATION_UNKNOWN) { + lm.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_EXPLANATION, + mImportanceExplanationCode); + // To avoid redundancy, we log the initial importance information only if it was + // overridden. + if (((mImportanceExplanationCode == MetricsEvent.IMPORTANCE_EXPLANATION_ASST) + || (mImportanceExplanationCode == MetricsEvent.IMPORTANCE_EXPLANATION_SYSTEM)) + && (stats.naturalImportance != IMPORTANCE_UNSPECIFIED)) { + // stats.naturalImportance is due to one of the 3 sources of initial importance. + lm.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL_EXPLANATION, + mInitialImportanceExplanationCode); + lm.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL, + stats.naturalImportance); + } + // Log Assistant override if it was itself overridden by System. Since System can't be + // overridden, it never needs logging. + if (mImportanceExplanationCode == MetricsEvent.IMPORTANCE_EXPLANATION_SYSTEM + && mAssistantImportance != IMPORTANCE_UNSPECIFIED) { + lm.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_ASST, + mAssistantImportance); + } + } + return lm; } public LogMaker getLogMaker() { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 4dcab5e7abdd..6f006e7d9d7c 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1952,7 +1952,7 @@ public class PackageManagerService extends IPackageManager.Stub } if (allNewUsers && !update) { - notifyPackageAdded(packageName); + notifyPackageAdded(packageName, res.uid); } // Log current value of "unknown sources" setting @@ -12317,7 +12317,7 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public void notifyPackageAdded(String packageName) { + public void notifyPackageAdded(String packageName, int uid) { final PackageListObserver[] observers; synchronized (mPackages) { if (mPackageListObservers.size() == 0) { @@ -12328,7 +12328,7 @@ public class PackageManagerService extends IPackageManager.Stub observers = mPackageListObservers.toArray(observerArray); } for (int i = observers.length - 1; i >= 0; --i) { - observers[i].onPackageAdded(packageName); + observers[i].onPackageAdded(packageName, uid); } } @@ -12339,7 +12339,7 @@ public class PackageManagerService extends IPackageManager.Stub }; @Override - public void notifyPackageRemoved(String packageName) { + public void notifyPackageRemoved(String packageName, int uid) { final PackageListObserver[] observers; synchronized (mPackages) { if (mPackageListObservers.size() == 0) { @@ -12350,7 +12350,7 @@ public class PackageManagerService extends IPackageManager.Stub observers = mPackageListObservers.toArray(observerArray); } for (int i = observers.length - 1; i >= 0; --i) { - observers[i].onPackageRemoved(packageName); + observers[i].onPackageRemoved(packageName, uid); } } @@ -17904,7 +17904,8 @@ public class PackageManagerService extends IPackageManager.Stub return; } Bundle extras = new Bundle(2); - extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid); + final int removedUid = removedAppId >= 0 ? removedAppId : uid; + extras.putInt(Intent.EXTRA_UID, removedUid); extras.putBoolean(Intent.EXTRA_DATA_REMOVED, dataRemoved); extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp); if (isUpdate || isRemovedPackageSystemUpdate) { @@ -17925,7 +17926,7 @@ public class PackageManagerService extends IPackageManager.Stub removedPackage, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, null, null, broadcastUsers, instantUserIds); - packageSender.notifyPackageRemoved(removedPackage); + packageSender.notifyPackageRemoved(removedPackage, removedUid); } } if (removedAppId >= 0) { @@ -24410,6 +24411,6 @@ interface PackageSender { final IIntentReceiver finishedReceiver, final int[] userIds, int[] instantUserIds); void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted, boolean includeStopped, int appId, int[] userIds, int[] instantUserIds); - void notifyPackageAdded(String packageName); - void notifyPackageRemoved(String packageName); + void notifyPackageAdded(String packageName, int uid); + void notifyPackageRemoved(String packageName, int uid); } diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java index 3b805d515178..f56231fc02af 100644 --- a/services/core/java/com/android/server/pm/dex/DexManager.java +++ b/services/core/java/com/android/server/pm/dex/DexManager.java @@ -16,7 +16,7 @@ package com.android.server.pm.dex; -import static android.provider.DeviceConfig.DexBoot; +import static android.provider.DeviceConfig.NAMESPACE_DEX_BOOT; import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo; @@ -72,6 +72,10 @@ public class DexManager { private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST = "pm.dexopt.priv-apps-oob-list"; + // flags for Device Config API + private static final String PRIV_APPS_OOB_ENABLED = "priv_apps_oob_enabled"; + private static final String PRIV_APPS_OOB_WHITELIST = "priv_apps_oob_whitelist"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private final Context mContext; @@ -713,8 +717,8 @@ public class DexManager { return isPackageSelectedToRunOobInternal( SystemProperties.getBoolean(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB, false), SystemProperties.get(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST, "ALL"), - DeviceConfig.getProperty(DexBoot.NAMESPACE, DexBoot.PRIV_APPS_OOB_ENABLED), - DeviceConfig.getProperty(DexBoot.NAMESPACE, DexBoot.PRIV_APPS_OOB_WHITELIST), + DeviceConfig.getProperty(NAMESPACE_DEX_BOOT, PRIV_APPS_OOB_ENABLED), + DeviceConfig.getProperty(NAMESPACE_DEX_BOOT, PRIV_APPS_OOB_WHITELIST), packageNamesInSameProcess); } diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index f7d8e0e27831..897b885c5a3c 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -1273,7 +1273,7 @@ public class PermissionManagerService { @NonNull ArraySet<String> sourcePerms, @NonNull String newPerm, @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg, @UserIdInt int userId) { - AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class); + AppOpsManagerInternal appOpsManager = LocalServices.getService(AppOpsManagerInternal.class); String pkgName = pkg.packageName; if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { @@ -1287,10 +1287,10 @@ public class PermissionManagerService { String sourcePerm = sourcePerms.valueAt(i); if (ps.hasRuntimePermission(sourcePerm, userId)) { - String sourceOp = permissionToOp(sourcePerm); + int sourceOp = permissionToOpCode(sourcePerm); - if (sourceOp != null) { - int mode = appOpsManager.unsafeCheckOpRaw(sourceOp, + if (sourceOp != OP_NONE) { + int mode = appOpsManager.checkOperationUnchecked(sourceOp, getUid(userId, getAppId(pkg.applicationInfo.uid)), pkgName); if (mode == MODE_FOREGROUND || mode == MODE_ERRORED) { diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index 871f9f862945..952399bf3a7d 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -684,7 +684,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { * @param status the RollbackManager.STATUS_* code with the failure. * @param message the failure message. */ - private void sendFailure(IntentSender statusReceiver, int status, String message) { + private void sendFailure(IntentSender statusReceiver, @RollbackManager.Status int status, + String message) { Log.e(TAG, message); try { final Intent fillIn = new Intent(); diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java index 86dc66dbca3b..d364a3765c22 100644 --- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java +++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java @@ -306,10 +306,10 @@ class LaunchParamsPersister { private class PackageListObserver implements PackageManagerInternal.PackageListObserver { @Override - public void onPackageAdded(String packageName) { } + public void onPackageAdded(String packageName, int uid) { } @Override - public void onPackageRemoved(String packageName) { + public void onPackageRemoved(String packageName, int uid) { removeRecordForPackage(packageName); } } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 300cd17f33dd..db7613ace705 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -193,8 +193,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } DisplayContent getTopFocusedDisplayContent() { - return getDisplayContent(mTopFocusedDisplayId == INVALID_DISPLAY - ? DEFAULT_DISPLAY : mTopFocusedDisplayId); + final DisplayContent dc = getDisplayContent(mTopFocusedDisplayId); + return dc != null ? dc : getDisplayContent(DEFAULT_DISPLAY); } @Override @@ -1045,6 +1045,15 @@ class RootWindowContainer extends WindowContainer<DisplayContent> mWmService.scheduleAnimationLocked(); } + @Override + protected void removeChild(DisplayContent dc) { + super.removeChild(dc); + if (mTopFocusedDisplayId == dc.getDisplayId()) { + mWmService.updateFocusedWindowLocked( + UPDATE_FOCUS_NORMAL, true /* updateInputWindows */); + } + } + /** * For all display at or below this call the callback. * diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index d7922b15d7e1..3999edd5042b 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -18,7 +18,7 @@ package com.android.server.devicepolicy; import static android.Manifest.permission.BIND_DEVICE_ADMIN; import static android.Manifest.permission.MANAGE_CA_CERTIFICATES; -import static android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY; +import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER; @@ -65,7 +65,7 @@ import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_OPPORTUNIST import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_UNKNOWN; import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_SET_ERROR_FAILURE_SETTING; -import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_SET_SUCCESS; +import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_SET_NO_ERROR; import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER; import static android.app.admin.DevicePolicyManager.WIPE_EUICC; import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE; @@ -4795,8 +4795,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final int callingUserId = mInjector.userHandleGetCallingUserId(); enforceUserUnlocked(callingUserId); mContext.enforceCallingOrSelfPermission( - REQUEST_SCREEN_LOCK_COMPLEXITY, - "Must have " + REQUEST_SCREEN_LOCK_COMPLEXITY + " permission."); + REQUEST_PASSWORD_COMPLEXITY, + "Must have " + REQUEST_PASSWORD_COMPLEXITY + " permission."); synchronized (getLockObject()) { int targetUserId = getCredentialOwner(callingUserId, /* parent= */ false); @@ -14010,7 +14010,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { "Host provided for opportunistic mode, but is not needed."); } putPrivateDnsSettings(ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC, null); - return PRIVATE_DNS_SET_SUCCESS; + return PRIVATE_DNS_SET_NO_ERROR; case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME: if (TextUtils.isEmpty(privateDnsHost) || !NetworkUtils.isWeaklyValidatedHostname(privateDnsHost)) { @@ -14023,7 +14023,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { putPrivateDnsSettings( ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, privateDnsHost); - return PRIVATE_DNS_SET_SUCCESS; + return PRIVATE_DNS_SET_NO_ERROR; default: throw new IllegalArgumentException( String.format("Provided mode, %d, is not a valid mode.", mode)); 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 039a4b74dbdd..28a815ec72a7 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -5201,7 +5201,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { public void testGetPasswordComplexity_currentUserNoPassword() { when(getServices().userManager.isUserUnlocked(DpmMockContext.CALLER_USER_HANDLE)) .thenReturn(true); - mServiceContext.permissions.add(permission.REQUEST_SCREEN_LOCK_COMPLEXITY); + mServiceContext.permissions.add(permission.REQUEST_PASSWORD_COMPLEXITY); when(getServices().userManager.getCredentialOwnerProfile(DpmMockContext.CALLER_USER_HANDLE)) .thenReturn(DpmMockContext.CALLER_USER_HANDLE); @@ -5211,7 +5211,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { public void testGetPasswordComplexity_currentUserHasPassword() { when(getServices().userManager.isUserUnlocked(DpmMockContext.CALLER_USER_HANDLE)) .thenReturn(true); - mServiceContext.permissions.add(permission.REQUEST_SCREEN_LOCK_COMPLEXITY); + mServiceContext.permissions.add(permission.REQUEST_PASSWORD_COMPLEXITY); when(getServices().userManager.getCredentialOwnerProfile(DpmMockContext.CALLER_USER_HANDLE)) .thenReturn(DpmMockContext.CALLER_USER_HANDLE); dpms.mUserPasswordMetrics.put( @@ -5224,7 +5224,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { public void testGetPasswordComplexity_unifiedChallengeReturnsParentUserPassword() { when(getServices().userManager.isUserUnlocked(DpmMockContext.CALLER_USER_HANDLE)) .thenReturn(true); - mServiceContext.permissions.add(permission.REQUEST_SCREEN_LOCK_COMPLEXITY); + mServiceContext.permissions.add(permission.REQUEST_PASSWORD_COMPLEXITY); UserInfo parentUser = new UserInfo(); parentUser.id = DpmMockContext.CALLER_USER_HANDLE + 10; diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java index 111fb7488d89..4cfd098936fb 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java @@ -56,11 +56,11 @@ public class PackageManagerServiceTest { } @Override - public void notifyPackageAdded(String packageName) { + public void notifyPackageAdded(String packageName, int uid) { } @Override - public void notifyPackageRemoved(String packageName) { + public void notifyPackageRemoved(String packageName, int uid) { } } diff --git a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java index 1f861716d380..958b23ff773f 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java @@ -175,9 +175,9 @@ public class AppTimeLimitControllerTests { /** Verify app usage limit observer is added */ @Test public void testAppUsageLimitObserver_AddObserver() { - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0); assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID1)); - addAppUsageLimitObserver(OBS_ID2, GROUP_GAME, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID2, GROUP_GAME, TIME_30_MIN, 0); assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID2)); assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID1)); } @@ -203,7 +203,7 @@ public class AppTimeLimitControllerTests { /** Verify app usage limit observer is removed */ @Test public void testAppUsageLimitObserver_RemoveObserver() { - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0); assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID1)); mController.removeAppUsageLimitObserver(UID, OBS_ID1, USER_ID); assertFalse("Observer wasn't removed", hasAppUsageLimitObserver(UID, OBS_ID1)); @@ -290,9 +290,9 @@ public class AppTimeLimitControllerTests { /** Re-adding an observer should result in only one copy */ @Test public void testAppUsageLimitObserver_ObserverReAdd() { - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0); assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID1)); - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_10_MIN, TIME_10_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_10_MIN, 0); assertTrue("Observer wasn't added", getAppUsageLimitObserver(UID, OBS_ID1).getTimeLimitMs() == TIME_10_MIN); mController.removeAppUsageLimitObserver(UID, OBS_ID1, USER_ID); @@ -304,7 +304,7 @@ public class AppTimeLimitControllerTests { public void testAllObservers_ExclusiveObserverIds() { addAppUsageObserver(OBS_ID1, GROUP1, TIME_10_MIN); addUsageSessionObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_1_MIN); - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_10_MIN, TIME_10_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_10_MIN, 0); assertTrue("Observer wasn't added", hasAppUsageObserver(UID, OBS_ID1)); assertTrue("Observer wasn't added", hasUsageSessionObserver(UID, OBS_ID1)); assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID1)); @@ -396,7 +396,7 @@ public class AppTimeLimitControllerTests { @Test public void testAppUsageLimitObserver_Accumulation() throws Exception { setTime(0L); - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0); startUsage(PKG_SOC1); // Add 10 mins setTime(TIME_10_MIN); @@ -456,7 +456,7 @@ public class AppTimeLimitControllerTests { @Test public void testAppUsageLimitObserver_TimeoutOtherApp() throws Exception { setTime(0L); - addAppUsageLimitObserver(OBS_ID1, GROUP1, 4_000L, 4_000L); + addAppUsageLimitObserver(OBS_ID1, GROUP1, 4_000L, 0); startUsage(PKG_SOC2); assertFalse(mLimitReachedLatch.await(6_000L, TimeUnit.MILLISECONDS)); setTime(6_000L); @@ -498,7 +498,7 @@ public class AppTimeLimitControllerTests { @Test public void testAppUsageLimitObserver_Timeout() throws Exception { setTime(0L); - addAppUsageLimitObserver(OBS_ID1, GROUP1, 4_000L, 4_000L); + addAppUsageLimitObserver(OBS_ID1, GROUP1, 4_000L, 0); startUsage(PKG_SOC1); setTime(6_000L); assertTrue(mLimitReachedLatch.await(6_000L, TimeUnit.MILLISECONDS)); @@ -551,7 +551,7 @@ public class AppTimeLimitControllerTests { setTime(TIME_10_MIN); startUsage(PKG_GAME1); setTime(TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID2, GROUP_GAME, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID2, GROUP_GAME, TIME_30_MIN, 0); setTime(TIME_30_MIN + TIME_10_MIN); stopUsage(PKG_GAME1); assertFalse(mLimitReachedLatch.await(1_000L, TimeUnit.MILLISECONDS)); @@ -612,7 +612,7 @@ public class AppTimeLimitControllerTests { startUsage(PKG_SOC1); setTime(TIME_10_MIN); // 10 second time limit - addAppUsageLimitObserver(OBS_ID1, GROUP_SOC, 10_000L, 10_000L); + addAppUsageLimitObserver(OBS_ID1, GROUP_SOC, 10_000L, 0); setTime(TIME_10_MIN + 5_000L); // Shouldn't call back in 6 seconds assertFalse(mLimitReachedLatch.await(6_000L, TimeUnit.MILLISECONDS)); @@ -692,23 +692,23 @@ public class AppTimeLimitControllerTests { public void testAppUsageLimitObserver_MaxObserverLimit() throws Exception { boolean receivedException = false; int ANOTHER_UID = UID + 1; - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID2, GROUP1, TIME_30_MIN, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID3, GROUP1, TIME_30_MIN, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID4, GROUP1, TIME_30_MIN, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID5, GROUP1, TIME_30_MIN, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID6, GROUP1, TIME_30_MIN, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID7, GROUP1, TIME_30_MIN, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID8, GROUP1, TIME_30_MIN, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID9, GROUP1, TIME_30_MIN, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID10, GROUP1, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0); + addAppUsageLimitObserver(OBS_ID2, GROUP1, TIME_30_MIN, 0); + addAppUsageLimitObserver(OBS_ID3, GROUP1, TIME_30_MIN, 0); + addAppUsageLimitObserver(OBS_ID4, GROUP1, TIME_30_MIN, 0); + addAppUsageLimitObserver(OBS_ID5, GROUP1, TIME_30_MIN, 0); + addAppUsageLimitObserver(OBS_ID6, GROUP1, TIME_30_MIN, 0); + addAppUsageLimitObserver(OBS_ID7, GROUP1, TIME_30_MIN, 0); + addAppUsageLimitObserver(OBS_ID8, GROUP1, TIME_30_MIN, 0); + addAppUsageLimitObserver(OBS_ID9, GROUP1, TIME_30_MIN, 0); + addAppUsageLimitObserver(OBS_ID10, GROUP1, TIME_30_MIN, 0); // Readding an observer should not cause an IllegalStateException - addAppUsageLimitObserver(OBS_ID5, GROUP1, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID5, GROUP1, TIME_30_MIN, 0); // Adding an observer for a different uid shouldn't cause an IllegalStateException mController.addAppUsageLimitObserver( - ANOTHER_UID, OBS_ID11, GROUP1, TIME_30_MIN, TIME_30_MIN, null, USER_ID); + ANOTHER_UID, OBS_ID11, GROUP1, TIME_30_MIN, 0, null, USER_ID); try { - addAppUsageLimitObserver(OBS_ID11, GROUP1, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID11, GROUP1, TIME_30_MIN, 0); } catch (IllegalStateException ise) { receivedException = true; } @@ -748,9 +748,9 @@ public class AppTimeLimitControllerTests { public void testAppUsageLimitObserver_MinimumTimeLimit() throws Exception { boolean receivedException = false; // adding an observer with a one minute time limit should not cause an exception - addAppUsageLimitObserver(OBS_ID1, GROUP1, MIN_TIME_LIMIT, MIN_TIME_LIMIT); + addAppUsageLimitObserver(OBS_ID1, GROUP1, MIN_TIME_LIMIT, 0); try { - addAppUsageLimitObserver(OBS_ID1, GROUP1, MIN_TIME_LIMIT - 1, MIN_TIME_LIMIT - 1); + addAppUsageLimitObserver(OBS_ID1, GROUP1, MIN_TIME_LIMIT - 1, 0); } catch (IllegalArgumentException iae) { receivedException = true; } @@ -807,7 +807,7 @@ public class AppTimeLimitControllerTests { @Test public void testAppUsageLimitObserver_ConcurrentUsage() throws Exception { setTime(0L); - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0); AppTimeLimitController.UsageGroup group = getAppUsageLimitObserver(UID, OBS_ID1); startUsage(PKG_SOC1); // Add 10 mins @@ -967,7 +967,7 @@ public class AppTimeLimitControllerTests { /** Verify app usage limit observer added correctly reports its total usage limit */ @Test public void testAppUsageLimitObserver_GetTotalUsageLimit() { - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0); AppTimeLimitController.AppUsageLimitGroup group = getAppUsageLimitObserver(UID, OBS_ID1); assertNotNull("Observer wasn't added", group); assertEquals("Observer didn't correctly report total usage limit", @@ -978,7 +978,7 @@ public class AppTimeLimitControllerTests { @Test public void testAppUsageLimitObserver_GetUsageRemaining() { setTime(0L); - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0); startUsage(PKG_SOC1); setTime(TIME_10_MIN); stopUsage(PKG_SOC1); @@ -993,8 +993,8 @@ public class AppTimeLimitControllerTests { */ @Test public void testAppUsageLimitObserver_GetAppUsageLimit() { - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN, TIME_10_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0); + addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN, 0); UsageStatsManagerInternal.AppUsageLimitData group = getAppUsageLimit(PKG_SOC1); assertEquals("Observer with the smallest usage limit remaining wasn't returned", TIME_10_MIN, group.getTotalUsageLimit()); @@ -1006,8 +1006,8 @@ public class AppTimeLimitControllerTests { @Test public void testAppUsageLimitObserver_GetAppUsageLimitUsed() { setTime(0L); - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN, TIME_10_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0); + addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN, 0); startUsage(PKG_GAME1); setTime(TIME_10_MIN * 2 + TIME_1_MIN); stopUsage(PKG_GAME1); @@ -1024,8 +1024,8 @@ public class AppTimeLimitControllerTests { @Test public void testAppUsageLimitObserver_GetAppUsageLimitAllUsed() { setTime(0L); - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN, TIME_10_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0); + addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN, 0); startUsage(PKG_SOC1); setTime(TIME_10_MIN); stopUsage(PKG_SOC1); @@ -1046,10 +1046,10 @@ public class AppTimeLimitControllerTests { } } - /** Verify that a limit of 0 is allowed for the special case of re-registering an observer. */ + /** Verify that timeUsed can be the same as timeLimit (for re-registering observers). */ @Test public void testAppUsageLimitObserver_ZeroTimeRemainingIsAllowed() { - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_1_MIN, 0); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_1_MIN, TIME_1_MIN); AppTimeLimitController.AppUsageLimitGroup group = getAppUsageLimitObserver(UID, OBS_ID1); assertNotNull("Observer wasn't added", group); assertEquals("Usage remaining was not 0.", 0, group.getUsageRemaining()); @@ -1078,8 +1078,8 @@ public class AppTimeLimitControllerTests { } private void addAppUsageLimitObserver(int observerId, String[] packages, long timeLimit, - long timeRemaining) { - mController.addAppUsageLimitObserver(UID, observerId, packages, timeLimit, timeRemaining, + long timeUsed) { + mController.addAppUsageLimitObserver(UID, observerId, packages, timeLimit, timeUsed, null, USER_ID); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java index 9f11472b9c7c..e375195af5c9 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java @@ -19,6 +19,7 @@ import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.app.NotificationManager.IMPORTANCE_HIGH; import static android.app.NotificationManager.IMPORTANCE_LOW; +import static android.service.notification.Adjustment.KEY_IMPORTANCE; import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE; import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL; import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_POSITIVE; @@ -423,6 +424,138 @@ public class NotificationRecordTest extends UiServiceTestCase { (int) logMaker.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS)); assertEquals(record.getInterruptionMs(timestamp), (int) logMaker.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_INTERRUPTION_MILLIS)); + // If no importance calculation has been run, no explanation is available. + assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_EXPLANATION)); + assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL)); + assertNull(logMaker.getTaggedData( + MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL_EXPLANATION)); + assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_ASST)); + } + + @Test + public void testLogMakerImportanceApp() { + long timestamp = 1000L; + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, + true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, + false /* lights */, false /* defaultLights */, null /* group */); + NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); + + record.calculateImportance(); // This importance calculation will yield 'app' + final LogMaker logMaker = record.getLogMaker(timestamp); + assertEquals(MetricsEvent.IMPORTANCE_EXPLANATION_APP, + logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_EXPLANATION)); + assertEquals(channel.getImportance(), + logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE)); + // The additional information is only populated if the initial importance is overridden. + assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL)); + assertNull(logMaker.getTaggedData( + MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL_EXPLANATION)); + assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_ASST)); + } + + @Test + public void testLogMakerImportanceAsst() { + long timestamp = 1000L; + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, + true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, + false /* lights */, false /* defaultLights */, null /* group */); + NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); + Bundle signals = new Bundle(); + signals.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW); + record.addAdjustment(new Adjustment(PKG_O, KEY_IMPORTANCE, signals, "", uid)); + record.applyAdjustments(); + record.calculateImportance(); // This importance calculation will yield 'asst' + final LogMaker logMaker = record.getLogMaker(timestamp); + assertEquals(MetricsEvent.IMPORTANCE_EXPLANATION_ASST, + logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_EXPLANATION)); + // Therefore this is the assistant-set importance + assertEquals(IMPORTANCE_LOW, + logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE)); + // Initial importance is populated so we know what it was, since it didn't get used. + assertEquals(channel.getImportance(), + logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL)); + assertEquals(MetricsEvent.IMPORTANCE_EXPLANATION_APP, + logMaker.getTaggedData( + MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL_EXPLANATION)); + // This field is only populated if the assistant was itself overridden by the system. + assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_ASST)); + } + + @Test + public void testLogMakerImportanceSystem() { + long timestamp = 1000L; + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, + true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, + false /* lights */, false /* defaultLights */, null /* group */); + NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); + record.setSystemImportance(IMPORTANCE_HIGH); + record.calculateImportance(); // This importance calculation will yield 'system' + final LogMaker logMaker = record.getLogMaker(timestamp); + assertEquals(MetricsEvent.IMPORTANCE_EXPLANATION_SYSTEM, + logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_EXPLANATION)); + // Therefore this is the system-set importance + assertEquals(IMPORTANCE_HIGH, + logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE)); + // Initial importance is populated so we know what it was, since it didn't get used. + assertEquals(channel.getImportance(), + logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL)); + assertEquals(MetricsEvent.IMPORTANCE_EXPLANATION_APP, + logMaker.getTaggedData( + MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL_EXPLANATION)); + assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_ASST)); + } + + @Test + public void testLogMakerImportanceUser() { + long timestamp = 1000L; + channel.lockFields(channel.USER_LOCKED_IMPORTANCE); + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, + true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, + false /* lights */, false /* defaultLights */, null /* group */); + NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); + record.calculateImportance(); // This importance calculation will yield 'user' + final LogMaker logMaker = record.getLogMaker(timestamp); + assertEquals(MetricsEvent.IMPORTANCE_EXPLANATION_USER, + logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_EXPLANATION)); + // Therefore this is the user-set importance + assertEquals(channel.getImportance(), + logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE)); + // The additional information is only populated if the initial importance is overridden. + assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL)); + assertNull(logMaker.getTaggedData( + MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL_EXPLANATION)); + assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_ASST)); + } + + @Test + public void testLogMakerImportanceMulti() { + long timestamp = 1000L; + channel.lockFields(channel.USER_LOCKED_IMPORTANCE); + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, + true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, + false /* lights */, false /* defaultLights */, null /* group */); + NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); + // Add all 3 ways of overriding the app-set importance of the notification + Bundle signals = new Bundle(); + signals.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW); + record.addAdjustment(new Adjustment(PKG_O, KEY_IMPORTANCE, signals, "", uid)); + record.applyAdjustments(); + record.setSystemImportance(IMPORTANCE_HIGH); + record.calculateImportance(); // This importance calculation will yield 'system' + final LogMaker logMaker = record.getLogMaker(timestamp); + assertEquals(MetricsEvent.IMPORTANCE_EXPLANATION_SYSTEM, + logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_EXPLANATION)); + // Therefore this is the system-set importance + assertEquals(IMPORTANCE_HIGH, + logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE)); + // Initial importance is populated so we know what it was, since it didn't get used. + assertEquals(channel.getImportance(), + logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL)); + assertEquals(MetricsEvent.IMPORTANCE_EXPLANATION_USER, logMaker.getTaggedData( + MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL_EXPLANATION)); + // Assistant importance is populated so we know what it was, since it didn't get used. + assertEquals(IMPORTANCE_LOW, logMaker.getTaggedData( + MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_ASST)); } @Test @@ -807,7 +940,7 @@ public class NotificationRecordTest extends UiServiceTestCase { assertEquals(IMPORTANCE_DEFAULT, record.getImportance()); Bundle bundle = new Bundle(); - bundle.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_LOW); + bundle.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW); Adjustment adjustment = new Adjustment( PKG_O, record.getKey(), bundle, "", record.getUserId()); @@ -831,7 +964,7 @@ public class NotificationRecordTest extends UiServiceTestCase { assertEquals(IMPORTANCE_DEFAULT, record.getImportance()); Bundle bundle = new Bundle(); - bundle.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_LOW); + bundle.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW); Adjustment adjustment = new Adjustment( PKG_O, record.getKey(), bundle, "", record.getUserId()); diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java index aeda473a9e6e..e4d3770de54c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java @@ -316,7 +316,7 @@ public class LaunchParamsPersisterTests extends ActivityTestsBase { public void testClearsRecordInMemoryOnPackageUninstalled() { mTarget.saveTask(mTestTask); - mObserver.onPackageRemoved(TEST_COMPONENT.getPackageName()); + mObserver.onPackageRemoved(TEST_COMPONENT.getPackageName(), TEST_USER_ID); mTarget.getLaunchParams(mTestTask, null, mResult); @@ -327,7 +327,7 @@ public class LaunchParamsPersisterTests extends ActivityTestsBase { public void testClearsWriteQueueItemOnPackageUninstalled() { mTarget.saveTask(mTestTask); - mObserver.onPackageRemoved(TEST_COMPONENT.getPackageName()); + mObserver.onPackageRemoved(TEST_COMPONENT.getPackageName(), TEST_USER_ID); final LaunchParamsPersister target = new LaunchParamsPersister(mPersisterQueue, mSupervisor, mUserFolderGetter); @@ -344,7 +344,7 @@ public class LaunchParamsPersisterTests extends ActivityTestsBase { mTarget.saveTask(mTestTask); mPersisterQueue.flush(); - mObserver.onPackageRemoved(TEST_COMPONENT.getPackageName()); + mObserver.onPackageRemoved(TEST_COMPONENT.getPackageName(), TEST_USER_ID); final LaunchParamsPersister target = new LaunchParamsPersister(mPersisterQueue, mSupervisor, mUserFolderGetter); diff --git a/services/usage/java/com/android/server/usage/AppTimeLimitController.java b/services/usage/java/com/android/server/usage/AppTimeLimitController.java index f3d63873dc4b..6861ad1b2e2d 100644 --- a/services/usage/java/com/android/server/usage/AppTimeLimitController.java +++ b/services/usage/java/com/android/server/usage/AppTimeLimitController.java @@ -511,10 +511,10 @@ public class AppTimeLimitController { class AppUsageLimitGroup extends UsageGroup { public AppUsageLimitGroup(UserData user, ObserverAppData observerApp, int observerId, - String[] observed, long timeLimitMs, long timeRemainingMs, + String[] observed, long timeLimitMs, long timeUsedMs, PendingIntent limitReachedCallback) { super(user, observerApp, observerId, observed, timeLimitMs, limitReachedCallback); - mUsageTimeMs = timeLimitMs - timeRemainingMs; + mUsageTimeMs = timeUsedMs; } @Override @@ -841,7 +841,7 @@ public class AppTimeLimitController { * Existing app usage limit observer with the same observerId will be removed. */ public void addAppUsageLimitObserver(int requestingUid, int observerId, String[] observed, - long timeLimit, long timeRemaining, PendingIntent callbackIntent, + long timeLimit, long timeUsed, PendingIntent callbackIntent, @UserIdInt int userId) { if (timeLimit < getMinTimeLimit()) { throw new IllegalArgumentException("Time limit must be >= " + getMinTimeLimit()); @@ -861,7 +861,7 @@ public class AppTimeLimitController { "Too many app usage observers added by uid " + requestingUid); } group = new AppUsageLimitGroup(user, observerApp, observerId, observed, timeLimit, - timeRemaining, timeRemaining == 0L ? null : callbackIntent); + timeUsed, timeUsed >= timeLimit ? null : callbackIntent); observerApp.appUsageLimitGroups.append(observerId, group); if (DEBUG) { diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 27fdbcb80275..1ec680f10a27 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -1399,7 +1399,7 @@ public class UsageStatsService extends SystemService implements @Override public void registerAppUsageLimitObserver(int observerId, String[] packages, - long timeLimitMs, long timeRemainingMs, PendingIntent callbackIntent, + long timeLimitMs, long timeUsedMs, PendingIntent callbackIntent, String callingPackage) { if (!hasPermissions(callingPackage, Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)) { @@ -1410,11 +1410,7 @@ public class UsageStatsService extends SystemService implements if (packages == null || packages.length == 0) { throw new IllegalArgumentException("Must specify at least one package"); } - if (timeRemainingMs > timeLimitMs) { - throw new IllegalArgumentException( - "Remaining time can't be greater than total time."); - } - if (callbackIntent == null && timeRemainingMs != 0L) { + if (callbackIntent == null && timeUsedMs < timeLimitMs) { throw new NullPointerException("callbackIntent can't be null"); } final int callingUid = Binder.getCallingUid(); @@ -1422,7 +1418,7 @@ public class UsageStatsService extends SystemService implements final long token = Binder.clearCallingIdentity(); try { UsageStatsService.this.registerAppUsageLimitObserver(callingUid, observerId, - packages, timeLimitMs, timeRemainingMs, callbackIntent, userId); + packages, timeLimitMs, timeUsedMs, callbackIntent, userId); } finally { Binder.restoreCallingIdentity(token); } @@ -1550,9 +1546,9 @@ public class UsageStatsService extends SystemService implements } void registerAppUsageLimitObserver(int callingUid, int observerId, String[] packages, - long timeLimitMs, long timeRemainingMs, PendingIntent callbackIntent, int userId) { + long timeLimitMs, long timeUsedMs, PendingIntent callbackIntent, int userId) { mAppTimeLimit.addAppUsageLimitObserver(callingUid, observerId, packages, - timeLimitMs, timeRemainingMs, callbackIntent, userId); + timeLimitMs, timeUsedMs, callbackIntent, userId); } void unregisterAppUsageLimitObserver(int callingUid, int observerId, int userId) { diff --git a/telephony/java/android/telephony/DebugEventReporter.java b/telephony/java/android/telephony/AnomalyReporter.java index 14b7dd6d1b72..9753d8be4065 100644 --- a/telephony/java/android/telephony/DebugEventReporter.java +++ b/telephony/java/android/telephony/AnomalyReporter.java @@ -29,7 +29,6 @@ import com.android.internal.util.IndentingPrintWriter; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.List; -import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -37,7 +36,7 @@ import java.util.concurrent.ConcurrentHashMap; /** * A Simple Surface for Telephony to notify a loosely-coupled debugger of particular issues. * - * DebugEventReporter allows an optional external logging component to receive events detected by + * AnomalyReporter allows an optional external logging component to receive events detected by * the framework and take action. This log surface is designed to provide maximium flexibility * to the receiver of these events. Envisioned use cases of this include notifying a vendor * component of: an event that necessitates (timely) log collection on non-AOSP components; @@ -49,8 +48,8 @@ import java.util.concurrent.ConcurrentHashMap; * * @hide */ -public final class DebugEventReporter { - private static final String TAG = "DebugEventReporter"; +public final class AnomalyReporter { + private static final String TAG = "AnomalyReporter"; private static Context sContext = null; @@ -63,12 +62,12 @@ public final class DebugEventReporter { */ private static String sDebugPackageName = null; - private DebugEventReporter() {}; + private AnomalyReporter() {}; /** * If enabled, build and send an intent to a Debug Service for logging. * - * This method sends the {@link TelephonyManager#DEBUG_EVENT DEBUG_EVENT} broadcast, which is + * This method sends the {@link TelephonyManager#ACTION_ANOMALY_REPORTED} broadcast, which is * system protected. Invoking this method unless you are the system will result in an error. * * @param eventId a fixed event ID that will be sent for each instance of the same event. This @@ -77,9 +76,9 @@ public final class DebugEventReporter { * identification and discussion of this event. This description should ideally be * static and must not contain any sensitive information (especially PII). */ - public static void sendEvent(@NonNull UUID eventId, String description) { + public static void reportAnomaly(@NonNull UUID eventId, String description) { if (sContext == null) { - Rlog.w(TAG, "DebugEventReporter not yet initialized, dropping event=" + eventId); + Rlog.w(TAG, "AnomalyReporter not yet initialized, dropping event=" + eventId); return; } @@ -94,28 +93,28 @@ public final class DebugEventReporter { // so drop these events silently. if (sDebugPackageName == null) return; - Intent dbgIntent = new Intent(TelephonyManager.ACTION_DEBUG_EVENT); - dbgIntent.putExtra(TelephonyManager.EXTRA_DEBUG_EVENT_ID, new ParcelUuid(eventId)); + Intent dbgIntent = new Intent(TelephonyManager.ACTION_ANOMALY_REPORTED); + dbgIntent.putExtra(TelephonyManager.EXTRA_ANOMALY_ID, new ParcelUuid(eventId)); if (description != null) { - dbgIntent.putExtra(TelephonyManager.EXTRA_DEBUG_EVENT_DESCRIPTION, description); + dbgIntent.putExtra(TelephonyManager.EXTRA_ANOMALY_DESCRIPTION, description); } dbgIntent.setPackage(sDebugPackageName); sContext.sendBroadcast(dbgIntent, android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE); } /** - * Initialize the DebugEventReporter with the current context. + * Initialize the AnomalyReporter with the current context. * - * This method must be invoked before any calls to sendEvent() will succeed. This method should - * only be invoked at most once. + * This method must be invoked before any calls to reportAnomaly() will succeed. This method + * should only be invoked at most once. * - * @param context a Context object used to initialize this singleton DebugEventReporter in + * @param context a Context object used to initialize this singleton AnomalyReporter in * the current process. */ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public static void initialize(@NonNull Context context) { if (context == null) { - throw new IllegalArgumentException("DebugEventReporter needs a non-null context."); + throw new IllegalArgumentException("AnomalyReporter needs a non-null context."); } // Ensure that this context has sufficient permissions to send debug events. @@ -129,13 +128,13 @@ public final class DebugEventReporter { PackageManager pm = sContext.getPackageManager(); if (pm == null) return; List<ResolveInfo> packages = pm.queryBroadcastReceivers( - new Intent(TelephonyManager.ACTION_DEBUG_EVENT), + new Intent(TelephonyManager.ACTION_ANOMALY_REPORTED), PackageManager.MATCH_SYSTEM_ONLY | PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); if (packages == null || packages.isEmpty()) return; if (packages.size() > 1) { - Rlog.e(TAG, "Multiple DebugEvent Receivers installed."); + Rlog.e(TAG, "Multiple Anomaly Receivers installed."); } for (ResolveInfo r : packages) { @@ -156,14 +155,14 @@ public final class DebugEventReporter { // Initialization may only be performed once. } - /** Dump the contents of the DebugEventReporter */ + /** Dump the contents of the AnomalyReporter */ public static void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { if (sContext == null) return; IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); sContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "Requires DUMP"); pw.println("Initialized=" + (sContext != null ? "Yes" : "No")); pw.println("Debug Package=" + sDebugPackageName); - pw.println("Event Counts:"); + pw.println("Anomaly Counts:"); pw.increaseIndent(); for (UUID event : sEvents.keySet()) { pw.println(event + ": " + sEvents.get(event)); diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index d79a168975e7..524d080c2ea5 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -2520,6 +2520,18 @@ public class CarrierConfigManager { "emergency_number_prefix_string_array"; /** + * Indicates when a carrier has a primary subscription and an opportunistic subscription active, + * and when Internet data is switched to opportunistic network, whether to still show + * signal bar of primary network. By default it will be false, meaning whenever data + * is going over opportunistic network, signal bar will reflect signal strength and rat + * icon of that network. + * + * @hide + */ + public static final String KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN = + "always_show_primary_signal_bar_in_opportunistic_network_boolean"; + + /** * GPS configs. See android.hardware.gnss@1.0 IGnssConfiguration. * @hide */ @@ -3052,6 +3064,8 @@ public class CarrierConfigManager { sDefaults.putStringArray(KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY, new String[0]); sDefaults.putBoolean(KEY_USE_USIM_BOOL, false); sDefaults.putBoolean(KEY_AUTO_CANCEL_CS_REJECT_NOTIFICATION, false); + sDefaults.putBoolean(KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN, + false); } /** diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java index 6c835dc46029..e5aadad60129 100644 --- a/telephony/java/android/telephony/CellIdentity.java +++ b/telephony/java/android/telephony/CellIdentity.java @@ -86,7 +86,7 @@ public abstract class CellIdentity implements Parcelable { } if ((mMccStr != null && mMncStr == null) || (mMccStr == null && mMncStr != null)) { - DebugEventReporter.sendEvent( + AnomalyReporter.reportAnomaly( UUID.fromString("a3ab0b9d-f2aa-4baf-911d-7096c0d4645a"), "CellIdentity Missing Half of PLMN ID"); } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 16dafd63e111..0c6bc4864877 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -1383,41 +1383,42 @@ public class TelephonyManager { * in the application manifest. For performance reasons, if no application to receive these * events is detected at boot, then these events will not be sent. * - * <p>Each event will include an {@link EXTRA_DEBUG_EVENT_ID} that will uniquely identify the + * <p>Each event will include an {@link EXTRA_ANOMALY_ID} that will uniquely identify the * event that has occurred. Each event will be sent to the diagnostic monitor only once per * boot cycle (as another optimization). * - * @see #EXTRA_DEBUG_EVENT_ID - * @see #EXTRA_DEBUG_EVENT_DESCRIPTION + * @see #EXTRA_ANOMALY_ID + * @see #EXTRA_ANOMALY_DESCRIPTION * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - public static final String ACTION_DEBUG_EVENT = "android.telephony.action.DEBUG_EVENT"; + public static final String ACTION_ANOMALY_REPORTED = + "android.telephony.action.ANOMALY_REPORTED"; /** * An arbitrary ParcelUuid which should be consistent for each occurrence of a DebugEvent. * - * This field must be included in all {@link ACTION_DEBUG_EVENT} events. + * This field must be included in all {@link ACTION_ANOMALY_REPORTED} events. * - * @see #ACTION_DEBUG_EVENT + * @see #ACTION_ANOMALY_REPORTED * @hide */ @SystemApi - public static final String EXTRA_DEBUG_EVENT_ID = "android.telephony.extra.DEBUG_EVENT_ID"; + public static final String EXTRA_ANOMALY_ID = "android.telephony.extra.ANOMALY_ID"; /** - * A freeform string description of the DebugEvent. + * A freeform string description of the Anomaly. * - * This field is optional for all {@link ACTION_DEBUG_EVENT}s, as a guideline should not + * This field is optional for all {@link ACTION_ANOMALY_REPORTED}s, as a guideline should not * exceed 80 characters, and should be as short as possible to convey the essence of the event. * - * @see #ACTION_DEBUG_EVENT + * @see #ACTION_ANOMALY_REPORTED * @hide */ @SystemApi - public static final String EXTRA_DEBUG_EVENT_DESCRIPTION = - "android.telephony.extra.DEBUG_EVENT_DESCRIPTION"; + public static final String EXTRA_ANOMALY_DESCRIPTION = + "android.telephony.extra.ANOMALY_DESCRIPTION"; // // @@ -5188,6 +5189,40 @@ public class TelephonyManager { } /** + * Opens a logical channel to the ICC card using the physical slot index. + * + * Use this method when no subscriptions are available on the SIM and the operation must be + * performed using the physical slot index. + * + * Input parameters equivalent to TS 27.007 AT+CCHO command. + * + * <p>Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}. + * + * @param slotIndex the physical slot index of the ICC card + * @param aid Application id. See ETSI 102.221 and 101.220. + * @param p2 P2 parameter (described in ISO 7816-4). + * @return an IccOpenLogicalChannelResponse object. + * @hide + */ + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @SystemApi + @Nullable + public IccOpenLogicalChannelResponse iccOpenLogicalChannelBySlot(int slotIndex, + @Nullable String aid, int p2) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.iccOpenLogicalChannelBySlot(slotIndex, getOpPackageName(), aid, + p2); + } + } catch (RemoteException ex) { + } catch (NullPointerException ex) { + } + return null; + } + + /** * Opens a logical channel to the ICC card. * * Input parameters equivalent to TS 27.007 AT+CCHO command. @@ -5231,6 +5266,38 @@ public class TelephonyManager { } /** + * Closes a previously opened logical channel to the ICC card using the physical slot index. + * + * Use this method when no subscriptions are available on the SIM and the operation must be + * performed using the physical slot index. + * + * Input parameters equivalent to TS 27.007 AT+CCHC command. + * + * <p>Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}. + * + * @param slotIndex the physical slot index of the ICC card + * @param channel is the channel id to be closed as returned by a successful + * iccOpenLogicalChannel. + * @return true if the channel was closed successfully. + * @hide + */ + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @SystemApi + @Nullable + public boolean iccCloseLogicalChannelBySlot(int slotIndex, int channel) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.iccCloseLogicalChannelBySlot(slotIndex, channel); + } + } catch (RemoteException ex) { + } catch (NullPointerException ex) { + } + return false; + } + + /** * Closes a previously opened logical channel to the ICC card. * * Input parameters equivalent to TS 27.007 AT+CCHC command. @@ -5239,7 +5306,7 @@ public class TelephonyManager { * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling * app has carrier privileges (see {@link #hasCarrierPrivileges}). * - * @param channel is the channel id to be closed as retruned by a successful + * @param channel is the channel id to be closed as returned by a successful * iccOpenLogicalChannel. * @return true if the channel was closed successfully. */ @@ -5257,7 +5324,7 @@ public class TelephonyManager { * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param subId The subscription to use. - * @param channel is the channel id to be closed as retruned by a successful + * @param channel is the channel id to be closed as returned by a successful * iccOpenLogicalChannel. * @return true if the channel was closed successfully. * @hide @@ -5274,6 +5341,48 @@ public class TelephonyManager { } /** + * Transmit an APDU to the ICC card over a logical channel using the physical slot index. + * + * Use this method when no subscriptions are available on the SIM and the operation must be + * performed using the physical slot index. + * + * Input parameters equivalent to TS 27.007 AT+CGLA command. + * + * <p>Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}. + * + * @param slotIndex the physical slot index of the ICC card + * @param channel is the channel id to be closed as returned by a successful + * iccOpenLogicalChannel. + * @param cla Class of the APDU command. + * @param instruction Instruction of the APDU command. + * @param p1 P1 value of the APDU command. + * @param p2 P2 value of the APDU command. + * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU + * is sent to the SIM. + * @param data Data to be sent with the APDU. + * @return The APDU response from the ICC card with the status appended at + * the end. + * @hide + */ + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @SystemApi + @Nullable + public String iccTransmitApduLogicalChannelBySlot(int slotIndex, int channel, int cla, + int instruction, int p1, int p2, int p3, @Nullable String data) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.iccTransmitApduLogicalChannelBySlot(slotIndex, channel, cla, + instruction, p1, p2, p3, data); + } + } catch (RemoteException ex) { + } catch (NullPointerException ex) { + } + return null; + } + + /** * Transmit an APDU to the ICC card over a logical channel. * * Input parameters equivalent to TS 27.007 AT+CGLA command. @@ -5337,6 +5446,46 @@ public class TelephonyManager { } /** + * Transmit an APDU to the ICC card over the basic channel using the physical slot index. + * + * Use this method when no subscriptions are available on the SIM and the operation must be + * performed using the physical slot index. + * + * Input parameters equivalent to TS 27.007 AT+CSIM command. + * + * <p>Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}. + * + * @param slotIndex the physical slot index of the ICC card to target + * @param cla Class of the APDU command. + * @param instruction Instruction of the APDU command. + * @param p1 P1 value of the APDU command. + * @param p2 P2 value of the APDU command. + * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU + * is sent to the SIM. + * @param data Data to be sent with the APDU. + * @return The APDU response from the ICC card with the status appended at + * the end. + * @hide + */ + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @SystemApi + @NonNull + public String iccTransmitApduBasicChannelBySlot(int slotIndex, int cla, int instruction, int p1, + int p2, int p3, @Nullable String data) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.iccTransmitApduBasicChannelBySlot(slotIndex, getOpPackageName(), + cla, instruction, p1, p2, p3, data); + } + } catch (RemoteException ex) { + } catch (NullPointerException ex) { + } + return null; + } + + /** * Transmit an APDU to the ICC card over the basic channel. * * Input parameters equivalent to TS 27.007 AT+CSIM command. diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index 0b1d1fb5114b..d0b52c9085a5 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -1641,6 +1641,7 @@ public class ApnSetting implements Parcelable { * * @param entryName the entry name to set for the APN */ + @NonNull public Builder setEntryName(String entryName) { this.mEntryName = entryName; return this; @@ -1651,6 +1652,7 @@ public class ApnSetting implements Parcelable { * * @param apnName the name to set for the APN */ + @NonNull public Builder setApnName(String apnName) { this.mApnName = apnName; return this; @@ -1681,6 +1683,7 @@ public class ApnSetting implements Parcelable { * * @param proxy the proxy address to set for the APN */ + @NonNull public Builder setProxyAddress(String proxy) { this.mProxyAddress = proxy; return this; @@ -1691,6 +1694,7 @@ public class ApnSetting implements Parcelable { * * @param port the proxy port to set for the APN */ + @NonNull public Builder setProxyPort(int port) { this.mProxyPort = port; return this; @@ -1701,6 +1705,7 @@ public class ApnSetting implements Parcelable { * * @param mmsc the MMSC Uri to set for the APN */ + @NonNull public Builder setMmsc(Uri mmsc) { this.mMmsc = mmsc; return this; @@ -1732,6 +1737,7 @@ public class ApnSetting implements Parcelable { * * @param mmsProxy the MMS proxy address to set for the APN */ + @NonNull public Builder setMmsProxyAddress(String mmsProxy) { this.mMmsProxyAddress = mmsProxy; return this; @@ -1742,6 +1748,7 @@ public class ApnSetting implements Parcelable { * * @param mmsPort the MMS proxy port to set for the APN */ + @NonNull public Builder setMmsProxyPort(int mmsPort) { this.mMmsProxyPort = mmsPort; return this; @@ -1752,6 +1759,7 @@ public class ApnSetting implements Parcelable { * * @param user the APN username to set for the APN */ + @NonNull public Builder setUser(String user) { this.mUser = user; return this; @@ -1763,6 +1771,7 @@ public class ApnSetting implements Parcelable { * @see android.provider.Telephony.Carriers#PASSWORD * @param password the APN password to set for the APN */ + @NonNull public Builder setPassword(String password) { this.mPassword = password; return this; @@ -1773,6 +1782,7 @@ public class ApnSetting implements Parcelable { * * @param authType the authentication type to set for the APN */ + @NonNull public Builder setAuthType(@AuthType int authType) { this.mAuthType = authType; return this; @@ -1789,6 +1799,7 @@ public class ApnSetting implements Parcelable { * * @param apnTypeBitmask a bitmask describing the types of the APN */ + @NonNull public Builder setApnTypeBitmask(@ApnType int apnTypeBitmask) { this.mApnTypeBitmask = apnTypeBitmask; return this; @@ -1801,6 +1812,7 @@ public class ApnSetting implements Parcelable { * * @param operatorNumeric the numeric operator ID to set for this entry */ + @NonNull public Builder setOperatorNumeric(String operatorNumeric) { this.mOperatorNumeric = operatorNumeric; return this; @@ -1813,6 +1825,7 @@ public class ApnSetting implements Parcelable { * * @param protocol the protocol to set to use to connect to this APN */ + @NonNull public Builder setProtocol(@ProtocolType int protocol) { this.mProtocol = protocol; return this; @@ -1825,6 +1838,7 @@ public class ApnSetting implements Parcelable { * * @param roamingProtocol the protocol to set to use to connect to this APN when roaming */ + @NonNull public Builder setRoamingProtocol(@ProtocolType int roamingProtocol) { this.mRoamingProtocol = roamingProtocol; return this; @@ -1835,6 +1849,7 @@ public class ApnSetting implements Parcelable { * * @param carrierEnabled the current status to set for this APN */ + @NonNull public Builder setCarrierEnabled(boolean carrierEnabled) { this.mCarrierEnabled = carrierEnabled; return this; @@ -1845,6 +1860,7 @@ public class ApnSetting implements Parcelable { * * @param networkTypeBitmask the Radio Technology (Network Type) info */ + @NonNull public Builder setNetworkTypeBitmask(int networkTypeBitmask) { this.mNetworkTypeBitmask = networkTypeBitmask; return this; @@ -1855,6 +1871,7 @@ public class ApnSetting implements Parcelable { * * @param mvnoType the MVNO match type to set for this APN */ + @NonNull public Builder setMvnoType(@MvnoType int mvnoType) { this.mMvnoType = mvnoType; return this; diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEventDescriptor.java b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEventDescriptor.java index 1fb8798b6f20..bcadc80bda54 100644 --- a/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEventDescriptor.java +++ b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEventDescriptor.java @@ -17,6 +17,7 @@ package android.telephony.ims; import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED; +import android.annotation.NonNull; import android.annotation.Nullable; import android.net.Uri; import android.os.Parcel; @@ -42,7 +43,7 @@ public class RcsGroupThreadIconChangedEventDescriptor extends RcsGroupThreadEven new RcsParticipant(mOriginatingParticipantId), mNewIcon); } - public static final @android.annotation.NonNull Creator<RcsGroupThreadIconChangedEventDescriptor> CREATOR = + public static final @NonNull Creator<RcsGroupThreadIconChangedEventDescriptor> CREATOR = new Creator<RcsGroupThreadIconChangedEventDescriptor>() { @Override public RcsGroupThreadIconChangedEventDescriptor createFromParcel(Parcel in) { diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEventDescriptor.java b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEventDescriptor.java index 980aba2da59d..597fa0a3f9f8 100644 --- a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEventDescriptor.java +++ b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEventDescriptor.java @@ -17,6 +17,7 @@ package android.telephony.ims; import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED; +import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; @@ -44,7 +45,7 @@ public class RcsGroupThreadNameChangedEventDescriptor extends RcsGroupThreadEven mNewName); } - public static final @android.annotation.NonNull Creator<RcsGroupThreadNameChangedEventDescriptor> CREATOR = + public static final @NonNull Creator<RcsGroupThreadNameChangedEventDescriptor> CREATOR = new Creator<RcsGroupThreadNameChangedEventDescriptor>() { @Override public RcsGroupThreadNameChangedEventDescriptor createFromParcel(Parcel in) { diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEventDescriptor.java b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEventDescriptor.java index e899e1c3eb92..abea10a641ac 100644 --- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEventDescriptor.java +++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEventDescriptor.java @@ -17,6 +17,7 @@ package android.telephony.ims; import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED; +import android.annotation.NonNull; import android.os.Parcel; import com.android.internal.annotations.VisibleForTesting; @@ -43,7 +44,7 @@ public class RcsGroupThreadParticipantJoinedEventDescriptor extends RcsGroupThre new RcsParticipant(mJoinedParticipantId)); } - public static final @android.annotation.NonNull Creator<RcsGroupThreadParticipantJoinedEventDescriptor> CREATOR = + public static final @NonNull Creator<RcsGroupThreadParticipantJoinedEventDescriptor> CREATOR = new Creator<RcsGroupThreadParticipantJoinedEventDescriptor>() { @Override public RcsGroupThreadParticipantJoinedEventDescriptor createFromParcel(Parcel in) { diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEventDescriptor.java b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEventDescriptor.java index 8eefb4bd27b4..f287db19da05 100644 --- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEventDescriptor.java +++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEventDescriptor.java @@ -17,6 +17,7 @@ package android.telephony.ims; import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED; +import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; @@ -44,7 +45,8 @@ public class RcsGroupThreadParticipantLeftEventDescriptor extends RcsGroupThread new RcsParticipant(mLeavingParticipantId)); } - public static final @android.annotation.NonNull Parcelable.Creator<RcsGroupThreadParticipantLeftEventDescriptor> CREATOR = + @NonNull + public static final Parcelable.Creator<RcsGroupThreadParticipantLeftEventDescriptor> CREATOR = new Creator<RcsGroupThreadParticipantLeftEventDescriptor>() { @Override public RcsGroupThreadParticipantLeftEventDescriptor createFromParcel(Parcel in) { diff --git a/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java b/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java index 955f263570f7..d95dc4fda3e3 100644 --- a/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java +++ b/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java @@ -17,6 +17,7 @@ package android.telephony.ims; import android.annotation.CheckResult; +import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; @@ -152,7 +153,7 @@ public final class RcsIncomingMessageCreationParams extends RcsMessageCreationPa return mSenderParticipantId; } - public static final @android.annotation.NonNull Creator<RcsIncomingMessageCreationParams> CREATOR = + public static final @NonNull Creator<RcsIncomingMessageCreationParams> CREATOR = new Creator<RcsIncomingMessageCreationParams>() { @Override public RcsIncomingMessageCreationParams createFromParcel(Parcel in) { diff --git a/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java b/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java index 22fd8a58a228..c001ffb354b0 100644 --- a/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java +++ b/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java @@ -16,6 +16,7 @@ package android.telephony.ims; +import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; @@ -64,7 +65,7 @@ public final class RcsOutgoingMessageCreationParams extends RcsMessageCreationPa super(in); } - public static final @android.annotation.NonNull Creator<RcsOutgoingMessageCreationParams> CREATOR = + public static final @NonNull Creator<RcsOutgoingMessageCreationParams> CREATOR = new Creator<RcsOutgoingMessageCreationParams>() { @Override public RcsOutgoingMessageCreationParams createFromParcel(Parcel in) { diff --git a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEventDescriptor.java b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEventDescriptor.java index aad9fb3e2ba6..b29896c12ab8 100644 --- a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEventDescriptor.java +++ b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEventDescriptor.java @@ -17,6 +17,7 @@ package android.telephony.ims; import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED; +import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; @@ -45,7 +46,7 @@ public class RcsParticipantAliasChangedEventDescriptor extends RcsEventDescripto mTimestamp, new RcsParticipant(mParticipantId), mNewAlias); } - public static final @android.annotation.NonNull Creator<RcsParticipantAliasChangedEventDescriptor> CREATOR = + public static final @NonNull Creator<RcsParticipantAliasChangedEventDescriptor> CREATOR = new Creator<RcsParticipantAliasChangedEventDescriptor>() { @Override public RcsParticipantAliasChangedEventDescriptor createFromParcel(Parcel in) { diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 122747a65a7d..62b92fd9a789 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -553,6 +553,20 @@ interface ITelephony { void setCellInfoListRate(int rateInMillis); /** + * Opens a logical channel to the ICC card using the physical slot index. + * + * Input parameters equivalent to TS 27.007 AT+CCHO command. + * + * @param slotIndex The physical slot index of the target ICC card + * @param callingPackage the name of the package making the call. + * @param AID Application id. See ETSI 102.221 and 101.220. + * @param p2 P2 parameter (described in ISO 7816-4). + * @return an IccOpenLogicalChannelResponse object. + */ + IccOpenLogicalChannelResponse iccOpenLogicalChannelBySlot( + int slotIndex, String callingPackage, String AID, int p2); + + /** * Opens a logical channel to the ICC card. * * Input parameters equivalent to TS 27.007 AT+CCHO command. @@ -567,12 +581,24 @@ interface ITelephony { int subId, String callingPackage, String AID, int p2); /** + * Closes a previously opened logical channel to the ICC card using the physical slot index. + * + * Input parameters equivalent to TS 27.007 AT+CCHC command. + * + * @param slotIndex The physical slot index of the target ICC card + * @param channel is the channel id to be closed as returned by a + * successful iccOpenLogicalChannel. + * @return true if the channel was closed successfully. + */ + boolean iccCloseLogicalChannelBySlot(int slotIndex, int channel); + + /** * Closes a previously opened logical channel to the ICC card. * * Input parameters equivalent to TS 27.007 AT+CCHC command. * * @param subId The subscription to use. - * @param channel is the channel id to be closed as retruned by a + * @param channel is the channel id to be closed as returned by a * successful iccOpenLogicalChannel. * @return true if the channel was closed successfully. */ @@ -580,12 +606,33 @@ interface ITelephony { boolean iccCloseLogicalChannel(int subId, int channel); /** + * Transmit an APDU to the ICC card over a logical channel using the physical slot index. + * + * Input parameters equivalent to TS 27.007 AT+CGLA command. + * + * @param slotIndex The physical slot index of the target ICC card + * @param channel is the channel id to be closed as returned by a + * successful iccOpenLogicalChannel. + * @param cla Class of the APDU command. + * @param instruction Instruction of the APDU command. + * @param p1 P1 value of the APDU command. + * @param p2 P2 value of the APDU command. + * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU + * is sent to the SIM. + * @param data Data to be sent with the APDU. + * @return The APDU response from the ICC card with the status appended at + * the end. + */ + String iccTransmitApduLogicalChannelBySlot(int slotIndex, int channel, int cla, int instruction, + int p1, int p2, int p3, String data); + + /** * Transmit an APDU to the ICC card over a logical channel. * * Input parameters equivalent to TS 27.007 AT+CGLA command. * * @param subId The subscription to use. - * @param channel is the channel id to be closed as retruned by a + * @param channel is the channel id to be closed as returned by a * successful iccOpenLogicalChannel. * @param cla Class of the APDU command. * @param instruction Instruction of the APDU command. @@ -602,6 +649,26 @@ interface ITelephony { int p1, int p2, int p3, String data); /** + * Transmit an APDU to the ICC card over the basic channel using the physical slot index. + * + * Input parameters equivalent to TS 27.007 AT+CSIM command. + * + * @param slotIndex The physical slot index of the target ICC card + * @param callingPackage the name of the package making the call. + * @param cla Class of the APDU command. + * @param instruction Instruction of the APDU command. + * @param p1 P1 value of the APDU command. + * @param p2 P2 value of the APDU command. + * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU + * is sent to the SIM. + * @param data Data to be sent with the APDU. + * @return The APDU response from the ICC card with the status appended at + * the end. + */ + String iccTransmitApduBasicChannelBySlot(int slotIndex, String callingPackage, int cla, + int instruction, int p1, int p2, int p3, String data); + + /** * Transmit an APDU to the ICC card over the basic channel. * * Input parameters equivalent to TS 27.007 AT+CSIM command. diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp index 8be721a04305..dfc3b6e15b3e 100644 --- a/tests/RollbackTest/Android.bp +++ b/tests/RollbackTest/Android.bp @@ -118,7 +118,7 @@ android_test { ":com.android.tests.rollback.testapex.RollbackTestApexV2", ], test_config: "RollbackTest.xml", - sdk_version: "system_current", + sdk_version: "test_current", } java_test_host { diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java index a03fae0aa606..9aed0748266a 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java @@ -340,16 +340,26 @@ class RollbackTestUtils { } /** - * Asserts that the given RollbackInfo has a single package with expected - * package name and versions. + * Asserts that the given RollbackInfo has the given packages with expected + * package names and all are rolled to and from the same given versions. */ - static void assertRollbackInfoEquals(String packageName, + static void assertRollbackInfoEquals(String[] packageNames, long versionRolledBackFrom, long versionRolledBackTo, RollbackInfo info, VersionedPackage... causePackages) { assertNotNull(info); - assertEquals(1, info.getPackages().size()); - assertPackageRollbackInfoEquals(packageName, versionRolledBackFrom, versionRolledBackTo, - info.getPackages().get(0)); + assertEquals(packageNames.length, info.getPackages().size()); + int foundPackages = 0; + for (String packageName : packageNames) { + for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) { + if (packageName.equals(pkgRollbackInfo.getPackageName())) { + foundPackages++; + assertPackageRollbackInfoEquals(packageName, versionRolledBackFrom, + versionRolledBackTo, pkgRollbackInfo); + break; + } + } + } + assertEquals(packageNames.length, foundPackages); assertEquals(causePackages.length, info.getCausePackages().size()); for (int i = 0; i < causePackages.length; ++i) { assertEquals(causePackages[i].getPackageName(), @@ -360,6 +370,18 @@ class RollbackTestUtils { } /** + * Asserts that the given RollbackInfo has a single package with expected + * package name and versions. + */ + static void assertRollbackInfoEquals(String packageName, + long versionRolledBackFrom, long versionRolledBackTo, + RollbackInfo info, VersionedPackage... causePackages) { + String[] packageNames = {packageName}; + assertRollbackInfoEquals(packageNames, versionRolledBackFrom, versionRolledBackTo, info, + causePackages); + } + + /** * Waits for the given session to be marked as ready. * Throws an assertion if the session fails. */ @@ -453,4 +475,17 @@ class RollbackTestUtils { fail(result); } } + + /** + * Return the rollback info for a recently committed rollback, by matching the rollback id, or + * return null if no matching rollback is found. + */ + static RollbackInfo getRecentlyCommittedRollbackInfoById(int getRollbackId) { + for (RollbackInfo info : getRollbackManager().getRecentlyCommittedRollbacks()) { + if (info.getRollbackId() == getRollbackId) { + return info; + } + } + return null; + } } diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java index 59ae8d9deaeb..047451b643da 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java @@ -17,6 +17,7 @@ package com.android.tests.rollback; import static com.android.tests.rollback.RollbackTestUtils.assertRollbackInfoEquals; +import static com.android.tests.rollback.RollbackTestUtils.getRecentlyCommittedRollbackInfoById; import static com.android.tests.rollback.RollbackTestUtils.getUniqueRollbackInfoForPackage; import android.Manifest; @@ -25,7 +26,6 @@ import android.content.rollback.RollbackManager; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import org.junit.After; @@ -47,6 +47,8 @@ public class StagedRollbackTest { private static final String TAG = "RollbackTest"; private static final String TEST_APP_A = "com.android.tests.rollback.testapp.A"; + private static final String TEST_APP_A_V1 = "RollbackTestAppAv1.apk"; + private static final String TEST_APP_A_V2 = "RollbackTestAppAv2.apk"; private static final String TEST_APEX_PKG = "com.android.tests.rollback.testapex"; private static final String TEST_APEX_V1 = "com.android.tests.rollback.testapex.RollbackTestApexV1.apex"; @@ -82,11 +84,11 @@ public class StagedRollbackTest { RollbackTestUtils.uninstall(TEST_APP_A); assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); - RollbackTestUtils.install("RollbackTestAppAv1.apk", false); + RollbackTestUtils.install(TEST_APP_A_V1, false); assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); RollbackTestUtils.processUserData(TEST_APP_A); - RollbackTestUtils.installStaged(true, "RollbackTestAppAv2.apk"); + RollbackTestUtils.installStaged(true, TEST_APP_A_V2); // At this point, the host test driver will reboot the device and run // testApkOnlyCommitRollback(). @@ -142,6 +144,86 @@ public class StagedRollbackTest { } /** + * Test rollbacks of staged installs an apk and an apex. + * Prepare apex (and apk) phase. + */ + @Test + public void testApkAndApexPrepare() throws Exception { + RollbackTestUtils.uninstall(TEST_APP_A); + assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + + // Note: can't uninstall the apex. See note in #testApexOnlyPrepareApex(). + RollbackTestUtils.installStaged(false, TEST_APP_A_V1, TEST_APEX_V1); + + // At this point, the host test driver will reboot the device and run + // testApkAndApexEnableRollback(). + } + + /** + * Test rollbacks of staged installs an apk and an apex. + * Enable rollback phase. + */ + @Test + public void testApkAndApexEnableRollback() throws Exception { + assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APEX_PKG)); + assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + + RollbackTestUtils.installStaged(true, TEST_APP_A_V2, TEST_APEX_V2); + + // At this point, the host test driver will reboot the device and run + // testApkAndApexCommitRollback(). + } + + /** + * Test rollbacks of staged installs an apk and an apex. + * Commit rollback phase. + */ + @Test + public void testApkAndApexCommitRollback() throws Exception { + assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APEX_PKG)); + assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + + RollbackTestUtils.processUserData(TEST_APP_A); + + RollbackManager rm = RollbackTestUtils.getRollbackManager(); + + RollbackInfo rollback = getUniqueRollbackInfoForPackage( + rm.getAvailableRollbacks(), TEST_APP_A); + String[] packagesNames = {TEST_APEX_PKG, TEST_APP_A}; + assertRollbackInfoEquals(packagesNames, 2, 1, rollback); + assertTrue(rollback.isStaged()); + + RollbackTestUtils.rollback(rollback.getRollbackId()); + + RollbackInfo committed = getRecentlyCommittedRollbackInfoById(rollback.getRollbackId()); + + assertRollbackInfoEquals(packagesNames, 2, 1, committed); + assertTrue(committed.isStaged()); + assertNotEquals(-1, committed.getCommittedSessionId()); + + RollbackTestUtils.waitForSessionReady(committed.getCommittedSessionId()); + + // The apex and apk should not be rolled back until after reboot. + assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APEX_PKG)); + assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + + // At this point, the host test driver will reboot the device and run + // testApkAndApexConfirmRollback(). + } + + /** + * Test rollbacks of staged installs an apk and an apex. + * Confirm rollback phase. + */ + @Test + public void testApkAndApexConfirmRollback() throws Exception { + assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APEX_PKG)); + assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + + RollbackTestUtils.processUserData(TEST_APP_A); + } + + /** * Test rollbacks of staged installs involving only apex. * Prepare apex phase. */ @@ -171,7 +253,7 @@ public class StagedRollbackTest { } /** - * Test rollbacks of staged installs involving only apks. + * Test rollbacks of staged installs involving only apex. * Commit rollback phase. */ @Test @@ -186,18 +268,8 @@ public class StagedRollbackTest { RollbackTestUtils.rollback(rollback.getRollbackId()); - // Note: We can't use getUniqueRollbackInfoForPackage for the apex, - // because we can't uninstall the apex (b/123667725), which means - // there's no way to clear info about rollbacks from previous tests - // run on the device. Look up the info by rollback id instead. - RollbackInfo committed = null; - for (RollbackInfo info : rm.getRecentlyCommittedRollbacks()) { - if (info.getRollbackId() == rollback.getRollbackId()) { - assertNull(committed); - committed = info; - break; - } - } + RollbackInfo committed = getRecentlyCommittedRollbackInfoById(rollback.getRollbackId()); + assertRollbackInfoEquals(TEST_APEX_PKG, 2, 1, committed); assertTrue(committed.isStaged()); assertNotEquals(-1, committed.getCommittedSessionId()); @@ -212,7 +284,7 @@ public class StagedRollbackTest { } /** - * Test rollbacks of staged installs involving only apks. + * Test rollbacks of staged installs involving only apex. * Confirm rollback phase. */ @Test diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java index 24a51dc5a060..ac7f634d51f1 100644 --- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java +++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java @@ -67,4 +67,18 @@ public class StagedRollbackTest extends BaseHostJUnit4Test { getDevice().reboot(); runPhase("testApexOnlyConfirmRollback"); } + + /** + * Tests staged rollbacks involving apk and apex. + */ + @Test + public void testApkAndApex() throws Exception { + runPhase("testApkAndApexPrepare"); + getDevice().reboot(); + runPhase("testApkAndApexEnableRollback"); + getDevice().reboot(); + runPhase("testApkAndApexCommitRollback"); + getDevice().reboot(); + runPhase("testApkAndApexConfirmRollback"); + } } diff --git a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java index adcd11a08bff..bb985d7f8be2 100644 --- a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java +++ b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java @@ -197,7 +197,7 @@ public class UsageStatsActivity extends ListActivity { intent.setPackage(getPackageName()); intent.putExtra(EXTRA_KEY_TIMEOUT, true); mUsageStatsManager.registerAppUsageLimitObserver(1, packages, - Duration.ofSeconds(60), Duration.ofSeconds(60), + Duration.ofSeconds(60), Duration.ofSeconds(0), PendingIntent.getActivity(UsageStatsActivity.this, 1, intent, 0)); } } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 985d66739d31..dc11bf359056 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -190,6 +190,8 @@ import org.mockito.stubbing.Answer; import java.net.Inet4Address; import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; @@ -206,6 +208,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; import java.util.function.Predicate; /** @@ -2549,7 +2552,8 @@ public class ConnectivityServiceTest { verifyActiveNetwork(TRANSPORT_CELLULAR); } - @Test + // TODO: deflake and re-enable + // @Test public void testPartialConnectivity() { // Register network callback. NetworkRequest request = new NetworkRequest.Builder() @@ -4018,17 +4022,24 @@ public class ConnectivityServiceTest { callback3.expectStopped(); } - @Test - public void testNattSocketKeepalives_SingleThreadExecutor() throws Exception { + // Helper method to prepare the executor and run test + private void runTestWithSerialExecutors(Consumer<Executor> functor) { final ExecutorService executorSingleThread = Executors.newSingleThreadExecutor(); - doTestNattSocketKeepalivesWithExecutor(executorSingleThread); + final Executor executorInline = (Runnable r) -> r.run(); + functor.accept(executorSingleThread); executorSingleThread.shutdown(); + functor.accept(executorInline); } @Test - public void testNattSocketKeepalives_InlineExecutor() throws Exception { - final Executor executorInline = (Runnable r) -> r.run(); - doTestNattSocketKeepalivesWithExecutor(executorInline); + public void testNattSocketKeepalives() { + runTestWithSerialExecutors(executor -> { + try { + doTestNattSocketKeepalivesWithExecutor(executor); + } catch (Exception e) { + fail(e.getMessage()); + } + }); } private void doTestNattSocketKeepalivesWithExecutor(Executor executor) throws Exception { @@ -4169,6 +4180,81 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent.disconnect(); waitFor(mWiFiNetworkAgent.getDisconnectedCV()); + mWiFiNetworkAgent = null; + } + + @Test + public void testTcpSocketKeepalives() { + runTestWithSerialExecutors(executor -> { + try { + doTestTcpSocketKeepalivesWithExecutor(executor); + } catch (Exception e) { + fail(e.getMessage()); + } + }); + } + + private void doTestTcpSocketKeepalivesWithExecutor(Executor executor) throws Exception { + final int srcPortV4 = 12345; + final int srcPortV6 = 23456; + final InetAddress myIPv4 = InetAddress.getByName("127.0.0.1"); + final InetAddress myIPv6 = InetAddress.getByName("::1"); + + final int validKaInterval = 15; + final int invalidKaInterval = 9; + + final LinkProperties lp = new LinkProperties(); + lp.setInterfaceName("wlan12"); + lp.addLinkAddress(new LinkAddress(myIPv6, 64)); + lp.addLinkAddress(new LinkAddress(myIPv4, 25)); + lp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234"))); + lp.addRoute(new RouteInfo(InetAddress.getByName("127.0.0.254"))); + + final Network notMyNet = new Network(61234); + final Network myNet = connectKeepaliveNetwork(lp); + + final Socket testSocketV4 = new Socket(); + final Socket testSocketV6 = new Socket(); + + TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); + SocketKeepalive ka; + + // Attempt to start Tcp keepalives with invalid parameters and check for errors. + // Invalid network. + ka = mCm.createSocketKeepalive(notMyNet, testSocketV4, executor, callback); + ka.start(validKaInterval); + callback.expectError(SocketKeepalive.ERROR_INVALID_NETWORK); + + // Invalid Socket (socket is not bound with IPv4 address). + ka = mCm.createSocketKeepalive(myNet, testSocketV4, executor, callback); + ka.start(validKaInterval); + callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET); + + // Invalid Socket (socket is not bound with IPv6 address). + ka = mCm.createSocketKeepalive(myNet, testSocketV6, executor, callback); + ka.start(validKaInterval); + callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET); + + // Bind the socket address + testSocketV4.bind(new InetSocketAddress(myIPv4, srcPortV4)); + testSocketV6.bind(new InetSocketAddress(myIPv6, srcPortV6)); + + // Invalid Socket (socket is bound with IPv4 address). + ka = mCm.createSocketKeepalive(myNet, testSocketV4, executor, callback); + ka.start(validKaInterval); + callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET); + + // Invalid Socket (socket is bound with IPv6 address). + ka = mCm.createSocketKeepalive(myNet, testSocketV6, executor, callback); + ka.start(validKaInterval); + callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET); + + testSocketV4.close(); + testSocketV6.close(); + + mWiFiNetworkAgent.disconnect(); + waitFor(mWiFiNetworkAgent.getDisconnectedCV()); + mWiFiNetworkAgent = null; } @Test diff --git a/wifi/java/android/net/wifi/IWifiUsabilityStatsListener.aidl b/wifi/java/android/net/wifi/IOnWifiUsabilityStatsListener.aidl index 284ffaa18257..4687f3088eef 100644 --- a/wifi/java/android/net/wifi/IWifiUsabilityStatsListener.aidl +++ b/wifi/java/android/net/wifi/IOnWifiUsabilityStatsListener.aidl @@ -23,7 +23,7 @@ import android.net.wifi.WifiUsabilityStatsEntry; * * @hide */ -oneway interface IWifiUsabilityStatsListener +oneway interface IOnWifiUsabilityStatsListener { /** * Service to manager callback providing current Wi-Fi usability stats. @@ -36,6 +36,6 @@ oneway interface IWifiUsabilityStatsListener * Wi-Fi usability stats. * @param stats The updated Wi-Fi usability statistics. */ - void onStatsUpdated(int seqNum, boolean isSameBssidAndFreq, + void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq, in WifiUsabilityStatsEntry stats); } diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 17948e7e1bc0..62ea9af49f51 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -28,7 +28,7 @@ import android.net.wifi.IDppCallback; import android.net.wifi.INetworkRequestMatchCallback; import android.net.wifi.ISoftApCallback; import android.net.wifi.ITrafficStateCallback; -import android.net.wifi.IWifiUsabilityStatsListener; +import android.net.wifi.IOnWifiUsabilityStatsListener; import android.net.wifi.PasspointManagementObjectDefinition; import android.net.wifi.ScanResult; import android.net.wifi.WifiActivityEnergyInfo; @@ -190,9 +190,9 @@ interface IWifiManager void unregisterSoftApCallback(int callbackIdentifier); - void addWifiUsabilityStatsListener(in IBinder binder, in IWifiUsabilityStatsListener listener, int listenerIdentifier); + void addOnWifiUsabilityStatsListener(in IBinder binder, in IOnWifiUsabilityStatsListener listener, int listenerIdentifier); - void removeWifiUsabilityStatsListener(int listenerIdentifier); + void removeOnWifiUsabilityStatsListener(int listenerIdentifier); void registerTrafficStateCallback(in IBinder binder, in ITrafficStateCallback callback, int callbackIdentifier); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 4fd00f7e2092..869f665048a3 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -65,6 +65,7 @@ import java.lang.ref.WeakReference; import java.net.InetAddress; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -511,7 +512,7 @@ public class WifiManager { /** * The look up key for an int that indicates why softAP started failed * currently support general and no_channel - * @see #SAP_START_FAILURE_GENERIC + * @see #SAP_START_FAILURE_GENERAL * @see #SAP_START_FAILURE_NO_CHANNEL * * @hide @@ -615,15 +616,15 @@ public class WifiManager { public @interface SapStartFailure {} /** - * If WIFI AP start failed, this reason code means there is no legal channel exists on - * user selected band by regulatory + * All other reasons for AP start failure besides {@link #SAP_START_FAILURE_NO_CHANNEL}. * * @hide */ public static final int SAP_START_FAILURE_GENERAL= 0; /** - * All other reason for AP start failed besides SAP_START_FAILURE_GENERAL + * If Wi-Fi AP start failed, this reason code means that no legal channel exists on user + * selected band due to regulatory constraints. * * @hide */ @@ -1272,7 +1273,10 @@ public class WifiManager { }) @NonNull public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders( - List<ScanResult> scanResults) { + @Nullable List<ScanResult> scanResults) { + if (scanResults == null) { + return new HashMap<>(); + } try { return mService.getMatchingOsuProviders(scanResults); } catch (RemoteException e) { @@ -4785,13 +4789,13 @@ public class WifiManager { /** * Interface for Wi-Fi usability statistics listener. Should be implemented by applications and - * set when calling {@link WifiManager#addWifiUsabilityStatsListener(Executor, - * WifiUsabilityStatsListener)}. + * set when calling {@link WifiManager#addOnWifiUsabilityStatsListener(Executor, + * OnWifiUsabilityStatsListener)}. * * @hide */ @SystemApi - public interface WifiUsabilityStatsListener { + public interface OnWifiUsabilityStatsListener { /** * Called when Wi-Fi usability statistics is updated. * @@ -4803,15 +4807,15 @@ public class WifiManager { * Wi-Fi usability stats. * @param stats The updated Wi-Fi usability statistics. */ - void onStatsUpdated(int seqNum, boolean isSameBssidAndFreq, - WifiUsabilityStatsEntry stats); + void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq, + @NonNull WifiUsabilityStatsEntry stats); } /** - * Adds a listener for Wi-Fi usability statistics. See {@link WifiUsabilityStatsListener}. + * Adds a listener for Wi-Fi usability statistics. See {@link OnWifiUsabilityStatsListener}. * Multiple listeners can be added. Callers will be invoked periodically by framework to * inform clients about the current Wi-Fi usability statistics. Callers can remove a previously - * added listener using {@link removeWifiUsabilityStatsListener}. + * added listener using {@link removeOnWifiUsabilityStatsListener}. * * @param executor The executor on which callback will be invoked. * @param listener Listener for Wifi usability statistics. @@ -4820,25 +4824,25 @@ public class WifiManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) - public void addWifiUsabilityStatsListener(@NonNull @CallbackExecutor Executor executor, - @NonNull WifiUsabilityStatsListener listener) { + public void addOnWifiUsabilityStatsListener(@NonNull @CallbackExecutor Executor executor, + @NonNull OnWifiUsabilityStatsListener listener) { if (executor == null) throw new IllegalArgumentException("executor cannot be null"); if (listener == null) throw new IllegalArgumentException("listener cannot be null"); if (mVerboseLoggingEnabled) { - Log.v(TAG, "addWifiUsabilityStatsListener: listener=" + listener); + Log.v(TAG, "addOnWifiUsabilityStatsListener: listener=" + listener); } try { - mService.addWifiUsabilityStatsListener(new Binder(), - new IWifiUsabilityStatsListener.Stub() { + mService.addOnWifiUsabilityStatsListener(new Binder(), + new IOnWifiUsabilityStatsListener.Stub() { @Override - public void onStatsUpdated(int seqNum, boolean isSameBssidAndFreq, + public void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq, WifiUsabilityStatsEntry stats) { if (mVerboseLoggingEnabled) { - Log.v(TAG, "WifiUsabilityStatsListener: onStatsUpdated: seqNum=" - + seqNum); + Log.v(TAG, "OnWifiUsabilityStatsListener: " + + "onWifiUsabilityStats: seqNum=" + seqNum); } Binder.withCleanCallingIdentity(() -> - executor.execute(() -> listener.onStatsUpdated(seqNum, + executor.execute(() -> listener.onWifiUsabilityStats(seqNum, isSameBssidAndFreq, stats))); } }, @@ -4859,13 +4863,13 @@ public class WifiManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) - public void removeWifiUsabilityStatsListener(@NonNull WifiUsabilityStatsListener listener) { + public void removeOnWifiUsabilityStatsListener(@NonNull OnWifiUsabilityStatsListener listener) { if (listener == null) throw new IllegalArgumentException("listener cannot be null"); if (mVerboseLoggingEnabled) { - Log.v(TAG, "removeWifiUsabilityStatsListener: listener=" + listener); + Log.v(TAG, "removeOnWifiUsabilityStatsListener: listener=" + listener); } try { - mService.removeWifiUsabilityStatsListener(listener.hashCode()); + mService.removeOnWifiUsabilityStatsListener(listener.hashCode()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -4879,7 +4883,8 @@ public class WifiManager { * * @param seqNum Sequence number of the Wi-Fi usability score. * @param score The Wi-Fi usability score. - * @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score. + * @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score in second, + * expected range: [0, 100]. * * @hide */ diff --git a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java index 2dee97120f11..51aa93a1c4c7 100644 --- a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java +++ b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java @@ -51,87 +51,88 @@ public final class WifiUsabilityStatsEntry implements Parcelable { public static final int PROBE_STATUS_FAILURE = 3; /** Absolute milliseconds from device boot when these stats were sampled */ - public final long timeStampMs; + private final long mTimeStampMillis; /** The RSSI (in dBm) at the sample time */ - public final int rssi; + private final int mRssi; /** Link speed at the sample time in Mbps */ - public final int linkSpeedMbps; + private final int mLinkSpeedMbps; /** The total number of tx success counted from the last radio chip reset */ - public final long totalTxSuccess; + private final long mTotalTxSuccess; /** The total number of MPDU data packet retries counted from the last radio chip reset */ - public final long totalTxRetries; + private final long mTotalTxRetries; /** The total number of tx bad counted from the last radio chip reset */ - public final long totalTxBad; + private final long mTotalTxBad; /** The total number of rx success counted from the last radio chip reset */ - public final long totalRxSuccess; + private final long mTotalRxSuccess; /** The total time the wifi radio is on in ms counted from the last radio chip reset */ - public final long totalRadioOnTimeMs; + private final long mTotalRadioOnTimeMillis; /** The total time the wifi radio is doing tx in ms counted from the last radio chip reset */ - public final long totalRadioTxTimeMs; + private final long mTotalRadioTxTimeMillis; /** The total time the wifi radio is doing rx in ms counted from the last radio chip reset */ - public final long totalRadioRxTimeMs; + private final long mTotalRadioRxTimeMillis; /** The total time spent on all types of scans in ms counted from the last radio chip reset */ - public final long totalScanTimeMs; + private final long mTotalScanTimeMillis; /** The total time spent on nan scans in ms counted from the last radio chip reset */ - public final long totalNanScanTimeMs; + private final long mTotalNanScanTimeMillis; /** The total time spent on background scans in ms counted from the last radio chip reset */ - public final long totalBackgroundScanTimeMs; + private final long mTotalBackgroundScanTimeMillis; /** The total time spent on roam scans in ms counted from the last radio chip reset */ - public final long totalRoamScanTimeMs; + private final long mTotalRoamScanTimeMillis; /** The total time spent on pno scans in ms counted from the last radio chip reset */ - public final long totalPnoScanTimeMs; + private final long mTotalPnoScanTimeMillis; /** The total time spent on hotspot2.0 scans and GAS exchange in ms counted from the last radio * chip reset */ - public final long totalHotspot2ScanTimeMs; + private final long mTotalHotspot2ScanTimeMillis; /** The total time CCA is on busy status on the current frequency in ms counted from the last * radio chip reset */ - public final long totalCcaBusyFreqTimeMs; - /** The total radio on time of the current frequency from the last radio chip reset */ - public final long totalRadioOnFreqTimeMs; + private final long mTotalCcaBusyFreqTimeMillis; + /** The total radio on time on the current frequency from the last radio chip reset */ + private final long mTotalRadioOnFreqTimeMillis; /** The total number of beacons received from the last radio chip reset */ - public final long totalBeaconRx; + private final long mTotalBeaconRx; /** The status of link probe since last stats update */ - public final int probeStatusSinceLastUpdate; + @ProbeStatus private final int mProbeStatusSinceLastUpdate; /** The elapsed time of the most recent link probe since last stats update */ - public final int probeElapsedTimeMsSinceLastUpdate; + private final int mProbeElapsedTimeSinceLastUpdateMillis; /** The MCS rate of the most recent link probe since last stats update */ - public final int probeMcsRateSinceLastUpdate; + private final int mProbeMcsRateSinceLastUpdate; /** Rx link speed at the sample time in Mbps */ - public final int rxLinkSpeedMbps; + private final int mRxLinkSpeedMbps; /** Constructor function {@hide} */ - public WifiUsabilityStatsEntry(long timeStampMs, int rssi, - int linkSpeedMbps, long totalTxSuccess, long totalTxRetries, - long totalTxBad, long totalRxSuccess, long totalRadioOnTimeMs, - long totalRadioTxTimeMs, long totalRadioRxTimeMs, long totalScanTimeMs, - long totalNanScanTimeMs, long totalBackgroundScanTimeMs, long totalRoamScanTimeMs, - long totalPnoScanTimeMs, long totalHotspot2ScanTimeMs, long totalCcaBusyFreqTimeMs, - long totalRadioOnFreqTimeMs, long totalBeaconRx, - @ProbeStatus int probeStatusSinceLastUpdate, int probeElapsedTimeMsSinceLastUpdate, + public WifiUsabilityStatsEntry(long timeStampMillis, int rssi, int linkSpeedMbps, + long totalTxSuccess, long totalTxRetries, long totalTxBad, long totalRxSuccess, + long totalRadioOnTimeMillis, long totalRadioTxTimeMillis, long totalRadioRxTimeMillis, + long totalScanTimeMillis, long totalNanScanTimeMillis, + long totalBackgroundScanTimeMillis, + long totalRoamScanTimeMillis, long totalPnoScanTimeMillis, + long totalHotspot2ScanTimeMillis, + long totalCcaBusyFreqTimeMillis, long totalRadioOnFreqTimeMillis, long totalBeaconRx, + @ProbeStatus int probeStatusSinceLastUpdate, int probeElapsedTimeSinceLastUpdateMillis, int probeMcsRateSinceLastUpdate, int rxLinkSpeedMbps) { - this.timeStampMs = timeStampMs; - this.rssi = rssi; - this.linkSpeedMbps = linkSpeedMbps; - this.totalTxSuccess = totalTxSuccess; - this.totalTxRetries = totalTxRetries; - this.totalTxBad = totalTxBad; - this.totalRxSuccess = totalRxSuccess; - this.totalRadioOnTimeMs = totalRadioOnTimeMs; - this.totalRadioTxTimeMs = totalRadioTxTimeMs; - this.totalRadioRxTimeMs = totalRadioRxTimeMs; - this.totalScanTimeMs = totalScanTimeMs; - this.totalNanScanTimeMs = totalNanScanTimeMs; - this.totalBackgroundScanTimeMs = totalBackgroundScanTimeMs; - this.totalRoamScanTimeMs = totalRoamScanTimeMs; - this.totalPnoScanTimeMs = totalPnoScanTimeMs; - this.totalHotspot2ScanTimeMs = totalHotspot2ScanTimeMs; - this.totalCcaBusyFreqTimeMs = totalCcaBusyFreqTimeMs; - this.totalRadioOnFreqTimeMs = totalRadioOnFreqTimeMs; - this.totalBeaconRx = totalBeaconRx; - this.probeStatusSinceLastUpdate = probeStatusSinceLastUpdate; - this.probeElapsedTimeMsSinceLastUpdate = probeElapsedTimeMsSinceLastUpdate; - this.probeMcsRateSinceLastUpdate = probeMcsRateSinceLastUpdate; - this.rxLinkSpeedMbps = rxLinkSpeedMbps; + mTimeStampMillis = timeStampMillis; + mRssi = rssi; + mLinkSpeedMbps = linkSpeedMbps; + mTotalTxSuccess = totalTxSuccess; + mTotalTxRetries = totalTxRetries; + mTotalTxBad = totalTxBad; + mTotalRxSuccess = totalRxSuccess; + mTotalRadioOnTimeMillis = totalRadioOnTimeMillis; + mTotalRadioTxTimeMillis = totalRadioTxTimeMillis; + mTotalRadioRxTimeMillis = totalRadioRxTimeMillis; + mTotalScanTimeMillis = totalScanTimeMillis; + mTotalNanScanTimeMillis = totalNanScanTimeMillis; + mTotalBackgroundScanTimeMillis = totalBackgroundScanTimeMillis; + mTotalRoamScanTimeMillis = totalRoamScanTimeMillis; + mTotalPnoScanTimeMillis = totalPnoScanTimeMillis; + mTotalHotspot2ScanTimeMillis = totalHotspot2ScanTimeMillis; + mTotalCcaBusyFreqTimeMillis = totalCcaBusyFreqTimeMillis; + mTotalRadioOnFreqTimeMillis = totalRadioOnFreqTimeMillis; + mTotalBeaconRx = totalBeaconRx; + mProbeStatusSinceLastUpdate = probeStatusSinceLastUpdate; + mProbeElapsedTimeSinceLastUpdateMillis = probeElapsedTimeSinceLastUpdateMillis; + mProbeMcsRateSinceLastUpdate = probeMcsRateSinceLastUpdate; + mRxLinkSpeedMbps = rxLinkSpeedMbps; } /** Implement the Parcelable interface */ @@ -141,29 +142,29 @@ public final class WifiUsabilityStatsEntry implements Parcelable { /** Implement the Parcelable interface */ public void writeToParcel(Parcel dest, int flags) { - dest.writeLong(timeStampMs); - dest.writeInt(rssi); - dest.writeInt(linkSpeedMbps); - dest.writeLong(totalTxSuccess); - dest.writeLong(totalTxRetries); - dest.writeLong(totalTxBad); - dest.writeLong(totalRxSuccess); - dest.writeLong(totalRadioOnTimeMs); - dest.writeLong(totalRadioTxTimeMs); - dest.writeLong(totalRadioRxTimeMs); - dest.writeLong(totalScanTimeMs); - dest.writeLong(totalNanScanTimeMs); - dest.writeLong(totalBackgroundScanTimeMs); - dest.writeLong(totalRoamScanTimeMs); - dest.writeLong(totalPnoScanTimeMs); - dest.writeLong(totalHotspot2ScanTimeMs); - dest.writeLong(totalCcaBusyFreqTimeMs); - dest.writeLong(totalRadioOnFreqTimeMs); - dest.writeLong(totalBeaconRx); - dest.writeInt(probeStatusSinceLastUpdate); - dest.writeInt(probeElapsedTimeMsSinceLastUpdate); - dest.writeInt(probeMcsRateSinceLastUpdate); - dest.writeInt(rxLinkSpeedMbps); + dest.writeLong(mTimeStampMillis); + dest.writeInt(mRssi); + dest.writeInt(mLinkSpeedMbps); + dest.writeLong(mTotalTxSuccess); + dest.writeLong(mTotalTxRetries); + dest.writeLong(mTotalTxBad); + dest.writeLong(mTotalRxSuccess); + dest.writeLong(mTotalRadioOnTimeMillis); + dest.writeLong(mTotalRadioTxTimeMillis); + dest.writeLong(mTotalRadioRxTimeMillis); + dest.writeLong(mTotalScanTimeMillis); + dest.writeLong(mTotalNanScanTimeMillis); + dest.writeLong(mTotalBackgroundScanTimeMillis); + dest.writeLong(mTotalRoamScanTimeMillis); + dest.writeLong(mTotalPnoScanTimeMillis); + dest.writeLong(mTotalHotspot2ScanTimeMillis); + dest.writeLong(mTotalCcaBusyFreqTimeMillis); + dest.writeLong(mTotalRadioOnFreqTimeMillis); + dest.writeLong(mTotalBeaconRx); + dest.writeInt(mProbeStatusSinceLastUpdate); + dest.writeInt(mProbeElapsedTimeSinceLastUpdateMillis); + dest.writeInt(mProbeMcsRateSinceLastUpdate); + dest.writeInt(mRxLinkSpeedMbps); } /** Implement the Parcelable interface */ @@ -186,4 +187,121 @@ public final class WifiUsabilityStatsEntry implements Parcelable { return new WifiUsabilityStatsEntry[size]; } }; + + /** Absolute milliseconds from device boot when these stats were sampled */ + public long getTimeStampMillis() { + return mTimeStampMillis; + } + + /** The RSSI (in dBm) at the sample time */ + public int getRssi() { + return mRssi; + } + + /** Link speed at the sample time in Mbps */ + public int getLinkSpeedMbps() { + return mLinkSpeedMbps; + } + + /** The total number of tx success counted from the last radio chip reset */ + public long getTotalTxSuccess() { + return mTotalTxSuccess; + } + + /** The total number of MPDU data packet retries counted from the last radio chip reset */ + public long getTotalTxRetries() { + return mTotalTxRetries; + } + + /** The total number of tx bad counted from the last radio chip reset */ + public long getTotalTxBad() { + return mTotalTxBad; + } + + /** The total number of rx success counted from the last radio chip reset */ + public long getTotalRxSuccess() { + return mTotalRxSuccess; + } + + /** The total time the wifi radio is on in ms counted from the last radio chip reset */ + public long getTotalRadioOnTimeMillis() { + return mTotalRadioOnTimeMillis; + } + + /** The total time the wifi radio is doing tx in ms counted from the last radio chip reset */ + public long getTotalRadioTxTimeMillis() { + return mTotalRadioTxTimeMillis; + } + + /** The total time the wifi radio is doing rx in ms counted from the last radio chip reset */ + public long getTotalRadioRxTimeMillis() { + return mTotalRadioRxTimeMillis; + } + + /** The total time spent on all types of scans in ms counted from the last radio chip reset */ + public long getTotalScanTimeMillis() { + return mTotalScanTimeMillis; + } + + /** The total time spent on nan scans in ms counted from the last radio chip reset */ + public long getTotalNanScanTimeMillis() { + return mTotalNanScanTimeMillis; + } + + /** The total time spent on background scans in ms counted from the last radio chip reset */ + public long getTotalBackgroundScanTimeMillis() { + return mTotalBackgroundScanTimeMillis; + } + + /** The total time spent on roam scans in ms counted from the last radio chip reset */ + public long getTotalRoamScanTimeMillis() { + return mTotalRoamScanTimeMillis; + } + + /** The total time spent on pno scans in ms counted from the last radio chip reset */ + public long getTotalPnoScanTimeMillis() { + return mTotalPnoScanTimeMillis; + } + + /** The total time spent on hotspot2.0 scans and GAS exchange in ms counted from the last radio + * chip reset */ + public long getTotalHotspot2ScanTimeMillis() { + return mTotalHotspot2ScanTimeMillis; + } + + /** The total time CCA is on busy status on the current frequency in ms counted from the last + * radio chip reset */ + public long getTotalCcaBusyFreqTimeMillis() { + return mTotalCcaBusyFreqTimeMillis; + } + + /** The total radio on time on the current frequency from the last radio chip reset */ + public long getTotalRadioOnFreqTimeMillis() { + return mTotalRadioOnFreqTimeMillis; + } + + /** The total number of beacons received from the last radio chip reset */ + public long getTotalBeaconRx() { + return mTotalBeaconRx; + } + + /** The status of link probe since last stats update */ + @ProbeStatus public int getProbeStatusSinceLastUpdate() { + return mProbeStatusSinceLastUpdate; + } + + /** The elapsed time of the most recent link probe since last stats update */ + public int getProbeElapsedTimeSinceLastUpdateMillis() { + return mProbeElapsedTimeSinceLastUpdateMillis; + } + + /** The MCS rate of the most recent link probe since last stats update */ + public int getProbeMcsRateSinceLastUpdate() { + return mProbeMcsRateSinceLastUpdate; + } + + /** Rx link speed at the sample time in Mbps */ + public int getRxLinkSpeedMbps() { + return mRxLinkSpeedMbps; + } } diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java index c236c7a05488..842d78ddcda2 100644 --- a/wifi/java/com/android/server/wifi/BaseWifiService.java +++ b/wifi/java/com/android/server/wifi/BaseWifiService.java @@ -23,10 +23,10 @@ import android.net.DhcpInfo; import android.net.Network; import android.net.wifi.IDppCallback; import android.net.wifi.INetworkRequestMatchCallback; +import android.net.wifi.IOnWifiUsabilityStatsListener; import android.net.wifi.ISoftApCallback; import android.net.wifi.ITrafficStateCallback; import android.net.wifi.IWifiManager; -import android.net.wifi.IWifiUsabilityStatsListener; import android.net.wifi.ScanResult; import android.net.wifi.WifiActivityEnergyInfo; import android.net.wifi.WifiConfiguration; @@ -467,13 +467,13 @@ public class BaseWifiService extends IWifiManager.Stub { } @Override - public void addWifiUsabilityStatsListener( - IBinder binder, IWifiUsabilityStatsListener listener, int listenerIdentifier) { + public void addOnWifiUsabilityStatsListener( + IBinder binder, IOnWifiUsabilityStatsListener listener, int listenerIdentifier) { throw new UnsupportedOperationException(); } @Override - public void removeWifiUsabilityStatsListener(int listenerIdentifier) { + public void removeOnWifiUsabilityStatsListener(int listenerIdentifier) { throw new UnsupportedOperationException(); } diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java index 5c2f626a24cc..600abc927b7f 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -59,9 +59,9 @@ import android.net.wifi.WifiManager.LocalOnlyHotspotReservation; import android.net.wifi.WifiManager.LocalOnlyHotspotSubscription; import android.net.wifi.WifiManager.NetworkRequestMatchCallback; import android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback; +import android.net.wifi.WifiManager.OnWifiUsabilityStatsListener; import android.net.wifi.WifiManager.SoftApCallback; import android.net.wifi.WifiManager.TrafficStateCallback; -import android.net.wifi.WifiManager.WifiUsabilityStatsListener; import android.os.Handler; import android.os.IBinder; import android.os.Message; @@ -105,7 +105,7 @@ public class WifiManagerTest { @Mock SoftApCallback mSoftApCallback; @Mock TrafficStateCallback mTrafficStateCallback; @Mock NetworkRequestMatchCallback mNetworkRequestMatchCallback; - @Mock WifiUsabilityStatsListener mWifiUsabilityStatsListener; + @Mock OnWifiUsabilityStatsListener mOnWifiUsabilityStatsListener; private Executor mExecutor; private Handler mHandler; @@ -1348,29 +1348,29 @@ i * Verify that a call to cancel WPS immediately returns a failure. } /** - * Verify the call to addWifiUsabilityStatsListener goes to WifiServiceImpl. + * Verify the call to addOnWifiUsabilityStatsListener goes to WifiServiceImpl. */ @Test - public void addWifiUsabilityStatsListeneroesToWifiServiceImpl() throws Exception { + public void addOnWifiUsabilityStatsListeneroesToWifiServiceImpl() throws Exception { mExecutor = new SynchronousExecutor(); - mWifiManager.addWifiUsabilityStatsListener(mExecutor, mWifiUsabilityStatsListener); - verify(mWifiService).addWifiUsabilityStatsListener(any(IBinder.class), - any(IWifiUsabilityStatsListener.Stub.class), anyInt()); + mWifiManager.addOnWifiUsabilityStatsListener(mExecutor, mOnWifiUsabilityStatsListener); + verify(mWifiService).addOnWifiUsabilityStatsListener(any(IBinder.class), + any(IOnWifiUsabilityStatsListener.Stub.class), anyInt()); } /** - * Verify the call to removeWifiUsabilityStatsListener goes to WifiServiceImpl. + * Verify the call to removeOnWifiUsabilityStatsListener goes to WifiServiceImpl. */ @Test - public void removeWifiUsabilityListenerGoesToWifiServiceImpl() throws Exception { + public void removeOnWifiUsabilityListenerGoesToWifiServiceImpl() throws Exception { ArgumentCaptor<Integer> listenerIdentifier = ArgumentCaptor.forClass(Integer.class); mExecutor = new SynchronousExecutor(); - mWifiManager.addWifiUsabilityStatsListener(mExecutor, mWifiUsabilityStatsListener); - verify(mWifiService).addWifiUsabilityStatsListener(any(IBinder.class), - any(IWifiUsabilityStatsListener.Stub.class), listenerIdentifier.capture()); + mWifiManager.addOnWifiUsabilityStatsListener(mExecutor, mOnWifiUsabilityStatsListener); + verify(mWifiService).addOnWifiUsabilityStatsListener(any(IBinder.class), + any(IOnWifiUsabilityStatsListener.Stub.class), listenerIdentifier.capture()); - mWifiManager.removeWifiUsabilityStatsListener(mWifiUsabilityStatsListener); - verify(mWifiService).removeWifiUsabilityStatsListener( + mWifiManager.removeOnWifiUsabilityStatsListener(mOnWifiUsabilityStatsListener); + verify(mWifiService).removeOnWifiUsabilityStatsListener( eq((int) listenerIdentifier.getValue())); } diff --git a/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java b/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java index a22f8ce853bf..8e371134fbd6 100644 --- a/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java +++ b/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java @@ -81,29 +81,35 @@ public class WifiUsabilityStatsEntryTest { private static void assertWifiUsabilityStatsEntryEquals( WifiUsabilityStatsEntry expected, WifiUsabilityStatsEntry actual) { - assertEquals(expected.timeStampMs, actual.timeStampMs); - assertEquals(expected.rssi, actual.rssi); - assertEquals(expected.linkSpeedMbps, actual.linkSpeedMbps); - assertEquals(expected.totalTxSuccess, actual.totalTxSuccess); - assertEquals(expected.totalTxRetries, actual.totalTxRetries); - assertEquals(expected.totalTxBad, actual.totalTxBad); - assertEquals(expected.totalRxSuccess, actual.totalRxSuccess); - assertEquals(expected.totalRadioOnTimeMs, actual.totalRadioOnTimeMs); - assertEquals(expected.totalRadioTxTimeMs, actual.totalRadioTxTimeMs); - assertEquals(expected.totalRadioRxTimeMs, actual.totalRadioRxTimeMs); - assertEquals(expected.totalScanTimeMs, actual.totalScanTimeMs); - assertEquals(expected.totalNanScanTimeMs, actual.totalNanScanTimeMs); - assertEquals(expected.totalBackgroundScanTimeMs, actual.totalBackgroundScanTimeMs); - assertEquals(expected.totalRoamScanTimeMs, actual.totalRoamScanTimeMs); - assertEquals(expected.totalPnoScanTimeMs, actual.totalPnoScanTimeMs); - assertEquals(expected.totalHotspot2ScanTimeMs, actual.totalHotspot2ScanTimeMs); - assertEquals(expected.totalCcaBusyFreqTimeMs, actual.totalCcaBusyFreqTimeMs); - assertEquals(expected.totalRadioOnFreqTimeMs, actual.totalRadioOnFreqTimeMs); - assertEquals(expected.totalBeaconRx, actual.totalBeaconRx); - assertEquals(expected.probeStatusSinceLastUpdate, actual.probeStatusSinceLastUpdate); - assertEquals(expected.probeElapsedTimeMsSinceLastUpdate, - actual.probeElapsedTimeMsSinceLastUpdate); - assertEquals(expected.probeMcsRateSinceLastUpdate, actual.probeMcsRateSinceLastUpdate); - assertEquals(expected.rxLinkSpeedMbps, actual.rxLinkSpeedMbps); + assertEquals(expected.getTimeStampMillis(), actual.getTimeStampMillis()); + assertEquals(expected.getRssi(), actual.getRssi()); + assertEquals(expected.getLinkSpeedMbps(), actual.getLinkSpeedMbps()); + assertEquals(expected.getTotalTxSuccess(), actual.getTotalTxSuccess()); + assertEquals(expected.getTotalTxRetries(), actual.getTotalTxRetries()); + assertEquals(expected.getTotalTxBad(), actual.getTotalTxBad()); + assertEquals(expected.getTotalRxSuccess(), actual.getTotalRxSuccess()); + assertEquals(expected.getTotalRadioOnTimeMillis(), actual.getTotalRadioOnTimeMillis()); + assertEquals(expected.getTotalRadioTxTimeMillis(), actual.getTotalRadioTxTimeMillis()); + assertEquals(expected.getTotalRadioRxTimeMillis(), actual.getTotalRadioRxTimeMillis()); + assertEquals(expected.getTotalScanTimeMillis(), actual.getTotalScanTimeMillis()); + assertEquals(expected.getTotalNanScanTimeMillis(), actual.getTotalNanScanTimeMillis()); + assertEquals(expected.getTotalBackgroundScanTimeMillis(), + actual.getTotalBackgroundScanTimeMillis()); + assertEquals(expected.getTotalRoamScanTimeMillis(), actual.getTotalRoamScanTimeMillis()); + assertEquals(expected.getTotalPnoScanTimeMillis(), actual.getTotalPnoScanTimeMillis()); + assertEquals(expected.getTotalHotspot2ScanTimeMillis(), + actual.getTotalHotspot2ScanTimeMillis()); + assertEquals(expected.getTotalCcaBusyFreqTimeMillis(), + actual.getTotalCcaBusyFreqTimeMillis()); + assertEquals(expected.getTotalRadioOnFreqTimeMillis(), + actual.getTotalRadioOnFreqTimeMillis()); + assertEquals(expected.getTotalBeaconRx(), actual.getTotalBeaconRx()); + assertEquals(expected.getProbeStatusSinceLastUpdate(), + actual.getProbeStatusSinceLastUpdate()); + assertEquals(expected.getProbeElapsedTimeSinceLastUpdateMillis(), + actual.getProbeElapsedTimeSinceLastUpdateMillis()); + assertEquals(expected.getProbeMcsRateSinceLastUpdate(), + actual.getProbeMcsRateSinceLastUpdate()); + assertEquals(expected.getRxLinkSpeedMbps(), actual.getRxLinkSpeedMbps()); } } |