Merge "Add new BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS binding flag and the mechanism to use it"
diff --git a/Android.bp b/Android.bp
index 4e7aa5f..e8f3561 100644
--- a/Android.bp
+++ b/Android.bp
@@ -636,7 +636,7 @@
"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 135a5b4..f0b491a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6509,9 +6509,9 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 28104d5..921a6bf 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1836,10 +1836,8 @@
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 @@
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.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 @@
}
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 46e061b..2913743 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -11,8 +11,10 @@
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 @@
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 @@
}
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 @@
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.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 @@
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 @@
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 3666d6a..469c964 100644
--- a/cmds/bootanimation/bootanim.rc
+++ b/cmds/bootanimation/bootanim.rc
@@ -2,9 +2,6 @@
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 7298da6..ce07d6d 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -219,6 +219,7 @@
"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 4856f77..69372cd 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -5759,7 +5759,7 @@
optional string tzdb_version = 1;
}
-/*
+/**
* Logs the GPU stats global health information.
*
* Logged from:
@@ -5791,22 +5791,34 @@
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 8445803..130bd85 100644
--- a/cmds/statsd/src/external/GpuStatsPuller.cpp
+++ b/cmds/statsd/src/external/GpuStatsPuller.cpp
@@ -70,6 +70,30 @@
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 @@
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 @@
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 4c7a4d6..2da199c 100644
--- a/cmds/statsd/src/external/GpuStatsPuller.h
+++ b/cmds/statsd/src/external/GpuStatsPuller.h
@@ -31,6 +31,12 @@
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 924704b..4f87272 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -244,6 +244,9 @@
// 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 0000000..8625487
--- /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 56bf8fa..694f6b0 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -139,6 +139,8 @@
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 @@
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 da45054..08cad04 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 @@
* @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 2d9fbf9..35658fb 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -1091,6 +1091,16 @@
*/
@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 @@
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 9605382..f66de8d 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_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 @@
*
* <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 @@
*
* <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 @@
* @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 @@
* 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 5a7124e..4771fd8 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -19,6 +19,7 @@
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 @@
* 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 @@
* 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 @@
* @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 @@
* @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 @@
* @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 @@
* {@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 @@
* 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 @@
* {@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 @@
* 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 @@
* {@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 @@
* 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 @@
* {@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 @@
* 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 @@
* @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 @@
* @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 @@
*
* @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 @@
* @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 @@
*
* @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 @@
* 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 @@
* @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 @@
* @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 @@
* 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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* 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 d82899e..f8ccb13 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2187,7 +2187,7 @@
* {@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 @@
* @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 @@
*
* @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 @@
* @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 62b24e9..83c1d61 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -60,7 +60,7 @@
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 cee6b87..e47ec22 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -747,7 +747,7 @@
*/
@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 @@
* 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 @@
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 ab8c196..b8a741a 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -19,6 +19,7 @@
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 @@
* 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 @@
* 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 f718415..fa2c9f8 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 @@
* 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 @@
* 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 91ac9e0..5c99319 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4098,7 +4098,7 @@
* @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 0715572..a2d3f6a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2441,7 +2441,7 @@
*
* @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 f14b228..33b9c72 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -24,6 +24,7 @@
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 @@
* @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 @@
*
* {@hide}
*/
- @SystemApi
+ @SystemApi @TestApi
@RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
public void setStaged() {
this.isStaged = true;
@@ -1602,7 +1603,7 @@
*
* {@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 cfd99ab..f781758 100644
--- a/core/java/android/content/pm/PackageList.java
+++ b/core/java/android/content/pm/PackageList.java
@@ -45,16 +45,16 @@
}
@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 d1ebcfd..9037759 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1389,6 +1389,14 @@
*/
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 2c1842c..0ef7656 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -78,9 +78,9 @@
/** 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 89c0690..ec42134 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1618,7 +1618,7 @@
}
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 @@
}
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 @@
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 @@
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 @@
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 @@
} 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);
- }
+ sa = res.obtainAttributes(parser,
+ com.android.internal.R.styleable.AndroidManifestUsesSdk);
- @Override public int getMinSdkVersion() {
- return getAttributeAsInt(
- R.styleable.AndroidManifestUsesSdk_minSdkVersion);
- }
+ int minVers = 1;
+ String minCode = null;
+ int targetVers = 0;
+ String targetCode = null;
- @Override public String getTargetSdkVersionCode() {
- return getAttributeAsString(
- R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
- }
+ 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;
+ }
+ }
- @Override public int getTargetSdkVersion() {
- return getAttributeAsInt(
- R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
- }
+ 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;
+ }
- 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;
- }
+ sa.recycle();
- 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) {
+ 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 @@
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 @@
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 b0785b1..2014751 100644
--- a/core/java/android/content/rollback/PackageRollbackInfo.java
+++ b/core/java/android/content/rollback/PackageRollbackInfo.java
@@ -18,6 +18,7 @@
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 @@
*
* @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 a363718..c09cfd5 100644
--- a/core/java/android/content/rollback/RollbackInfo.java
+++ b/core/java/android/content/rollback/RollbackInfo.java
@@ -18,6 +18,7 @@
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 @@
*
* @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 4e8c254..9038b03 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 @@
* @see PackageInstaller.SessionParams#setEnableRollback()
* @hide
*/
-@SystemApi
+@SystemApi @TestApi
@SystemService(Context.ROLLBACK_SERVICE)
public final class RollbackManager {
private final String mCallerPackageName;
@@ -112,6 +116,20 @@
"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 @@
*
* @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 @@
* @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 23401432..d5d25c5 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -680,7 +680,7 @@
}
/**
- * 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 3f8410f..2a357ff 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2805,7 +2805,7 @@
* {@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 @@
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 60f4f06..ff551d4 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -120,10 +120,6 @@
mUsapPoolSecondarySocketAddress =
new LocalSocketAddress(Zygote.USAP_POOL_SECONDARY_SOCKET_NAME,
LocalSocketAddress.Namespace.RESERVED);
-
- if (fetchUsapPoolEnabledProp()) {
- informZygotesOfUsapPoolStatus();
- }
}
public ZygoteProcess(LocalSocketAddress primarySocketAddress,
@@ -179,14 +175,18 @@
* 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 @@
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 @@
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 @@
return;
}
- try {
- attemptConnectionToSecondaryZygote();
-
+ if (mZygoteSecondarySocketAddress != null) {
try {
- secondaryZygoteState.mZygoteOutputWriter.write(command);
- secondaryZygoteState.mZygoteOutputWriter.flush();
+ attemptConnectionToSecondaryZygote();
- // Wait for the secondary Zygote to finish its work.
- secondaryZygoteState.mZygoteInputStream.readInt();
+ 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 e4593e5..7a0bb91 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -31,6 +31,7 @@
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 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 @@
}
/**
- * 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 @@
*
* @hide
*/
- @SystemApi
+ @SystemApi @TestApi
public interface Rollback {
/**
@@ -406,6 +403,7 @@
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 @@
@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 @@
@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 @@
@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 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 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 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 e931826..2814474 100644
--- a/core/java/android/provider/FontsContract.java
+++ b/core/java/android/provider/FontsContract.java
@@ -34,7 +34,6 @@
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 @@
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 e8f91ca..a750c79 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5590,6 +5590,15 @@
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 @@
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 c928da1..32982f9 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -674,7 +674,8 @@
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 @@
* @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 e4200ac..6f0628a 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.
+ * Does the native Hyphenator initialization.
*
- * 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.
- *
- * <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 2d5f3bf..fb6dc22 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -437,7 +437,8 @@
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 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 @@
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 @@
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 defe2ce..9fefc83 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -779,7 +779,8 @@
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 @@
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.
- *
- * You can extract start hyphen edit and end hyphen edit by using
- * {@link Hyphenator#unpackStartHyphenEdit(int)} and
- * {@link Hyphenator#unpackEndHyphenEdit(int)}.
+ * Returns the start hyphen edit value for this line.
*
* @param lineNumber a line number
- * @return A packed hyphen edit value.
+ * @return A start hyphen edit value.
* @hide
*/
@Override
- public int getHyphen(int lineNumber) {
- return mLines[mColumns * lineNumber + HYPHEN] & HYPHEN_MASK;
+ 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 An end hyphen edit value.
+ * @hide
+ */
+ @Override
+ public @Paint.EndHyphenEdit int getEndHyphenEdit(int lineNumber) {
+ return unpackEndHyphenEdit(mLines[mColumns * lineNumber + HYPHEN] & HYPHEN_MASK);
}
/**
@@ -1395,6 +1418,9 @@
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 915a18e..8665106 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -1012,19 +1012,14 @@
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 @@
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 @@
// 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 @@
}
}
// 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 @@
&& 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 13ac9ff..98f58be 100644
--- a/core/java/android/text/style/ImageSpan.java
+++ b/core/java/android/text/style/ImageSpan.java
@@ -46,10 +46,10 @@
* <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 e2af6f5..436cb4f 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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 c4f815b..aee1d6a 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -51,7 +51,6 @@
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 e4de704..cf49803 100644
--- a/core/java/android/util/LongSparseArray.java
+++ b/core/java/android/util/LongSparseArray.java
@@ -21,6 +21,9 @@
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 @@
* 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 @@
* 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 @@
*/
@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 @@
* 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 f167f00..8dcdb40 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 @@
* 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 @@
* 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 67dfb02..89ea2d3 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 @@
* 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 @@
* 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 @@
*/
@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 @@
* <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 03fa1c9..d4c4095 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 @@
* 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 @@
* 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 @@
* 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 c68dc4e..9e6bad1 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 @@
* 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 @@
* 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 @@
* 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 37a9202..81db2b7 100644
--- a/core/java/android/util/SparseLongArray.java
+++ b/core/java/android/util/SparseLongArray.java
@@ -182,10 +182,6 @@
* 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 @@
* 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 998ad2a..cd075bf 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -63,6 +63,7 @@
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 @@
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 @@
}
/**
+ * 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 3d3d941..f5657df 100644
--- a/core/java/android/webkit/WebViewDelegate.java
+++ b/core/java/android/webkit/WebViewDelegate.java
@@ -209,19 +209,17 @@
* 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 @@
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 6d88530..528a6a8 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -448,8 +448,7 @@
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 25e5dd3..16b903d 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -702,7 +702,7 @@
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 2798296..03e7e10 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -887,9 +887,9 @@
*
* @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 @@
*
* @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 @@
*
* @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 @@
*
* @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 @@
* 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 @@
* <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 8ee31e2..37bed65 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -35,6 +35,9 @@
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 @@
* 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 @@
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 91928b5..79cf4c42 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -236,7 +236,6 @@
mServiceConnections.remove(sri.connection);
if (mServiceConnections.isEmpty()) {
sendVoiceChoicesIfNeeded();
- mChooserListAdapter.setShowServiceTargets(true);
}
break;
@@ -250,7 +249,6 @@
unbindRemainingServices();
sendVoiceChoicesIfNeeded();
mChooserListAdapter.completeServiceTargetLoading();
- mChooserListAdapter.setShowServiceTargets(true);
break;
case SHORTCUT_MANAGER_SHARE_TARGET_RESULT:
@@ -265,7 +263,6 @@
case SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED:
sendVoiceChoicesIfNeeded();
- mChooserListAdapter.setShowServiceTargets(true);
break;
default:
@@ -446,6 +443,11 @@
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 @@
}
}
+ 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 @@
super(context, payloadIntents, null, rList, launchedFromUid, filterLastUsed,
resolverListController);
- mServiceTargets = createPlaceHolders();
+ createPlaceHolders();
if (initialIntents != null) {
final PackageManager pm = getPackageManager();
@@ -1840,12 +1850,11 @@
}
}
- 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 int getCallerTargetCount() {
- return mCallerTargets.size();
+ return Math.min(mCallerTargets.size(), MAX_SUGGESTED_APP_TARGETS);
}
/**
@@ -1940,18 +1949,18 @@
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 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 @@
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 @@
}
/**
- * 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 @@
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 @@
});
}
+ 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 @@
@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();
}
- RowViewHolder createViewHolder(ViewGroup parent) {
- final ViewGroup row = (ViewGroup) mLayoutInflater.inflate(R.layout.chooser_row,
- parent, false);
- final RowViewHolder holder = new RowViewHolder(row, mColumnCount);
- final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ @Override
+ public int getItemViewType(int position) {
+ final int start = getFirstRowPosition(position);
+ final int startType = mChooserListAdapter.getPositionTargetType(start);
- for (int i = 0; i < mColumnCount; i++) {
- final View v = mChooserListAdapter.createView(row);
+ if (startType == ChooserListAdapter.TARGET_SERVICE) {
+ return VIEW_TYPE_DIRECT_SHARE;
+ }
+
+ return VIEW_TYPE_NORMAL;
+ }
+
+ @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 < 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 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 @@
} 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 @@
}
}
- 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 @@
}
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 @@
}
}
- 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 callerCount = mChooserListAdapter.getCallerTargetCount();
- final int callerRows = (int) Math.ceil((float) callerCount / mColumnCount);
-
- if (row < callerRows) {
- return row * mColumnCount;
+ 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 serviceCount = mChooserListAdapter.getServiceTargetCount();
- final int serviceRows = (int) Math.ceil((float) serviceCount / mColumnCount);
-
+ final int callerCount = mChooserListAdapter.getCallerTargetCount();
+ final int callerRows = (int) Math.ceil((float) callerCount / getMaxTargetsPerRow());
if (row < callerRows + serviceRows) {
- return callerCount + (row - callerRows) * mColumnCount;
+ return serviceCount + (row - serviceRows) * getMaxTargetsPerRow();
}
return callerCount + serviceCount
- + (row - callerRows - serviceRows) * mColumnCount;
+ + (row - callerRows - serviceRows) * getMaxTargetsPerRow();
+ }
+
+ public void handleScroll(View v, int y, int oldy) {
+ if (mDirectShareViewHolder != null) {
+ mDirectShareViewHolder.handleScroll(mAdapterView, y, oldy, getMaxTargetsPerRow());
+ }
}
}
- static class RowViewHolder {
- public final View[] cells;
- public final boolean [] cellVisibility;
- public final ViewGroup row;
- int measuredRowHeight;
- int[] itemIndices;
+ abstract class RowViewHolder {
+ protected int mMeasuredRowHeight;
+ private int[] mItemIndices;
+ protected final View[] mCells;
+ private final boolean[] mCellVisibility;
+ private final int mColumnCount;
- public RowViewHolder(ViewGroup row, int cellCount) {
- this.row = row;
- this.cells = new View[cellCount];
- this.cellVisibility = new boolean[cellCount];
- this.itemIndices = new int[cellCount];
+ 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);
- row.measure(spec, spec);
- measuredRowHeight = row.getMeasuredHeight();
+ 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 mRow;
+ }
+ }
+
+ 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;
+
+ 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);
+ 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 @@
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 011cc04..c60a96b 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -99,7 +99,7 @@
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 2442d0b..8b25e2d 100644
--- a/core/java/com/android/internal/os/KernelWakelockReader.java
+++ b/core/java/com/android/internal/os/KernelWakelockReader.java
@@ -66,7 +66,7 @@
*/
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 @@
}
}
- 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 6595317..4aff912 100644
--- a/core/java/com/android/internal/os/ZygoteServer.java
+++ b/core/java/com/android/internal/os/ZygoteServer.java
@@ -277,17 +277,31 @@
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 @@
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 42fb1f5..bb7423a 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.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 @@
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 @@
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 @@
// 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 @@
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 ee8637d8..9722fcb 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -502,6 +502,7 @@
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 85f1159..cd7346e 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -923,14 +923,24 @@
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 @@
{"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 89d908b..4a6c72b 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -1164,6 +1164,25 @@
}
}
+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 @@
{"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 21717d8..a82326f 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 @@
VALID = 1;
INVALID = 2;
PORTAL = 3;
+ PARTIAL = 4;
}
enum ApBand {
@@ -86,4 +87,4 @@
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 67bff6b..ea300aa 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 0000000..d7e36ee
--- /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 bfb6d24..dce144a 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 a69655a..bf7c8f2 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 69def5b..503bbce 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 43f8db1..7322a54 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -655,6 +655,7 @@
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 b1c896e..0ebf03f 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.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 @@
@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 585360f..0617caf 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -209,7 +209,8 @@
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 9eeb43b..452f7c9 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -364,19 +364,79 @@
*/
private static final int CURSOR_OPT_MAX_VALUE = CURSOR_AT;
- /**
- * Mask for hyphen edits that happen at the end of a line. Keep in sync with the definition in
- * Minikin's Hyphenator.h.
- * @hide
- */
- public static final int HYPHENEDIT_MASK_END_OF_LINE = 0x07;
+ /** @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 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 no modification for hyphenation.
*/
- public static final int HYPHENEDIT_MASK_START_OF_LINE = 0x03 << 3;
+ 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;
/**
* The Style specifies if the primitive being drawn is filled, stroked, or
@@ -1873,54 +1933,80 @@
}
/**
- * Get the current value of packed hyphen edit.
+ * Get the current value of start hyphen 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)}.
+ * The default value is 0 which is equivalent to {@link #START_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}.
- *
- * @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 @StartHyphenEdit int getStartHyphenEdit() {
+ return nGetStartHyphenEdit(mNativePaint);
}
/**
- * Set a packed hyphen edit on the paint.
+ * Get the current value of end hyphen edit.
*
- * 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)
+ * The default value is 0 which is equivalent to {@link #END_HYPHEN_EDIT_NO_EDIT}.
+ *
+ * @return the current starting hyphen edit value
+ * @see #setStartHyphenEdit(int)
+ */
+ public @EndHyphenEdit int getEndHyphenEdit() {
+ return nGetEndHyphenEdit(mNativePaint);
+ }
+
+ /**
+ * Set a start hyphen edit on the paint.
+ *
+ * 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 @@
@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 void nSetHyphenEdit(long paintPtr, int hyphen);
+ private static native int nGetEndHyphenEdit(long paintPtr);
+ @CriticalNative
+ private static native void nSetStartHyphenEdit(long paintPtr, int hyphen);
+ @CriticalNative
+ 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 9518714..86f658b 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -33,12 +33,12 @@
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.util.Preconditions;
import dalvik.annotation.optimization.CriticalNative;
-import dalvik.system.VMRuntime;
import libcore.util.NativeAllocationRegistry;
@@ -262,18 +261,29 @@
? 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 f715f43..f92802f 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -354,6 +354,10 @@
/**
* 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 046bbcf..9cabf1c 100644
--- a/graphics/java/android/graphics/text/LineBreaker.java
+++ b/graphics/java/android/graphics/text/LineBreaker.java
@@ -342,8 +342,12 @@
*/
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 @@
}
/**
- * 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 733f8e4..5f6b53a 100644
--- a/libs/hwui/hwui/MinikinUtils.cpp
+++ b/libs/hwui/hwui/MinikinUtils.cpp
@@ -58,9 +58,8 @@
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 @@
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 601b3c2..9b2fa9d 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 @@
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));
+ }
- uint32_t getHyphenEdit() const { return mHyphenEdit; }
+ void setEndHyphenEdit(uint32_t endHyphen) {
+ mHyphenEdit = minikin::packHyphenEdit(
+ minikin::startHyphenEdit(mHyphenEdit),
+ static_cast<minikin::EndHyphenEdit>(endHyphen));
+ }
+
+ 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 ed74333..673b411 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -150,7 +150,7 @@
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 @@
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 @@
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 09ac9ca..d63de09 100644
--- a/media/apex/java/android/media/MediaSession2.java
+++ b/media/apex/java/android/media/MediaSession2.java
@@ -511,7 +511,8 @@
}
/**
- * 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 dc970ae..d7cb978 100644
--- a/media/apex/java/android/media/Session2Token.java
+++ b/media/apex/java/android/media/Session2Token.java
@@ -216,10 +216,11 @@
/**
* @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 7783a4d..c11f446 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3308,6 +3308,7 @@
/**
* @hide
+ * Unregisters an {@link AudioPolicy} asynchronously.
* @param policy the non-null {@link AudioPolicy} to unregister.
*/
@SystemApi
@@ -3329,6 +3330,27 @@
}
}
+ /**
+ * @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 0285667..95d89bb 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -199,6 +199,8 @@
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 9258b85..f5abb24 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.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.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 @@
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 @@
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 @@
* 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 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 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 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 @@
/**
* 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 @@
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<>();
- public EventHandler(@NonNull MediaDrm md, @NonNull Looper looper) {
- super(looper);
- mMediaDrm = md;
+ // 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);
}
+ }
- @Override
- public void handleMessage(@NonNull Message msg) {
- if (mMediaDrm.mNativeContext == 0) {
- Log.w(TAG, "MediaDrm went away with unhandled events");
- return;
+ // 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);
+ }
+
+ 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;
}
- 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;
-
- 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;
-
- 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;
-
- 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;
-
- default:
- Log.e(TAG, "Unknown message type " + msg.what);
- return;
+ byte[] data = args.parcel.createByteArray();
+ if (data.length == 0) {
+ data = null;
}
+
+ Log.i(TAG, "Drm event (" + args.arg1 + "," + args.arg2 + ")");
+ listener.onEvent(this, sessionId, args.arg1, args.arg2, data);
+ };
+ }
+
+ 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);
+
+ Log.i(TAG, "Drm key status changed");
+ listener.onKeyStatusChange(this, sessionId, keyStatusList, hasNewUsableKey);
+ }
+ };
+ }
+
+ private Consumer<ListenerArgs> createOnExpirationUpdateListener(
+ OnExpirationUpdateListener listener) {
+ return args -> {
+ byte[] sessionId = args.parcel.createByteArray();
+ if (sessionId.length > 0) {
+ long expirationTime = args.parcel.readLong();
+
+ 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 @@
}
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 5f65d58..978583e 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -43,8 +43,11 @@
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 @@
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 @@
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 @@
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 e85461f..cfcc294 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -55,8 +55,8 @@
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 5ee52ce..7334044 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -18,7 +18,6 @@
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 @@
/**
* @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 fde4f88..f530442 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -424,17 +424,33 @@
}
/**
- * 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 0c35204..3b278b4 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
@@ -20,9 +20,11 @@
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 StatusBarKeyguardViewManager createStatusBarKeyguardViewManager(Context context,
- ViewMediatorCallback viewMediatorCallback, LockPatternUtils lockPatternUtils) {
+ ViewMediatorCallback viewMediatorCallback, LockPatternUtils lockPatternUtils) {
return new CarStatusBarKeyguardViewManager(context, viewMediatorCallback, lockPatternUtils);
}
@@ -92,4 +94,12 @@
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 0000000..6d9c7ba
--- /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 bd0e0b8..8732524 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 @@
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 221e1d7..aee67e1 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 719417e..63ac8c7 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.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 @@
*/
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 @@
private long mInstalledSize;
private boolean mJustCancelledByUser;
- private PendingIntent mPiCancel;
- private PendingIntent mPiRebootToDynamicAndroid;
- private PendingIntent mPiUninstallAndReboot;
-
private InstallationAsyncTask mInstallTask;
@@ -155,6 +154,8 @@
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 @@
}
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 @@
}
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 @@
// 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 @@
}
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 d1ca109..e23f10f 100644
--- a/packages/NetworkStack/src/android/net/metrics/DataStallStatsUtils.java
+++ b/packages/NetworkStack/src/android/net/metrics/DataStallStatsUtils.java
@@ -48,6 +48,8 @@
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 4ed1154..f6cd971 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 @@
mMgr.addOnActiveSessionsChangedListener(mSessionsListener, null, mHandler);
mInit = true;
postUpdateSessions();
- mMgr.setRemoteVolumeController(mRvc);
+ mMgr.registerRemoteVolumeController(mRvc);
}
protected void postUpdateSessions() {
@@ -110,6 +110,7 @@
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 59fbb72..800c401 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 AccessPoint(Context context, WifiConfiguration config) {
mContext = context;
loadConfig(config);
+ updateKey();
}
/**
@@ -317,6 +318,7 @@
mContext = context;
mFqdn = config.getHomeSp().getFqdn();
mProviderFriendlyName = config.getHomeSp().getFriendlyName();
+ updateKey();
}
/**
@@ -355,7 +357,6 @@
security = getSecurity(config);
networkId = config.networkId;
mConfig = config;
- updateKey();
}
/** Updates {@link #mKey} and should only called upon object creation/initialization. */
@@ -363,6 +364,8 @@
// 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 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 7c367c7..9c8e3f4 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 @@
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 9425941..c2495b5 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -58,7 +58,6 @@
"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 5f4cf03..2b10ccb 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 @@
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 @@
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 bca3530..42600c1 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 @@
}
}
-
- @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 0000000..9b90729
--- /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 0000000..f3d8d3b9
--- /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 235d0fc..c51e71b 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 e028214..de853c7 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 a620a8e..d90d5e9 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 ca34c23..130be89 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 c83cb59..30c29dc 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 5086c99..72ab02c 100644
--- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
@@ -215,7 +215,7 @@
} 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 @@
@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 @@
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 @@
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 2bc4720..d063a0f 100644
--- a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
@@ -33,8 +33,8 @@
*/
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 @@
}
/**
- * 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 @@
onUpdateList();
}
- protected abstract void onUpdateList();
+ protected void onUpdateList() {
+ setSeparatedViewVisibility(mAdapter.hasSeparatedItems());
+ }
public void setRotationListener(RotationListener listener) {
mRotationListener = listener;
@@ -156,13 +156,13 @@
* 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 @@
* @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 b2f707f..bc3f48d 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.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.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 @@
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 @@
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 @@
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 b07f909..ce58895 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.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 @@
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 @@
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 @@
mHasLogoutButton = true;
}
} else if (GLOBAL_ACTION_KEY_EMERGENCY.equals(actionKey)) {
- if (mUseSeparatedList
+ if (shouldUseSeparatedView()
&& !mEmergencyAffordanceManager.needsEmergencyAffordance()) {
mItems.add(new EmergencyDialerAction());
}
@@ -407,8 +404,7 @@
}
})
: 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 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 @@
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 @@
}
@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 @@
}
@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 @@
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 @@
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 @@
});
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 @@
}
/**
- * 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 cda7669..058ea60 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 @@
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 @@
@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 @@
parent.addView(v);
}
}
+ updateSnapPosition();
}
@Override
@@ -115,6 +117,19 @@
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 @@
}
/**
- * 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 6c106df..048f801 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 @@
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 @@
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 b7e07f8..5e6f18e 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.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 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 @@
private final DataSaverController mDataSaverController;
private final HotspotAndDataSaverCallbacks mCallbacks = new HotspotAndDataSaverCallbacks();
- private final GlobalSetting mAirplaneMode;
private boolean mListening;
@Inject
@@ -55,12 +52,6 @@
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 @@
}
@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 @@
}
@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 @@
}
@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 @@
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 @@
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 409d60f..2d54970 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;
-public class NavBarTintController {
+/**
+ * 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 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);
}
- public void start() {
+ void onDraw() {
+ if (mUpdateOnNextDraw) {
+ mUpdateOnNextDraw = false;
+ requestUpdateSamplingListener();
+ }
+ }
+
+ 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();
}
- private void updateTint() {
- int[] navPos = new int[2];
- int[] butPos = new int[2];
+ @Override
+ public void onViewDetachedFromWindow(View view) {
+ // Defer calling updateSamplingListener the attach info has not yet been reset
+ requestUpdateSamplingListener();
+ }
+
+ @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);
-
- if (mNavigationBarView.getCurrentView() == null || viewIconRect.isEmpty()) {
- scheduleColorAdaption();
- return;
- }
- 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 (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();
- }
- scheduleColorAdaption();
}
- private void scheduleColorAdaption() {
- mColorAdaptionHandler.removeCallbacksAndMessages(null);
- if (!mRunning || !isEnabled(mNavigationBarView.getContext())) {
- return;
+ private void requestUpdateSamplingListener() {
+ mHandler.removeCallbacks(mUpdateSamplingListener);
+ mHandler.post(mUpdateSamplingListener);
+ }
+
+ private void updateSamplingListener() {
+ if (mSamplingListenerRegistered) {
+ mSamplingListenerRegistered = false;
+ CompositionSamplingListener.unregister(mSamplingListener);
}
- mColorAdaptionHandler.postDelayed(this::updateTint, COLOR_ADAPTION_TIMEOUT);
+ 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;
+ }
+ mSamplingListenerRegistered = true;
+ CompositionSamplingListener.register(mSamplingListener, DEFAULT_DISPLAY,
+ mNavigationBarView.getViewRootImpl().getSurfaceControl().getHandle(),
+ mSamplingBounds);
+ }
+ }
+
+ 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 */);
+ }
+ }
+
+ 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 b68c7c6..0978901 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 @@
}
} 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 b540fb4..a64ff0f 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 @@
if (enabled) {
mColorAdaptionController.start();
} else {
- mColorAdaptionController.end();
+ mColorAdaptionController.stop();
}
}
@@ -486,6 +486,12 @@
}
}
+ @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 @@
if (visible) {
mColorAdaptionController.start();
} else {
- mColorAdaptionController.end();
+ mColorAdaptionController.stop();
}
}
@@ -1244,7 +1250,7 @@
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
mColorAdaptionController.start();
} else {
- mColorAdaptionController.end();
+ mColorAdaptionController.stop();
}
}
@@ -1330,7 +1336,6 @@
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 @@
mGestureHelper.destroy();
}
mPrototypeController.unregister();
- mColorAdaptionController.stop();
setUpSwipeUpOnboarding(false);
for (int i = 0; i < mButtonDispatchers.size(); ++i) {
mButtonDispatchers.valueAt(i).onDestroy();
@@ -1454,6 +1458,7 @@
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 0461057..d1a2253 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.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 @@
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 @@
// 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 f79ad71..f4d6237 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_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.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 @@
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 @@
mSubscriptionListener = new SubListener();
}
mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);
+ mPhone.listen(mPhoneStateListener, LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
// broadcasts
IntentFilter filter = new IntentFilter();
@@ -525,6 +539,7 @@
@VisibleForTesting
void handleConfigurationChanged() {
+ updateMobileControllers();
for (int i = 0; i < mMobileSignalControllers.size(); i++) {
MobileSignalController controller = mMobileSignalControllers.valueAt(i);
controller.setConfiguration(mConfig);
@@ -539,13 +554,39 @@
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 1596ddb..6e740b8 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 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 @@
"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 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 @@
"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 4c16297..9192a25 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.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 @@
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 @@
}
}
+ 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 @@
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 @@
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 @@
});
}
}
+
+ @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 ffd8206..398b309 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.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 @@
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 @@
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 @@
updateRowsH(getActiveRow());
initRingerH();
initSettingsH();
+ initODICaptionsH();
}
protected ViewGroup getDialogView() {
@@ -478,6 +486,42 @@
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 @@
mDialog.show();
Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked());
mController.notifyVisible(true);
+ mController.getCaptionsComponentState();
}
protected void rescheduleTimeoutH() {
@@ -1151,6 +1196,11 @@
}
}
+
+ @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 7797cb3..7bd4158 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 @@
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.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 @@
@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 0000000..6b83fed
--- /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 9673a84..bc42863 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -260,6 +260,18 @@
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 @@
// 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 9f049cf..0d17f22 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -1957,7 +1957,7 @@
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 @@
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 @@
}
// 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 @@
// 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 @@
// 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 4293157..85c82bc 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.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 @@
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 1bf4e3a..6018f00 100644
--- a/services/core/java/com/android/server/BluetoothService.java
+++ b/services/core/java/com/android/server/BluetoothService.java
@@ -18,15 +18,26 @@
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 @@
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 70733ef..ea23081 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 @@
// 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 1e406c0..676cc33 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 @@
}
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 ba7288e..9c26526 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 @@
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 @@
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 @@
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 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 41a3c98..cb0bbd9 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 @@
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 91d19de..100113c 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 @@
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 d84a4d2..123564e 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.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 @@
// 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 @@
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 @@
//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 @@
}
}
- 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 @@
| 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 b5ec603..717e3da 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 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 a94ed60..ac906bb 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 @@
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 @@
": 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 @@
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 b86328b..94f289f 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.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 @@
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 @@
}
/**
- * 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 @@
*/
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 @@
}
}
- 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 @@
}
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 @@
}
@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 @@
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 46ce4bf..d9ab132 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 @@
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 @@
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 @@
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 @@
requestedImportance = IMPORTANCE_HIGH;
}
importance = requestedImportance;
+ mInitialImportanceExplanationCode =
+ MetricsEvent.IMPORTANCE_EXPLANATION_APP_PRE_CHANNELS;
}
stats.naturalImportance = importance;
@@ -540,7 +550,7 @@
+ 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 @@
}
/**
- * 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 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 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 3c1ee3e..cd0cbd6 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -10,76 +10,48 @@
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 45b3b5b..2de50e2 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 @@
}
}
+ /** {@hide} */
+ boolean isCommitted() {
+ synchronized (mLock) {
+ return mCommitted;
+ }
+ }
+
@GuardedBy("mLock")
private void assertPreparedAndNotSealedLocked(String cookie) {
assertPreparedAndNotCommittedOrDestroyedLocked(cookie);
@@ -1064,7 +1071,13 @@
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 4dcab5e..6f006e7 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 @@
}
if (allNewUsers && !update) {
- notifyPackageAdded(packageName);
+ notifyPackageAdded(packageName, res.uid);
}
// Log current value of "unknown sources" setting
@@ -12317,7 +12317,7 @@
}
@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 @@
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 @@
};
@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 @@
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 @@
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 @@
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 @@
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 4ee6eaf..088146d 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 @@
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 @@
}
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 @@
}
}
}
+
+ 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 3b805d51..f56231f 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 @@
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 @@
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 f7d8e0e..897b885 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 @@
@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 @@
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 871f9f8..952399b 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 @@
* @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 86dc66d..d364a37 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 @@
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 300cd17..db7613a 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 @@
}
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 @@
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 c16de5b..3999edd 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_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 @@
"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 @@
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 111fb74..4cfd098 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 @@
}
@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 1f86171..958b23f 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 @@
/** 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 @@
/** 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 @@
/** 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 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 @@
@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 @@
@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 @@
@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 @@
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 @@
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 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 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 @@
@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 @@
/** 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 @@
@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 @@
*/
@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 @@
@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 @@
@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 @@
}
}
- /** 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 @@
}
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 7df52b2..4626840 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.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 @@
@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 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 9f11472..e375195 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.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 @@
(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 @@
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 @@
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 83c0af9..c072d4e 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 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 db04f11..a98a604 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 @@
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 70c8c93..68b40b9 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 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 @@
@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 aeda473..e4d3770 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 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 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 @@
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 a7a785d..0dec8ee 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 @@
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 @@
}
}, 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 @@
}
@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 @@
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 fb698d9..032eba1 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 @@
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 7d7c398..2fc6efa 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.view.SurfaceControl;
import android.view.SurfaceSession;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.After;
@@ -211,6 +212,7 @@
return createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, name);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeWithNoTarget() {
mDisplayContent.mInputMethodTarget = null;
@@ -228,6 +230,7 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeWithAppTarget() {
final WindowState imeAppTarget = createWindow("imeAppTarget");
@@ -247,6 +250,7 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() {
final WindowState imeAppTarget = createWindow("imeAppTarget");
@@ -273,6 +277,7 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() {
final WindowState appBelowImeTarget = createWindow("appBelowImeTarget");
@@ -296,6 +301,7 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeNonAppImeTarget() {
final WindowState imeSystemOverlayTarget = createWindow(null, TYPE_SYSTEM_OVERLAY,
@@ -323,6 +329,7 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForStatusBarImeTarget() {
mDisplayContent.mInputMethodTarget = mStatusBarWindow;
@@ -337,6 +344,7 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testStackLayers() {
final WindowState anyWindow1 = createWindow("anyWindow");
@@ -424,6 +432,7 @@
}
}
+ @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 f3d6387..6861ad1 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 @@
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 @@
* 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 @@
"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 27fdbcb..1ec680f 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 @@
@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 @@
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 @@
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 @@
}
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
similarity index 82%
rename from telephony/java/android/telephony/DebugEventReporter.java
rename to telephony/java/android/telephony/AnomalyReporter.java
index 14b7dd6..9753d8b 100644
--- a/telephony/java/android/telephony/DebugEventReporter.java
+++ b/telephony/java/android/telephony/AnomalyReporter.java
@@ -29,7 +29,6 @@
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 @@
/**
* 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 @@
*
* @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 @@
*/
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 @@
* 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 @@
// 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 @@
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 @@
// 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 d79a168..524d080 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2520,6 +2520,18 @@
"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 @@
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 6c835dc..e5aadad 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -86,7 +86,7 @@
}
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 16dafd6..0c6bc48 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1383,41 +1383,42 @@
* 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
* {@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 @@
* 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 0b1d1fb..d0b52c9 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1641,6 +1641,7 @@
*
* @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 @@
*
* @param apnName the name to set for the APN
*/
+ @NonNull
public Builder setApnName(String apnName) {
this.mApnName = apnName;
return this;
@@ -1681,6 +1683,7 @@
*
* @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 @@
*
* @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 @@
*
* @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 @@
*
* @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 @@
*
* @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 @@
*
* @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 @@
* @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 @@
*
* @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 @@
*
* @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 @@
*
* @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 @@
*
* @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 @@
*
* @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 @@
*
* @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 @@
*
* @param networkTypeBitmask the Radio Technology (Network Type) info
*/
+ @NonNull
public Builder setNetworkTypeBitmask(int networkTypeBitmask) {
this.mNetworkTypeBitmask = networkTypeBitmask;
return this;
@@ -1855,6 +1871,7 @@
*
* @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 1fb8798..bcadc80 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEventDescriptor.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEventDescriptor.java
@@ -17,6 +17,7 @@
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 @@
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 980aba2..597fa0a 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEventDescriptor.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEventDescriptor.java
@@ -17,6 +17,7 @@
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 @@
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 e899e1c..abea10a 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEventDescriptor.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEventDescriptor.java
@@ -17,6 +17,7 @@
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 @@
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 8eefb4b..f287db1 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEventDescriptor.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEventDescriptor.java
@@ -17,6 +17,7 @@
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 @@
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 955f263..d95dc4f 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 @@
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 22fd8a5..c001ffb 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 @@
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 aad9fb3..b29896c 100644
--- a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEventDescriptor.java
+++ b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEventDescriptor.java
@@ -17,6 +17,7 @@
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 @@
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 122747a65..62b92fd 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -553,6 +553,20 @@
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 @@
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 @@
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 @@
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 8be721a..dfc3b6e 100644
--- a/tests/RollbackTest/Android.bp
+++ b/tests/RollbackTest/Android.bp
@@ -118,7 +118,7 @@
":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 a03fae0..9aed074 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 @@
}
/**
- * 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 @@
}
/**
+ * 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 @@
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 59ae8d9..047451b 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 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 @@
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 @@
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 @@
}
/**
+ * 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 @@
}
/**
- * Test rollbacks of staged installs involving only apks.
+ * Test rollbacks of staged installs involving only apex.
* Commit rollback phase.
*/
@Test
@@ -186,18 +268,8 @@
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 @@
}
/**
- * 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 24a51dc..ac7f634 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 @@
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 adcd11a..bb985d7 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 @@
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 985d667..dc11bf3 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -190,6 +190,8 @@
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.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 @@
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 @@
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 @@
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
similarity index 92%
rename from wifi/java/android/net/wifi/IWifiUsabilityStatsListener.aidl
rename to wifi/java/android/net/wifi/IOnWifiUsabilityStatsListener.aidl
index 284ffaa..4687f30 100644
--- a/wifi/java/android/net/wifi/IWifiUsabilityStatsListener.aidl
+++ b/wifi/java/android/net/wifi/IOnWifiUsabilityStatsListener.aidl
@@ -23,7 +23,7 @@
*
* @hide
*/
-oneway interface IWifiUsabilityStatsListener
+oneway interface IOnWifiUsabilityStatsListener
{
/**
* Service to manager callback providing current Wi-Fi usability stats.
@@ -36,6 +36,6 @@
* 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 17948e7..62ea9af 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.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 @@
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 4fd00f7..869f665 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -65,6 +65,7 @@
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 @@
/**
* 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 @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 @@
})
@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 @@
/**
* 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 @@
* 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 @@
*/
@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 @@
*/
@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 @@
*
* @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 2dee971..51aa93a 100644
--- a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
+++ b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
@@ -51,87 +51,88 @@
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 @@
/** 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 @@
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 c236c7a..842d78d 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.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 @@
}
@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 5c2f626..600abc9 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.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 @@
@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 @@
}
/**
- * 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 a22f8ce..8e37113 100644
--- a/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java
@@ -81,29 +81,35 @@
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());
}
}