diff options
189 files changed, 4327 insertions, 1944 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 135a5b4ae8ae..f0b491a548fb 100644 --- a/api/current.txt +++ b/api/current.txt @@ -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"; @@ -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(); @@ -14431,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(); @@ -14441,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); @@ -14455,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(); @@ -14510,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); @@ -14524,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); @@ -14550,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 @@ -15928,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); } @@ -24740,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(); @@ -24776,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 @@ -26399,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(); @@ -45442,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); } } @@ -46004,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); } @@ -56388,10 +56394,10 @@ package android.widget { method public int getWindowLayoutType(); method public boolean isAboveAnchor(); method public boolean isAttachedInDecor(); - method public boolean isClipToScreenEnabled(); + method public boolean isClippedToScreen(); method public boolean isClippingEnabled(); method public boolean isFocusable(); - method public boolean isLayoutInScreenEnabled(); + method public boolean isLaidOutInScreen(); method public boolean isOutsideTouchable(); method public boolean isShowing(); method public boolean isSplitTouchEnabled(); @@ -56400,7 +56406,6 @@ package android.widget { method public void setAnimationStyle(int); method public void setAttachedInDecor(boolean); method public void setBackgroundDrawable(android.graphics.drawable.Drawable); - method public void setClipToScreenEnabled(boolean); method public void setClippingEnabled(boolean); method public void setContentView(android.view.View); method public void setElevation(float); @@ -56411,7 +56416,8 @@ package android.widget { method public void setHeight(int); method public void setIgnoreCheekPress(); method public void setInputMethodMode(int); - method public void setLayoutInScreenEnabled(boolean); + method public void setIsClippedToScreen(boolean); + method public void setIsLaidOutInScreen(boolean); method public void setOnDismissListener(android.widget.PopupWindow.OnDismissListener); method public void setOutsideTouchable(boolean); method public void setOverlapAnchor(boolean); diff --git a/api/system-current.txt b/api/system-current.txt index 28104d56f85a..921a6bf2f272 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -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 @@ -3722,10 +3721,6 @@ package android.media.audiopolicy { package android.media.session { - public static final class MediaController.PlaybackInfo implements android.os.Parcelable { - ctor public MediaController.PlaybackInfo(int, int, int, int, android.media.AudioAttributes); - } - public final class MediaSessionManager { method @RequiresPermission(android.Manifest.permission.SET_MEDIA_KEY_LISTENER) public void setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, @Nullable android.os.Handler); method @RequiresPermission(android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER) public void setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, @Nullable android.os.Handler); @@ -4070,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 { @@ -4741,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(); @@ -4756,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); @@ -4801,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 { @@ -4937,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; } } @@ -5866,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"; @@ -5881,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"; @@ -8068,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(); @@ -8103,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"; @@ -8111,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 4856f777237e..69372cd379ea 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -5759,7 +5759,7 @@ message TimeZoneDataInfo { optional string tzdb_version = 1; } -/* +/** * Logs the GPU stats global health information. * * Logged from: @@ -5791,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/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 d82899eefda9..f8ccb13b6b53 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -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 }) @@ -10478,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. @@ -10514,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 91ac9e0dcb01..5c9931970d5c 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4098,7 +4098,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/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index f14b22861006..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; 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/PackageManager.java b/core/java/android/content/pm/PackageManager.java index d1ebcfdaca3a..9037759722b2 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1389,6 +1389,14 @@ public abstract class PackageManager { */ public static final int INSTALL_FAILED_BAD_SIGNATURE = -118; + /** + * Installation failed return code: a new staged session was attempted to be committed while + * there is already one in-progress. + * + * @hide + */ + public static final int INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS = -119; + /** @hide */ @IntDef(flag = true, prefix = { "DELETE_" }, value = { DELETE_KEEP_DATA, 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/rollback/PackageRollbackInfo.java b/core/java/android/content/rollback/PackageRollbackInfo.java index b0785b1fbc11..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; 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/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/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index e4593e55a2c6..7a0bb91d9f36 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -31,6 +31,7 @@ import android.database.ContentObserver; import android.net.Uri; import android.provider.Settings.ResetMode; import android.util.ArrayMap; +import android.util.Log; import android.util.Pair; import com.android.internal.annotations.GuardedBy; @@ -105,6 +106,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 +299,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 +319,7 @@ public final class DeviceConfig { * * @hide */ - @SystemApi + @SystemApi @TestApi public interface Rollback { /** @@ -406,6 +403,7 @@ public final class DeviceConfig { new ArrayMap<>(); @GuardedBy("sLock") private static Map<String, Pair<ContentObserver, Integer>> sNamespaces = new HashMap<>(); + private static final String TAG = "DeviceConfig"; // Should never be invoked private DeviceConfig() { @@ -479,9 +477,13 @@ public final class DeviceConfig { @RequiresPermission(READ_DEVICE_CONFIG) public static int getInt(String namespace, String name, int defaultValue) { String value = getProperty(namespace, name); + if (value == null) { + return defaultValue; + } try { return Integer.parseInt(value); } catch (NumberFormatException e) { + Log.e(TAG, "Parsing integer failed for " + namespace + ":" + name); return defaultValue; } } @@ -501,9 +503,13 @@ public final class DeviceConfig { @RequiresPermission(READ_DEVICE_CONFIG) public static long getLong(String namespace, String name, long defaultValue) { String value = getProperty(namespace, name); + if (value == null) { + return defaultValue; + } try { return Long.parseLong(value); } catch (NumberFormatException e) { + Log.e(TAG, "Parsing long failed for " + namespace + ":" + name); return defaultValue; } } @@ -523,11 +529,13 @@ public final class DeviceConfig { @RequiresPermission(READ_DEVICE_CONFIG) public static float getFloat(String namespace, String name, float defaultValue) { String value = getProperty(namespace, name); + if (value == null) { + return defaultValue; + } try { return Float.parseFloat(value); } catch (NumberFormatException e) { - return defaultValue; - } catch (NullPointerException e) { + Log.e(TAG, "Parsing float failed for " + namespace + ":" + name); return defaultValue; } } @@ -915,9 +923,13 @@ public final class DeviceConfig { public int getInt(@NonNull String name, int defaultValue) { Preconditions.checkNotNull(name); String value = mMap.get(name); + if (value == null) { + return defaultValue; + } try { return Integer.parseInt(value); } catch (NumberFormatException e) { + Log.e(TAG, "Parsing int failed for " + name); return defaultValue; } } @@ -933,9 +945,13 @@ public final class DeviceConfig { public long getLong(@NonNull String name, long defaultValue) { Preconditions.checkNotNull(name); String value = mMap.get(name); + if (value == null) { + return defaultValue; + } try { return Long.parseLong(value); } catch (NumberFormatException e) { + Log.e(TAG, "Parsing long failed for " + name); return defaultValue; } } @@ -951,11 +967,13 @@ public final class DeviceConfig { public float getFloat(@NonNull String name, float defaultValue) { Preconditions.checkNotNull(name); String value = mMap.get(name); + if (value == null) { + return defaultValue; + } try { return Float.parseFloat(value); } catch (NumberFormatException e) { - return defaultValue; - } catch (NullPointerException e) { + Log.e(TAG, "Parsing float failed for " + name); return defaultValue; } } 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 e8f91ca04d63..a750c7917fc2 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/text/style/ImageSpan.java b/core/java/android/text/style/ImageSpan.java index 13ac9ff2ddaf..98f58bef5932 100644 --- a/core/java/android/text/style/ImageSpan.java +++ b/core/java/android/text/style/ImageSpan.java @@ -46,10 +46,10 @@ import java.io.InputStream; * <p> * For example, an <code>ImagedSpan</code> can be used like this: * <pre> - * SpannableString string = SpannableString("Bottom: span.\nBaseline: span."); + * SpannableString string = new SpannableString("Bottom: span.\nBaseline: span."); * // using the default alignment: ALIGN_BOTTOM - * string.setSpan(ImageSpan(this, R.mipmap.ic_launcher), 7, 8, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - * string.setSpan(ImageSpan(this, R.mipmap.ic_launcher, DynamicDrawableSpan.ALIGN_BASELINE), + * string.setSpan(new ImageSpan(this, R.mipmap.ic_launcher), 7, 8, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + * string.setSpan(new ImageSpan(this, R.mipmap.ic_launcher, DynamicDrawableSpan.ALIGN_BASELINE), * 22, 23, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); * </pre> * <img src="{@docRoot}reference/android/images/text/style/imagespan.png" /> 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 c4f815b36239..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"); 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/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/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java index 25e5dd32c6b2..16b903d4da9e 100644 --- a/core/java/android/widget/ListPopupWindow.java +++ b/core/java/android/widget/ListPopupWindow.java @@ -702,7 +702,7 @@ public class ListPopupWindow implements ShowableListMenu { mPopup.setWidth(widthSpec); mPopup.setHeight(heightSpec); - mPopup.setClipToScreenEnabled(true); + mPopup.setIsClippedToScreen(true); // use outside touchable to dismiss drop down when touching outside of it, so // only set this if the dropdown is not always visible diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index 279829672c57..03e7e10aaf84 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -887,9 +887,9 @@ public class PopupWindow { * * @return true if popup will be clipped to the screen instead of the window, false otherwise * - * @see #setClipToScreenEnabled(boolean) + * @see #setIsClippedToScreen(boolean) */ - public boolean isClipToScreenEnabled() { + public boolean isClippedToScreen() { return mClipToScreen; } @@ -902,9 +902,9 @@ public class PopupWindow { * * @param enabled true to clip to the screen. * - * @see #isClipToScreenEnabled() + * @see #isClippedToScreen() */ - public void setClipToScreenEnabled(boolean enabled) { + public void setIsClippedToScreen(boolean enabled) { mClipToScreen = enabled; } @@ -961,9 +961,9 @@ public class PopupWindow { * * @return true if the window will always be positioned in screen coordinates. * - * @see #setLayoutInScreenEnabled(boolean) + * @see #setIsLaidOutInScreen(boolean) */ - public boolean isLayoutInScreenEnabled() { + public boolean isLaidOutInScreen() { return mLayoutInScreen; } @@ -974,9 +974,9 @@ public class PopupWindow { * * @param enabled true if the popup should always be positioned in screen coordinates * - * @see #isLayoutInScreenEnabled() + * @see #isLaidOutInScreen() */ - public void setLayoutInScreenEnabled(boolean enabled) { + public void setIsLaidOutInScreen(boolean enabled) { mLayoutInScreen = enabled; } @@ -1016,7 +1016,7 @@ public class PopupWindow { * This will cause the popup to inset its content to account for system windows overlaying * the screen, such as the status bar. * - * <p>This will often be combined with {@link #setLayoutInScreenEnabled(boolean)}. + * <p>This will often be combined with {@link #setIsLaidOutInScreen(boolean)}. * * @param enabled true if the popup's views should inset content to account for system windows, * the way that decor views behave for full-screen windows. @@ -2114,7 +2114,7 @@ public class PopupWindow { * <li>{@link #setTouchable(boolean)}</li> * <li>{@link #setAnimationStyle(int)}</li> * <li>{@link #setTouchModal(boolean)} (boolean)}</li> - * <li>{@link #setClipToScreenEnabled(boolean)}</li> + * <li>{@link #setIsClippedToScreen(boolean)}</li> * </ul> */ public void update() { 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/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 91928b55ec60..79cf4c42f746 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -236,7 +236,6 @@ public class ChooserActivity extends ResolverActivity { mServiceConnections.remove(sri.connection); if (mServiceConnections.isEmpty()) { sendVoiceChoicesIfNeeded(); - mChooserListAdapter.setShowServiceTargets(true); } break; @@ -250,7 +249,6 @@ public class ChooserActivity extends ResolverActivity { unbindRemainingServices(); sendVoiceChoicesIfNeeded(); mChooserListAdapter.completeServiceTargetLoading(); - mChooserListAdapter.setShowServiceTargets(true); break; case SHORTCUT_MANAGER_SHARE_TARGET_RESULT: @@ -265,7 +263,6 @@ public class ChooserActivity extends ResolverActivity { case SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED: sendVoiceChoicesIfNeeded(); - mChooserListAdapter.setShowServiceTargets(true); break; default: @@ -446,6 +443,11 @@ public class ChooserActivity extends ResolverActivity { mChooserRowServiceSpacing = getResources() .getDimensionPixelSize(R.dimen.chooser_service_spacing); + // expand/shrink direct share 4 -> 8 viewgroup + if (mResolverDrawerLayout != null) { + mResolverDrawerLayout.setOnScrollChangeListener(this::handleScroll); + } + if (DEBUG) { Log.d(TAG, "System Time Cost is " + systemCost); } @@ -1756,18 +1758,26 @@ public class ChooserActivity extends ResolverActivity { } } + private void handleScroll(View view, int x, int y, int oldx, int oldy) { + if (mChooserRowAdapter != null) { + mChooserRowAdapter.handleScroll(view, y, oldy); + } + } + public class ChooserListAdapter extends ResolveListAdapter { public static final int TARGET_BAD = -1; public static final int TARGET_CALLER = 0; public static final int TARGET_SERVICE = 1; public static final int TARGET_STANDARD = 2; - private static final int MAX_SERVICE_TARGETS = 4; + private static final int MAX_SUGGESTED_APP_TARGETS = 4; private static final int MAX_TARGETS_PER_SERVICE = 2; + private static final int MAX_SERVICE_TARGETS = 8; + // Reserve spots for incoming direct share targets by adding placeholders private ChooserTargetInfo mPlaceHolderTargetInfo = new PlaceHolderTargetInfo(); - private List<ChooserTargetInfo> mServiceTargets; + private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>(); private final List<TargetInfo> mCallerTargets = new ArrayList<>(); private boolean mShowServiceTargets; @@ -1786,7 +1796,7 @@ public class ChooserActivity extends ResolverActivity { super(context, payloadIntents, null, rList, launchedFromUid, filterLastUsed, resolverListController); - mServiceTargets = createPlaceHolders(); + createPlaceHolders(); if (initialIntents != null) { final PackageManager pm = getPackageManager(); @@ -1840,12 +1850,11 @@ public class ChooserActivity extends ResolverActivity { } } - private List<ChooserTargetInfo> createPlaceHolders() { - List<ChooserTargetInfo> list = new ArrayList<>(); + private void createPlaceHolders() { + mServiceTargets.clear(); for (int i = 0; i < MAX_SERVICE_TARGETS; i++) { - list.add(mPlaceHolderTargetInfo); + mServiceTargets.add(mPlaceHolderTargetInfo); } - return list; } @Override @@ -1913,7 +1922,7 @@ public class ChooserActivity extends ResolverActivity { } public int getCallerTargetCount() { - return mCallerTargets.size(); + return Math.min(mCallerTargets.size(), MAX_SUGGESTED_APP_TARGETS); } /** @@ -1940,18 +1949,18 @@ public class ChooserActivity extends ResolverActivity { public int getPositionTargetType(int position) { int offset = 0; - final int callerTargetCount = getCallerTargetCount(); - if (position < callerTargetCount) { - return TARGET_CALLER; - } - offset += callerTargetCount; - final int serviceTargetCount = getServiceTargetCount(); - if (position - offset < serviceTargetCount) { + if (position < serviceTargetCount) { return TARGET_SERVICE; } offset += serviceTargetCount; + final int callerTargetCount = getCallerTargetCount(); + if (position - offset < callerTargetCount) { + return TARGET_CALLER; + } + offset += callerTargetCount; + final int standardTargetCount = super.getCount(); if (position - offset < standardTargetCount) { return TARGET_STANDARD; @@ -1969,19 +1978,19 @@ public class ChooserActivity extends ResolverActivity { public TargetInfo targetInfoForPosition(int position, boolean filtered) { int offset = 0; - final int callerTargetCount = getCallerTargetCount(); - if (position < callerTargetCount) { - return mCallerTargets.get(position); - } - offset += callerTargetCount; - final int serviceTargetCount = filtered ? getServiceTargetCount() : getSelectableServiceTargetCount(); - if (position - offset < serviceTargetCount) { - return mServiceTargets.get(position - offset); + if (position < serviceTargetCount) { + return mServiceTargets.get(position); } offset += serviceTargetCount; + final int callerTargetCount = getCallerTargetCount(); + if (position - offset < callerTargetCount) { + return mCallerTargets.get(position - offset); + } + offset += callerTargetCount; + return filtered ? super.getItem(position - offset) : getDisplayInfoAt(position - offset); } @@ -1995,7 +2004,7 @@ public class ChooserActivity extends ResolverActivity { if (mTargetsNeedPruning && targets.size() > 0) { // First proper update since we got an onListRebuilt() with (transient) 0 items. // Clear out the target list and rebuild. - mServiceTargets = createPlaceHolders(); + createPlaceHolders(); mTargetsNeedPruning = false; // Add back any app-supplied direct share targets that may have been @@ -2037,26 +2046,6 @@ public class ChooserActivity extends ResolverActivity { } /** - * Set to true to reveal all service targets at once. - */ - public void setShowServiceTargets(boolean show) { - // mShowServiceTargets is only flipped once to show direct share targets. But after the - // initial display the list can be re-sorted and the user will see the target list - // change. This will log the initial show and the subsequent shuffle to help us get - // accurate timing of the UX. - if (show) { - getMetricsLogger().write( - new LogMaker(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN_DIRECT_TARGET) - .setSubtype(mShowServiceTargets ? MetricsEvent.PREVIOUSLY_VISIBLE - : MetricsEvent.PREVIOUSLY_HIDDEN)); - } - if (show != mShowServiceTargets) { - mShowServiceTargets = show; - notifyDataSetChanged(); - } - } - - /** * Calling this marks service target loading complete, and will attempt to no longer * update the direct share area. */ @@ -2102,9 +2091,13 @@ public class ChooserActivity extends ResolverActivity { class ChooserRowAdapter extends BaseAdapter { private ChooserListAdapter mChooserListAdapter; private final LayoutInflater mLayoutInflater; - private final int mColumnCount = 4; private int mAnimationCount = 0; + private DirectShareViewHolder mDirectShareViewHolder; + + private static final int VIEW_TYPE_DIRECT_SHARE = 0; + private static final int VIEW_TYPE_NORMAL = 1; + public ChooserRowAdapter(ChooserListAdapter wrappedAdapter) { mChooserListAdapter = wrappedAdapter; mLayoutInflater = LayoutInflater.from(ChooserActivity.this); @@ -2124,22 +2117,29 @@ public class ChooserActivity extends ResolverActivity { }); } + private int getMaxTargetsPerRow() { + // this will soon hold logic for portrait/landscape + return 4; + } + @Override public int getCount() { return (int) ( getCallerTargetRowCount() + getServiceTargetRowCount() + Math.ceil( - (float) mChooserListAdapter.getStandardTargetCount() / mColumnCount) + (float) mChooserListAdapter.getStandardTargetCount() + / getMaxTargetsPerRow()) ); } public int getCallerTargetRowCount() { return (int) Math.ceil( - (float) mChooserListAdapter.getCallerTargetCount() / mColumnCount); + (float) mChooserListAdapter.getCallerTargetCount() / getMaxTargetsPerRow()); } - // There can be at most one row of service targets. + // There can be at most one row in the listview, that is internally + // a ViewGroup with 2 rows public int getServiceTargetRowCount() { return 1; } @@ -2158,29 +2158,48 @@ public class ChooserActivity extends ResolverActivity { @Override public View getView(int position, View convertView, ViewGroup parent) { final RowViewHolder holder; + int viewType = getItemViewType(position); + if (convertView == null) { - holder = createViewHolder(parent); + holder = createViewHolder(viewType, parent); } else { holder = (RowViewHolder) convertView.getTag(); } - bindViewHolder(position, holder); - return holder.row; + bindViewHolder(position, holder, viewType == VIEW_TYPE_DIRECT_SHARE + ? ChooserListAdapter.MAX_SERVICE_TARGETS : getMaxTargetsPerRow()); + + return holder.getViewGroup(); + } + + @Override + public int getItemViewType(int position) { + final int start = getFirstRowPosition(position); + final int startType = mChooserListAdapter.getPositionTargetType(start); + + if (startType == ChooserListAdapter.TARGET_SERVICE) { + return VIEW_TYPE_DIRECT_SHARE; + } + + return VIEW_TYPE_NORMAL; } - RowViewHolder createViewHolder(ViewGroup parent) { - final ViewGroup row = (ViewGroup) mLayoutInflater.inflate(R.layout.chooser_row, - parent, false); - final RowViewHolder holder = new RowViewHolder(row, mColumnCount); + @Override + public int getViewTypeCount() { + return 2; + } + + private RowViewHolder loadViewsIntoRow(RowViewHolder holder) { final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + int columnCount = holder.getColumnCount(); - for (int i = 0; i < mColumnCount; i++) { - final View v = mChooserListAdapter.createView(row); + for (int i = 0; i < columnCount; i++) { + final View v = mChooserListAdapter.createView(holder.getRow(i)); final int column = i; v.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - startSelected(holder.itemIndices[column], false, true); + startSelected(holder.getItemIndex(column), false, true); } }); v.setOnLongClickListener(new OnLongClickListener() { @@ -2188,12 +2207,11 @@ public class ChooserActivity extends ResolverActivity { public boolean onLongClick(View v) { showTargetDetails( mChooserListAdapter.resolveInfoForPosition( - holder.itemIndices[column], true)); + holder.getItemIndex(column), true)); return true; } }); - row.addView(v); - holder.cells[i] = v; + ViewGroup row = holder.addView(i, v); // Force height to be a given so we don't have visual disruption during scaling. LayoutParams lp = v.getLayoutParams(); @@ -2204,47 +2222,75 @@ public class ChooserActivity extends ResolverActivity { } else { lp.height = v.getMeasuredHeight(); } - if (i != (mColumnCount - 1)) { - row.addView(new Space(ChooserActivity.this), - new LinearLayout.LayoutParams(0, 0, 1)); - } } + final ViewGroup viewGroup = holder.getViewGroup(); + // Pre-measure so we can scale later. holder.measure(); - LayoutParams lp = row.getLayoutParams(); + LayoutParams lp = viewGroup.getLayoutParams(); if (lp == null) { - lp = new LayoutParams(LayoutParams.MATCH_PARENT, holder.measuredRowHeight); - row.setLayoutParams(lp); + lp = new LayoutParams(LayoutParams.MATCH_PARENT, holder.getMeasuredRowHeight()); + viewGroup.setLayoutParams(lp); } else { - lp.height = holder.measuredRowHeight; + lp.height = holder.getMeasuredRowHeight(); } - row.setTag(holder); + + viewGroup.setTag(holder); + return holder; } - void bindViewHolder(int rowPosition, RowViewHolder holder) { + RowViewHolder createViewHolder(int viewType, ViewGroup parent) { + if (viewType == VIEW_TYPE_DIRECT_SHARE) { + ViewGroup parentGroup = (ViewGroup) mLayoutInflater.inflate( + R.layout.chooser_row_direct_share, parent, false); + ViewGroup row1 = (ViewGroup) mLayoutInflater.inflate(R.layout.chooser_row, + parentGroup, false); + ViewGroup row2 = (ViewGroup) mLayoutInflater.inflate(R.layout.chooser_row, + parentGroup, false); + parentGroup.addView(row1); + parentGroup.addView(row2); + + mDirectShareViewHolder = new DirectShareViewHolder(parentGroup, + Lists.newArrayList(row1, row2), getMaxTargetsPerRow()); + loadViewsIntoRow(mDirectShareViewHolder); + + return mDirectShareViewHolder; + } else { + ViewGroup row = (ViewGroup) mLayoutInflater.inflate(R.layout.chooser_row, parent, + false); + RowViewHolder holder = new SingleRowViewHolder(row, getMaxTargetsPerRow()); + loadViewsIntoRow(holder); + + return holder; + } + } + + void bindViewHolder(int rowPosition, RowViewHolder holder, int columnCount) { final int start = getFirstRowPosition(rowPosition); final int startType = mChooserListAdapter.getPositionTargetType(start); final int lastStartType = mChooserListAdapter.getPositionTargetType( getFirstRowPosition(rowPosition - 1)); + final ViewGroup row = holder.getViewGroup(); + if (startType != lastStartType || rowPosition == 0) { - holder.row.setBackground(mChooserRowLayer); - setVertPadding(holder, mChooserRowServiceSpacing, 0); + row.setBackground(mChooserRowLayer); + setVertPadding(row, mChooserRowServiceSpacing, 0); } else { - holder.row.setBackground(null); - setVertPadding(holder, 0, 0); + row.setBackground(null); + setVertPadding(row, 0, 0); } - int end = start + mColumnCount - 1; + int end = start + columnCount - 1; while (mChooserListAdapter.getPositionTargetType(end) != startType && end >= start) { end--; } if (end == start && mChooserListAdapter.getItem(start) instanceof EmptyTargetInfo) { - final TextView textView = holder.row.findViewById(R.id.chooser_row_text_option); + final TextView textView = row.findViewById(R.id.chooser_row_text_option); if (textView.getVisibility() != View.VISIBLE) { textView.setAlpha(0.0f); @@ -2269,12 +2315,12 @@ public class ChooserActivity extends ResolverActivity { } } - for (int i = 0; i < mColumnCount; i++) { - final View v = holder.cells[i]; + for (int i = 0; i < columnCount; i++) { + final View v = holder.getView(i); if (start + i <= end) { setCellVisibility(holder, i, View.VISIBLE); - holder.itemIndices[i] = start + i; - mChooserListAdapter.bindView(holder.itemIndices[i], v); + holder.setItemIndex(i, start + i); + mChooserListAdapter.bindView(holder.getItemIndex(i), v); } else { setCellVisibility(holder, i, View.INVISIBLE); } @@ -2282,13 +2328,13 @@ public class ChooserActivity extends ResolverActivity { } private void setCellVisibility(RowViewHolder holder, int i, int visibility) { - final View v = holder.cells[i]; + final View v = holder.getView(i); if (visibility == View.VISIBLE) { - holder.cellVisibility[i] = true; + holder.setViewVisibility(i, true); v.setVisibility(visibility); v.setAlpha(1.0f); - } else if (visibility == View.INVISIBLE && holder.cellVisibility[i]) { - holder.cellVisibility[i] = false; + } else if (visibility == View.INVISIBLE && holder.getViewVisibility(i)) { + holder.setViewVisibility(i, false); ValueAnimator fadeAnim = ObjectAnimator.ofFloat(v, "alpha", 1.0f, 0f); fadeAnim.setDuration(NO_DIRECT_SHARE_ANIM_IN_MILLIS); @@ -2302,49 +2348,218 @@ public class ChooserActivity extends ResolverActivity { } } - private void setVertPadding(RowViewHolder holder, int top, int bottom) { - holder.row.setPadding(holder.row.getPaddingLeft(), top, - holder.row.getPaddingRight(), bottom); + private void setVertPadding(ViewGroup row, int top, int bottom) { + row.setPadding(row.getPaddingLeft(), top, row.getPaddingRight(), bottom); } int getFirstRowPosition(int row) { + final int serviceCount = mChooserListAdapter.getServiceTargetCount(); + final int serviceRows = (int) Math.ceil((float) serviceCount + / ChooserListAdapter.MAX_SERVICE_TARGETS); + if (row < serviceRows) { + return row * getMaxTargetsPerRow(); + } + final int callerCount = mChooserListAdapter.getCallerTargetCount(); - final int callerRows = (int) Math.ceil((float) callerCount / mColumnCount); + final int callerRows = (int) Math.ceil((float) callerCount / getMaxTargetsPerRow()); + if (row < callerRows + serviceRows) { + return serviceCount + (row - serviceRows) * getMaxTargetsPerRow(); + } + + return callerCount + serviceCount + + (row - callerRows - serviceRows) * getMaxTargetsPerRow(); + } - if (row < callerRows) { - return row * mColumnCount; + public void handleScroll(View v, int y, int oldy) { + if (mDirectShareViewHolder != null) { + mDirectShareViewHolder.handleScroll(mAdapterView, y, oldy, getMaxTargetsPerRow()); } + } + } - final int serviceCount = mChooserListAdapter.getServiceTargetCount(); - final int serviceRows = (int) Math.ceil((float) serviceCount / mColumnCount); + abstract class RowViewHolder { + protected int mMeasuredRowHeight; + private int[] mItemIndices; + protected final View[] mCells; + private final boolean[] mCellVisibility; + private final int mColumnCount; - if (row < callerRows + serviceRows) { - return callerCount + (row - callerRows) * mColumnCount; + RowViewHolder(int cellCount) { + this.mCells = new View[cellCount]; + this.mItemIndices = new int[cellCount]; + this.mCellVisibility = new boolean[cellCount]; + this.mColumnCount = cellCount; + } + + abstract ViewGroup addView(int index, View v); + + abstract ViewGroup getViewGroup(); + + abstract ViewGroup getRow(int index); + + public int getColumnCount() { + return mColumnCount; + } + + public void setViewVisibility(int index, boolean visibility) { + mCellVisibility[index] = visibility; + } + + public boolean getViewVisibility(int index) { + return mCellVisibility[index]; + } + + public void measure() { + final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + getViewGroup().measure(spec, spec); + mMeasuredRowHeight = getViewGroup().getMeasuredHeight(); + } + + public int getMeasuredRowHeight() { + return mMeasuredRowHeight; + } + + protected void addSpacer(ViewGroup row) { + row.addView(new Space(ChooserActivity.this), + new LinearLayout.LayoutParams(0, 0, 1)); + } + + public void setItemIndex(int itemIndex, int listIndex) { + mItemIndices[itemIndex] = listIndex; + } + + public int getItemIndex(int itemIndex) { + return mItemIndices[itemIndex]; + } + + public View getView(int index) { + return mCells[index]; + } + } + + class SingleRowViewHolder extends RowViewHolder { + private final ViewGroup mRow; + + SingleRowViewHolder(ViewGroup row, int cellCount) { + super(cellCount); + + this.mRow = row; + } + + public ViewGroup getViewGroup() { + return mRow; + } + + public ViewGroup getRow(int index) { + return mRow; + } + + public ViewGroup addView(int index, View v) { + mRow.addView(v); + mCells[index] = v; + + if (index != (mCells.length - 1)) { + addSpacer(mRow); } - return callerCount + serviceCount - + (row - callerRows - serviceRows) * mColumnCount; + return mRow; } } - static class RowViewHolder { - public final View[] cells; - public final boolean [] cellVisibility; - public final ViewGroup row; - int measuredRowHeight; - int[] itemIndices; + class DirectShareViewHolder extends RowViewHolder { + private final ViewGroup mParent; + private final List<ViewGroup> mRows; + private int mCellCountPerRow; + + private boolean mHideDirectShareExpansion = false; + private int mDirectShareMinHeight = 0; + private int mDirectShareCurrHeight = 0; + private int mDirectShareMaxHeight = 0; - public RowViewHolder(ViewGroup row, int cellCount) { - this.row = row; - this.cells = new View[cellCount]; - this.cellVisibility = new boolean[cellCount]; - this.itemIndices = new int[cellCount]; + DirectShareViewHolder(ViewGroup parent, List<ViewGroup> rows, int cellCountPerRow) { + super(rows.size() * cellCountPerRow); + + this.mParent = parent; + this.mRows = rows; + this.mCellCountPerRow = cellCountPerRow; + } + + public ViewGroup addView(int index, View v) { + ViewGroup row = getRow(index); + row.addView(v); + mCells[index] = v; + + if (index % mCellCountPerRow != (mCellCountPerRow - 1)) { + addSpacer(row); + } + + return row; + } + + public ViewGroup getViewGroup() { + return mParent; + } + + public ViewGroup getRow(int index) { + return mRows.get(index / mCellCountPerRow); } public void measure() { final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - row.measure(spec, spec); - measuredRowHeight = row.getMeasuredHeight(); + getRow(0).measure(spec, spec); + getRow(1).measure(spec, spec); + + // uses ChooserActiivty state variables to track height + mDirectShareMinHeight = getRow(0).getMeasuredHeight(); + mDirectShareCurrHeight = mDirectShareCurrHeight > 0 + ? mDirectShareCurrHeight : mDirectShareMinHeight; + mDirectShareMaxHeight = 2 * mDirectShareMinHeight; + } + + public int getMeasuredRowHeight() { + return mDirectShareCurrHeight; + } + + public void handleScroll(AbsListView view, int y, int oldy, int maxTargetsPerRow) { + // only expand if we have more than 4 targets, and delay that decision until + // they start to scroll + if (mHideDirectShareExpansion) { + return; + } + + if (mChooserListAdapter.getSelectableServiceTargetCount() <= maxTargetsPerRow) { + mHideDirectShareExpansion = true; + return; + } + + int yDiff = (int) ((oldy - y) * 0.7f); + + int prevHeight = mDirectShareCurrHeight; + mDirectShareCurrHeight = Math.min(mDirectShareCurrHeight + yDiff, + mDirectShareMaxHeight); + mDirectShareCurrHeight = Math.max(mDirectShareCurrHeight, mDirectShareMinHeight); + yDiff = mDirectShareCurrHeight - prevHeight; + + if (view == null || view.getChildCount() == 0) { + return; + } + + ViewGroup expansionGroup = (ViewGroup) view.getChildAt(0); + int widthSpec = MeasureSpec.makeMeasureSpec(expansionGroup.getWidth(), + MeasureSpec.EXACTLY); + int heightSpec = MeasureSpec.makeMeasureSpec(mDirectShareCurrHeight, + MeasureSpec.EXACTLY); + expansionGroup.measure(widthSpec, heightSpec); + expansionGroup.getLayoutParams().height = expansionGroup.getMeasuredHeight(); + expansionGroup.layout(expansionGroup.getLeft(), expansionGroup.getTop(), + expansionGroup.getRight(), + expansionGroup.getTop() + expansionGroup.getMeasuredHeight()); + + // reposition list items + int items = view.getChildCount(); + for (int i = 1; i < items; i++) { + view.getChildAt(i).offsetTopAndBottom(yDiff); + } } } @@ -2525,7 +2740,7 @@ public class ChooserActivity extends ResolverActivity { mCachedView = null; } final View v = mChooserRowAdapter.getView(pos, mCachedView, mListView); - int height = ((RowViewHolder) (v.getTag())).measuredRowHeight; + int height = ((RowViewHolder) (v.getTag())).getMeasuredRowHeight(); offset += (int) (height); diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 011cc041f0c1..c60a96b3d437 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -99,7 +99,7 @@ public class ResolverActivity extends Activity { protected ResolveListAdapter mAdapter; private boolean mSafeForwardingMode; - private AbsListView mAdapterView; + protected AbsListView mAdapterView; private Button mAlwaysButton; private Button mOnceButton; private Button mSettingsButton; diff --git a/core/java/com/android/internal/os/KernelWakelockReader.java b/core/java/com/android/internal/os/KernelWakelockReader.java index 2442d0b84bd6..8b25e2dcf7a3 100644 --- a/core/java/com/android/internal/os/KernelWakelockReader.java +++ b/core/java/com/android/internal/os/KernelWakelockReader.java @@ -66,7 +66,7 @@ public class KernelWakelockReader { */ public final KernelWakelockStats readKernelWakelockStats(KernelWakelockStats staleStats) { byte[] buffer = new byte[32*1024]; - int len; + int len = 0; boolean wakeup_sources; final long startTime = SystemClock.uptimeMillis(); @@ -87,7 +87,11 @@ public class KernelWakelockReader { } } - len = is.read(buffer); + int cnt; + while ((cnt = is.read(buffer, len, buffer.length - len)) > 0) { + len += cnt; + } + is.close(); } catch (java.io.IOException e) { Slog.wtf(TAG, "failed to read kernel wakelocks", e); 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/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java index 42fb1f5c34e9..bb7423a67754 100644 --- a/core/java/com/android/internal/widget/FloatingToolbar.java +++ b/core/java/com/android/internal/widget/FloatingToolbar.java @@ -33,7 +33,6 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.text.TextUtils; import android.util.Size; -import android.util.TypedValue; import android.view.ContextThemeWrapper; import android.view.Gravity; import android.view.LayoutInflater; @@ -593,7 +592,7 @@ public final class FloatingToolbar { refreshCoordinatesAndOverflowDirection(contentRectOnScreen); preparePopupContent(); // We need to specify the position in window coordinates. - // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can + // TODO: Consider to use PopupWindow.setIsLaidOutInScreen(true) so that we can // specify the popup position in screen coordinates. mPopupWindow.showAtLocation( mParent, Gravity.NO_GRAVITY, mCoordsOnWindow.x, mCoordsOnWindow.y); @@ -661,7 +660,7 @@ public final class FloatingToolbar { refreshCoordinatesAndOverflowDirection(contentRectOnScreen); preparePopupContent(); // We need to specify the position in window coordinates. - // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can + // TODO: Consider to use PopupWindow.setIsLaidOutInScreen(true) so that we can // specify the popup position in screen coordinates. mPopupWindow.update( mCoordsOnWindow.x, mCoordsOnWindow.y, @@ -755,7 +754,7 @@ public final class FloatingToolbar { // and screen coordiantes, where the offset between them should be equal to the window // origin, and 2) we can use an arbitrary for this calculation while calculating the // location of the rootview is supposed to be least expensive. - // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can avoid + // TODO: Consider to use PopupWindow.setIsLaidOutInScreen(true) so that we can avoid // the following calculation. mParent.getRootView().getLocationOnScreen(mTmpCoords); int rootViewLeftOnScreen = mTmpCoords[0]; @@ -1722,7 +1721,7 @@ public final class FloatingToolbar { private static PopupWindow createPopupWindow(ViewGroup content) { ViewGroup popupContentHolder = new LinearLayout(content.getContext()); PopupWindow popupWindow = new PopupWindow(popupContentHolder); - // TODO: Use .setLayoutInScreenEnabled(true) instead of .setClippingEnabled(false) + // TODO: Use .setIsLaidOutInScreen(true) instead of .setClippingEnabled(false) // unless FLAG_LAYOUT_IN_SCREEN has any unintentional side-effects. popupWindow.setClippingEnabled(false); popupWindow.setWindowLayoutType( diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java index ee8637d8c773..9722fcb129f6 100644 --- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java +++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java @@ -502,6 +502,7 @@ public class ResolverDrawerLayout extends ViewGroup { new LogMaker(MetricsEvent.ACTION_SHARESHEET_COLLAPSED_CHANGED) .setSubtype(isCollapsedNew ? 1 : 0)); } + onScrollChanged(0, (int) newPos, 0, (int) (newPos - dy)); postInvalidateOnAnimation(); return dy; } 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 67bff6bb67f6..ea300aa170ee 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -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/layout/chooser_row_direct_share.xml b/core/res/res/layout/chooser_row_direct_share.xml new file mode 100644 index 000000000000..d7e36eedfe92 --- /dev/null +++ b/core/res/res/layout/chooser_row_direct_share.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** 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. +*/ +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="200dp"> + +</LinearLayout> + + 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 a69655aa555c..bf7c8f276cee 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -525,8 +525,8 @@ <!-- label for screenshot item in power menu --> <string name="global_action_screenshot">Screenshot</string> - <!-- Take bug report menu title [CHAR LIMIT=NONE] --> - <string name="bugreport_title">Take bug report</string> + <!-- Take bug report menu title [CHAR LIMIT=20] --> + <string name="bugreport_title">Bug report</string> <!-- Message in bugreport dialog describing what it does [CHAR LIMIT=NONE] --> <!-- TODO: remove if not used anymore --> <string name="bugreport_message">This will collect information about your diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 69def5b70f07..503bbced1937 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2770,6 +2770,7 @@ <java-symbol type="drawable" name="scroll_indicator_material" /> <java-symbol type="layout" name="chooser_row" /> + <java-symbol type="layout" name="chooser_row_direct_share" /> <java-symbol type="id" name="target_badge" /> <java-symbol type="bool" name="config_supportDoubleTapWake" /> <java-symbol type="drawable" name="ic_perm_device_info" /> @@ -3382,6 +3383,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/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/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/MediaController.java b/media/java/android/media/session/MediaController.java index 5ee52ce08d10..73340441c706 100644 --- a/media/java/android/media/session/MediaController.java +++ b/media/java/android/media/session/MediaController.java @@ -18,7 +18,6 @@ package android.media.session; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; import android.content.Context; @@ -954,7 +953,6 @@ public final class MediaController { /** * @hide */ - @SystemApi public PlaybackInfo(int type, int control, int max, int current, AudioAttributes attrs) { mVolumeType = type; mVolumeControl = control; 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/DynamicAndroidInstallationService/res/values/strings.xml b/packages/DynamicAndroidInstallationService/res/values/strings.xml index 221e1d75b133..aee67e10692a 100644 --- a/packages/DynamicAndroidInstallationService/res/values/strings.xml +++ b/packages/DynamicAndroidInstallationService/res/values/strings.xml @@ -13,7 +13,7 @@ <string name="keyguard_description">Please enter your password and continue to AndroidOnTap installation</string> <!-- Displayed on notification: DynAndroid installation is completed [CHAR LIMIT=128] --> - <string name="notification_install_completed">Installation is completed, you can reboot into the new installed system now.</string> + <string name="notification_install_completed">New system is ready, you can reboot into it or discard it.</string> <!-- Displayed on notification: DynAndroid installation is in progress [CHAR LIMIT=128] --> <string name="notification_install_inprogress">Installation is in progress.</string> <!-- Displayed on notification: DynAndroid installation is in progress [CHAR LIMIT=128] --> @@ -30,4 +30,6 @@ <!-- Action on notification: Reboot to AndroidOnTap [CHAR LIMIT=16] --> <string name="notification_action_reboot_to_dynandroid">Reboot</string> + <!-- Toast when installed AndroidOnTap is discarded [CHAR LIMIT=64] --> + <string name="toast_dynandroid_discarded">Installed AndroidOnTap is discarded.</string> </resources> diff --git a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java index 719417e96015..63ac8c73decf 100644 --- a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java +++ b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java @@ -54,6 +54,7 @@ import android.os.Messenger; import android.os.PowerManager; import android.os.RemoteException; import android.util.Log; +import android.widget.Toast; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -73,6 +74,8 @@ public class DynamicAndroidInstallationService extends Service */ private static final String ACTION_CANCEL_INSTALL = "com.android.dynandroid.ACTION_CANCEL_INSTALL"; + private static final String ACTION_DISCARD_INSTALL = + "com.android.dynandroid.ACTION_DISCARD_INSTALL"; private static final String ACTION_REBOOT_TO_DYN_ANDROID = "com.android.dynandroid.ACTION_REBOOT_TO_DYN_ANDROID"; private static final String ACTION_REBOOT_TO_NORMAL = @@ -118,10 +121,6 @@ public class DynamicAndroidInstallationService extends Service private long mInstalledSize; private boolean mJustCancelledByUser; - private PendingIntent mPiCancel; - private PendingIntent mPiRebootToDynamicAndroid; - private PendingIntent mPiUninstallAndReboot; - private InstallationAsyncTask mInstallTask; @@ -155,6 +154,8 @@ public class DynamicAndroidInstallationService extends Service executeInstallCommand(intent); } else if (ACTION_CANCEL_INSTALL.equals(action)) { executeCancelCommand(); + } else if (ACTION_DISCARD_INSTALL.equals(action)) { + executeDiscardCommand(); } else if (ACTION_REBOOT_TO_DYN_ANDROID.equals(action)) { executeRebootToDynAndroidCommand(); } else if (ACTION_REBOOT_TO_NORMAL.equals(action)) { @@ -210,7 +211,7 @@ public class DynamicAndroidInstallationService extends Service } if (mInstallTask != null) { - Log.e(TAG, "There is already an install task running"); + Log.e(TAG, "There is already an installation task running"); return; } @@ -234,10 +235,8 @@ public class DynamicAndroidInstallationService extends Service } private void executeCancelCommand() { - if (mInstallTask == null || mInstallTask.getStatus() == PENDING) { + if (mInstallTask == null || mInstallTask.getStatus() != RUNNING) { Log.e(TAG, "Cancel command triggered, but there is no task running"); - mNM.cancel(NOTIFICATION_ID); - return; } @@ -247,17 +246,34 @@ public class DynamicAndroidInstallationService extends Service // Will cleanup and post status in onCancelled() Log.d(TAG, "Cancel request filed successfully"); } else { - Log.d(TAG, "Requested cancel, completed task will be discarded"); + Log.e(TAG, "Trying to cancel installation while it's already completed."); + } + } - resetTaskAndStop(); - postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED); + private void executeDiscardCommand() { + if (isInDynamicAndroid()) { + Log.e(TAG, "We are now running in AOT, please reboot to normal system first"); + return; } + if (getStatus() != STATUS_READY) { + Log.e(TAG, "Trying to discard AOT while there is no complete installation"); + return; + } + + Toast.makeText(this, + getString(R.string.toast_dynandroid_discarded), + Toast.LENGTH_LONG).show(); + + resetTaskAndStop(); + postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED); + + mDynAndroid.remove(); } private void executeRebootToDynAndroidCommand() { if (mInstallTask == null || mInstallTask.getStatus() != FINISHED) { - Log.e(TAG, "Trying to reboot to DynamicAndroid, but there is no complete installation"); + Log.e(TAG, "Trying to reboot to AOT while there is no complete installation"); return; } @@ -277,8 +293,13 @@ public class DynamicAndroidInstallationService extends Service } private void executeRebootToNormalCommand() { - mDynAndroid.remove(); + if (!isInDynamicAndroid()) { + Log.e(TAG, "It's already running in normal system."); + return; + } + // Per current design, we don't have disable() API. AOT is disabled on next reboot. + // TODO: Use better status query when b/125079548 is done. PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); if (powerManager != null) { @@ -287,9 +308,14 @@ public class DynamicAndroidInstallationService extends Service } private void executeNotifyIfInUseCommand() { - if (isInDynamicAndroid()) { + int status = getStatus(); + + if (status == STATUS_IN_USE) { startForeground(NOTIFICATION_ID, buildNotification(STATUS_IN_USE, CAUSE_NOT_SPECIFIED)); + } else if (status == STATUS_READY) { + startForeground(NOTIFICATION_ID, + buildNotification(STATUS_READY, CAUSE_NOT_SPECIFIED)); } } @@ -312,18 +338,12 @@ public class DynamicAndroidInstallationService extends Service if (mNM != null) { mNM.createNotificationChannel(chan); } + } - Intent intentCancel = new Intent(this, DynamicAndroidInstallationService.class); - intentCancel.setAction(ACTION_CANCEL_INSTALL); - mPiCancel = PendingIntent.getService(this, 0, intentCancel, 0); - - Intent intentRebootToDyn = new Intent(this, DynamicAndroidInstallationService.class); - intentRebootToDyn.setAction(ACTION_REBOOT_TO_DYN_ANDROID); - mPiRebootToDynamicAndroid = PendingIntent.getService(this, 0, intentRebootToDyn, 0); - - Intent intentUninstallAndReboot = new Intent(this, DynamicAndroidInstallationService.class); - intentUninstallAndReboot.setAction(ACTION_REBOOT_TO_NORMAL); - mPiUninstallAndReboot = PendingIntent.getService(this, 0, intentUninstallAndReboot, 0); + private PendingIntent createPendingIntent(String action) { + Intent intent = new Intent(this, DynamicAndroidInstallationService.class); + intent.setAction(action); + return PendingIntent.getService(this, 0, intent, 0); } private Notification buildNotification(int status, int cause) { @@ -342,7 +362,7 @@ public class DynamicAndroidInstallationService extends Service builder.addAction(new Notification.Action.Builder( null, getString(R.string.notification_action_cancel), - mPiCancel).build()); + createPendingIntent(ACTION_CANCEL_INSTALL)).build()); break; @@ -351,11 +371,11 @@ public class DynamicAndroidInstallationService extends Service builder.addAction(new Notification.Action.Builder( null, getString(R.string.notification_action_reboot_to_dynandroid), - mPiRebootToDynamicAndroid).build()); + createPendingIntent(ACTION_REBOOT_TO_DYN_ANDROID)).build()); builder.addAction(new Notification.Action.Builder( - null, getString(R.string.notification_action_cancel), - mPiCancel).build()); + null, getString(R.string.notification_action_discard), + createPendingIntent(ACTION_DISCARD_INSTALL)).build()); break; @@ -364,7 +384,7 @@ public class DynamicAndroidInstallationService extends Service builder.addAction(new Notification.Action.Builder( null, getString(R.string.notification_action_uninstall), - mPiUninstallAndReboot).build()); + createPendingIntent(ACTION_REBOOT_TO_NORMAL)).build()); break; @@ -427,10 +447,10 @@ public class DynamicAndroidInstallationService extends Service private int getStatus() { if (isInDynamicAndroid()) { return STATUS_IN_USE; - + } else if (isDynamicAndroidInstalled()) { + return STATUS_READY; } else if (mInstallTask == null) { return STATUS_NOT_STARTED; - } switch (mInstallTask.getStatus()) { @@ -458,6 +478,10 @@ public class DynamicAndroidInstallationService extends Service return mDynAndroid.isInUse(); } + private boolean isDynamicAndroidInstalled() { + return mDynAndroid.isInstalled(); + } + void handleMessage(Message msg) { switch (msg.what) { case DynamicAndroidClient.MSG_REGISTER_LISTENER: 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/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/Android.bp b/packages/SystemUI/Android.bp index 94259416d274..c2495b586144 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -58,7 +58,6 @@ android_library { "androidx.arch.core_core-runtime", "androidx.lifecycle_lifecycle-extensions", "androidx.dynamicanimation_dynamicanimation", - "iconloader_base", "SystemUI-tags", "SystemUI-proto", "dagger2-2.19", 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/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-land/global_actions_grid.xml b/packages/SystemUI/res/layout-land/global_actions_grid.xml index 235d0fc62e2d..c51e71b5c61f 100644 --- a/packages/SystemUI/res/layout-land/global_actions_grid.xml +++ b/packages/SystemUI/res/layout-land/global_actions_grid.xml @@ -7,7 +7,8 @@ android:orientation="horizontal" android:clipToPadding="false" android:theme="@style/qs_theme" - android:gravity="top|right" + android:paddingLeft="@dimen/global_actions_top_padding" + android:gravity="top|left" android:clipChildren="false" > <LinearLayout diff --git a/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml b/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml index e028214532f0..de853c77daae 100644 --- a/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml +++ b/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml @@ -7,7 +7,8 @@ android:orientation="horizontal" android:clipToPadding="false" android:theme="@style/qs_theme" - android:gravity="top|left" + android:gravity="top|right" + android:paddingRight="@dimen/global_actions_top_padding" android:clipChildren="false" > <LinearLayout diff --git a/packages/SystemUI/res/layout/global_actions_grid.xml b/packages/SystemUI/res/layout/global_actions_grid.xml index a620a8eb144b..d90d5e9f676b 100644 --- a/packages/SystemUI/res/layout/global_actions_grid.xml +++ b/packages/SystemUI/res/layout/global_actions_grid.xml @@ -6,8 +6,9 @@ android:layout_height="match_parent" android:orientation="horizontal" android:clipToPadding="false" + android:paddingTop="@dimen/global_actions_top_padding" android:theme="@style/qs_theme" - android:gravity="bottom|center" + android:gravity="top|center" android:clipChildren="false" > <LinearLayout 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..30c29dcff9e0 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> @@ -865,10 +867,12 @@ <!-- Global actions power menu --> <dimen name="global_actions_panel_width">120dp</dimen> - <dimen name="global_actions_top_padding">120dp</dimen> <dimen name="global_actions_padding">12dp</dimen> <dimen name="global_actions_translate">9dp</dimen> + <!-- Distance from the top of screen in pixels, to position the power menu near the button. --> + <dimen name="global_actions_top_padding">330px</dimen> + <!-- Global actions grid layout --> <dimen name="global_actions_grid_side_margin">4dp</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java index 5086c997613a..72ab02c21192 100644 --- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java +++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java @@ -215,7 +215,7 @@ public class HardwareUiLayout extends MultiListLayout implements Tunable { } else { rotateLeft(); } - if (mSeparated) { + if (mAdapter.hasSeparatedItems()) { if (from == ROTATION_SEASCAPE || to == ROTATION_SEASCAPE) { // Separated view has top margin, so seascape separated view need special rotation, // not a full left or right rotation. @@ -257,10 +257,10 @@ public class HardwareUiLayout extends MultiListLayout implements Tunable { @Override public void onUpdateList() { - removeAllItems(); + super.onUpdateList(); ArrayList<GlobalActionsDialog.Action> separatedActions = - mAdapter.getSeparatedItems(mSeparated); - ArrayList<GlobalActionsDialog.Action> listActions = mAdapter.getListItems(mSeparated); + mAdapter.getSeparatedItems(); + ArrayList<GlobalActionsDialog.Action> listActions = mAdapter.getListItems(); for (int i = 0; i < mAdapter.getCount(); i++) { Object action = mAdapter.getItem(i); @@ -461,8 +461,9 @@ public class HardwareUiLayout extends MultiListLayout implements Tunable { if (mList == null) return; // If got separated button, setRotatedBackground to false, // all items won't get white background. - mListBackground.setRotatedBackground(mSeparated); - mSeparatedViewBackground.setRotatedBackground(mSeparated); + boolean separated = mAdapter.hasSeparatedItems(); + mListBackground.setRotatedBackground(separated); + mSeparatedViewBackground.setRotatedBackground(separated); if (mDivision != null && mDivision.getVisibility() == VISIBLE) { int index = mRotatedBackground ? 0 : 1; mDivision.getLocationOnScreen(mTmp2); @@ -508,26 +509,27 @@ public class HardwareUiLayout extends MultiListLayout implements Tunable { int screenHeight; int totalHeight; int targetGravity; + boolean separated = mAdapter.hasSeparatedItems(); MarginLayoutParams params = (MarginLayoutParams) mSeparatedView.getLayoutParams(); switch (RotationUtils.getRotation(getContext())) { case RotationUtils.ROTATION_LANDSCAPE: defaultTopPadding = getPaddingLeft(); viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth(); - separatedViewTopMargin = mSeparated ? params.leftMargin : 0; + separatedViewTopMargin = separated ? params.leftMargin : 0; screenHeight = getMeasuredWidth(); targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.TOP; break; case RotationUtils.ROTATION_SEASCAPE: defaultTopPadding = getPaddingRight(); viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth(); - separatedViewTopMargin = mSeparated ? params.leftMargin : 0; + separatedViewTopMargin = separated ? params.leftMargin : 0; screenHeight = getMeasuredWidth(); targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM; break; default: // Portrait defaultTopPadding = getPaddingTop(); viewsTotalHeight = mList.getMeasuredHeight() + mSeparatedView.getMeasuredHeight(); - separatedViewTopMargin = mSeparated ? params.topMargin : 0; + separatedViewTopMargin = separated ? params.topMargin : 0; screenHeight = getMeasuredHeight(); targetGravity = Gravity.CENTER_VERTICAL|Gravity.RIGHT; break; diff --git a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java index 2bc472065676..d063a0f4086e 100644 --- a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java +++ b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java @@ -33,8 +33,8 @@ import java.util.ArrayList; */ public abstract class MultiListLayout extends LinearLayout { protected boolean mHasOutsideTouch; - protected boolean mSeparated; protected MultiListAdapter mAdapter; + protected boolean mSnapToEdge; protected int mRotation; protected RotationListener mRotationListener; @@ -70,12 +70,10 @@ public abstract class MultiListLayout extends LinearLayout { } /** - * Sets whether the separated view should be shown, and handles updating visibility on - * that view. + * Sets whether the GlobalActions view should snap to the edge of the screen. */ - public void setSeparated(boolean separated) { - mSeparated = separated; - setSeparatedViewVisibility(separated); + public void setSnapToEdge(boolean snap) { + mSnapToEdge = snap; } /** @@ -123,7 +121,9 @@ public abstract class MultiListLayout extends LinearLayout { onUpdateList(); } - protected abstract void onUpdateList(); + protected void onUpdateList() { + setSeparatedViewVisibility(mAdapter.hasSeparatedItems()); + } public void setRotationListener(RotationListener listener) { mRotationListener = listener; @@ -156,13 +156,13 @@ public abstract class MultiListLayout extends LinearLayout { * Creates an ArrayList of items which should be rendered in the separated view. * @param useSeparatedView is true if the separated view will be used, false otherwise. */ - public abstract ArrayList getSeparatedItems(boolean useSeparatedView); + public abstract ArrayList getSeparatedItems(); /** * Creates an ArrayList of items which should be rendered in the list view. * @param useSeparatedView True if the separated view will be used, false otherwise. */ - public abstract ArrayList getListItems(boolean useSeparatedView); + public abstract ArrayList getListItems(); /** * Callback to run when an individual item is clicked or pressed. @@ -176,5 +176,13 @@ public abstract class MultiListLayout extends LinearLayout { * @return True if the long-click was handled, false otherwise. */ public abstract boolean onLongClickItem(int position); + + /** + * Determines whether the mAdapter contains any separated items, used to determine whether + * or not to hide the separated list from view. + */ + public boolean hasSeparatedItems() { + return getSeparatedItems().size() > 0; + } } } 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/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index b07f90970cbe..ce588955298c 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -38,7 +38,6 @@ import android.graphics.Point; import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.net.ConnectivityManager; -import android.os.Build; import android.os.Handler; import android.os.Message; import android.os.RemoteException; @@ -156,7 +155,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private boolean mHasVibrator; private boolean mHasLogoutButton; private boolean mHasLockdownButton; - private boolean mUseSeparatedList; private final boolean mShowSilentToggle; private final EmergencyAffordanceManager mEmergencyAffordanceManager; private final ScreenshotHelper mScreenshotHelper; @@ -334,7 +332,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, ArraySet<String> addedKeys = new ArraySet<String>(); mHasLogoutButton = false; mHasLockdownButton = false; - mUseSeparatedList = true; for (int i = 0; i < defaultActions.length; i++) { String actionKey = defaultActions[i]; if (addedKeys.contains(actionKey)) { @@ -382,7 +379,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mHasLogoutButton = true; } } else if (GLOBAL_ACTION_KEY_EMERGENCY.equals(actionKey)) { - if (mUseSeparatedList + if (shouldUseSeparatedView() && !mEmergencyAffordanceManager.needsEmergencyAffordance()) { mItems.add(new EmergencyDialerAction()); } @@ -407,8 +404,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } }) : null; - ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, mUseSeparatedList, - panelViewController); + ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, panelViewController); dialog.setCanceledOnTouchOutside(false); // Handled by the custom class. dialog.setKeyguardShowing(mKeyguardShowing); @@ -636,14 +632,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, public boolean showBeforeProvisioning() { return false; } - - @Override - public String getStatus() { - return mContext.getString( - R.string.bugreport_status, - Build.VERSION.RELEASE, - Build.ID); - } } private final class LogoutAction extends SinglePressAction { @@ -702,7 +690,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private Action getEmergencyAction() { Drawable emergencyIcon = mContext.getDrawable(R.drawable.emergency_icon); - if (!mUseSeparatedList) { + if (!shouldUseSeparatedView()) { // use un-colored legacy treatment emergencyIcon.setTintList(null); } @@ -931,9 +919,9 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } @Override - public ArrayList<Action> getSeparatedItems(boolean shouldUseSeparatedView) { + public ArrayList<Action> getSeparatedItems() { ArrayList<Action> separatedActions = new ArrayList<Action>(); - if (!shouldUseSeparatedView) { + if (!shouldUseSeparatedView()) { return separatedActions; } for (int i = 0; i < mItems.size(); i++) { @@ -946,8 +934,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } @Override - public ArrayList<Action> getListItems(boolean shouldUseSeparatedView) { - if (!shouldUseSeparatedView) { + public ArrayList<Action> getListItems() { + if (!shouldUseSeparatedView()) { return new ArrayList<Action>(mItems); } ArrayList<Action> listActions = new ArrayList<Action>(); @@ -1495,17 +1483,15 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private final ColorExtractor mColorExtractor; private final GlobalActionsPanelPlugin.PanelViewController mPanelController; private boolean mKeyguardShowing; - private boolean mUseSeparatedList; private boolean mShowing; private final float mScrimAlpha; - ActionsDialog(Context context, MyAdapter adapter, boolean separated, + ActionsDialog(Context context, MyAdapter adapter, GlobalActionsPanelPlugin.PanelViewController plugin) { super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions); mContext = context; mAdapter = adapter; mColorExtractor = Dependency.get(SysuiColorExtractor.class); - mUseSeparatedList = separated; // Window initialization Window window = getWindow(); @@ -1569,7 +1555,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mGlobalActionsLayout = (MultiListLayout) findViewById(com.android.systemui.R.id.global_actions_view); mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss()); - mGlobalActionsLayout.setSeparated(mUseSeparatedList); mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() { @Override public boolean dispatchPopulateAccessibilityEvent( @@ -1581,11 +1566,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, }); mGlobalActionsLayout.setRotationListener(this::onRotate); mGlobalActionsLayout.setAdapter(mAdapter); - } - - private boolean isPanelEnabled(Context context) { - return FeatureFlagUtils.isEnabled( - context, FeatureFlagUtils.GLOBAL_ACTIONS_PANEL_ENABLED); + mGlobalActionsLayout.setSnapToEdge(isPanelEnabled(mContext) + && mPanelController != null); } private int getGlobalActionsLayoutId(Context context) { @@ -1726,9 +1708,24 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } /** - * Determines whether or not the Global Actions Dialog should use the newer grid-style layout. + * Determines whether or not the Global Actions menu should use the newer grid-style layout. */ - public static boolean isGridEnabled(Context context) { + private static boolean isGridEnabled(Context context) { return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.GLOBAL_ACTIONS_GRID_ENABLED); } + + /** + * Determines whether or not the Global Actions Panel should appear when the power button + * is held. + */ + private static boolean isPanelEnabled(Context context) { + return FeatureFlagUtils.isEnabled( + context, FeatureFlagUtils.GLOBAL_ACTIONS_PANEL_ENABLED); } + + /** + * Determines whether the Global Actions menu should use a separated view for emergency actions. + */ + private static boolean shouldUseSeparatedView() { + return true; + } } diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java index cda7669a90b6..058ea605bc87 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java @@ -19,6 +19,7 @@ package com.android.systemui.globalactions; import android.content.Context; import android.text.TextUtils; import android.util.AttributeSet; +import android.view.Gravity; import android.view.View; import android.view.ViewGroup; @@ -71,10 +72,10 @@ public class GlobalActionsGridLayout extends MultiListLayout { @Override public void onUpdateList() { - removeAllItems(); + super.onUpdateList(); ArrayList<GlobalActionsDialog.Action> separatedActions = - mAdapter.getSeparatedItems(mSeparated); - ArrayList<GlobalActionsDialog.Action> listActions = mAdapter.getListItems(mSeparated); + mAdapter.getSeparatedItems(); + ArrayList<GlobalActionsDialog.Action> listActions = mAdapter.getListItems(); setExpectedListItemCount(listActions.size()); int rotation = RotationUtils.getRotation(mContext); @@ -108,6 +109,7 @@ public class GlobalActionsGridLayout extends MultiListLayout { parent.addView(v); } } + updateSnapPosition(); } @Override @@ -115,6 +117,19 @@ public class GlobalActionsGridLayout extends MultiListLayout { return findViewById(com.android.systemui.R.id.separated_button); } + private void updateSnapPosition() { + if (mSnapToEdge) { + setPadding(0, 0, 0, 0); + if (mRotation == RotationUtils.ROTATION_LANDSCAPE) { + setGravity(Gravity.RIGHT); + } else if (mRotation == RotationUtils.ROTATION_SEASCAPE) { + setGravity(Gravity.LEFT); + } else { + setGravity(Gravity.BOTTOM); + } + } + } + @Override protected ListGridLayout getListView() { return findViewById(android.R.id.list); @@ -148,7 +163,7 @@ public class GlobalActionsGridLayout extends MultiListLayout { } /** - * Not used in this implementation of the Global Actions Menu, but necessary for some others. + * Not ued in this implementation of the Global Actions Menu, but necessary for some others. */ @Override public void setDivisionView(View v) { diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java index 6c106dfe9db6..048f80196781 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java @@ -114,7 +114,7 @@ public class ListGridLayout extends LinearLayout { if (mExpectedCount == 3) { return 1; } - return (int) Math.ceil(Math.sqrt(mExpectedCount)); + return (int) Math.round(Math.sqrt(mExpectedCount)); } private int getColumnCount() { @@ -122,6 +122,6 @@ public class ListGridLayout extends LinearLayout { if (mExpectedCount == 3) { return 3; } - return (int) Math.round(Math.sqrt(mExpectedCount)); + return (int) Math.ceil(Math.sqrt(mExpectedCount)); } } 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/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/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/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/OWNERS b/services/core/java/com/android/server/pm/OWNERS index 3c1ee3ece7ad..cd0cbd628040 100644 --- a/services/core/java/com/android/server/pm/OWNERS +++ b/services/core/java/com/android/server/pm/OWNERS @@ -10,76 +10,48 @@ toddke@android.com toddke@google.com # apex support -per-file ApexManager.java = dariofreni@google.com, narayan@google.com, toddke@android.com, toddke@google.com -per-file StagingManager.java = dariofreni@google.com, narayan@google.com, toddke@android.com, toddke@google.com +per-file ApexManager.java = dariofreni@google.com +per-file StagingManager.java = dariofreni@google.com # dex -per-file AbstractStatsBase.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com -per-file AbstractStatsBase.java = calin@google.com, toddke@google.com, svetoslavganov@google.com -per-file AbstractStatsBase.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com -per-file BackgroundDexOptService.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com -per-file BackgroundDexOptService.java = calin@google.com, toddke@google.com, svetoslavganov@google.com -per-file BackgroundDexOptService.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com -per-file CompilerStats.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com -per-file CompilerStats.java = calin@google.com, toddke@google.com, svetoslavganov@google.com -per-file CompilerStats.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com -per-file DynamicCodeLoggingService.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com -per-file DynamicCodeLoggingService.java = calin@google.com, toddke@google.com, svetoslavganov@google.com -per-file DynamicCodeLoggingService.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com -per-file InstructionSets.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com -per-file InstructionSets.java = calin@google.com, toddke@google.com, svetoslavganov@google.com -per-file InstructionSets.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com -per-file OtaDexoptService.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com -per-file OtaDexoptService.java = calin@google.com, toddke@google.com, svetoslavganov@google.com -per-file OtaDexoptService.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com -per-file OtaDexoptShellCommand.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com -per-file OtaDexoptShellCommand.java = calin@google.com, toddke@google.com, svetoslavganov@google.com -per-file OtaDexoptShellCommand.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com -per-file PackageDexOptimizer.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com -per-file PackageDexOptimizer.java = calin@google.com, toddke@google.com, svetoslavganov@google.com -per-file PackageDexOptimizer.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com -per-file PackageManagerServiceCompilerMapping.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com -per-file PackageManagerServiceCompilerMapping.java = calin@google.com, toddke@google.com, svetoslavganov@google.com -per-file PackageManagerServiceCompilerMapping.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com -per-file PackageUsage.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com -per-file PackageUsage.java = calin@google.com, toddke@google.com, svetoslavganov@google.com -per-file PackageUsage.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com +per-file AbstractStatsBase.java = agampe@google.com, calin@google.com, ngeoffray@google.com +per-file BackgroundDexOptService.java = agampe@google.com, calin@google.com, ngeoffray@google.com +per-file CompilerStats.java = agampe@google.com, calin@google.com, ngeoffray@google.com +per-file DynamicCodeLoggingService.java = agampe@google.com, calin@google.com, ngeoffray@google.com +per-file InstructionSets.java = agampe@google.com, calin@google.com, ngeoffray@google.com +per-file OtaDexoptService.java = agampe@google.com, calin@google.com, ngeoffray@google.com +per-file OtaDexoptShellCommand.java = agampe@google.com, calin@google.com, ngeoffray@google.com +per-file PackageDexOptimizer.java = agampe@google.com, calin@google.com, ngeoffray@google.com +per-file PackageManagerServiceCompilerMapping.java = agampe@google.com, calin@google.com, ngeoffray@google.com +per-file PackageUsage.java = agampe@google.com, calin@google.com, ngeoffray@google.com # multi user / cross profile -per-file CrossProfileAppsServiceImpl.java = omakoto@google.com, yamasani@google.com, hackbod@google.com -per-file CrossProfileAppsServiceImpl.java = yamasani@google.com, omakoto@google.com, hackbod@google.com -per-file CrossProfileAppsService.java = omakoto@google.com, yamasani@google.com, hackbod@google.com -per-file CrossProfileAppsService.java = yamasani@google.com, omakoto@google.com, hackbod@google.com -per-file CrossProfileIntentFilter.java = omakoto@google.com, yamasani@google.com, hackbod@google.com -per-file CrossProfileIntentFilter.java = yamasani@google.com, omakoto@google.com, hackbod@google.com -per-file CrossProfileIntentResolver.java = omakoto@google.com, yamasani@google.com, hackbod@google.com -per-file CrossProfileIntentResolver.java = yamasani@google.com, omakoto@google.com, hackbod@google.com -per-file UserManagerService.java = omakoto@google.com, yamasani@google.com, hackbod@google.com -per-file UserManagerService.java = yamasani@google.com, omakoto@google.com, hackbod@google.com -per-file UserRestrictionsUtils.java = omakoto@google.com, yamasani@google.com, hackbod@google.com -per-file UserRestrictionsUtils.java = yamasani@google.com, omakoto@google.com, hackbod@google.com -per-file UserRestrictionsUtils.java = rubinxu@google.com, yamasani@google.com, hackbod@google.com -per-file UserRestrictionsUtils.java = sandness@google.com, yamasani@google.com, hackbod@google.com +per-file CrossProfileAppsServiceImpl.java = omakoto@google.com, yamasani@google.com +per-file CrossProfileAppsService.java = omakoto@google.com, yamasani@google.com +per-file CrossProfileIntentFilter.java = omakoto@google.com, yamasani@google.com +per-file CrossProfileIntentResolver.java = omakoto@google.com, yamasani@google.com +per-file UserManagerService.java = omakoto@google.com, yamasani@google.com +per-file UserRestrictionsUtils.java = omakoto@google.com, rubinxu@google.com, sandness@google.com, yamasani@google.com # security -per-file KeySetHandle.java = cbrubaker@google.com, svetoslavganov@google.com, hackbod@google.com -per-file KeySetManagerService.java = cbrubaker@google.com, svetoslavganov@google.com, hackbod@google.com -per-file PackageKeySetData.java = cbrubaker@google.com, svetoslavganov@google.com, hackbod@google.com -per-file PackageSignatures.java = cbrubaker@google.com, svetoslavganov@google.com, hackbod@google.com -per-file SELinuxMMAC.java = cbrubaker@google.com, svetoslavganov@google.com, hackbod@google.com +per-file KeySetHandle.java = cbrubaker@google.com +per-file KeySetManagerService.java = cbrubaker@google.com +per-file PackageKeySetData.java = cbrubaker@google.com +per-file PackageSignatures.java = cbrubaker@google.com +per-file SELinuxMMAC.java = cbrubaker@google.com # shortcuts -per-file LauncherAppsService.java = omakoto@google.com, yamasani@google.com, hackbod@google.com -per-file ShareTargetInfo.java = omakoto@google.com, yamasani@google.com, hackbod@google.com -per-file ShortcutBitmapSaver.java = omakoto@google.com, yamasani@google.com, hackbod@google.com -per-file ShortcutDumpFiles.java = omakoto@google.com, yamasani@google.com, hackbod@google.com -per-file ShortcutLauncher.java = omakoto@google.com, yamasani@google.com, hackbod@google.com -per-file ShortcutNonPersistentUser.java = omakoto@google.com, yamasani@google.com, hackbod@google.com -per-file ShortcutPackage.java = omakoto@google.com, yamasani@google.com, hackbod@google.com -per-file ShortcutPackageInfo.java = omakoto@google.com, yamasani@google.com, hackbod@google.com -per-file ShortcutPackageItem.java = omakoto@google.com, yamasani@google.com, hackbod@google.com -per-file ShortcutParser.java = omakoto@google.com, yamasani@google.com, hackbod@google.com -per-file ShortcutRequestPinProcessor.java = omakoto@google.com, yamasani@google.com, hackbod@google.com -per-file ShortcutService.java = omakoto@google.com, yamasani@google.com, hackbod@google.com -per-file ShortcutUser.java = omakoto@google.com, yamasani@google.com, hackbod@google.com +per-file LauncherAppsService.java = omakoto@google.com, yamasani@google.com +per-file ShareTargetInfo.java = omakoto@google.com, yamasani@google.com +per-file ShortcutBitmapSaver.java = omakoto@google.com, yamasani@google.com +per-file ShortcutDumpFiles.java = omakoto@google.com, yamasani@google.com +per-file ShortcutLauncher.java = omakoto@google.com, yamasani@google.com +per-file ShortcutNonPersistentUser.java = omakoto@google.com, yamasani@google.com +per-file ShortcutPackage.java = omakoto@google.com, yamasani@google.com +per-file ShortcutPackageInfo.java = omakoto@google.com, yamasani@google.com +per-file ShortcutPackageItem.java = omakoto@google.com, yamasani@google.com +per-file ShortcutParser.java = omakoto@google.com, yamasani@google.com +per-file ShortcutRequestPinProcessor.java = omakoto@google.com, yamasani@google.com +per-file ShortcutService.java = omakoto@google.com, yamasani@google.com +per-file ShortcutUser.java = omakoto@google.com, yamasani@google.com diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 45b3b5b1e18e..2de50e2a0c4e 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -510,6 +510,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } + /** {@hide} */ + boolean isCommitted() { + synchronized (mLock) { + return mCommitted; + } + } + @GuardedBy("mLock") private void assertPreparedAndNotSealedLocked(String cookie) { assertPreparedAndNotCommittedOrDestroyedLocked(cookie); @@ -1064,7 +1071,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private void handleCommit() { if (params.isStaged) { - mStagingManager.commitSession(this); + try { + mStagingManager.commitSession(this); + } catch (StagingManager.AlreadyInProgressStagedSessionException e) { + dispatchSessionFinished( + PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS, + e.getMessage(), null); + } destroyInternal(); dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null); return; 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/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 4ee6eafd0d44..088146d2d658 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -17,6 +17,7 @@ package com.android.server.pm; import android.annotation.NonNull; +import android.annotation.Nullable; import android.apex.ApexInfo; import android.apex.ApexInfoList; import android.apex.ApexSessionInfo; @@ -479,11 +480,42 @@ public class StagingManager { return true; } - void commitSession(@NonNull PackageInstallerSession session) { + void commitSession(@NonNull PackageInstallerSession session) + throws AlreadyInProgressStagedSessionException { + PackageInstallerSession activeSession = getActiveSession(); + boolean anotherSessionAlreadyInProgress = + activeSession != null && session.sessionId != activeSession.sessionId; updateStoredSession(session); + if (anotherSessionAlreadyInProgress) { + session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, + "There is already in-progress committed staged session " + + activeSession.sessionId); + throw new AlreadyInProgressStagedSessionException(activeSession.sessionId); + } mBgHandler.post(() -> preRebootVerification(session)); } + @Nullable + private PackageInstallerSession getActiveSession() { + synchronized (mStagedSessions) { + for (int i = 0; i < mStagedSessions.size(); i++) { + final PackageInstallerSession session = mStagedSessions.valueAt(i); + if (!session.isCommitted()) { + continue; + } + if (session.hasParentSessionId()) { + // Staging manager will finalize only parent session. Ignore child sessions + // picking the active. + continue; + } + if (!session.isStagedSessionApplied() && !session.isStagedSessionFailed()) { + return session; + } + } + } + return null; + } + void createSession(@NonNull PackageInstallerSession sessionInfo) { synchronized (mStagedSessions) { mStagedSessions.append(sessionInfo.sessionId, sessionInfo); @@ -497,8 +529,8 @@ public class StagingManager { } void abortCommittedSession(@NonNull PackageInstallerSession session) { - if (session.isStagedSessionApplied()) { - Slog.w(TAG, "Cannot abort applied session!"); + if (session.isStagedSessionApplied() || session.isStagedSessionFailed()) { + Slog.w(TAG, "Cannot abort already finalized session : " + session.sessionId); return; } abortSession(session); @@ -618,4 +650,12 @@ public class StagingManager { } } } + + static final class AlreadyInProgressStagedSessionException extends Exception { + + AlreadyInProgressStagedSessionException(int sessionId) { + super("There is already in-progress committed staged session " + + sessionId); + } + } } 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 c16de5b01948..3999edd5042b 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -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; @@ -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/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/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 7df52b2ae06a..4626840e6263 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -117,6 +117,7 @@ import android.util.ArraySet; import android.util.AtomicFile; import androidx.annotation.Nullable; +import androidx.test.InstrumentationRegistry; import com.android.internal.R; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; @@ -311,6 +312,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Before public void setUp() throws Exception { + InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity( + "android.permission.WRITE_DEVICE_CONFIG", "android.permission.READ_DEVICE_CONFIG"); + MockitoAnnotations.initMocks(this); LocalServices.removeServiceForTest(UriGrantsManagerInternal.class); @@ -392,6 +396,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void tearDown() throws Exception { mFile.delete(); clearDeviceConfig(); + InstrumentationRegistry.getInstrumentation() + .getUiAutomation().dropShellPermissionIdentity(); } public void waitForIdle() { 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/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java index 83c0af92a6ee..c072d4e28e81 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java @@ -59,7 +59,7 @@ public class AppChangeTransitionTests extends WindowTestsBase { public void setUpOnDisplay(DisplayContent dc) { mStack = createTaskStackOnDisplay(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, dc); mTask = createTaskInStack(mStack, 0 /* userId */); - mToken = WindowTestUtils.createTestAppWindowToken(dc); + mToken = WindowTestUtils.createTestAppWindowToken(dc, false /* skipOnParentChanged */); mTask.addChild(mToken, 0); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java index db04f1159150..a98a6046890d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java @@ -60,7 +60,7 @@ public class AppWindowTokenAnimationTests extends WindowTestsBase { MockitoAnnotations.initMocks(this); mToken = createTestAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN, - ACTIVITY_TYPE_STANDARD); + ACTIVITY_TYPE_STANDARD, false /* skipOnParentChanged */); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java index 70c8c937c481..68b40b92b9cc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java @@ -81,7 +81,8 @@ public class AppWindowTokenTests extends WindowTestsBase { public void setUp() throws Exception { mStack = createTaskStackOnDisplay(mDisplayContent); mTask = createTaskInStack(mStack, 0 /* userId */); - mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent); + mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent, + false /* skipOnParentChanged */); mTask.addChild(mToken, 0); } @@ -218,6 +219,9 @@ public class AppWindowTokenTests extends WindowTestsBase { @Test public void testSizeCompatBounds() { + // The real surface transaction is unnecessary. + mToken.setSkipPrepareSurfaces(true); + final Rect fixedBounds = mToken.getRequestedOverrideConfiguration().windowConfiguration .getBounds(); fixedBounds.set(0, 0, 1200, 1600); 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/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java index a7a785d14d6a..0dec8ee7776f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java @@ -56,15 +56,24 @@ class WindowTestUtils { static TestAppWindowToken createTestAppWindowToken(DisplayContent dc) { synchronized (dc.mWmService.mGlobalLock) { - return new TestAppWindowToken(dc); + return new TestAppWindowToken(dc, true /* skipOnParentChanged */); + } + } + + static TestAppWindowToken createTestAppWindowToken(DisplayContent dc, + boolean skipOnParentChanged) { + synchronized (dc.mWmService.mGlobalLock) { + return new TestAppWindowToken(dc, skipOnParentChanged); } } /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */ static class TestAppWindowToken extends AppWindowToken { boolean mOnTop = false; + private boolean mSkipPrepareSurfaces; + boolean mSkipOnParentChanged = true; - private TestAppWindowToken(DisplayContent dc) { + private TestAppWindowToken(DisplayContent dc, boolean skipOnParentChanged) { super(dc.mWmService, new IApplicationToken.Stub() { @Override public String getName() { @@ -72,6 +81,7 @@ class WindowTestUtils { } }, new ComponentName("", ""), false, dc, true /* fillsParent */); mTargetSdk = Build.VERSION_CODES.CUR_DEVELOPMENT; + mSkipOnParentChanged = skipOnParentChanged; mActivityRecord = mock(ActivityRecord.class); mActivityRecord.app = mock(WindowProcessController.class); } @@ -93,10 +103,44 @@ class WindowTestUtils { } @Override + void onParentChanged() { + if (!mSkipOnParentChanged) { + super.onParentChanged(); + } else { + updateConfigurationFromParent(this); + } + } + + @Override boolean isOnTop() { return mOnTop; } + @Override + void prepareSurfaces() { + if (!mSkipPrepareSurfaces) { + super.prepareSurfaces(); + } + } + + void setSkipPrepareSurfaces(boolean ignore) { + mSkipPrepareSurfaces = ignore; + } + } + + /** + * Used when we don't want to perform surface related operation in + * {@link WindowContainer#onParentChanged} or the overridden method, but the configuration + * still needs to propagate from parent. + * + * @see ConfigurationContainer#onParentChanged + */ + static void updateConfigurationFromParent(WindowContainer container) { + final WindowContainer parent = container.getParent(); + if (parent != null) { + container.onConfigurationChanged(parent.getConfiguration()); + container.onMergedOverrideConfigurationChanged(); + } } static TestWindowToken createTestWindowToken(int type, DisplayContent dc) { @@ -202,5 +246,10 @@ class WindowTestUtils { mHasSurface = hadSurface; } + + @Override + void onParentChanged() { + updateConfigurationFromParent(this); + } } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index fb698d92db20..032eba17a6b5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -269,10 +269,16 @@ class WindowTestsBase { WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int windowingMode, int activityType) { + return createTestAppWindowToken(dc, windowingMode, activityType, + false /*skipOnParentChanged */); + } + + WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int + windowingMode, int activityType, boolean skipOnParentChanged) { final TaskStack stack = createTaskStackOnDisplay(windowingMode, activityType, dc); final Task task = createTaskInStack(stack, 0 /* userId */); final WindowTestUtils.TestAppWindowToken appWindowToken = - WindowTestUtils.createTestAppWindowToken(dc); + WindowTestUtils.createTestAppWindowToken(dc, skipOnParentChanged); task.addChild(appWindowToken, 0); return appWindowToken; } diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java index 7d7c398554dd..2fc6efa3313c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java @@ -43,6 +43,7 @@ import android.platform.test.annotations.Presubmit; import android.view.SurfaceControl; import android.view.SurfaceSession; +import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.After; @@ -211,6 +212,7 @@ public class ZOrderingTests extends WindowTestsBase { return createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, name); } + @FlakyTest(bugId = 124088319) @Test public void testAssignWindowLayers_ForImeWithNoTarget() { mDisplayContent.mInputMethodTarget = null; @@ -228,6 +230,7 @@ public class ZOrderingTests extends WindowTestsBase { assertWindowHigher(mImeDialogWindow, mImeWindow); } + @FlakyTest(bugId = 124088319) @Test public void testAssignWindowLayers_ForImeWithAppTarget() { final WindowState imeAppTarget = createWindow("imeAppTarget"); @@ -247,6 +250,7 @@ public class ZOrderingTests extends WindowTestsBase { assertWindowHigher(mImeDialogWindow, mImeWindow); } + @FlakyTest(bugId = 124088319) @Test public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() { final WindowState imeAppTarget = createWindow("imeAppTarget"); @@ -273,6 +277,7 @@ public class ZOrderingTests extends WindowTestsBase { assertWindowHigher(mImeDialogWindow, mImeWindow); } + @FlakyTest(bugId = 124088319) @Test public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() { final WindowState appBelowImeTarget = createWindow("appBelowImeTarget"); @@ -296,6 +301,7 @@ public class ZOrderingTests extends WindowTestsBase { assertWindowHigher(mImeDialogWindow, mImeWindow); } + @FlakyTest(bugId = 124088319) @Test public void testAssignWindowLayers_ForImeNonAppImeTarget() { final WindowState imeSystemOverlayTarget = createWindow(null, TYPE_SYSTEM_OVERLAY, @@ -323,6 +329,7 @@ public class ZOrderingTests extends WindowTestsBase { assertWindowHigher(mImeDialogWindow, mImeWindow); } + @FlakyTest(bugId = 124088319) @Test public void testAssignWindowLayers_ForStatusBarImeTarget() { mDisplayContent.mInputMethodTarget = mStatusBarWindow; @@ -337,6 +344,7 @@ public class ZOrderingTests extends WindowTestsBase { assertWindowHigher(mImeDialogWindow, mImeWindow); } + @FlakyTest(bugId = 124088319) @Test public void testStackLayers() { final WindowState anyWindow1 = createWindow("anyWindow"); @@ -424,6 +432,7 @@ public class ZOrderingTests extends WindowTestsBase { } } + @FlakyTest(bugId = 124088319) @Test public void testDockedDividerPosition() { final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED, 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()); } } |