Merge "Wallpaper color extraction API stub" into oc-dev
diff --git a/api/current.txt b/api/current.txt
index b4e52a3..98db4f7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -211,6 +211,7 @@
ctor public R.attr();
field public static final int __removed1 = 16844099; // 0x1010543
field public static final int __removed2 = 16844104; // 0x1010548
+ field public static final int __removed3 = 16844116; // 0x1010554
field public static final int absListViewStyle = 16842858; // 0x101006a
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -313,7 +314,6 @@
field public static final int autoUrlDetect = 16843404; // 0x101028c
field public static final int autoVerify = 16844014; // 0x10104ee
field public static final int autofillHints = 16844121; // 0x1010559
- field public static final int autofillMode = 16844116; // 0x1010554
field public static final int background = 16842964; // 0x10100d4
field public static final int backgroundDimAmount = 16842802; // 0x1010032
field public static final int backgroundDimEnabled = 16843295; // 0x101021f
@@ -3615,6 +3615,7 @@
method public android.net.Uri getReferrer();
method public int getRequestedOrientation();
method public final android.view.SearchEvent getSearchEvent();
+ method public long getStartInitiatedTime();
method public int getTaskId();
method public final java.lang.CharSequence getTitle();
method public final int getTitleColor();
@@ -3941,7 +3942,8 @@
field public static final int IMPORTANCE_FOREGROUND = 100; // 0x64
field public static final int IMPORTANCE_FOREGROUND_SERVICE = 125; // 0x7d
field public static final int IMPORTANCE_GONE = 1000; // 0x3e8
- field public static final int IMPORTANCE_PERCEPTIBLE = 130; // 0x82
+ field public static final int IMPORTANCE_PERCEPTIBLE = 230; // 0xe6
+ field public static final deprecated int IMPORTANCE_PERCEPTIBLE_DEPRECATED = 130; // 0x82
field public static final int IMPORTANCE_SERVICE = 300; // 0x12c
field public static final int IMPORTANCE_TOP_SLEEPING = 150; // 0x96
field public static final int IMPORTANCE_VISIBLE = 200; // 0xc8
@@ -6887,6 +6889,14 @@
field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_JOB_SERVICE";
}
+ public abstract class JobServiceEngine {
+ ctor public JobServiceEngine(android.content.Context);
+ method public final android.os.IBinder getBinder();
+ method public final void jobFinished(android.app.job.JobParameters, boolean);
+ method public abstract boolean onStartJob(android.app.job.JobParameters);
+ method public abstract boolean onStopJob(android.app.job.JobParameters);
+ }
+
public final class JobWorkItem implements android.os.Parcelable {
ctor public JobWorkItem(android.content.Intent);
ctor public JobWorkItem(android.os.Parcel);
@@ -8087,7 +8097,12 @@
method public void flushPendingScanResults(android.bluetooth.le.ScanCallback);
method public void startScan(android.bluetooth.le.ScanCallback);
method public void startScan(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
+ method public int startScan(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.app.PendingIntent);
method public void stopScan(android.bluetooth.le.ScanCallback);
+ method public void stopScan(android.app.PendingIntent);
+ field public static final java.lang.String EXTRA_CALLBACK_TYPE = "android.bluetooth.le.extra.CALLBACK_TYPE";
+ field public static final java.lang.String EXTRA_ERROR_CODE = "android.bluetooth.le.extra.ERROR_CODE";
+ field public static final java.lang.String EXTRA_LIST_SCAN_RESULT = "android.bluetooth.le.extra.LIST_SCAN_RESULT";
}
public final class PeriodicAdvertisingParameters implements android.os.Parcelable {
@@ -8262,7 +8277,8 @@
method public android.companion.BluetoothLEDeviceFilter build();
method public android.companion.BluetoothLEDeviceFilter.Builder setNamePattern(java.util.regex.Pattern);
method public android.companion.BluetoothLEDeviceFilter.Builder setRawDataFilter(byte[], byte[]);
- method public android.companion.BluetoothLEDeviceFilter.Builder setRename(java.lang.String, java.lang.String, int, int, boolean);
+ method public android.companion.BluetoothLEDeviceFilter.Builder setRenameFromBytes(java.lang.String, java.lang.String, int, int, boolean);
+ method public android.companion.BluetoothLEDeviceFilter.Builder setRenameFromName(java.lang.String, java.lang.String, int, int);
method public android.companion.BluetoothLEDeviceFilter.Builder setScanFilter(android.bluetooth.le.ScanFilter);
}
@@ -8270,6 +8286,8 @@
method public void associate(android.companion.AssociationRequest, android.companion.CompanionDeviceManager.Callback, android.os.Handler);
method public void disassociate(java.lang.String);
method public java.util.List<java.lang.String> getAssociations();
+ method public boolean hasNotificationAccess(android.content.ComponentName);
+ method public void requestNotificationAccess(android.content.ComponentName);
field public static final java.lang.String EXTRA_DEVICE = "android.companion.extra.DEVICE";
}
@@ -9342,7 +9360,6 @@
field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
- field public static final deprecated java.lang.String ACTION_MASTER_CLEAR = "android.intent.action.MASTER_CLEAR";
field public static final java.lang.String ACTION_MEDIA_BAD_REMOVAL = "android.intent.action.MEDIA_BAD_REMOVAL";
field public static final java.lang.String ACTION_MEDIA_BUTTON = "android.intent.action.MEDIA_BUTTON";
field public static final java.lang.String ACTION_MEDIA_CHECKING = "android.intent.action.MEDIA_CHECKING";
@@ -12552,6 +12569,7 @@
field public boolean inJustDecodeBounds;
field public boolean inMutable;
field public deprecated boolean inPreferQualityOverSpeed;
+ field public android.graphics.ColorSpace inPreferredColorSpace;
field public android.graphics.Bitmap.Config inPreferredConfig;
field public boolean inPremultiplied;
field public deprecated boolean inPurgeable;
@@ -25540,22 +25558,25 @@
method public java.lang.String getName();
method public int getTruncationLengthBits();
method public void writeToParcel(android.os.Parcel, int);
- field public static final java.lang.String ALGO_AUTH_HMAC_MD5 = "hmac(md5)";
- field public static final java.lang.String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)";
- field public static final java.lang.String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)";
- field public static final java.lang.String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)";
- field public static final java.lang.String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)";
- field public static final java.lang.String ALGO_CRYPT_AES_CBC = "cbc(aes)";
+ field public static final java.lang.String AUTH_HMAC_MD5 = "hmac(md5)";
+ field public static final java.lang.String AUTH_HMAC_SHA1 = "hmac(sha1)";
+ field public static final java.lang.String AUTH_HMAC_SHA256 = "hmac(sha256)";
+ field public static final java.lang.String AUTH_HMAC_SHA384 = "hmac(sha384)";
+ field public static final java.lang.String AUTH_HMAC_SHA512 = "hmac(sha512)";
field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
+ field public static final java.lang.String CRYPT_AES_CBC = "cbc(aes)";
}
public final class IpSecManager {
method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException;
method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;
+ method public void applyTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;
method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
+ method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform);
+ method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;
method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
}
@@ -25795,6 +25816,10 @@
method public android.net.NetworkRequest.Builder removeCapability(int);
method public android.net.NetworkRequest.Builder removeTransportType(int);
method public android.net.NetworkRequest.Builder setNetworkSpecifier(java.lang.String);
+ method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
+ }
+
+ public abstract class NetworkSpecifier {
}
public class ParseException extends java.lang.RuntimeException {
@@ -37048,8 +37073,10 @@
method public final android.os.IBinder onBind(android.content.Intent);
method public void onConnected();
method public void onDisconnected();
- method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
- method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
+ method public void onFillRequest(android.service.autofill.FillRequest, android.os.CancellationSignal, android.service.autofill.FillCallback);
+ method public abstract deprecated void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
+ method public void onSaveRequest(android.service.autofill.SaveRequest, android.service.autofill.SaveCallback);
+ method public abstract deprecated void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
}
@@ -37074,6 +37101,25 @@
method public void onSuccess(android.service.autofill.FillResponse);
}
+ public final class FillContext implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getRequestId();
+ method public android.app.assist.AssistStructure getStructure();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.FillContext> CREATOR;
+ }
+
+ public final class FillRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.os.Bundle getClientState();
+ method public int getFlags();
+ method public int getId();
+ method public android.app.assist.AssistStructure getStructure();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.FillRequest> CREATOR;
+ field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1
+ }
+
public final class FillResponse implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -37085,7 +37131,8 @@
method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
method public android.service.autofill.FillResponse build();
method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
- method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
+ method public android.service.autofill.FillResponse.Builder setClientState(android.os.Bundle);
+ method public deprecated android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
}
@@ -37114,6 +37161,14 @@
method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]);
}
+ public final class SaveRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.os.Bundle getClientState();
+ method public java.util.List<android.service.autofill.FillContext> getFillContexts();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.SaveRequest> CREATOR;
+ }
+
}
package android.service.carrier {
@@ -45383,7 +45438,6 @@
method public android.view.animation.Animation getAnimation();
method public android.os.IBinder getApplicationWindowToken();
method public java.lang.String[] getAutofillHints();
- method public int getAutofillMode();
method public int getAutofillType();
method public android.view.autofill.AutofillValue getAutofillValue();
method public android.graphics.drawable.Drawable getBackground();
@@ -45472,7 +45526,6 @@
method public float getPivotX();
method public float getPivotY();
method public android.view.PointerIcon getPointerIcon();
- method public int getResolvedAutofillMode();
method public android.content.res.Resources getResources();
method public final boolean getRevealOnFocusHint();
method public final int getRight();
@@ -45705,7 +45758,6 @@
method public void setAlpha(float);
method public void setAnimation(android.view.animation.Animation);
method public void setAutofillHints(java.lang.String...);
- method public void setAutofillMode(int);
method public void setBackground(android.graphics.drawable.Drawable);
method public void setBackgroundColor(int);
method public deprecated void setBackgroundDrawable(android.graphics.drawable.Drawable);
@@ -45861,9 +45913,6 @@
field public static final java.lang.String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress";
field public static final java.lang.String AUTOFILL_HINT_POSTAL_CODE = "postalCode";
field public static final java.lang.String AUTOFILL_HINT_USERNAME = "username";
- field public static final int AUTOFILL_MODE_AUTO = 1; // 0x1
- field public static final int AUTOFILL_MODE_INHERIT = 0; // 0x0
- field public static final int AUTOFILL_MODE_MANUAL = 2; // 0x2
field public static final int AUTOFILL_TYPE_DATE = 4; // 0x4
field public static final int AUTOFILL_TYPE_LIST = 3; // 0x3
field public static final int AUTOFILL_TYPE_NONE = 0; // 0x0
@@ -46431,7 +46480,6 @@
method public abstract int getLayoutDirection();
method public abstract android.view.ViewParent getParent();
method public abstract android.view.ViewParent getParentForAccessibility();
- method public default int getResolvedAutofillMode();
method public abstract int getTextAlignment();
method public abstract int getTextDirection();
method public abstract deprecated void invalidateChild(android.view.View, android.graphics.Rect);
@@ -47818,7 +47866,7 @@
field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
field public static final java.lang.String EXTRA_DATA_EXTRAS = "android.view.autofill.extra.DATA_EXTRAS";
- field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1
+ field public static final deprecated int FLAG_MANUAL_REQUEST = 1; // 0x1
}
public static abstract class AutofillManager.AutofillCallback {
diff --git a/api/system-current.txt b/api/system-current.txt
index bd82ef4..2767fd5 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -329,6 +329,7 @@
ctor public R.attr();
field public static final int __removed1 = 16844099; // 0x1010543
field public static final int __removed2 = 16844104; // 0x1010548
+ field public static final int __removed3 = 16844116; // 0x1010554
field public static final int absListViewStyle = 16842858; // 0x101006a
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -431,7 +432,6 @@
field public static final int autoUrlDetect = 16843404; // 0x101028c
field public static final int autoVerify = 16844014; // 0x10104ee
field public static final int autofillHints = 16844121; // 0x1010559
- field public static final int autofillMode = 16844116; // 0x1010554
field public static final int background = 16842964; // 0x10100d4
field public static final int backgroundDimAmount = 16842802; // 0x1010032
field public static final int backgroundDimEnabled = 16843295; // 0x101021f
@@ -3743,6 +3743,7 @@
method public android.net.Uri getReferrer();
method public int getRequestedOrientation();
method public final android.view.SearchEvent getSearchEvent();
+ method public long getStartInitiatedTime();
method public int getTaskId();
method public final java.lang.CharSequence getTitle();
method public final int getTitleColor();
@@ -4087,7 +4088,8 @@
field public static final int IMPORTANCE_FOREGROUND = 100; // 0x64
field public static final int IMPORTANCE_FOREGROUND_SERVICE = 125; // 0x7d
field public static final int IMPORTANCE_GONE = 1000; // 0x3e8
- field public static final int IMPORTANCE_PERCEPTIBLE = 130; // 0x82
+ field public static final int IMPORTANCE_PERCEPTIBLE = 230; // 0xe6
+ field public static final deprecated int IMPORTANCE_PERCEPTIBLE_DEPRECATED = 130; // 0x82
field public static final int IMPORTANCE_SERVICE = 300; // 0x12c
field public static final int IMPORTANCE_TOP_SLEEPING = 150; // 0x96
field public static final int IMPORTANCE_VISIBLE = 200; // 0xc8
@@ -7321,6 +7323,14 @@
field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_JOB_SERVICE";
}
+ public abstract class JobServiceEngine {
+ ctor public JobServiceEngine(android.content.Context);
+ method public final android.os.IBinder getBinder();
+ method public final void jobFinished(android.app.job.JobParameters, boolean);
+ method public abstract boolean onStartJob(android.app.job.JobParameters);
+ method public abstract boolean onStopJob(android.app.job.JobParameters);
+ }
+
public final class JobWorkItem implements android.os.Parcelable {
ctor public JobWorkItem(android.content.Intent);
ctor public JobWorkItem(android.os.Parcel);
@@ -8559,10 +8569,15 @@
method public void flushPendingScanResults(android.bluetooth.le.ScanCallback);
method public void startScan(android.bluetooth.le.ScanCallback);
method public void startScan(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
+ method public int startScan(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.app.PendingIntent);
method public void startScanFromSource(android.os.WorkSource, android.bluetooth.le.ScanCallback);
method public void startScanFromSource(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.os.WorkSource, android.bluetooth.le.ScanCallback);
method public void startTruncatedScan(java.util.List<android.bluetooth.le.TruncatedFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
method public void stopScan(android.bluetooth.le.ScanCallback);
+ method public void stopScan(android.app.PendingIntent);
+ field public static final java.lang.String EXTRA_CALLBACK_TYPE = "android.bluetooth.le.extra.CALLBACK_TYPE";
+ field public static final java.lang.String EXTRA_ERROR_CODE = "android.bluetooth.le.extra.ERROR_CODE";
+ field public static final java.lang.String EXTRA_LIST_SCAN_RESULT = "android.bluetooth.le.extra.LIST_SCAN_RESULT";
}
public final class PeriodicAdvertisingParameters implements android.os.Parcelable {
@@ -8756,7 +8771,8 @@
method public android.companion.BluetoothLEDeviceFilter build();
method public android.companion.BluetoothLEDeviceFilter.Builder setNamePattern(java.util.regex.Pattern);
method public android.companion.BluetoothLEDeviceFilter.Builder setRawDataFilter(byte[], byte[]);
- method public android.companion.BluetoothLEDeviceFilter.Builder setRename(java.lang.String, java.lang.String, int, int, boolean);
+ method public android.companion.BluetoothLEDeviceFilter.Builder setRenameFromBytes(java.lang.String, java.lang.String, int, int, boolean);
+ method public android.companion.BluetoothLEDeviceFilter.Builder setRenameFromName(java.lang.String, java.lang.String, int, int);
method public android.companion.BluetoothLEDeviceFilter.Builder setScanFilter(android.bluetooth.le.ScanFilter);
}
@@ -8764,6 +8780,8 @@
method public void associate(android.companion.AssociationRequest, android.companion.CompanionDeviceManager.Callback, android.os.Handler);
method public void disassociate(java.lang.String);
method public java.util.List<java.lang.String> getAssociations();
+ method public boolean hasNotificationAccess(android.content.ComponentName);
+ method public void requestNotificationAccess(android.content.ComponentName);
field public static final java.lang.String EXTRA_DEVICE = "android.companion.extra.DEVICE";
}
@@ -13322,6 +13340,7 @@
field public boolean inJustDecodeBounds;
field public boolean inMutable;
field public deprecated boolean inPreferQualityOverSpeed;
+ field public android.graphics.ColorSpace inPreferredColorSpace;
field public android.graphics.Bitmap.Config inPreferredConfig;
field public boolean inPremultiplied;
field public deprecated boolean inPurgeable;
@@ -27725,22 +27744,25 @@
method public java.lang.String getName();
method public int getTruncationLengthBits();
method public void writeToParcel(android.os.Parcel, int);
- field public static final java.lang.String ALGO_AUTH_HMAC_MD5 = "hmac(md5)";
- field public static final java.lang.String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)";
- field public static final java.lang.String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)";
- field public static final java.lang.String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)";
- field public static final java.lang.String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)";
- field public static final java.lang.String ALGO_CRYPT_AES_CBC = "cbc(aes)";
+ field public static final java.lang.String AUTH_HMAC_MD5 = "hmac(md5)";
+ field public static final java.lang.String AUTH_HMAC_SHA1 = "hmac(sha1)";
+ field public static final java.lang.String AUTH_HMAC_SHA256 = "hmac(sha256)";
+ field public static final java.lang.String AUTH_HMAC_SHA384 = "hmac(sha384)";
+ field public static final java.lang.String AUTH_HMAC_SHA512 = "hmac(sha512)";
field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
+ field public static final java.lang.String CRYPT_AES_CBC = "cbc(aes)";
}
public final class IpSecManager {
method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException;
method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;
+ method public void applyTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;
method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
+ method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform);
+ method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;
method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
}
@@ -28017,6 +28039,7 @@
method public android.net.NetworkRequest.Builder removeCapability(int);
method public android.net.NetworkRequest.Builder removeTransportType(int);
method public android.net.NetworkRequest.Builder setNetworkSpecifier(java.lang.String);
+ method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
}
public class NetworkScoreManager {
@@ -28035,6 +28058,9 @@
field public static final java.lang.String EXTRA_PACKAGE_NAME = "packageName";
}
+ public abstract class NetworkSpecifier {
+ }
+
public class ParseException extends java.lang.RuntimeException {
field public java.lang.String response;
}
@@ -40164,8 +40190,10 @@
method public final android.os.IBinder onBind(android.content.Intent);
method public void onConnected();
method public void onDisconnected();
- method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
- method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
+ method public void onFillRequest(android.service.autofill.FillRequest, android.os.CancellationSignal, android.service.autofill.FillCallback);
+ method public abstract deprecated void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
+ method public void onSaveRequest(android.service.autofill.SaveRequest, android.service.autofill.SaveCallback);
+ method public abstract deprecated void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
}
@@ -40190,6 +40218,25 @@
method public void onSuccess(android.service.autofill.FillResponse);
}
+ public final class FillContext implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getRequestId();
+ method public android.app.assist.AssistStructure getStructure();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.FillContext> CREATOR;
+ }
+
+ public final class FillRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.os.Bundle getClientState();
+ method public int getFlags();
+ method public int getId();
+ method public android.app.assist.AssistStructure getStructure();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.FillRequest> CREATOR;
+ field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1
+ }
+
public final class FillResponse implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -40201,7 +40248,8 @@
method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
method public android.service.autofill.FillResponse build();
method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
- method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
+ method public android.service.autofill.FillResponse.Builder setClientState(android.os.Bundle);
+ method public deprecated android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
}
@@ -40230,6 +40278,14 @@
method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]);
}
+ public final class SaveRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.os.Bundle getClientState();
+ method public java.util.List<android.service.autofill.FillContext> getFillContexts();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.SaveRequest> CREATOR;
+ }
+
}
package android.service.carrier {
@@ -48963,7 +49019,6 @@
method public android.view.animation.Animation getAnimation();
method public android.os.IBinder getApplicationWindowToken();
method public java.lang.String[] getAutofillHints();
- method public int getAutofillMode();
method public int getAutofillType();
method public android.view.autofill.AutofillValue getAutofillValue();
method public android.graphics.drawable.Drawable getBackground();
@@ -49052,7 +49107,6 @@
method public float getPivotX();
method public float getPivotY();
method public android.view.PointerIcon getPointerIcon();
- method public int getResolvedAutofillMode();
method public android.content.res.Resources getResources();
method public final boolean getRevealOnFocusHint();
method public final int getRight();
@@ -49285,7 +49339,6 @@
method public void setAlpha(float);
method public void setAnimation(android.view.animation.Animation);
method public void setAutofillHints(java.lang.String...);
- method public void setAutofillMode(int);
method public void setBackground(android.graphics.drawable.Drawable);
method public void setBackgroundColor(int);
method public deprecated void setBackgroundDrawable(android.graphics.drawable.Drawable);
@@ -49441,9 +49494,6 @@
field public static final java.lang.String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress";
field public static final java.lang.String AUTOFILL_HINT_POSTAL_CODE = "postalCode";
field public static final java.lang.String AUTOFILL_HINT_USERNAME = "username";
- field public static final int AUTOFILL_MODE_AUTO = 1; // 0x1
- field public static final int AUTOFILL_MODE_INHERIT = 0; // 0x0
- field public static final int AUTOFILL_MODE_MANUAL = 2; // 0x2
field public static final int AUTOFILL_TYPE_DATE = 4; // 0x4
field public static final int AUTOFILL_TYPE_LIST = 3; // 0x3
field public static final int AUTOFILL_TYPE_NONE = 0; // 0x0
@@ -50011,7 +50061,6 @@
method public abstract int getLayoutDirection();
method public abstract android.view.ViewParent getParent();
method public abstract android.view.ViewParent getParentForAccessibility();
- method public default int getResolvedAutofillMode();
method public abstract int getTextAlignment();
method public abstract int getTextDirection();
method public abstract deprecated void invalidateChild(android.view.View, android.graphics.Rect);
@@ -51401,7 +51450,7 @@
field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
field public static final java.lang.String EXTRA_DATA_EXTRAS = "android.view.autofill.extra.DATA_EXTRAS";
- field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1
+ field public static final deprecated int FLAG_MANUAL_REQUEST = 1; // 0x1
}
public static abstract class AutofillManager.AutofillCallback {
diff --git a/api/test-current.txt b/api/test-current.txt
index 780446c..090df83 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -211,6 +211,7 @@
ctor public R.attr();
field public static final int __removed1 = 16844099; // 0x1010543
field public static final int __removed2 = 16844104; // 0x1010548
+ field public static final int __removed3 = 16844116; // 0x1010554
field public static final int absListViewStyle = 16842858; // 0x101006a
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -313,7 +314,6 @@
field public static final int autoUrlDetect = 16843404; // 0x101028c
field public static final int autoVerify = 16844014; // 0x10104ee
field public static final int autofillHints = 16844121; // 0x1010559
- field public static final int autofillMode = 16844116; // 0x1010554
field public static final int background = 16842964; // 0x10100d4
field public static final int backgroundDimAmount = 16842802; // 0x1010032
field public static final int backgroundDimEnabled = 16843295; // 0x101021f
@@ -3617,6 +3617,7 @@
method public android.net.Uri getReferrer();
method public int getRequestedOrientation();
method public final android.view.SearchEvent getSearchEvent();
+ method public long getStartInitiatedTime();
method public int getTaskId();
method public final java.lang.CharSequence getTitle();
method public final int getTitleColor();
@@ -3951,7 +3952,8 @@
field public static final int IMPORTANCE_FOREGROUND = 100; // 0x64
field public static final int IMPORTANCE_FOREGROUND_SERVICE = 125; // 0x7d
field public static final int IMPORTANCE_GONE = 1000; // 0x3e8
- field public static final int IMPORTANCE_PERCEPTIBLE = 130; // 0x82
+ field public static final int IMPORTANCE_PERCEPTIBLE = 230; // 0xe6
+ field public static final deprecated int IMPORTANCE_PERCEPTIBLE_DEPRECATED = 130; // 0x82
field public static final int IMPORTANCE_SERVICE = 300; // 0x12c
field public static final int IMPORTANCE_TOP_SLEEPING = 150; // 0x96
field public static final int IMPORTANCE_VISIBLE = 200; // 0xc8
@@ -6917,6 +6919,14 @@
field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_JOB_SERVICE";
}
+ public abstract class JobServiceEngine {
+ ctor public JobServiceEngine(android.content.Context);
+ method public final android.os.IBinder getBinder();
+ method public final void jobFinished(android.app.job.JobParameters, boolean);
+ method public abstract boolean onStartJob(android.app.job.JobParameters);
+ method public abstract boolean onStopJob(android.app.job.JobParameters);
+ }
+
public final class JobWorkItem implements android.os.Parcelable {
ctor public JobWorkItem(android.content.Intent);
ctor public JobWorkItem(android.os.Parcel);
@@ -8118,7 +8128,12 @@
method public void flushPendingScanResults(android.bluetooth.le.ScanCallback);
method public void startScan(android.bluetooth.le.ScanCallback);
method public void startScan(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
+ method public int startScan(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.app.PendingIntent);
method public void stopScan(android.bluetooth.le.ScanCallback);
+ method public void stopScan(android.app.PendingIntent);
+ field public static final java.lang.String EXTRA_CALLBACK_TYPE = "android.bluetooth.le.extra.CALLBACK_TYPE";
+ field public static final java.lang.String EXTRA_ERROR_CODE = "android.bluetooth.le.extra.ERROR_CODE";
+ field public static final java.lang.String EXTRA_LIST_SCAN_RESULT = "android.bluetooth.le.extra.LIST_SCAN_RESULT";
}
public final class PeriodicAdvertisingParameters implements android.os.Parcelable {
@@ -8293,7 +8308,8 @@
method public android.companion.BluetoothLEDeviceFilter build();
method public android.companion.BluetoothLEDeviceFilter.Builder setNamePattern(java.util.regex.Pattern);
method public android.companion.BluetoothLEDeviceFilter.Builder setRawDataFilter(byte[], byte[]);
- method public android.companion.BluetoothLEDeviceFilter.Builder setRename(java.lang.String, java.lang.String, int, int, boolean);
+ method public android.companion.BluetoothLEDeviceFilter.Builder setRenameFromBytes(java.lang.String, java.lang.String, int, int, boolean);
+ method public android.companion.BluetoothLEDeviceFilter.Builder setRenameFromName(java.lang.String, java.lang.String, int, int);
method public android.companion.BluetoothLEDeviceFilter.Builder setScanFilter(android.bluetooth.le.ScanFilter);
}
@@ -8301,6 +8317,8 @@
method public void associate(android.companion.AssociationRequest, android.companion.CompanionDeviceManager.Callback, android.os.Handler);
method public void disassociate(java.lang.String);
method public java.util.List<java.lang.String> getAssociations();
+ method public boolean hasNotificationAccess(android.content.ComponentName);
+ method public void requestNotificationAccess(android.content.ComponentName);
field public static final java.lang.String EXTRA_DEVICE = "android.companion.extra.DEVICE";
}
@@ -9376,7 +9394,6 @@
field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
- field public static final deprecated java.lang.String ACTION_MASTER_CLEAR = "android.intent.action.MASTER_CLEAR";
field public static final java.lang.String ACTION_MEDIA_BAD_REMOVAL = "android.intent.action.MEDIA_BAD_REMOVAL";
field public static final java.lang.String ACTION_MEDIA_BUTTON = "android.intent.action.MEDIA_BUTTON";
field public static final java.lang.String ACTION_MEDIA_CHECKING = "android.intent.action.MEDIA_CHECKING";
@@ -12594,6 +12611,7 @@
field public boolean inJustDecodeBounds;
field public boolean inMutable;
field public deprecated boolean inPreferQualityOverSpeed;
+ field public android.graphics.ColorSpace inPreferredColorSpace;
field public android.graphics.Bitmap.Config inPreferredConfig;
field public boolean inPremultiplied;
field public deprecated boolean inPurgeable;
@@ -25647,22 +25665,25 @@
method public java.lang.String getName();
method public int getTruncationLengthBits();
method public void writeToParcel(android.os.Parcel, int);
- field public static final java.lang.String ALGO_AUTH_HMAC_MD5 = "hmac(md5)";
- field public static final java.lang.String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)";
- field public static final java.lang.String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)";
- field public static final java.lang.String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)";
- field public static final java.lang.String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)";
- field public static final java.lang.String ALGO_CRYPT_AES_CBC = "cbc(aes)";
+ field public static final java.lang.String AUTH_HMAC_MD5 = "hmac(md5)";
+ field public static final java.lang.String AUTH_HMAC_SHA1 = "hmac(sha1)";
+ field public static final java.lang.String AUTH_HMAC_SHA256 = "hmac(sha256)";
+ field public static final java.lang.String AUTH_HMAC_SHA384 = "hmac(sha384)";
+ field public static final java.lang.String AUTH_HMAC_SHA512 = "hmac(sha512)";
field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
+ field public static final java.lang.String CRYPT_AES_CBC = "cbc(aes)";
}
public final class IpSecManager {
method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException;
method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;
+ method public void applyTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;
method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
+ method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform);
+ method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;
method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
}
@@ -25902,6 +25923,10 @@
method public android.net.NetworkRequest.Builder removeCapability(int);
method public android.net.NetworkRequest.Builder removeTransportType(int);
method public android.net.NetworkRequest.Builder setNetworkSpecifier(java.lang.String);
+ method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
+ }
+
+ public abstract class NetworkSpecifier {
}
public class ParseException extends java.lang.RuntimeException {
@@ -37201,8 +37226,10 @@
method public final android.os.IBinder onBind(android.content.Intent);
method public void onConnected();
method public void onDisconnected();
- method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
- method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
+ method public void onFillRequest(android.service.autofill.FillRequest, android.os.CancellationSignal, android.service.autofill.FillCallback);
+ method public abstract deprecated void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
+ method public void onSaveRequest(android.service.autofill.SaveRequest, android.service.autofill.SaveCallback);
+ method public abstract deprecated void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
}
@@ -37227,6 +37254,25 @@
method public void onSuccess(android.service.autofill.FillResponse);
}
+ public final class FillContext implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getRequestId();
+ method public android.app.assist.AssistStructure getStructure();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.FillContext> CREATOR;
+ }
+
+ public final class FillRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.os.Bundle getClientState();
+ method public int getFlags();
+ method public int getId();
+ method public android.app.assist.AssistStructure getStructure();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.FillRequest> CREATOR;
+ field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1
+ }
+
public final class FillResponse implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -37238,7 +37284,8 @@
method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
method public android.service.autofill.FillResponse build();
method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
- method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
+ method public android.service.autofill.FillResponse.Builder setClientState(android.os.Bundle);
+ method public deprecated android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
}
@@ -37267,6 +37314,14 @@
method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]);
}
+ public final class SaveRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.os.Bundle getClientState();
+ method public java.util.List<android.service.autofill.FillContext> getFillContexts();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.SaveRequest> CREATOR;
+ }
+
}
package android.service.carrier {
@@ -45749,7 +45804,6 @@
method public android.view.animation.Animation getAnimation();
method public android.os.IBinder getApplicationWindowToken();
method public java.lang.String[] getAutofillHints();
- method public int getAutofillMode();
method public int getAutofillType();
method public android.view.autofill.AutofillValue getAutofillValue();
method public android.graphics.drawable.Drawable getBackground();
@@ -45838,7 +45892,6 @@
method public float getPivotX();
method public float getPivotY();
method public android.view.PointerIcon getPointerIcon();
- method public int getResolvedAutofillMode();
method public android.content.res.Resources getResources();
method public final boolean getRevealOnFocusHint();
method public final int getRight();
@@ -46074,7 +46127,6 @@
method public void setAlpha(float);
method public void setAnimation(android.view.animation.Animation);
method public void setAutofillHints(java.lang.String...);
- method public void setAutofillMode(int);
method public void setAutofilled(boolean);
method public void setBackground(android.graphics.drawable.Drawable);
method public void setBackgroundColor(int);
@@ -46231,9 +46283,6 @@
field public static final java.lang.String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress";
field public static final java.lang.String AUTOFILL_HINT_POSTAL_CODE = "postalCode";
field public static final java.lang.String AUTOFILL_HINT_USERNAME = "username";
- field public static final int AUTOFILL_MODE_AUTO = 1; // 0x1
- field public static final int AUTOFILL_MODE_INHERIT = 0; // 0x0
- field public static final int AUTOFILL_MODE_MANUAL = 2; // 0x2
field public static final int AUTOFILL_TYPE_DATE = 4; // 0x4
field public static final int AUTOFILL_TYPE_LIST = 3; // 0x3
field public static final int AUTOFILL_TYPE_NONE = 0; // 0x0
@@ -46805,7 +46854,6 @@
method public abstract int getLayoutDirection();
method public abstract android.view.ViewParent getParent();
method public abstract android.view.ViewParent getParentForAccessibility();
- method public default int getResolvedAutofillMode();
method public abstract int getTextAlignment();
method public abstract int getTextDirection();
method public abstract deprecated void invalidateChild(android.view.View, android.graphics.Rect);
@@ -48196,7 +48244,7 @@
field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
field public static final java.lang.String EXTRA_DATA_EXTRAS = "android.view.autofill.extra.DATA_EXTRAS";
- field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1
+ field public static final deprecated int FLAG_MANUAL_REQUEST = 1; // 0x1
}
public static abstract class AutofillManager.AutofillCallback {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 950991b..b36a160 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -18,6 +18,7 @@
import android.metrics.LogMaker;
import android.graphics.Rect;
+import android.os.SystemClock;
import android.view.ViewRootImpl.ActivityConfigCallback;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
@@ -7433,6 +7434,25 @@
}
}
+ /**
+ * Return the timestamp at which this activity start was last initiated by the system in the
+ * {@link SystemClock#uptimeMillis()} time base.
+ *
+ * This can be used to understand how much time is taken for an activity to be started and
+ * displayed to the user.
+ *
+ * @return timestamp at which this activity start was initiated by the system
+ * or {@code 0} if for any reason the timestamp could not be retrieved.
+ */
+ public long getStartInitiatedTime() {
+ try {
+ return ActivityManager.getService().getActivityStartInitiatedTime(mToken);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to call getActivityStartTime", e);
+ return 0;
+ }
+ }
+
class HostCallbacks extends FragmentHostCallback<Activity> {
public HostCallbacks() {
super(Activity.this /*activity*/);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 8859831..66167a3 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -30,6 +30,8 @@
import android.graphics.Matrix;
import android.graphics.Point;
import android.os.BatteryStats;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
@@ -138,14 +140,17 @@
static final class UidObserver extends IUidObserver.Stub {
final OnUidImportanceListener mListener;
+ final Context mContext;
- UidObserver(OnUidImportanceListener listener) {
+ UidObserver(OnUidImportanceListener listener, Context clientContext) {
mListener = listener;
+ mContext = clientContext;
}
@Override
public void onUidStateChanged(int uid, int procState, long procStateSeq) {
- mListener.onUidImportance(uid, RunningAppProcessInfo.procStateToImportance(procState));
+ mListener.onUidImportance(uid, RunningAppProcessInfo.procStateToImportanceForClient(
+ procState, mContext));
}
@Override
@@ -3102,10 +3107,32 @@
public static final int IMPORTANCE_VISIBLE = 200;
/**
- * Constant for {@link #importance}: This process is not something the user
- * is directly aware of, but is otherwise perceptable to them to some degree.
+ * Constant for {@link #importance}: {@link #IMPORTANCE_PERCEPTIBLE} had this wrong value
+ * before {@link Build.VERSION_CODES#O}. Since the {@link Build.VERSION_CODES#O} SDK,
+ * the value of {@link #IMPORTANCE_PERCEPTIBLE} has been fixed.
+ *
+ * @deprecated Use {@link #IMPORTANCE_PERCEPTIBLE} instead.
*/
- public static final int IMPORTANCE_PERCEPTIBLE = 130;
+ @Deprecated
+ public static final int IMPORTANCE_PERCEPTIBLE_DEPRECATED = 130;
+
+ /**
+ * Constant for {@link #importance}: This process is not something the user
+ * is directly aware of, but is otherwise perceptible to them to some degree.
+ */
+ public static final int IMPORTANCE_PERCEPTIBLE = 230;
+
+ /**
+ * Constant for {@link #importance}: {@link #IMPORTANCE_CANT_SAVE_STATE} had
+ * this wrong value
+ * before {@link Build.VERSION_CODES#O}. Since the {@link Build.VERSION_CODES#O} SDK,
+ * the value of {@link #IMPORTANCE_CANT_SAVE_STATE} has been fixed.
+ *
+ * @deprecated Use {@link #IMPORTANCE_CANT_SAVE_STATE} instead.
+ * @hide
+ */
+ @Deprecated
+ public static final int IMPORTANCE_CANT_SAVE_STATE_DEPRECATED = 170;
/**
* Constant for {@link #importance}: This process is running an
@@ -3113,7 +3140,7 @@
* while in the background.
* @hide
*/
- public static final int IMPORTANCE_CANT_SAVE_STATE = 170;
+ public static final int IMPORTANCE_CANT_SAVE_STATE= 270;
/**
* Constant for {@link #importance}: This process is contains services
@@ -3149,7 +3176,11 @@
*/
public static final int IMPORTANCE_GONE = 1000;
- /** @hide */
+ /**
+ * Convert a proc state to the correspondent IMPORTANCE_* constant. If the return value
+ * will be passed to a client, use {@link #procStateToImportanceForClient}.
+ * @hide
+ */
public static int procStateToImportance(int procState) {
if (procState == PROCESS_STATE_NONEXISTENT) {
return IMPORTANCE_GONE;
@@ -3172,6 +3203,28 @@
}
}
+ /**
+ * Convert a proc state to the correspondent IMPORTANCE_* constant for a client represented
+ * by a given {@link Context}, with converting {@link #IMPORTANCE_PERCEPTIBLE}
+ * and {@link #IMPORTANCE_CANT_SAVE_STATE} to the corresponding "wrong" value if the
+ * client's target SDK < {@link VERSION_CODES#O}.
+ * @hide
+ */
+ public static int procStateToImportanceForClient(int procState, Context clientContext) {
+ final int importance = procStateToImportance(procState);
+
+ // For pre O apps, convert to the old, wrong values.
+ if (clientContext.getApplicationInfo().targetSdkVersion < VERSION_CODES.O) {
+ switch (importance) {
+ case IMPORTANCE_PERCEPTIBLE:
+ return IMPORTANCE_PERCEPTIBLE_DEPRECATED;
+ case IMPORTANCE_CANT_SAVE_STATE:
+ return IMPORTANCE_CANT_SAVE_STATE_DEPRECATED;
+ }
+ }
+ return importance;
+ }
+
/** @hide */
public static int importanceToProcState(int importance) {
if (importance == IMPORTANCE_GONE) {
@@ -3401,7 +3454,7 @@
try {
int procState = getService().getPackageProcessState(packageName,
mContext.getOpPackageName());
- return RunningAppProcessInfo.procStateToImportance(procState);
+ return RunningAppProcessInfo.procStateToImportanceForClient(procState, mContext);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3421,7 +3474,7 @@
try {
int procState = getService().getUidProcessState(uid,
mContext.getOpPackageName());
- return RunningAppProcessInfo.procStateToImportance(procState);
+ return RunningAppProcessInfo.procStateToImportanceForClient(procState, mContext);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3471,7 +3524,7 @@
throw new IllegalArgumentException("Listener already registered: " + listener);
}
// TODO: implement the cut point in the system process to avoid IPCs.
- UidObserver observer = new UidObserver(listener);
+ UidObserver observer = new UidObserver(listener, mContext);
try {
getService().registerUidObserver(observer,
UID_OBSERVER_PROCSTATE | UID_OBSERVER_GONE,
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index fc827a9..4210d2e 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -632,6 +632,8 @@
*/
void backgroundWhitelistUid(int uid);
+ long getActivityStartInitiatedTime(IBinder token);
+
// WARNING: when these transactions are updated, check if they are any callers on the native
// side. If so, make sure they are using the correct transaction ids and arguments.
// If a transaction which will also be used on the native side is being inserted, add it
diff --git a/core/java/android/app/job/JobService.java b/core/java/android/app/job/JobService.java
index f4019ce..9096b47 100644
--- a/core/java/android/app/job/JobService.java
+++ b/core/java/android/app/job/JobService.java
@@ -60,161 +60,24 @@
public static final String PERMISSION_BIND =
"android.permission.BIND_JOB_SERVICE";
- /**
- * Identifier for a message that will result in a call to
- * {@link #onStartJob(android.app.job.JobParameters)}.
- */
- private static final int MSG_EXECUTE_JOB = 0;
- /**
- * Message that will result in a call to {@link #onStopJob(android.app.job.JobParameters)}.
- */
- private static final int MSG_STOP_JOB = 1;
- /**
- * Message that the client has completed execution of this job.
- */
- private static final int MSG_JOB_FINISHED = 2;
-
- /** Lock object for {@link #mHandler}. */
- private final Object mHandlerLock = new Object();
-
- /**
- * Handler we post jobs to. Responsible for calling into the client logic, and handling the
- * callback to the system.
- */
- @GuardedBy("mHandlerLock")
- JobHandler mHandler;
-
- static final class JobInterface extends IJobService.Stub {
- final WeakReference<JobService> mService;
-
- JobInterface(JobService service) {
- mService = new WeakReference<>(service);
- }
-
- @Override
- public void startJob(JobParameters jobParams) throws RemoteException {
- JobService service = mService.get();
- if (service != null) {
- service.ensureHandler();
- Message m = Message.obtain(service.mHandler, MSG_EXECUTE_JOB, jobParams);
- m.sendToTarget();
- }
- }
-
- @Override
- public void stopJob(JobParameters jobParams) throws RemoteException {
- JobService service = mService.get();
- if (service != null) {
- service.ensureHandler();
- Message m = Message.obtain(service.mHandler, MSG_STOP_JOB, jobParams);
- m.sendToTarget();
- }
-
- }
- }
-
- IJobService mBinder;
-
- /** @hide */
- void ensureHandler() {
- synchronized (mHandlerLock) {
- if (mHandler == null) {
- mHandler = new JobHandler(getMainLooper());
- }
- }
- }
-
- /**
- * Runs on application's main thread - callbacks are meant to offboard work to some other
- * (app-specified) mechanism.
- * @hide
- */
- class JobHandler extends Handler {
- JobHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- final JobParameters params = (JobParameters) msg.obj;
- switch (msg.what) {
- case MSG_EXECUTE_JOB:
- try {
- boolean workOngoing = JobService.this.onStartJob(params);
- ackStartMessage(params, workOngoing);
- } catch (Exception e) {
- Log.e(TAG, "Error while executing job: " + params.getJobId());
- throw new RuntimeException(e);
- }
- break;
- case MSG_STOP_JOB:
- try {
- boolean ret = JobService.this.onStopJob(params);
- ackStopMessage(params, ret);
- } catch (Exception e) {
- Log.e(TAG, "Application unable to handle onStopJob.", e);
- throw new RuntimeException(e);
- }
- break;
- case MSG_JOB_FINISHED:
- final boolean needsReschedule = (msg.arg2 == 1);
- IJobCallback callback = params.getCallback();
- if (callback != null) {
- try {
- callback.jobFinished(params.getJobId(), needsReschedule);
- } catch (RemoteException e) {
- Log.e(TAG, "Error reporting job finish to system: binder has gone" +
- "away.");
- }
- } else {
- Log.e(TAG, "finishJob() called for a nonexistent job id.");
- }
- break;
- default:
- Log.e(TAG, "Unrecognised message received.");
- break;
- }
- }
-
- private void ackStartMessage(JobParameters params, boolean workOngoing) {
- final IJobCallback callback = params.getCallback();
- final int jobId = params.getJobId();
- if (callback != null) {
- try {
- callback.acknowledgeStartMessage(jobId, workOngoing);
- } catch(RemoteException e) {
- Log.e(TAG, "System unreachable for starting job.");
- }
- } else {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Attempting to ack a job that has already been processed.");
- }
- }
- }
-
- private void ackStopMessage(JobParameters params, boolean reschedule) {
- final IJobCallback callback = params.getCallback();
- final int jobId = params.getJobId();
- if (callback != null) {
- try {
- callback.acknowledgeStopMessage(jobId, reschedule);
- } catch(RemoteException e) {
- Log.e(TAG, "System unreachable for stopping job.");
- }
- } else {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Attempting to ack a job that has already been processed.");
- }
- }
- }
- }
+ private JobServiceEngine mEngine;
/** @hide */
public final IBinder onBind(Intent intent) {
- if (mBinder == null) {
- mBinder = new JobInterface(this);
+ if (mEngine == null) {
+ mEngine = new JobServiceEngine(this) {
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ return JobService.this.onStartJob(params);
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ return JobService.this.onStopJob(params);
+ }
+ };
}
- return mBinder.asBinder();
+ return mEngine.getBinder();
}
/**
@@ -269,9 +132,6 @@
* criteria specified at schedule-time. False otherwise.
*/
public final void jobFinished(JobParameters params, boolean needsReschedule) {
- ensureHandler();
- Message m = Message.obtain(mHandler, MSG_JOB_FINISHED, params);
- m.arg2 = needsReschedule ? 1 : 0;
- m.sendToTarget();
+ mEngine.jobFinished(params, needsReschedule);
}
}
\ No newline at end of file
diff --git a/core/java/android/app/job/JobServiceEngine.java b/core/java/android/app/job/JobServiceEngine.java
new file mode 100644
index 0000000..879212e
--- /dev/null
+++ b/core/java/android/app/job/JobServiceEngine.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.app.job;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Helper for implementing a {@link android.app.Service} that interacts with
+ * {@link JobScheduler}.
+ */
+public abstract class JobServiceEngine {
+ private static final String TAG = "JobServiceEngine";
+
+ /**
+ * Identifier for a message that will result in a call to
+ * {@link #onStartJob(android.app.job.JobParameters)}.
+ */
+ private static final int MSG_EXECUTE_JOB = 0;
+ /**
+ * Message that will result in a call to {@link #onStopJob(android.app.job.JobParameters)}.
+ */
+ private static final int MSG_STOP_JOB = 1;
+ /**
+ * Message that the client has completed execution of this job.
+ */
+ private static final int MSG_JOB_FINISHED = 2;
+
+ /**
+ * Context we are running in.
+ */
+ private final Context mContext;
+
+ private final IJobService mBinder;
+
+ /** Lock object for {@link #mHandler}. */
+ private final Object mHandlerLock = new Object();
+
+ /**
+ * Handler we post jobs to. Responsible for calling into the client logic, and handling the
+ * callback to the system.
+ */
+ @GuardedBy("mHandlerLock")
+ JobHandler mHandler;
+
+ static final class JobInterface extends IJobService.Stub {
+ final WeakReference<JobServiceEngine> mService;
+
+ JobInterface(JobServiceEngine service) {
+ mService = new WeakReference<>(service);
+ }
+
+ @Override
+ public void startJob(JobParameters jobParams) throws RemoteException {
+ JobServiceEngine service = mService.get();
+ if (service != null) {
+ Message m = Message.obtain(service.mHandler, MSG_EXECUTE_JOB, jobParams);
+ m.sendToTarget();
+ }
+ }
+
+ @Override
+ public void stopJob(JobParameters jobParams) throws RemoteException {
+ JobServiceEngine service = mService.get();
+ if (service != null) {
+ Message m = Message.obtain(service.mHandler, MSG_STOP_JOB, jobParams);
+ m.sendToTarget();
+ }
+ }
+ }
+
+ /**
+ * Runs on application's main thread - callbacks are meant to offboard work to some other
+ * (app-specified) mechanism.
+ * @hide
+ */
+ class JobHandler extends Handler {
+ JobHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ final JobParameters params = (JobParameters) msg.obj;
+ switch (msg.what) {
+ case MSG_EXECUTE_JOB:
+ try {
+ boolean workOngoing = JobServiceEngine.this.onStartJob(params);
+ ackStartMessage(params, workOngoing);
+ } catch (Exception e) {
+ Log.e(TAG, "Error while executing job: " + params.getJobId());
+ throw new RuntimeException(e);
+ }
+ break;
+ case MSG_STOP_JOB:
+ try {
+ boolean ret = JobServiceEngine.this.onStopJob(params);
+ ackStopMessage(params, ret);
+ } catch (Exception e) {
+ Log.e(TAG, "Application unable to handle onStopJob.", e);
+ throw new RuntimeException(e);
+ }
+ break;
+ case MSG_JOB_FINISHED:
+ final boolean needsReschedule = (msg.arg2 == 1);
+ IJobCallback callback = params.getCallback();
+ if (callback != null) {
+ try {
+ callback.jobFinished(params.getJobId(), needsReschedule);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error reporting job finish to system: binder has gone" +
+ "away.");
+ }
+ } else {
+ Log.e(TAG, "finishJob() called for a nonexistent job id.");
+ }
+ break;
+ default:
+ Log.e(TAG, "Unrecognised message received.");
+ break;
+ }
+ }
+
+ private void ackStartMessage(JobParameters params, boolean workOngoing) {
+ final IJobCallback callback = params.getCallback();
+ final int jobId = params.getJobId();
+ if (callback != null) {
+ try {
+ callback.acknowledgeStartMessage(jobId, workOngoing);
+ } catch(RemoteException e) {
+ Log.e(TAG, "System unreachable for starting job.");
+ }
+ } else {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Attempting to ack a job that has already been processed.");
+ }
+ }
+ }
+
+ private void ackStopMessage(JobParameters params, boolean reschedule) {
+ final IJobCallback callback = params.getCallback();
+ final int jobId = params.getJobId();
+ if (callback != null) {
+ try {
+ callback.acknowledgeStopMessage(jobId, reschedule);
+ } catch(RemoteException e) {
+ Log.e(TAG, "System unreachable for stopping job.");
+ }
+ } else {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Attempting to ack a job that has already been processed.");
+ }
+ }
+ }
+ }
+
+ /**
+ * Create a new engine, ready for use.
+ *
+ * @param context The {@link Service} that is creating this engine.
+ */
+ public JobServiceEngine(Context context) {
+ mContext = context;
+ mBinder = new JobInterface(this);
+ mHandler = new JobHandler(mContext.getMainLooper());
+ }
+
+ /**
+ * Retrieve the engine's IPC interface that should be returned by
+ * {@link Service#onBind(Intent)}.
+ */
+ public final IBinder getBinder() {
+ return mBinder.asBinder();
+ }
+
+ /**
+ * Engine's report that a job has started. See
+ * {@link JobService#onStartJob(JobParameters) JobService.onStartJob} for more information.
+ */
+ public abstract boolean onStartJob(JobParameters params);
+
+ /**
+ * Engine's report that a job has stopped. See
+ * {@link JobService#onStopJob(JobParameters) JobService.onStopJob} for more information.
+ */
+ public abstract boolean onStopJob(JobParameters params);
+
+ /**
+ * Call in to engine to report that a job has finished executing. See
+ * {@link JobService#jobFinished(JobParameters, boolean)} JobService.jobFinished} for more
+ * information.
+ */
+ public final void jobFinished(JobParameters params, boolean needsReschedule) {
+ Message m = Message.obtain(mHandler, MSG_JOB_FINISHED, params);
+ m.arg2 = needsReschedule ? 1 : 0;
+ m.sendToTarget();
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 334e88b..582709c 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -16,6 +16,7 @@
package android.bluetooth;
+import android.app.PendingIntent;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.le.AdvertiseSettings;
@@ -47,6 +48,9 @@
void unregisterScanner(in int scannerId);
void startScan(in int scannerId, in ScanSettings settings, in List<ScanFilter> filters,
in WorkSource workSource, in List scanStorages, in String callingPackage);
+ void startScanForIntent(in PendingIntent intent, in ScanSettings settings, in List<ScanFilter> filters,
+ in String callingPackage);
+ void stopScanForIntent(in PendingIntent intent, in String callingPackage);
void stopScan(in int scannerId);
void flushPendingBatchResults(in int scannerId);
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index b63c614..b65a7ad 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -17,17 +17,18 @@
package android.bluetooth.le;
import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.app.ActivityThread;
+import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothManager;
-import android.bluetooth.le.IScannerCallback;
import android.os.Handler;
import android.os.Looper;
-import android.os.ParcelUuid;
import android.os.RemoteException;
import android.os.WorkSource;
import android.util.Log;
@@ -36,7 +37,6 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.UUID;
/**
* This class provides methods to perform scan related operations for Bluetooth LE devices. An
@@ -57,6 +57,27 @@
private static final boolean DBG = true;
private static final boolean VDBG = false;
+ /**
+ * Extra containing a list of ScanResults. It can have one or more results if there was no
+ * error. In case of error, {@link #EXTRA_ERROR_CODE} will contain the error code and this
+ * extra will not be available.
+ */
+ public static final String EXTRA_LIST_SCAN_RESULT
+ = "android.bluetooth.le.extra.LIST_SCAN_RESULT";
+
+ /**
+ * Optional extra indicating the error code, if any. The error code will be one of the
+ * SCAN_FAILED_* codes in {@link ScanCallback}.
+ */
+ public static final String EXTRA_ERROR_CODE = "android.bluetooth.le.extra.ERROR_CODE";
+
+ /**
+ * Optional extra indicating the callback type, which will be one of
+ * ScanSettings.CALLBACK_TYPE_*.
+ * @see ScanCallback#onScanResult(int, ScanResult)
+ */
+ public static final String EXTRA_CALLBACK_TYPE = "android.bluetooth.le.extra.CALLBACK_TYPE";
+
private final IBluetoothManager mBluetoothManager;
private final Handler mHandler;
private BluetoothAdapter mBluetoothAdapter;
@@ -110,7 +131,27 @@
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public void startScan(List<ScanFilter> filters, ScanSettings settings,
final ScanCallback callback) {
- startScan(filters, settings, null, callback, null);
+ startScan(filters, settings, null, callback, /*callbackIntent=*/ null, null);
+ }
+
+ /**
+ * Start Bluetooth LE scan using a {@link PendingIntent}. The scan results will be delivered via
+ * the PendingIntent. Use this method of scanning if your process is not always running and it
+ * should be started when scan results are available.
+ *
+ * @param filters Optional list of ScanFilters for finding exact BLE devices.
+ * @param settings Optional settings for the scan.
+ * @param callbackIntent The PendingIntent to deliver the result to.
+ * @return Returns 0 for success or an error code from {@link ScanCallback} if the scan request
+ * could not be sent.
+ * @see #stopScan(PendingIntent)
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ public int startScan(@Nullable List<ScanFilter> filters, @Nullable ScanSettings settings,
+ @NonNull PendingIntent callbackIntent) {
+ return startScan(filters,
+ settings != null ? settings : new ScanSettings.Builder().build(),
+ null, null, callbackIntent, null);
}
/**
@@ -145,23 +186,23 @@
Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.UPDATE_DEVICE_STATS })
public void startScanFromSource(List<ScanFilter> filters, ScanSettings settings,
final WorkSource workSource, final ScanCallback callback) {
- startScan(filters, settings, workSource, callback, null);
+ startScan(filters, settings, workSource, callback, null, null);
}
- private void startScan(List<ScanFilter> filters, ScanSettings settings,
+ private int startScan(List<ScanFilter> filters, ScanSettings settings,
final WorkSource workSource, final ScanCallback callback,
+ final PendingIntent callbackIntent,
List<List<ResultStorageDescriptor>> resultStorages) {
BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
- if (callback == null) {
+ if (callback == null && callbackIntent == null) {
throw new IllegalArgumentException("callback is null");
}
if (settings == null) {
throw new IllegalArgumentException("settings is null");
}
synchronized (mLeScanClients) {
- if (mLeScanClients.containsKey(callback)) {
+ if (callback != null && mLeScanClients.containsKey(callback)) {
postCallbackError(callback, ScanCallback.SCAN_FAILED_ALREADY_STARTED);
- return;
}
IBluetoothGatt gatt;
try {
@@ -170,28 +211,34 @@
gatt = null;
}
if (gatt == null) {
- postCallbackError(callback, ScanCallback.SCAN_FAILED_INTERNAL_ERROR);
- return;
+ return postCallbackErrorOrReturn(callback, ScanCallback.SCAN_FAILED_INTERNAL_ERROR);
}
if (!isSettingsConfigAllowedForScan(settings)) {
- postCallbackError(callback,
- ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED);
- return;
+ return postCallbackErrorOrReturn(callback,
+ ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED);
}
if (!isHardwareResourcesAvailableForScan(settings)) {
- postCallbackError(callback,
- ScanCallback.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES);
- return;
+ return postCallbackErrorOrReturn(callback,
+ ScanCallback.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES);
}
if (!isSettingsAndFilterComboAllowed(settings, filters)) {
- postCallbackError(callback,
+ return postCallbackErrorOrReturn(callback,
ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED);
- return;
}
- BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(gatt, filters,
- settings, workSource, callback, resultStorages);
- wrapper.startRegisteration();
+ if (callback != null) {
+ BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(gatt, filters,
+ settings, workSource, callback, resultStorages);
+ wrapper.startRegistration();
+ } else {
+ try {
+ gatt.startScanForIntent(callbackIntent, settings, filters,
+ ActivityThread.currentOpPackageName());
+ } catch (RemoteException e) {
+ return ScanCallback.SCAN_FAILED_INTERNAL_ERROR;
+ }
+ }
}
+ return ScanCallback.NO_ERROR;
}
/**
@@ -215,6 +262,25 @@
}
/**
+ * Stops an ongoing Bluetooth LE scan started using a PendingIntent.
+ * <p>
+ * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
+ *
+ * @param callbackIntent The PendingIntent that was used to start the scan.
+ * @see #startScan(List, ScanSettings, PendingIntent)
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ public void stopScan(PendingIntent callbackIntent) {
+ BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
+ IBluetoothGatt gatt;
+ try {
+ gatt = mBluetoothManager.getBluetoothGatt();
+ gatt.stopScanForIntent(callbackIntent, ActivityThread.currentOpPackageName());
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
* Flush pending batch scan results stored in Bluetooth controller. This will return Bluetooth
* LE scan results batched on bluetooth controller. Returns immediately, batch scan results data
* will be delivered through the {@code callback}.
@@ -252,7 +318,7 @@
scanFilters.add(filter.getFilter());
scanStorages.add(filter.getStorageDescriptors());
}
- startScan(scanFilters, settings, null, callback, scanStorages);
+ startScan(scanFilters, settings, null, callback, null, scanStorages);
}
/**
@@ -295,7 +361,7 @@
mResultStorages = resultStorages;
}
- public void startRegisteration() {
+ public void startRegistration() {
synchronized (this) {
// Scan stopped.
if (mScannerId == -1) return;
@@ -399,7 +465,6 @@
mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult);
}
});
-
}
@Override
@@ -453,6 +518,15 @@
}
}
+ private int postCallbackErrorOrReturn(final ScanCallback callback, final int errorCode) {
+ if (callback == null) {
+ return errorCode;
+ } else {
+ postCallbackError(callback, errorCode);
+ return ScanCallback.NO_ERROR;
+ }
+ }
+
private void postCallbackError(final ScanCallback callback, final int errorCode) {
mHandler.post(new Runnable() {
@Override
diff --git a/core/java/android/bluetooth/le/ScanCallback.java b/core/java/android/bluetooth/le/ScanCallback.java
index 61b2e78..aff2e90 100644
--- a/core/java/android/bluetooth/le/ScanCallback.java
+++ b/core/java/android/bluetooth/le/ScanCallback.java
@@ -50,6 +50,8 @@
*/
public static final int SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES = 5;
+ static final int NO_ERROR = 0;
+
/**
* Callback when a BLE advertisement has been found.
*
diff --git a/core/java/android/companion/BluetoothDeviceFilterUtils.java b/core/java/android/companion/BluetoothDeviceFilterUtils.java
index 8a316f1..3665d1b 100644
--- a/core/java/android/companion/BluetoothDeviceFilterUtils.java
+++ b/core/java/android/companion/BluetoothDeviceFilterUtils.java
@@ -37,7 +37,7 @@
private BluetoothDeviceFilterUtils() {}
private static final boolean DEBUG = false;
- private static final String LOG_TAG = "BluetoothDeviceFilterUtil";
+ private static final String LOG_TAG = "BluetoothDeviceFilterUtils";
@Nullable
static String patternToString(@Nullable Pattern p) {
@@ -50,8 +50,10 @@
}
static boolean matches(ScanFilter filter, BluetoothDevice device) {
- return matchesAddress(filter.getDeviceAddress(), device)
+ boolean result = matchesAddress(filter.getDeviceAddress(), device)
&& matchesServiceUuid(filter.getServiceUuid(), filter.getServiceUuidMask(), device);
+ if (DEBUG) debugLogMatchResult(result, device, filter);
+ return result;
}
static boolean matchesAddress(String deviceAddress, BluetoothDevice device) {
diff --git a/core/java/android/companion/BluetoothLEDeviceFilter.java b/core/java/android/companion/BluetoothLEDeviceFilter.java
index 0444775..76051d7 100644
--- a/core/java/android/companion/BluetoothLEDeviceFilter.java
+++ b/core/java/android/companion/BluetoothLEDeviceFilter.java
@@ -21,6 +21,7 @@
import static android.companion.BluetoothDeviceFilterUtils.patternToString;
import static com.android.internal.util.Preconditions.checkArgument;
+import static com.android.internal.util.Preconditions.checkState;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -31,6 +32,7 @@
import android.os.Parcel;
import android.provider.OneTimeUseBuilder;
import android.text.TextUtils;
+import android.util.Log;
import com.android.internal.util.BitUtils;
import com.android.internal.util.ObjectUtils;
@@ -47,6 +49,9 @@
*/
public final class BluetoothLEDeviceFilter implements DeviceFilter<ScanResult> {
+ private static final boolean DEBUG = false;
+ private static final String LOG_TAG = "BluetoothLEDeviceFilter";
+
private static final int RENAME_PREFIX_LENGTH_LIMIT = 10;
private final Pattern mNamePattern;
@@ -57,12 +62,14 @@
private final String mRenameSuffix;
private final int mRenameBytesFrom;
private final int mRenameBytesTo;
+ private final int mRenameNameFrom;
+ private final int mRenameNameTo;
private final boolean mRenameBytesReverseOrder;
private BluetoothLEDeviceFilter(Pattern namePattern, ScanFilter scanFilter,
byte[] rawDataFilter, byte[] rawDataFilterMask, String renamePrefix,
String renameSuffix, int renameBytesFrom, int renameBytesTo,
- boolean renameBytesReverseOrder) {
+ int renameNameFrom, int renameNameTo, boolean renameBytesReverseOrder) {
mNamePattern = namePattern;
mScanFilter = ObjectUtils.firstNotNull(scanFilter, ScanFilter.EMPTY);
mRawDataFilter = rawDataFilter;
@@ -71,6 +78,8 @@
mRenameSuffix = renameSuffix;
mRenameBytesFrom = renameBytesFrom;
mRenameBytesTo = renameBytesTo;
+ mRenameNameFrom = renameNameFrom;
+ mRenameNameTo = renameNameTo;
mRenameBytesReverseOrder = renameBytesReverseOrder;
}
@@ -129,15 +138,23 @@
@Override
@Nullable
public String getDeviceDisplayName(ScanResult sr) {
- if (mRenameBytesFrom < 0) return getDeviceDisplayNameInternal(sr.getDevice());
- final byte[] bytes = sr.getScanRecord().getBytes();
+ if (mRenameBytesFrom < 0 && mRenameNameFrom < 0) {
+ return getDeviceDisplayNameInternal(sr.getDevice());
+ }
final StringBuilder sb = new StringBuilder(TextUtils.emptyIfNull(mRenamePrefix));
- int startInclusive = mRenameBytesFrom;
- int endInclusive = mRenameBytesTo - 1;
- int initial = mRenameBytesReverseOrder ? endInclusive : startInclusive;
- int step = mRenameBytesReverseOrder ? -1 : 1;
- for (int i = initial; startInclusive <= i && i <= endInclusive; i+=step) {
- sb.append(Byte.toHexString(bytes[i], true));
+ if (mRenameBytesFrom >= 0) {
+ final byte[] bytes = sr.getScanRecord().getBytes();
+ int startInclusive = mRenameBytesFrom;
+ int endInclusive = mRenameBytesTo - 1;
+ int initial = mRenameBytesReverseOrder ? endInclusive : startInclusive;
+ int step = mRenameBytesReverseOrder ? -1 : 1;
+ for (int i = initial; startInclusive <= i && i <= endInclusive; i += step) {
+ sb.append(Byte.toHexString(bytes[i], true));
+ }
+ } else {
+ sb.append(
+ getDeviceDisplayNameInternal(sr.getDevice())
+ .substring(mRenameNameFrom, mRenameNameTo));
}
return sb.append(TextUtils.emptyIfNull(mRenameSuffix)).toString();
}
@@ -145,9 +162,13 @@
/** @hide */
@Override
public boolean matches(ScanResult device) {
- return matches(device.getDevice())
- && BitUtils.maskedEquals(device.getScanRecord().getBytes(),
- mRawDataFilter, mRawDataFilterMask);
+ boolean result = matches(device.getDevice())
+ && (mRawDataFilter == null
+ || BitUtils.maskedEquals(device.getScanRecord().getBytes(),
+ mRawDataFilter, mRawDataFilterMask));
+ if (DEBUG) Log.i(LOG_TAG, "matches(this = " + this + ", device = " + device +
+ ") -> " + result);
+ return result;
}
private boolean matches(BluetoothDevice device) {
@@ -194,6 +215,8 @@
dest.writeString(mRenameSuffix);
dest.writeInt(mRenameBytesFrom);
dest.writeInt(mRenameBytesTo);
+ dest.writeInt(mRenameNameFrom);
+ dest.writeInt(mRenameNameTo);
dest.writeBoolean(mRenameBytesReverseOrder);
}
@@ -218,9 +241,16 @@
String suffix = in.readString();
int bytesFrom = in.readInt();
int bytesTo = in.readInt();
+ int nameFrom = in.readInt();
+ int nameTo = in.readInt();
boolean bytesReverseOrder = in.readBoolean();
if (renamePrefix != null) {
- builder.setRename(renamePrefix, suffix, bytesFrom, bytesTo, bytesReverseOrder);
+ if (bytesFrom >= 0) {
+ builder.setRenameFromBytes(renamePrefix, suffix, bytesFrom, bytesTo,
+ bytesReverseOrder);
+ } else {
+ builder.setRenameFromName(renamePrefix, suffix, nameFrom, nameTo);
+ }
}
return builder.build();
}
@@ -247,6 +277,8 @@
private String mRenameSuffix;
private int mRenameBytesFrom = -1;
private int mRenameBytesTo;
+ private int mRenameNameFrom = -1;
+ private int mRenameNameTo;
private boolean mRenameBytesReverseOrder = false;
/**
@@ -312,17 +344,57 @@
* @return self for chaining
*/
@NonNull
- public Builder setRename(@NonNull String prefix, @NonNull String suffix,
+ public Builder setRenameFromBytes(@NonNull String prefix, @NonNull String suffix,
int bytesFrom, int bytesTo, boolean bytesReverseOrder) {
- checkNotUsed();
- checkArgument(TextUtils.length(prefix) >= getRenamePrefixLengthLimit(),
- "Prefix is too short");
- mRenamePrefix = prefix;
- mRenameSuffix = suffix;
- checkArgument(bytesFrom < bytesTo, "Byte range must be non-empty");
+ checkRenameNotSet();
+ checkRangeNotEmpty(bytesFrom, bytesTo);
mRenameBytesFrom = bytesFrom;
mRenameBytesTo = bytesTo;
mRenameBytesReverseOrder = bytesReverseOrder;
+ return setRename(prefix, suffix);
+ }
+
+ /**
+ * Rename the devices shown in the list, using specific characters from the advertised name,
+ * as well as a custom prefix/suffix around them
+ *
+ * Note that the prefix length is limited to {@link #getRenamePrefixLengthLimit} characters
+ * to ensure that there's enough space to display the byte data
+ *
+ * The range of name characters to be displayed cannot be empty
+ *
+ * @param prefix to be displayed before the byte data
+ * @param suffix to be displayed after the byte data
+ * @param nameFrom the start name character index to be displayed (inclusive)
+ * @param nameTo the end name character index to be displayed (exclusive)
+ * @return self for chaining
+ */
+ @NonNull
+ public Builder setRenameFromName(@NonNull String prefix, @NonNull String suffix,
+ int nameFrom, int nameTo) {
+ checkRenameNotSet();
+ checkRangeNotEmpty(nameFrom, nameTo);
+ mRenameNameFrom = nameFrom;
+ mRenameNameTo = nameTo;
+ mRenameBytesReverseOrder = false;
+ return setRename(prefix, suffix);
+ }
+
+ private void checkRenameNotSet() {
+ checkState(mRenamePrefix == null, "Renaming rule can only be set once");
+ }
+
+ private void checkRangeNotEmpty(int bytesFrom, int bytesTo) {
+ checkArgument(bytesFrom < bytesTo, "Range must be non-empty");
+ }
+
+ @NonNull
+ private Builder setRename(@NonNull String prefix, @NonNull String suffix) {
+ checkNotUsed();
+ checkArgument(TextUtils.length(prefix) <= getRenamePrefixLengthLimit(),
+ "Prefix is too long");
+ mRenamePrefix = prefix;
+ mRenameSuffix = suffix;
return this;
}
@@ -334,7 +406,9 @@
return new BluetoothLEDeviceFilter(mNamePattern, mScanFilter,
mRawDataFilter, mRawDataFilterMask,
mRenamePrefix, mRenameSuffix,
- mRenameBytesFrom, mRenameBytesTo, mRenameBytesReverseOrder);
+ mRenameBytesFrom, mRenameBytesTo,
+ mRenameNameFrom, mRenameNameTo,
+ mRenameBytesReverseOrder);
}
}
}
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 4d788e7..e50b2a9 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -22,11 +22,13 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PendingIntent;
+import android.content.ComponentName;
import android.content.Context;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.RemoteException;
+import android.service.notification.NotificationListenerService;
import android.util.Log;
import java.util.Collections;
@@ -195,22 +197,47 @@
}
}
- /** @hide */
- public void requestNotificationAccess() {
+ /**
+ * Request notification access for the given component.
+ *
+ * The given component must follow the protocol specified in {@link NotificationListenerService}
+ *
+ * Only components from the same {@link ComponentName#getPackageName package} as the calling app
+ * are allowed.
+ *
+ * Your app must have an association with a device before calling this API
+ */
+ public void requestNotificationAccess(ComponentName component) {
if (!checkFeaturePresent()) {
return;
}
- //TODO implement
- throw new UnsupportedOperationException("Not yet implemented");
+ try {
+ mService.requestNotificationAccess(component).send();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } catch (PendingIntent.CanceledException e) {
+ throw new RuntimeException(e);
+ }
}
- /** @hide */
- public boolean haveNotificationAccess() {
+ /**
+ * Check whether the given component can access the notifications via a
+ * {@link NotificationListenerService}
+ *
+ * Your app must have an association with a device before calling this API
+ *
+ * @param component the name of the component
+ * @return whether the given component has the notification listener permission
+ */
+ public boolean hasNotificationAccess(ComponentName component) {
if (!checkFeaturePresent()) {
return false;
}
- //TODO implement
- throw new UnsupportedOperationException("Not yet implemented");
+ try {
+ return mService.hasNotificationAccess(component);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
private boolean checkFeaturePresent() {
diff --git a/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl b/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl
index 6bbb58da..5f73e55 100644
--- a/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl
+++ b/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl
@@ -19,4 +19,5 @@
/** @hide */
interface ICompanionDeviceDiscoveryServiceCallback {
oneway void onDeviceSelected(String packageName, int userId, String deviceAddress);
+ oneway void onDeviceSelectionCancel();
}
diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl
index 7798406..d395208 100644
--- a/core/java/android/companion/ICompanionDeviceManager.aidl
+++ b/core/java/android/companion/ICompanionDeviceManager.aidl
@@ -16,8 +16,10 @@
package android.companion;
+import android.app.PendingIntent;
import android.companion.IFindDeviceCallback;
import android.companion.AssociationRequest;
+import android.content.ComponentName;
/**
* Interface for communication with the core companion device manager service.
@@ -32,7 +34,6 @@
List<String> getAssociations(String callingPackage, int userId);
void disassociate(String deviceMacAddress, String callingPackage);
- //TODO add these
-// boolean haveNotificationAccess(String packageName);
-// oneway void requestNotificationAccess(String packageName);
+ boolean hasNotificationAccess(in ComponentName component);
+ PendingIntent requestNotificationAccess(in ComponentName component);
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 0da4f8d..5ca4fa3 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3424,8 +3424,10 @@
/**
* Deprecated - use ACTION_FACTORY_RESET instead.
+ * @hide
*/
@Deprecated
+ @SystemApi
public static final String ACTION_MASTER_CLEAR = "android.intent.action.MASTER_CLEAR";
/**
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index 7fea4a2..ce7894f 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -32,7 +32,7 @@
*
* <p>Valid lengths for this key are {128, 192, 256}.
*/
- public static final String ALGO_CRYPT_AES_CBC = "cbc(aes)";
+ public static final String CRYPT_AES_CBC = "cbc(aes)";
/**
* MD5 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in new
@@ -40,7 +40,7 @@
*
* <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 128.
*/
- public static final String ALGO_AUTH_HMAC_MD5 = "hmac(md5)";
+ public static final String AUTH_HMAC_MD5 = "hmac(md5)";
/**
* SHA1 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in
@@ -48,35 +48,35 @@
*
* <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 160.
*/
- public static final String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)";
+ public static final String AUTH_HMAC_SHA1 = "hmac(sha1)";
/**
* SHA256 HMAC Authentication/Integrity Algorithm.
*
* <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 256.
*/
- public static final String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)";
+ public static final String AUTH_HMAC_SHA256 = "hmac(sha256)";
/**
* SHA384 HMAC Authentication/Integrity Algorithm.
*
* <p>Valid truncation lengths are multiples of 8 bits from 192 to (default) 384.
*/
- public static final String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)";
+ public static final String AUTH_HMAC_SHA384 = "hmac(sha384)";
/**
* SHA512 HMAC Authentication/Integrity Algorithm
*
* <p>Valid truncation lengths are multiples of 8 bits from 256 to (default) 512.
*/
- public static final String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)";
+ public static final String AUTH_HMAC_SHA512 = "hmac(sha512)";
/** @hide */
@StringDef({
- ALGO_CRYPT_AES_CBC,
- ALGO_AUTH_HMAC_MD5,
- ALGO_AUTH_HMAC_SHA1,
- ALGO_AUTH_HMAC_SHA256,
- ALGO_AUTH_HMAC_SHA512
+ CRYPT_AES_CBC,
+ AUTH_HMAC_MD5,
+ AUTH_HMAC_SHA1,
+ AUTH_HMAC_SHA256,
+ AUTH_HMAC_SHA512
})
@Retention(RetentionPolicy.SOURCE)
public @interface AlgorithmName {}
@@ -164,17 +164,17 @@
private static boolean isTruncationLengthValid(String algo, int truncLenBits) {
switch (algo) {
- case ALGO_CRYPT_AES_CBC:
+ case CRYPT_AES_CBC:
return (truncLenBits == 128 || truncLenBits == 192 || truncLenBits == 256);
- case ALGO_AUTH_HMAC_MD5:
+ case AUTH_HMAC_MD5:
return (truncLenBits >= 96 && truncLenBits <= 128);
- case ALGO_AUTH_HMAC_SHA1:
+ case AUTH_HMAC_SHA1:
return (truncLenBits >= 96 && truncLenBits <= 160);
- case ALGO_AUTH_HMAC_SHA256:
+ case AUTH_HMAC_SHA256:
return (truncLenBits >= 96 && truncLenBits <= 256);
- case ALGO_AUTH_HMAC_SHA384:
+ case AUTH_HMAC_SHA384:
return (truncLenBits >= 192 && truncLenBits <= 384);
- case ALGO_AUTH_HMAC_SHA512:
+ case AUTH_HMAC_SHA512:
return (truncLenBits >= 256 && truncLenBits <= 512);
default:
return false;
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index 6852beb..f8702e2 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -193,15 +193,44 @@
*
* @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT}
* @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress.
- * @param requestedSpi the requested SPI, or '0' to allocate a random SPI.
* @return the reserved SecurityParameterIndex
* @throws ResourceUnavailableException indicating that too many SPIs are currently allocated
* for this user
* @throws SpiUnavailableException indicating that a particular SPI cannot be reserved
*/
public SecurityParameterIndex reserveSecurityParameterIndex(
+ int direction, InetAddress remoteAddress)
+ throws ResourceUnavailableException {
+ try {
+ return new SecurityParameterIndex(
+ mService,
+ direction,
+ remoteAddress,
+ IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
+ } catch (SpiUnavailableException unlikely) {
+ throw new ResourceUnavailableException("No SPIs available");
+ }
+ }
+
+ /**
+ * Reserve an SPI for traffic bound towards the specified remote address.
+ *
+ * <p>If successful, this SPI is guaranteed available until released by a call to {@link
+ * SecurityParameterIndex#close()}.
+ *
+ * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT}
+ * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress.
+ * @param requestedSpi the requested SPI, or '0' to allocate a random SPI.
+ * @return the reserved SecurityParameterIndex
+ * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated
+ * for this user
+ */
+ public SecurityParameterIndex reserveSecurityParameterIndex(
int direction, InetAddress remoteAddress, int requestedSpi)
throws SpiUnavailableException, ResourceUnavailableException {
+ if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) {
+ throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI");
+ }
return new SecurityParameterIndex(mService, direction, remoteAddress, requestedSpi);
}
@@ -249,6 +278,23 @@
}
/**
+ * Apply an active Transport Mode IPsec Transform to a stream socket to perform IPsec
+ * encapsulation of the traffic flowing between the socket and the remote InetAddress of that
+ * transform. For security reasons, attempts to send traffic to any IP address other than the
+ * address associated with that transform will throw an IOException. In addition, if the
+ * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to
+ * send() or receive() until the transform is removed from the socket by calling {@link
+ * #removeTransportModeTransform(Socket, IpSecTransform)};
+ *
+ * @param socket a socket file descriptor
+ * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
+ */
+ public void applyTransportModeTransform(FileDescriptor socket, IpSecTransform transform)
+ throws IOException {
+ applyTransportModeTransform(new ParcelFileDescriptor(socket), transform);
+ }
+
+ /**
* Apply an active Tunnel Mode IPsec Transform to a network, which will tunnel all traffic to
* and from that network's interface with IPsec (applies an outer IP header and IPsec Header to
* all traffic, and expects an additional IP header and IPsec Header on all inbound traffic).
@@ -289,6 +335,20 @@
removeTransportModeTransform(ParcelFileDescriptor.fromDatagramSocket(socket), transform);
}
+ /**
+ * Remove a transform from a given stream socket. Once removed, traffic on the socket will not
+ * be encypted. This allows sockets that have been used for IPsec to be reclaimed for
+ * communication in the clear in the event socket reuse is desired. This operation will succeed
+ * regardless of the underlying state of a transform. If a transform is removed, communication
+ * on all sockets to which that transform was applied will fail until this method is called.
+ *
+ * @param socket a socket file descriptor that previously had a transform applied to it.
+ * @param transform the IPsec Transform that was previously applied to the given socket
+ */
+ public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform) {
+ removeTransportModeTransform(new ParcelFileDescriptor(socket), transform);
+ }
+
/* Call down to activate a transform */
private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {
try {
diff --git a/core/java/android/net/MatchAllNetworkSpecifier.java b/core/java/android/net/MatchAllNetworkSpecifier.java
new file mode 100644
index 0000000..7aafc93
--- /dev/null
+++ b/core/java/android/net/MatchAllNetworkSpecifier.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * MatchAllNetworkSpecifier is a marker class used by NetworkFactory classes to indicate
+ * that they accept (match) any network specifier in requests.
+ *
+ * The class must never be used as part of a network request (those semantics aren't specified).
+ *
+ * @hide
+ */
+public final class MatchAllNetworkSpecifier extends NetworkSpecifier implements Parcelable {
+ /**
+ * Utility method which verifies that the ns argument is not a MatchAllNetworkSpecifier and
+ * throws an IllegalArgumentException if it is.
+ */
+ public static void checkNotMatchAllNetworkSpecifier(NetworkSpecifier ns) {
+ if (ns instanceof MatchAllNetworkSpecifier) {
+ throw new IllegalArgumentException("A MatchAllNetworkSpecifier is not permitted");
+ }
+ }
+
+ public boolean satisfiedBy(NetworkSpecifier other) {
+ /*
+ * The method is called by a NetworkRequest to see if it is satisfied by a proposed
+ * network (e.g. as offered by a network factory). Since MatchAllNetweorkSpecifier must
+ * not be used in network requests this method should never be called.
+ */
+ throw new IllegalStateException(
+ "MatchAllNetworkSpecifier must not be used in NetworkRequests");
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof MatchAllNetworkSpecifier;
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ // Nothing to write.
+ }
+
+ public static final Parcelable.Creator<MatchAllNetworkSpecifier> CREATOR =
+ new Parcelable.Creator<MatchAllNetworkSpecifier>() {
+ public MatchAllNetworkSpecifier createFromParcel(Parcel in) {
+ return new MatchAllNetworkSpecifier();
+ }
+ public MatchAllNetworkSpecifier[] newArray(int size) {
+ return new MatchAllNetworkSpecifier[size];
+ }
+ };
+}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index a594bef..afca0b0 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -18,9 +18,11 @@
import android.os.Parcel;
import android.os.Parcelable;
-import android.text.TextUtils;
+
import com.android.internal.util.BitUtils;
+import java.util.Objects;
+
/**
* This class represents the capabilities of a network. This is used both to specify
* needs to {@link ConnectivityManager} and when inspecting a network.
@@ -33,6 +35,8 @@
* all cellular based connections are metered and all Wi-Fi based connections are not.
*/
public final class NetworkCapabilities implements Parcelable {
+ private static final String TAG = "NetworkCapabilities";
+
/**
* @hide
*/
@@ -205,19 +209,6 @@
(1 << NET_CAPABILITY_FOREGROUND);
/**
- * Network specifier for factories which want to match any network specifier
- * (NS) in a request. Behavior:
- * <li>Empty NS in request matches any network factory NS</li>
- * <li>Empty NS in the network factory NS only matches a request with an
- * empty NS</li>
- * <li>"*" (this constant) NS in the network factory matches requests with
- * any NS</li>
- *
- * @hide
- */
- public static final String MATCH_ALL_REQUESTS_NETWORK_SPECIFIER = "*";
-
- /**
* Network capabilities that are not allowed in NetworkRequests. This exists because the
* NetworkFactory / NetworkAgent model does not deal well with the situation where a
* capability's presence cannot be known in advance. If such a capability is requested, then we
@@ -579,63 +570,56 @@
this.mLinkDownBandwidthKbps == nc.mLinkDownBandwidthKbps);
}
- private String mNetworkSpecifier;
+ private NetworkSpecifier mNetworkSpecifier = null;
+
/**
* Sets the optional bearer specific network specifier.
* This has no meaning if a single transport is also not specified, so calling
* this without a single transport set will generate an exception, as will
* subsequently adding or removing transports after this is set.
* </p>
- * The interpretation of this {@code String} is bearer specific and bearers that use
- * it should document their particulars. For example, Bluetooth may use some sort of
- * device id while WiFi could used SSID and/or BSSID. Cellular may use carrier SPN (name)
- * or Subscription ID.
*
- * @param networkSpecifier An {@code String} of opaque format used to specify the bearer
- * specific network specifier where the bearer has a choice of
- * networks.
+ * @param networkSpecifier A concrete, parcelable framework class that extends
+ * NetworkSpecifier.
* @return This NetworkCapabilities instance, to facilitate chaining.
* @hide
*/
- public NetworkCapabilities setNetworkSpecifier(String networkSpecifier) {
- if (TextUtils.isEmpty(networkSpecifier) == false && Long.bitCount(mTransportTypes) != 1) {
+ public NetworkCapabilities setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
+ if (networkSpecifier != null && Long.bitCount(mTransportTypes) != 1) {
throw new IllegalStateException("Must have a single transport specified to use " +
"setNetworkSpecifier");
}
+
mNetworkSpecifier = networkSpecifier;
+
return this;
}
/**
* Gets the optional bearer specific network specifier.
*
- * @return The optional {@code String} specifying the bearer specific network specifier.
- * See {@link #setNetworkSpecifier}.
+ * @return The optional {@link NetworkSpecifier} specifying the bearer specific network
+ * specifier. See {@link #setNetworkSpecifier}.
* @hide
*/
- public String getNetworkSpecifier() {
+ public NetworkSpecifier getNetworkSpecifier() {
return mNetworkSpecifier;
}
private void combineSpecifiers(NetworkCapabilities nc) {
- String otherSpecifier = nc.getNetworkSpecifier();
- if (TextUtils.isEmpty(otherSpecifier)) return;
- if (TextUtils.isEmpty(mNetworkSpecifier) == false) {
+ if (mNetworkSpecifier != null && !mNetworkSpecifier.equals(nc.mNetworkSpecifier)) {
throw new IllegalStateException("Can't combine two networkSpecifiers");
}
- setNetworkSpecifier(otherSpecifier);
+ setNetworkSpecifier(nc.mNetworkSpecifier);
}
+
private boolean satisfiedBySpecifier(NetworkCapabilities nc) {
- return (TextUtils.isEmpty(mNetworkSpecifier) ||
- mNetworkSpecifier.equals(nc.mNetworkSpecifier) ||
- MATCH_ALL_REQUESTS_NETWORK_SPECIFIER.equals(nc.mNetworkSpecifier));
+ return mNetworkSpecifier == null || mNetworkSpecifier.satisfiedBy(nc.mNetworkSpecifier)
+ || nc.mNetworkSpecifier instanceof MatchAllNetworkSpecifier;
}
+
private boolean equalsSpecifier(NetworkCapabilities nc) {
- if (TextUtils.isEmpty(mNetworkSpecifier)) {
- return TextUtils.isEmpty(nc.mNetworkSpecifier);
- } else {
- return mNetworkSpecifier.equals(nc.mNetworkSpecifier);
- }
+ return Objects.equals(mNetworkSpecifier, nc.mNetworkSpecifier);
}
/**
@@ -797,7 +781,7 @@
((int)(mTransportTypes >> 32) * 7) +
(mLinkUpBandwidthKbps * 11) +
(mLinkDownBandwidthKbps * 13) +
- (TextUtils.isEmpty(mNetworkSpecifier) ? 0 : mNetworkSpecifier.hashCode() * 17) +
+ Objects.hashCode(mNetworkSpecifier) * 17 +
(mSignalStrength * 19));
}
@@ -811,7 +795,7 @@
dest.writeLong(mTransportTypes);
dest.writeInt(mLinkUpBandwidthKbps);
dest.writeInt(mLinkDownBandwidthKbps);
- dest.writeString(mNetworkSpecifier);
+ dest.writeParcelable((Parcelable) mNetworkSpecifier, flags);
dest.writeInt(mSignalStrength);
}
@@ -825,7 +809,7 @@
netCap.mTransportTypes = in.readLong();
netCap.mLinkUpBandwidthKbps = in.readInt();
netCap.mLinkDownBandwidthKbps = in.readInt();
- netCap.mNetworkSpecifier = in.readString();
+ netCap.mNetworkSpecifier = in.readParcelable(null);
netCap.mSignalStrength = in.readInt();
return netCap;
}
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index cb78009..95a8bb4 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -18,6 +18,7 @@
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import java.util.Objects;
@@ -259,10 +260,27 @@
* networks.
*/
public Builder setNetworkSpecifier(String networkSpecifier) {
- if (NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER.equals(networkSpecifier)) {
- throw new IllegalArgumentException("Invalid network specifier - must not be '"
- + NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER + "'");
- }
+ /*
+ * A StringNetworkSpecifier does not accept null or empty ("") strings. When network
+ * specifiers were strings a null string and an empty string were considered equivalent.
+ * Hence no meaning is attached to a null or empty ("") string.
+ */
+ return setNetworkSpecifier(TextUtils.isEmpty(networkSpecifier) ? null
+ : new StringNetworkSpecifier(networkSpecifier));
+ }
+
+ /**
+ * Sets the optional bearer specific network specifier.
+ * This has no meaning if a single transport is also not specified, so calling
+ * this without a single transport set will generate an exception, as will
+ * subsequently adding or removing transports after this is set.
+ * </p>
+ *
+ * @param networkSpecifier A concrete, parcelable framework class that extends
+ * NetworkSpecifier.
+ */
+ public Builder setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
+ MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(networkSpecifier);
mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
return this;
}
diff --git a/core/java/android/net/NetworkSpecifier.java b/core/java/android/net/NetworkSpecifier.java
new file mode 100644
index 0000000..87a2b05
--- /dev/null
+++ b/core/java/android/net/NetworkSpecifier.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+/**
+ * Describes specific properties of a network for use in a {@link NetworkRequest}.
+ *
+ * Applications cannot instantiate this class by themselves, but can obtain instances of
+ * subclasses of this class via other APIs.
+ */
+public abstract class NetworkSpecifier {
+ /** @hide */
+ public NetworkSpecifier() {}
+
+ /**
+ * Returns true if a request with this {@link NetworkSpecifier} is satisfied by a network
+ * with the given NetworkSpecifier.
+ *
+ * @hide
+ */
+ public abstract boolean satisfiedBy(NetworkSpecifier other);
+}
diff --git a/core/java/android/net/StringNetworkSpecifier.java b/core/java/android/net/StringNetworkSpecifier.java
new file mode 100644
index 0000000..cb7f6bf
--- /dev/null
+++ b/core/java/android/net/StringNetworkSpecifier.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
+
+/** @hide */
+public final class StringNetworkSpecifier extends NetworkSpecifier implements Parcelable {
+ /**
+ * Arbitrary string used to pass (additional) information to the network factory.
+ */
+ public final String specifier;
+
+ public StringNetworkSpecifier(String specifier) {
+ Preconditions.checkStringNotEmpty(specifier);
+ this.specifier = specifier;
+ }
+
+ @Override
+ public boolean satisfiedBy(NetworkSpecifier other) {
+ return equals(other);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof StringNetworkSpecifier)) return false;
+ return TextUtils.equals(specifier, ((StringNetworkSpecifier) o).specifier);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(specifier);
+ }
+
+ @Override
+ public String toString() {
+ return specifier;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(specifier);
+ }
+
+ public static final Parcelable.Creator<StringNetworkSpecifier> CREATOR =
+ new Parcelable.Creator<StringNetworkSpecifier>() {
+ public StringNetworkSpecifier createFromParcel(Parcel in) {
+ return new StringNetworkSpecifier(in.readString());
+ }
+ public StringNetworkSpecifier[] newArray(int size) {
+ return new StringNetworkSpecifier[size];
+ }
+ };
+}
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 15bd175..ff0bc69 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -16,9 +16,15 @@
package android.os;
+import android.util.ExceptionUtils;
import android.util.Log;
import android.util.Slog;
+
import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.FunctionalUtils;
+import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
+import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
+
import libcore.io.IoUtils;
import java.io.FileDescriptor;
@@ -26,7 +32,6 @@
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.lang.reflect.Modifier;
-import java.util.function.Supplier;
/**
* Base class for a remotable object, the core part of a lightweight
@@ -251,14 +256,23 @@
* Convenience method for running the provided action enclosed in
* {@link #clearCallingIdentity}/{@link #restoreCallingIdentity}
*
+ * Any exception thrown by the given action will be caught and rethrown after the call to
+ * {@link #restoreCallingIdentity}
+ *
* @hide
*/
- public static final void withCleanCallingIdentity(Runnable action) {
+ public static final void withCleanCallingIdentity(ThrowingRunnable action) {
long callingIdentity = clearCallingIdentity();
+ Throwable throwableToPropagate = null;
try {
action.run();
+ } catch (Throwable throwable) {
+ throwableToPropagate = throwable;
} finally {
restoreCallingIdentity(callingIdentity);
+ if (throwableToPropagate != null) {
+ throw ExceptionUtils.propagate(throwableToPropagate);
+ }
}
}
@@ -266,14 +280,24 @@
* Convenience method for running the provided action enclosed in
* {@link #clearCallingIdentity}/{@link #restoreCallingIdentity} returning the result
*
+ * Any exception thrown by the given action will be caught and rethrown after the call to
+ * {@link #restoreCallingIdentity}
+ *
* @hide
*/
- public static final <T> T withCleanCallingIdentity(Supplier<T> action) {
+ public static final <T> T withCleanCallingIdentity(ThrowingSupplier<T> action) {
long callingIdentity = clearCallingIdentity();
+ Throwable throwableToPropagate = null;
try {
return action.get();
+ } catch (Throwable throwable) {
+ throwableToPropagate = throwable;
+ return null; // overridden by throwing in finally block
} finally {
restoreCallingIdentity(callingIdentity);
+ if (throwableToPropagate != null) {
+ throw ExceptionUtils.propagate(throwableToPropagate);
+ }
}
}
diff --git a/core/java/android/provider/SettingsStringUtil.java b/core/java/android/provider/SettingsStringUtil.java
index 3dfedea..a3dc947 100644
--- a/core/java/android/provider/SettingsStringUtil.java
+++ b/core/java/android/provider/SettingsStringUtil.java
@@ -23,6 +23,7 @@
import com.android.internal.util.ArrayUtils;
+import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.function.Function;
@@ -80,6 +81,12 @@
return s;
}
+ public static String addAll(String delimitedElements, Collection<String> elements) {
+ final ColonDelimitedSet<String> set
+ = new ColonDelimitedSet.OfStrings(delimitedElements);
+ return set.addAll(elements) ? set.toString() : delimitedElements;
+ }
+
public static String add(String delimitedElements, String element) {
final ColonDelimitedSet<String> set
= new ColonDelimitedSet.OfStrings(delimitedElements);
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index a4d3fb2..5e49b8f 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -34,6 +34,8 @@
import com.android.internal.os.SomeArgs;
+import java.util.List;
+
//TODO(b/33197203): improve javadoc (of both class and methods); in particular, make sure the
//life-cycle (and how state could be maintained on server-side) is well documented.
@@ -103,24 +105,22 @@
}
@Override
- public void onFillRequest(AssistStructure structure, Bundle extras,
- IFillCallback callback, int flags) {
+ public void onFillRequest(FillRequest request, IFillCallback callback) {
ICancellationSignal transport = CancellationSignal.createTransport();
try {
callback.onCancellable(transport);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
- mHandlerCaller.obtainMessageIIOOOO(MSG_ON_FILL_REQUEST, flags, UNUSED_ARG, structure,
- CancellationSignal.fromTransport(transport), extras, callback)
+ mHandlerCaller.obtainMessageOOO(MSG_ON_FILL_REQUEST, request,
+ CancellationSignal.fromTransport(transport), callback)
.sendToTarget();
}
@Override
- public void onSaveRequest(AssistStructure structure, Bundle extras,
- ISaveCallback callback) {
- mHandlerCaller.obtainMessageOOO(MSG_ON_SAVE_REQUEST, structure,
- extras, callback).sendToTarget();
+ public void onSaveRequest(SaveRequest request, ISaveCallback callback) {
+ mHandlerCaller.obtainMessageOO(MSG_ON_SAVE_REQUEST, request,
+ callback).sendToTarget();
}
};
@@ -131,23 +131,20 @@
break;
} case MSG_ON_FILL_REQUEST: {
final SomeArgs args = (SomeArgs) msg.obj;
- final AssistStructure structure = (AssistStructure) args.arg1;
+ final FillRequest request = (FillRequest) args.arg1;
final CancellationSignal cancellation = (CancellationSignal) args.arg2;
- final Bundle extras = (Bundle) args.arg3;
- final IFillCallback callback = (IFillCallback) args.arg4;
- final FillCallback fillCallback = new FillCallback(callback);
- final int flags = msg.arg1;
+ final IFillCallback callback = (IFillCallback) args.arg3;
+ final FillCallback fillCallback = new FillCallback(callback, request.getId());
args.recycle();
- onFillRequest(structure, extras, flags, cancellation, fillCallback);
+ onFillRequest(request, cancellation, fillCallback);
break;
} case MSG_ON_SAVE_REQUEST: {
final SomeArgs args = (SomeArgs) msg.obj;
- final AssistStructure structure = (AssistStructure) args.arg1;
- final Bundle extras = (Bundle) args.arg2;
- final ISaveCallback callback = (ISaveCallback) args.arg3;
+ final SaveRequest request = (SaveRequest) args.arg1;
+ final ISaveCallback callback = (ISaveCallback) args.arg2;
final SaveCallback saveCallback = new SaveCallback(callback);
args.recycle();
- onSaveRequest(structure, extras, saveCallback);
+ onSaveRequest(request, saveCallback);
break;
} case MSG_DISCONNECT: {
onDisconnected();
@@ -198,6 +195,28 @@
* or {@link FillCallback#onFailure(CharSequence)})
* to notify the result of the request.
*
+ * @param request the {@link FillRequest request} to handle.
+ * See {@link FillResponse} for examples of multiple-sections requests.
+ * @param cancellationSignal signal for observing cancellation requests. The system will use
+ * this to notify you that the fill result is no longer needed and you should stop
+ * handling this fill request in order to save resources.
+ * @param callback object used to notify the result of the request.
+ */
+ public void onFillRequest(@NonNull FillRequest request,
+ @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback) {
+ onFillRequest(request.getStructure(), request.getClientState(), request.getFlags(),
+ cancellationSignal, callback);
+ }
+
+ /**
+ * Called by the Android system do decide if an {@link Activity} can be autofilled by the
+ * service.
+ *
+ * <p>Service must call one of the {@link FillCallback} methods (like
+ * {@link FillCallback#onSuccess(FillResponse)}
+ * or {@link FillCallback#onFailure(CharSequence)})
+ * to notify the result of the request.
+ *
* @param structure {@link Activity}'s view structure.
* @param data bundle containing data passed by the service in a last call to
* {@link FillResponse.Builder#setExtras(Bundle)}, if any. This bundle allows your
@@ -211,6 +230,7 @@
* handling this fill request in order to save resources.
* @param callback object used to notify the result of the request.
*/
+ @Deprecated
public abstract void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
int flags, @NonNull CancellationSignal cancellationSignal,
@NonNull FillCallback callback);
@@ -222,6 +242,23 @@
* {@link SaveCallback#onSuccess()} or {@link SaveCallback#onFailure(CharSequence)})
* to notify the result of the request.
*
+ * @param request the {@link SaveRequest request} to handle.
+ * See {@link FillResponse} for examples of multiple-sections requests.
+ * @param callback object used to notify the result of the request.
+ */
+ public void onSaveRequest(@NonNull SaveRequest request, @NonNull SaveCallback callback) {
+ List<FillContext> contexts = request.getFillContexts();
+ onSaveRequest(contexts.get(contexts.size() - 1).getStructure(),
+ request.getClientState(), callback);
+ }
+
+ /**
+ * Called when user requests service to save the fields of an {@link Activity}.
+ *
+ * <p>Service must call one of the {@link SaveCallback} methods (like
+ * {@link SaveCallback#onSuccess()} or {@link SaveCallback#onFailure(CharSequence)})
+ * to notify the result of the request.
+ *
* @param structure {@link Activity}'s view structure.
* @param data bundle containing data passed by the service in a last call to
* {@link FillResponse.Builder#setExtras(Bundle)}, if any. This bundle allows your
@@ -231,6 +268,7 @@
* See {@link FillResponse} for examples of multiple-sections requests.
* @param callback object used to notify the result of the request.
*/
+ @Deprecated
public abstract void onSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
@NonNull SaveCallback callback);
diff --git a/core/java/android/service/autofill/FillCallback.java b/core/java/android/service/autofill/FillCallback.java
index e8ad14f..a009be8 100644
--- a/core/java/android/service/autofill/FillCallback.java
+++ b/core/java/android/service/autofill/FillCallback.java
@@ -27,11 +27,13 @@
*/
public final class FillCallback {
private final IFillCallback mCallback;
+ private final int mRequestId;
private boolean mCalled;
/** @hide */
- public FillCallback(IFillCallback callback) {
+ public FillCallback(IFillCallback callback, int requestId) {
mCallback = callback;
+ mRequestId = requestId;
}
/**
@@ -47,7 +49,7 @@
assertNotCalled();
mCalled = true;
try {
- mCallback.onSuccess(response);
+ mCallback.onSuccess(response, mRequestId);
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
diff --git a/core/java/android/service/autofill/FillContext.java b/core/java/android/service/autofill/FillContext.java
new file mode 100644
index 0000000..2efa08c
--- /dev/null
+++ b/core/java/android/service/autofill/FillContext.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import android.annotation.NonNull;
+import android.app.assist.AssistStructure;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class represents a context for each fill request made via {@link
+ * AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback)}.
+ * It contains a snapshot of the UI state, the view ids that were returned by
+ * the {@link AutofillService autofill service} as both required to trigger a save
+ * and optional that can be saved, and the id of the corresponding {@link
+ * FillRequest}.
+ * <p>
+ * This context allows you to inspect the values for the interesting views
+ * in the context they appeared. Also a reference to the corresponding fill
+ * request is useful to store meta-data in the client state bundle passed
+ * to {@link FillResponse.Builder#setClientState(Bundle)} to avoid interpreting
+ * the UI state again while saving.
+ */
+public final class FillContext implements Parcelable {
+ private final int mRequestId;
+ private final @NonNull AssistStructure mStructure;
+
+ /** @hide */
+ public FillContext(int requestId, @NonNull AssistStructure structure) {
+ mRequestId = requestId;
+ mStructure = structure;
+ }
+
+ private FillContext(Parcel parcel) {
+ this(parcel.readInt(), parcel.readParcelable(null));
+ }
+
+ /**
+ * Gets the id of the {@link FillRequest fill request} this context
+ * corresponds to. This is useful to associate your custom client
+ * state with every request to avoid reinterpreting the UI when saving
+ * user data.
+ *
+ * @return The request id.
+ */
+ public int getRequestId() {
+ return mRequestId;
+ }
+
+ /**
+ * @return The screen content.
+ */
+ public AssistStructure getStructure() {
+ return mStructure;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeInt(mRequestId);
+ parcel.writeParcelable(mStructure, flags);
+ }
+
+ public static final Parcelable.Creator<FillContext> CREATOR =
+ new Parcelable.Creator<FillContext>() {
+ @Override
+ public FillContext createFromParcel(Parcel parcel) {
+ return new FillContext(parcel);
+ }
+
+ @Override
+ public FillContext[] newArray(int size) {
+ return new FillContext[size];
+ }
+ };
+}
diff --git a/core/java/android/service/autofill/FillRequest.aidl b/core/java/android/service/autofill/FillRequest.aidl
new file mode 100644
index 0000000..2b1a8fe
--- /dev/null
+++ b/core/java/android/service/autofill/FillRequest.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+parcelable FillRequest;
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
new file mode 100644
index 0000000..aa6db4d
--- /dev/null
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.assist.AssistStructure;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.Parcel;
+import android.os.Parcelable;
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * This class represents a request to an {@link AutofillService autofill provider}
+ * to interpret the screen and provide information to the system which views are
+ * interesting for saving and what are the possible ways to fill the inputs on
+ * the screen if applicable.
+ *
+ * @see AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback)
+ */
+public final class FillRequest implements Parcelable {
+ private static AtomicInteger sIdCounter = new AtomicInteger();
+
+ /**
+ * Indicates autofill was explicitly requested by the user.
+ */
+ public static final int FLAG_MANUAL_REQUEST = 0x1;
+
+ /** @hide */
+ @IntDef(
+ flag = true,
+ value = {FLAG_MANUAL_REQUEST})
+ @Retention(RetentionPolicy.SOURCE)
+ @interface RequestFlags{}
+
+ private final int mId;
+ private final @RequestFlags int mFlags;
+ private final @NonNull AssistStructure mStructure;
+ private final @Nullable Bundle mClientState;
+
+ /** @hide */
+ public FillRequest(@NonNull AssistStructure structure,
+ @Nullable Bundle clientState, @RequestFlags int flags) {
+ this(sIdCounter.incrementAndGet(), structure, clientState, flags);
+ }
+
+ private FillRequest(@NonNull Parcel parcel) {
+ mId = parcel.readInt();
+ mStructure = parcel.readParcelable(null);
+ mClientState = parcel.readBundle();
+ mFlags = parcel.readInt();
+ }
+
+ private FillRequest(int id, @NonNull AssistStructure structure,
+ @Nullable Bundle clientState, @RequestFlags int flags) {
+ mId = id;
+ mFlags = Preconditions.checkFlagsArgument(flags, FLAG_MANUAL_REQUEST);
+ mStructure = Preconditions.checkNotNull(structure, "structure");
+ mClientState = clientState;
+ }
+
+ /**
+ * @return The unique id of this request.
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * @return The flags associated with this request.
+ *
+ * @see #FLAG_MANUAL_REQUEST
+ */
+ public @RequestFlags int getFlags() {
+ return mFlags;
+ }
+
+ /**
+ * @return The structure capturing the UI state.
+ */
+ public @NonNull AssistStructure getStructure() {
+ return mStructure;
+ }
+
+ /**
+ * Gets the extra client state returned from the last {@link
+ * AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback)
+ * fill request}.
+ * <p>
+ * Once a {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)
+ * save request} is made the client state is cleared.
+ *
+ * @return The client state.
+ */
+ public @Nullable Bundle getClientState() {
+ return mClientState;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeInt(mId);
+ parcel.writeParcelable(mStructure, flags);
+ parcel.writeBundle(mClientState);
+ parcel.writeInt(mFlags);
+ }
+
+ public static final Parcelable.Creator<FillRequest> CREATOR =
+ new Parcelable.Creator<FillRequest>() {
+ @Override
+ public FillRequest createFromParcel(Parcel parcel) {
+ return new FillRequest(parcel);
+ }
+
+ @Override
+ public FillRequest[] newArray(int size) {
+ return new FillRequest[size];
+ }
+ };
+}
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index eab0d4c..8c8060a 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -132,25 +132,25 @@
*/
public final class FillResponse implements Parcelable {
- private final ArrayList<Dataset> mDatasets;
- private final SaveInfo mSaveInfo;
- private final Bundle mExtras;
- private final RemoteViews mPresentation;
- private final IntentSender mAuthentication;
- private AutofillId[] mAuthenticationIds;
+ private final @Nullable ArrayList<Dataset> mDatasets;
+ private final @Nullable SaveInfo mSaveInfo;
+ private final @Nullable Bundle mClientState;
+ private final @Nullable RemoteViews mPresentation;
+ private final @Nullable IntentSender mAuthentication;
+ private final @Nullable AutofillId[] mAuthenticationIds;
private FillResponse(@NonNull Builder builder) {
mDatasets = builder.mDatasets;
mSaveInfo = builder.mSaveInfo;
- mExtras = builder.mExtras;
+ mClientState = builder.mCLientState;
mPresentation = builder.mPresentation;
mAuthentication = builder.mAuthentication;
mAuthenticationIds = builder.mAuthenticationIds;
}
/** @hide */
- public @Nullable Bundle getExtras() {
- return mExtras;
+ public @Nullable Bundle getClientState() {
+ return mClientState;
}
/** @hide */
@@ -185,7 +185,7 @@
public static final class Builder {
private ArrayList<Dataset> mDatasets;
private SaveInfo mSaveInfo;
- private Bundle mExtras;
+ private Bundle mCLientState;
private RemoteViews mPresentation;
private IntentSender mAuthentication;
private AutofillId[] mAuthenticationIds;
@@ -289,23 +289,35 @@
return this;
}
+ @Deprecated
+ public Builder setExtras(@Nullable Bundle extras) {
+ throwIfDestroyed();
+ mCLientState = extras;
+ return this;
+ }
+
/**
- * Sets a {@link Bundle} that will be passed to subsequent APIs that
+ * Sets a {@link Bundle state} that will be passed to subsequent APIs that
* manipulate this response. For example, they are passed to subsequent
* calls to {@link AutofillService#onFillRequest(
* android.app.assist.AssistStructure, Bundle, int,
* android.os.CancellationSignal, FillCallback)} and {@link AutofillService#onSaveRequest(
- * android.app.assist.AssistStructure, Bundle, SaveCallback)}.
+ * android.app.assist.AssistStructure, Bundle, SaveCallback)}. You can use
+ * this to store intermediate state that is persistent across multiple
+ * fill requests and the subsequent save request.
*
* <p>If this method is called on multiple {@link FillResponse} objects for the same
* activity, just the latest bundle is passed back to the service.
*
- * @param extras The response extras.
+ * <p>Once a {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)
+ * save request} is made the client state is cleared.
+ *
+ * @param clientState The custom client state.
* @return This builder.
*/
- public Builder setExtras(Bundle extras) {
+ public Builder setClientState(@Nullable Bundle clientState) {
throwIfDestroyed();
- mExtras = extras;
+ mCLientState = clientState;
return this;
}
@@ -344,7 +356,7 @@
return new StringBuilder(
"FillResponse: [datasets=").append(mDatasets)
.append(", saveInfo=").append(mSaveInfo)
- .append(", hasExtras=").append(mExtras != null)
+ .append(", clientState=").append(mClientState != null)
.append(", hasPresentation=").append(mPresentation != null)
.append(", hasAuthentication=").append(mAuthentication != null)
.append(", authenticationSize=").append(mAuthenticationIds != null
@@ -365,7 +377,7 @@
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeTypedArrayList(mDatasets, flags);
parcel.writeParcelable(mSaveInfo, flags);
- parcel.writeParcelable(mExtras, flags);
+ parcel.writeParcelable(mClientState, flags);
parcel.writeParcelableArray(mAuthenticationIds, flags);
parcel.writeParcelable(mAuthentication, flags);
parcel.writeParcelable(mPresentation, flags);
diff --git a/core/java/android/service/autofill/IAutoFillService.aidl b/core/java/android/service/autofill/IAutoFillService.aidl
index a8d86ca..23a1a3f 100644
--- a/core/java/android/service/autofill/IAutoFillService.aidl
+++ b/core/java/android/service/autofill/IAutoFillService.aidl
@@ -16,10 +16,10 @@
package android.service.autofill;
-import android.app.assist.AssistStructure;
-import android.os.Bundle;
+import android.service.autofill.FillRequest;
import android.service.autofill.IFillCallback;
import android.service.autofill.ISaveCallback;
+import android.service.autofill.SaveRequest;
import com.android.internal.os.IResultReceiver;
/**
@@ -29,8 +29,6 @@
*/
oneway interface IAutoFillService {
void onConnectedStateChanged(boolean connected);
- void onFillRequest(in AssistStructure structure, in Bundle extras,
- in IFillCallback callback, int flags);
- void onSaveRequest(in AssistStructure structure, in Bundle extras,
- in ISaveCallback callback);
+ void onFillRequest(in FillRequest request, in IFillCallback callback);
+ void onSaveRequest(in SaveRequest request, in ISaveCallback callback);
}
diff --git a/core/java/android/service/autofill/IFillCallback.aidl b/core/java/android/service/autofill/IFillCallback.aidl
index 2bb3e9a..688ac84 100644
--- a/core/java/android/service/autofill/IFillCallback.aidl
+++ b/core/java/android/service/autofill/IFillCallback.aidl
@@ -27,6 +27,6 @@
*/
interface IFillCallback {
void onCancellable(in ICancellationSignal cancellation);
- void onSuccess(in FillResponse response);
+ void onSuccess(in FillResponse response, int requestId);
void onFailure(CharSequence message);
}
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 4ad0f08..258d257 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -140,7 +140,19 @@
*/
public static final int SAVE_DATA_TYPE_EMAIL_ADDRESS = 0x10;
- private final int mType;
+ /** @hide */
+ @IntDef(
+ flag = true,
+ value = {
+ SAVE_DATA_TYPE_GENERIC,
+ SAVE_DATA_TYPE_PASSWORD,
+ SAVE_DATA_TYPE_ADDRESS,
+ SAVE_DATA_TYPE_CREDIT_CARD,
+ SAVE_DATA_TYPE_EMAIL_ADDRESS})
+ @Retention(RetentionPolicy.SOURCE)
+ @interface SaveDataType{}
+
+ private final @SaveDataType int mType;
private final CharSequence mNegativeActionTitle;
private final IntentSender mNegativeActionListener;
private final AutofillId[] mRequiredIds;
@@ -177,7 +189,7 @@
}
/** @hide */
- public int getType() {
+ public @SaveDataType int getType() {
return mType;
}
@@ -191,7 +203,7 @@
*/
public static final class Builder {
- private final int mType;
+ private final @SaveDataType int mType;
private CharSequence mNegativeActionTitle;
private IntentSender mNegativeActionListener;
// TODO(b/33197203): make mRequiredIds final once addSavableIds() is gone
@@ -215,7 +227,7 @@
*
* @throws IllegalArgumentException if {@code requiredIds} is {@code null} or empty.
*/
- public Builder(int type, @NonNull AutofillId[] requiredIds) {
+ public Builder(@SaveDataType int type, @NonNull AutofillId[] requiredIds) {
if (false) {// TODO(b/33197203): re-move when clients use it
Preconditions.checkArgument(requiredIds != null && requiredIds.length > 0,
"must have at least one required id: " + Arrays.toString(requiredIds));
@@ -230,7 +242,7 @@
* // TODO(b/33197203): make sure is removed when clients migrated
*/
@Deprecated
- public Builder(int type) {
+ public Builder(@SaveDataType int type) {
this(type, null);
}
diff --git a/core/java/android/service/autofill/SaveRequest.aidl b/core/java/android/service/autofill/SaveRequest.aidl
new file mode 100644
index 0000000..7789b577
--- /dev/null
+++ b/core/java/android/service/autofill/SaveRequest.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+parcelable SaveRequest;
diff --git a/core/java/android/service/autofill/SaveRequest.java b/core/java/android/service/autofill/SaveRequest.java
new file mode 100644
index 0000000..9de9315
--- /dev/null
+++ b/core/java/android/service/autofill/SaveRequest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.Parcel;
+import android.os.Parcelable;
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class represents a request to an {@link AutofillService
+ * autofill provider} to save applicable data entered by the user.
+ *
+ * @see AutofillService#onSaveRequest(SaveRequest, SaveCallback)
+ */
+public final class SaveRequest implements Parcelable {
+ private final @NonNull ArrayList<FillContext> mFillContexts;
+ private final @Nullable Bundle mClientState;
+
+ /** @hide */
+ public SaveRequest(@NonNull ArrayList<FillContext> fillContexts,
+ @Nullable Bundle clientState) {
+ mFillContexts = Preconditions.checkNotNull(fillContexts, "fillContexts");
+ mClientState = clientState;
+ }
+
+ private SaveRequest(@NonNull Parcel parcel) {
+ this(parcel.readTypedArrayList(null), parcel.readBundle());
+ }
+
+ /**
+ * @return The contexts associated with each previous fill request.
+ */
+ public @NonNull List<FillContext> getFillContexts() {
+ return mFillContexts;
+ }
+
+ /**
+ * Gets the extra client state returned from the last {@link
+ * AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback)}
+ * fill request}.
+ *
+ * @return The client state.
+ */
+ public @Nullable Bundle getClientState() {
+ return mClientState;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeTypedArrayList(mFillContexts, flags);
+ parcel.writeBundle(mClientState);
+ }
+
+ public static final Creator<SaveRequest> CREATOR =
+ new Creator<SaveRequest>() {
+ @Override
+ public SaveRequest createFromParcel(Parcel parcel) {
+ return new SaveRequest(parcel);
+ }
+
+ @Override
+ public SaveRequest[] newArray(int size) {
+ return new SaveRequest[size];
+ }
+ };
+}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a522652..172ad8d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -109,7 +109,6 @@
import android.widget.ScrollBarDrawable;
import com.android.internal.R;
-import com.android.internal.util.Preconditions;
import com.android.internal.view.TooltipPopup;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.widget.ScrollBarUtils;
@@ -954,41 +953,6 @@
private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE};
- /** @hide */
- @IntDef({
- AUTOFILL_MODE_INHERIT,
- AUTOFILL_MODE_AUTO,
- AUTOFILL_MODE_MANUAL
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface AutofillMode {}
-
- /**
- * This view inherits the autofill state from it's parent. If there is no parent it is
- * {@link #AUTOFILL_MODE_AUTO}.
- * Use with {@link #setAutofillMode(int)} and <a href="#attr_android:autofillMode">
- * {@code android:autofillMode}.
- */
- public static final int AUTOFILL_MODE_INHERIT = 0;
-
- /**
- * Allows this view to automatically trigger an autofill request when it get focus.
- * Use with {@link #setAutofillMode(int)} and <a href="#attr_android:autofillMode">
- * {@code android:autofillMode}.
- */
- public static final int AUTOFILL_MODE_AUTO = 1;
-
- /**
- * Do not trigger an autofill request if this view is focused. The user can still force
- * an autofill request.
- * <p>This does not prevent this field from being autofilled if an autofill operation is
- * triggered from a different view.</p>
- *
- * Use with {@link #setAutofillMode(int)} and <a href="#attr_android:autofillMode">{@code
- * android:autofillMode}.
- */
- public static final int AUTOFILL_MODE_MANUAL = 2;
-
/**
* This view contains an email address.
*
@@ -2762,7 +2726,7 @@
* 1 PFLAG3_IS_AUTOFILLED
* 1 PFLAG3_FINGER_DOWN
* 1 PFLAG3_FOCUSED_BY_DEFAULT
- * 11 PFLAG3_AUTO_FILL_MODE_MASK
+ * __ unused
* 11 PFLAG3_IMPORTANT_FOR_AUTOFILL
* 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE
* 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED
@@ -2992,23 +2956,6 @@
private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000;
/**
- * Shift for the place where the autofill mode is stored in the pflags
- *
- * @see #getAutofillMode()
- * @see #setAutofillMode(int)
- */
- private static final int PFLAG3_AUTOFILL_MODE_SHIFT = 19;
-
- /**
- * Mask for autofill modes
- *
- * @see #getAutofillMode()
- * @see #setAutofillMode(int)
- */
- private static final int PFLAG3_AUTOFILL_MODE_MASK = (AUTOFILL_MODE_INHERIT
- | AUTOFILL_MODE_AUTO | AUTOFILL_MODE_MANUAL) << PFLAG3_AUTOFILL_MODE_SHIFT;
-
- /**
* Shift for the bits in {@link #mPrivateFlags3} related to the
* "importantForAutofill" attribute.
*/
@@ -5055,11 +5002,6 @@
setFocusedByDefault(a.getBoolean(attr, true));
}
break;
- case R.styleable.View_autofillMode:
- if (a.peekValue(attr) != null) {
- setAutofillMode(a.getInt(attr, AUTOFILL_MODE_INHERIT));
- }
- break;
case R.styleable.View_autofillHints:
if (a.peekValue(attr) != null) {
CharSequence[] rawHints = null;
@@ -6849,8 +6791,7 @@
}
private void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) {
- if (isAutofillable() && isAttachedToWindow()
- && getResolvedAutofillMode() == AUTOFILL_MODE_AUTO) {
+ if (isAutofillable() && isAttachedToWindow()) {
AutofillManager afm = getAutofillManager();
if (afm != null) {
if (enter && hasWindowFocus() && isFocused()) {
@@ -9159,21 +9100,6 @@
}
/**
- * Set autofill mode for the view.
- *
- * @param autofillMode One of {@link #AUTOFILL_MODE_INHERIT}, {@link #AUTOFILL_MODE_AUTO},
- * or {@link #AUTOFILL_MODE_MANUAL}.
- * @attr ref android.R.styleable#View_autofillMode
- */
- public void setAutofillMode(@AutofillMode int autofillMode) {
- Preconditions.checkArgumentInRange(autofillMode, AUTOFILL_MODE_INHERIT,
- AUTOFILL_MODE_MANUAL, "autofillMode");
-
- mPrivateFlags3 &= ~PFLAG3_AUTOFILL_MODE_MASK;
- mPrivateFlags3 |= autofillMode << PFLAG3_AUTOFILL_MODE_SHIFT;
- }
-
- /**
* Sets the hints that helps the autofill service to select the appropriate data to fill the
* view.
*
@@ -9810,48 +9736,6 @@
}
/**
- * Returns the autofill mode for this view.
- *
- * @return One of {@link #AUTOFILL_MODE_INHERIT}, {@link #AUTOFILL_MODE_AUTO}, or
- * {@link #AUTOFILL_MODE_MANUAL}.
- * @attr ref android.R.styleable#View_autofillMode
- */
- @ViewDebug.ExportedProperty(mapping = {
- @ViewDebug.IntToString(from = AUTOFILL_MODE_INHERIT, to = "AUTOFILL_MODE_INHERIT"),
- @ViewDebug.IntToString(from = AUTOFILL_MODE_AUTO, to = "AUTOFILL_MODE_AUTO"),
- @ViewDebug.IntToString(from = AUTOFILL_MODE_MANUAL, to = "AUTOFILL_MODE_MANUAL")
- })
- @AutofillMode
- public int getAutofillMode() {
- return (mPrivateFlags3 & PFLAG3_AUTOFILL_MODE_MASK) >> PFLAG3_AUTOFILL_MODE_SHIFT;
- }
-
- /**
- * Returns the resolved autofill mode for this view.
- *
- * This is the same as {@link #getAutofillMode()} but if the mode is
- * {@link #AUTOFILL_MODE_INHERIT} the parents autofill mode will be returned.
- *
- * @return One of {@link #AUTOFILL_MODE_AUTO}, or {@link #AUTOFILL_MODE_MANUAL}. If the auto-
- * fill mode can not be resolved e.g. {@link #getAutofillMode()} is
- * {@link #AUTOFILL_MODE_INHERIT} and the {@link View} is detached
- * {@link #AUTOFILL_MODE_AUTO} is returned.
- */
- public @AutofillMode int getResolvedAutofillMode() {
- @AutofillMode int autofillMode = getAutofillMode();
-
- if (autofillMode == AUTOFILL_MODE_INHERIT) {
- if (mParent == null) {
- return AUTOFILL_MODE_AUTO;
- } else {
- return mParent.getResolvedAutofillMode();
- }
- } else {
- return autofillMode;
- }
- }
-
- /**
* Find the nearest view in the specified direction that can take focus.
* This does not actually give focus to that view.
*
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index d5aab48..cc11cb8 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -659,17 +659,4 @@
* @return true if the action was consumed by this ViewParent
*/
public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle arguments);
-
- /**
- * Return the resolved autofill mode.
- *
- * @return One of {@link View#AUTOFILL_MODE_AUTO}, {@link View#AUTOFILL_MODE_MANUAL} if the
- * autofill mode can be resolved. If the autofill mode cannot be resolved
- * {@link View#AUTOFILL_MODE_AUTO}.
- *
- * @see View#getResolvedAutofillMode()
- */
- default @View.AutofillMode int getResolvedAutofillMode() {
- return View.AUTOFILL_MODE_AUTO;
- }
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 41c209c..ec6559c 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -101,7 +101,10 @@
// Public flags start from the lowest bit
/**
* Indicates autofill was explicitly requested by the user.
+ *
+ * @deprecated Use {@link android.service.autofill.FillRequest#FLAG_MANUAL_REQUEST}
*/
+ @Deprecated
public static final int FLAG_MANUAL_REQUEST = 0x1;
// Private flags start from the highest bit
@@ -760,8 +763,8 @@
}
}
- private void requestShowFillUi(IBinder windowToken, AutofillId id, int width, int height,
- Rect anchorBounds, IAutofillWindowPresenter presenter) {
+ private void requestShowFillUi(int sessionId, IBinder windowToken, AutofillId id, int width,
+ int height, Rect anchorBounds, IAutofillWindowPresenter presenter) {
final View anchor = findAchorView(windowToken, id);
if (anchor == null) {
return;
@@ -769,9 +772,15 @@
AutofillCallback callback = null;
synchronized (mLock) {
- if (getClientLocked().autofillCallbackRequestShowFillUi(anchor, width, height,
- anchorBounds, presenter) && mCallback != null) {
- callback = mCallback;
+ if (mSessionId == sessionId) {
+ AutofillClient client = getClientLocked();
+
+ if (client != null) {
+ if (client.autofillCallbackRequestShowFillUi(anchor, width, height,
+ anchorBounds, presenter) && mCallback != null) {
+ callback = mCallback;
+ }
+ }
}
}
@@ -785,6 +794,23 @@
}
}
+ private void authenticate(int sessionId, IntentSender intent, Intent fillInIntent) {
+ synchronized (mLock) {
+ if (sessionId == mSessionId) {
+ AutofillClient client = getClientLocked();
+ if (client != null) {
+ client.autofillCallbackAuthenticate(intent, fillInIntent);
+ }
+ }
+ }
+ }
+
+ private void setState(boolean enabled) {
+ synchronized (mLock) {
+ mEnabled = enabled;
+ }
+ }
+
/**
* Sets a view as autofilled if the current value is the {code targetValue}.
*
@@ -804,80 +830,92 @@
}
}
- private void handleAutofill(IBinder windowToken, List<AutofillId> ids,
+ private void autofill(int sessionId, IBinder windowToken, List<AutofillId> ids,
List<AutofillValue> values) {
- final View root = WindowManagerGlobal.getInstance().getWindowView(windowToken);
- if (root == null) {
- return;
- }
-
- final int itemCount = ids.size();
- int numApplied = 0;
- ArrayMap<View, SparseArray<AutofillValue>> virtualValues = null;
-
- for (int i = 0; i < itemCount; i++) {
- final AutofillId id = ids.get(i);
- final AutofillValue value = values.get(i);
- final int viewId = id.getViewId();
- final View view = root.findViewByAccessibilityIdTraversal(viewId);
- if (view == null) {
- Log.w(TAG, "autofill(): no View with id " + viewId);
- continue;
+ synchronized (mLock) {
+ if (sessionId != mSessionId) {
+ return;
}
- if (id.isVirtual()) {
- if (virtualValues == null) {
- // Most likely there will be just one view with virtual children.
- virtualValues = new ArrayMap<>(1);
+
+ final View root = WindowManagerGlobal.getInstance().getWindowView(windowToken);
+ if (root == null) {
+ return;
+ }
+
+ final int itemCount = ids.size();
+ int numApplied = 0;
+ ArrayMap<View, SparseArray<AutofillValue>> virtualValues = null;
+
+ for (int i = 0; i < itemCount; i++) {
+ final AutofillId id = ids.get(i);
+ final AutofillValue value = values.get(i);
+ final int viewId = id.getViewId();
+ final View view = root.findViewByAccessibilityIdTraversal(viewId);
+ if (view == null) {
+ Log.w(TAG, "autofill(): no View with id " + viewId);
+ continue;
}
- SparseArray<AutofillValue> valuesByParent = virtualValues.get(view);
- if (valuesByParent == null) {
- // We don't know the size yet, but usually it will be just a few fields...
- valuesByParent = new SparseArray<>(5);
- virtualValues.put(view, valuesByParent);
- }
- valuesByParent.put(id.getVirtualChildId(), value);
- } else {
- synchronized (mLock) {
+ if (id.isVirtual()) {
+ if (virtualValues == null) {
+ // Most likely there will be just one view with virtual children.
+ virtualValues = new ArrayMap<>(1);
+ }
+ SparseArray<AutofillValue> valuesByParent = virtualValues.get(view);
+ if (valuesByParent == null) {
+ // We don't know the size yet, but usually it will be just a few fields...
+ valuesByParent = new SparseArray<>(5);
+ virtualValues.put(view, valuesByParent);
+ }
+ valuesByParent.put(id.getVirtualChildId(), value);
+ } else {
// Mark the view as to be autofilled with 'value'
if (mLastAutofilledData == null) {
mLastAutofilledData = new ParcelableMap(itemCount - i);
}
mLastAutofilledData.put(id, value);
+
+ view.autofill(value);
+
+ // Set as autofilled if the values match now, e.g. when the value was updated
+ // synchronously.
+ // If autofill happens async, the view is set to autofilled in
+ // notifyValueChanged.
+ setAutofilledIfValuesIs(view, value);
+
+ numApplied++;
}
-
- view.autofill(value);
-
- // Set as autofilled if the values match now, e.g. when the value was updated
- // synchronously.
- // If autofill happens async, the view is set to autofilled in notifyValueChanged.
- setAutofilledIfValuesIs(view, value);
-
- numApplied++;
}
- }
- if (virtualValues != null) {
- for (int i = 0; i < virtualValues.size(); i++) {
- final View parent = virtualValues.keyAt(i);
- final SparseArray<AutofillValue> childrenValues = virtualValues.valueAt(i);
- parent.autofill(childrenValues);
- numApplied += childrenValues.size();
+ if (virtualValues != null) {
+ for (int i = 0; i < virtualValues.size(); i++) {
+ final View parent = virtualValues.keyAt(i);
+ final SparseArray<AutofillValue> childrenValues = virtualValues.valueAt(i);
+ parent.autofill(childrenValues);
+ numApplied += childrenValues.size();
+ }
}
- }
- final LogMaker log = new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_DATASET_APPLIED);
- log.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, itemCount);
- log.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_VIEWS_FILLED, numApplied);
- mMetricsLogger.write(log);
+ final LogMaker log = new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_DATASET_APPLIED);
+ log.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, itemCount);
+ log.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_VIEWS_FILLED,
+ numApplied);
+ mMetricsLogger.write(log);
+ }
}
- private void requestHideFillUi(IBinder windowToken, AutofillId id) {
+ private void requestHideFillUi(int sessionId, IBinder windowToken, AutofillId id) {
final View anchor = findAchorView(windowToken, id);
AutofillCallback callback = null;
synchronized (mLock) {
- if (getClientLocked().autofillCallbackRequestHideFillUi() && mCallback != null) {
- callback = mCallback;
+ if (mSessionId == sessionId) {
+ AutofillClient client = getClientLocked();
+
+ if (client != null) {
+ if (client.autofillCallbackRequestHideFillUi() && mCallback != null) {
+ callback = mCallback;
+ }
+ }
}
}
@@ -891,12 +929,14 @@
}
}
- private void notifyNoFillUi(IBinder windowToken, AutofillId id) {
+ private void notifyNoFillUi(int sessionId, IBinder windowToken, AutofillId id) {
final View anchor = findAchorView(windowToken, id);
- AutofillCallback callback;
+ AutofillCallback callback = null;
synchronized (mLock) {
- callback = mCallback;
+ if (mSessionId == sessionId && getClientLocked() != null) {
+ callback = mCallback;
+ }
}
if (callback != null) {
@@ -999,73 +1039,57 @@
public void setState(boolean enabled) {
final AutofillManager afm = mAfm.get();
if (afm != null) {
- afm.mContext.getMainThreadHandler().post(() -> {
- synchronized (afm.mLock) {
- afm.mEnabled = enabled;
- }
- });
+ afm.mContext.getMainThreadHandler().post(() -> afm.setState(enabled));
}
}
@Override
- public void autofill(IBinder windowToken, List<AutofillId> ids,
+ public void autofill(int sessionId, IBinder windowToken, List<AutofillId> ids,
List<AutofillValue> values) {
// TODO(b/33197203): must keep the dataset so subsequent calls pass the same
// dataset.extras to service
final AutofillManager afm = mAfm.get();
if (afm != null) {
- afm.mContext.getMainThreadHandler().post(() ->
- afm.handleAutofill(windowToken, ids, values));
+ afm.mContext.getMainThreadHandler().post(
+ () -> afm.autofill(sessionId, windowToken, ids, values));
}
}
@Override
- public void authenticate(IntentSender intent, Intent fillInIntent) {
+ public void authenticate(int sessionId, IntentSender intent, Intent fillInIntent) {
final AutofillManager afm = mAfm.get();
if (afm != null) {
- afm.mContext.getMainThreadHandler().post(() -> {
- if (afm.getClientLocked() != null) {
- afm.getClientLocked().autofillCallbackAuthenticate(intent, fillInIntent);
- }
- });
+ afm.mContext.getMainThreadHandler().post(
+ () -> afm.authenticate(sessionId, intent, fillInIntent));
}
}
@Override
- public void requestShowFillUi(IBinder windowToken, AutofillId id,
+ public void requestShowFillUi(int sessionId, IBinder windowToken, AutofillId id,
int width, int height, Rect anchorBounds, IAutofillWindowPresenter presenter) {
final AutofillManager afm = mAfm.get();
if (afm != null) {
- afm.mContext.getMainThreadHandler().post(() -> {
- if (afm.getClientLocked() != null) {
- afm.requestShowFillUi(windowToken, id, width,
- height, anchorBounds, presenter);
- }
- });
+ afm.mContext.getMainThreadHandler().post(
+ () -> afm.requestShowFillUi(sessionId, windowToken, id, width, height,
+ anchorBounds, presenter));
}
}
@Override
- public void requestHideFillUi(IBinder windowToken, AutofillId id) {
+ public void requestHideFillUi(int sessionId, IBinder windowToken, AutofillId id) {
final AutofillManager afm = mAfm.get();
if (afm != null) {
- afm.mContext.getMainThreadHandler().post(() -> {
- if (afm.getClientLocked() != null) {
- afm.requestHideFillUi(windowToken, id);
- }
- });
+ afm.mContext.getMainThreadHandler().post(
+ () -> afm.requestHideFillUi(sessionId, windowToken, id));
}
}
@Override
- public void notifyNoFillUi(IBinder windowToken, AutofillId id) {
+ public void notifyNoFillUi(int sessionId, IBinder windowToken, AutofillId id) {
final AutofillManager afm = mAfm.get();
if (afm != null) {
- afm.mContext.getMainThreadHandler().post(() -> {
- if (afm.getClientLocked() != null) {
- afm.notifyNoFillUi(windowToken, id);
- }
- });
+ afm.mContext.getMainThreadHandler().post(
+ () -> afm.notifyNoFillUi(sessionId, windowToken, id));
}
}
diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
index 176eaac..56f91ed 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -40,28 +40,29 @@
/**
* Autofills the activity with the contents of a dataset.
*/
- void autofill(in IBinder windowToken, in List<AutofillId> ids, in List<AutofillValue> values);
+ void autofill(int sessionId, in IBinder windowToken, in List<AutofillId> ids,
+ in List<AutofillValue> values);
/**
* Authenticates a fill response or a data set.
*/
- void authenticate(in IntentSender intent, in Intent fillInIntent);
+ void authenticate(int sessionId, in IntentSender intent, in Intent fillInIntent);
/**
* Requests showing the fill UI.
*/
- void requestShowFillUi(in IBinder windowToken, in AutofillId id, int width,
+ void requestShowFillUi(int sessionId, in IBinder windowToken, in AutofillId id, int width,
int height, in Rect anchorBounds, in IAutofillWindowPresenter presenter);
/**
* Requests hiding the fill UI.
*/
- void requestHideFillUi(in IBinder windowToken, in AutofillId id);
+ void requestHideFillUi(int sessionId, in IBinder windowToken, in AutofillId id);
/**
* Notifies no fill UI will be shown.
*/
- void notifyNoFillUi(in IBinder windowToken, in AutofillId id);
+ void notifyNoFillUi(int sessionId, in IBinder windowToken, in AutofillId id);
/**
* Starts the provided intent sender
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index 2f12e9b..28d9fcf 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -155,7 +155,7 @@
public static final int IME_ACTION_PREVIOUS = 0x00000007;
/**
- * Flag of {@link #imeOptions}: used to request that the IME does not update any personalized
+ * Flag of {@link #imeOptions}: used to request that the IME should not update any personalized
* data such as typing history and personalized language model based on what the user typed on
* this text editing object. Typical use cases are:
* <ul>
diff --git a/core/java/com/android/internal/app/AlertActivity.java b/core/java/com/android/internal/app/AlertActivity.java
index 35ffa71..999a908 100644
--- a/core/java/com/android/internal/app/AlertActivity.java
+++ b/core/java/com/android/internal/app/AlertActivity.java
@@ -67,10 +67,15 @@
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- event.setClassName(Dialog.class.getName());
- event.setPackageName(getPackageName());
+ return dispatchPopulateAccessibilityEvent(this, event);
+ }
- ViewGroup.LayoutParams params = getWindow().getAttributes();
+ public static boolean dispatchPopulateAccessibilityEvent(Activity act,
+ AccessibilityEvent event) {
+ event.setClassName(Dialog.class.getName());
+ event.setPackageName(act.getPackageName());
+
+ ViewGroup.LayoutParams params = act.getWindow().getAttributes();
boolean isFullScreen = (params.width == ViewGroup.LayoutParams.MATCH_PARENT) &&
(params.height == ViewGroup.LayoutParams.MATCH_PARENT);
event.setFullScreen(isFullScreen);
@@ -86,8 +91,7 @@
* @see #mAlertParams
*/
protected void setupAlert() {
- mAlertParams.apply(mAlert);
- mAlert.installContent();
+ mAlert.installContent(mAlertParams);
}
@Override
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 95c291a..46cb546 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -247,6 +247,11 @@
return false;
}
+ public void installContent(AlertParams params) {
+ params.apply(this);
+ installContent();
+ }
+
public void installContent() {
int contentView = selectContentView();
mWindow.setContentView(contentView);
diff --git a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
index cb2b019..46f47a3 100644
--- a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
+++ b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
@@ -16,6 +16,10 @@
package com.android.internal.app;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Configuration;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
@@ -57,6 +61,10 @@
private final boolean mCountryMode;
private LayoutInflater mInflater;
+ private Locale mDisplayLocale = null;
+ // used to potentially cache a modified Context that uses mDisplayLocale
+ private Context mContextOverride = null;
+
public SuggestedLocaleAdapter(Set<LocaleStore.LocaleInfo> localeOptions, boolean countryMode) {
mCountryMode = countryMode;
mLocaleOptions = new ArrayList<>(localeOptions.size());
@@ -126,6 +134,31 @@
return position;
}
+ /**
+ * Overrides the locale used to display localized labels. Setting the locale to null will reset
+ * the Adapter to use the default locale for the labels.
+ */
+ public void setDisplayLocale(@NonNull Context context, @Nullable Locale locale) {
+ if (locale == null) {
+ mDisplayLocale = null;
+ mContextOverride = null;
+ } else if (!locale.equals(mDisplayLocale)) {
+ mDisplayLocale = locale;
+ final Configuration configOverride = new Configuration();
+ configOverride.setLocale(locale);
+ mContextOverride = context.createConfigurationContext(configOverride);
+ }
+ }
+
+ private void setTextTo(@NonNull TextView textView, int resId) {
+ if (mContextOverride == null) {
+ textView.setText(resId);
+ } else {
+ textView.setText(mContextOverride.getText(resId));
+ // If mContextOverride is not null, mDisplayLocale can't be null either.
+ }
+ }
+
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null && mInflater == null) {
@@ -143,15 +176,16 @@
}
TextView textView = (TextView) convertView;
if (itemType == TYPE_HEADER_SUGGESTED) {
- textView.setText(R.string.language_picker_section_suggested);
+ setTextTo(textView, R.string.language_picker_section_suggested);
} else {
if (mCountryMode) {
- textView.setText(R.string.region_picker_section_all);
+ setTextTo(textView, R.string.region_picker_section_all);
} else {
- textView.setText(R.string.language_picker_section_all);
+ setTextTo(textView, R.string.language_picker_section_all);
}
}
- textView.setTextLocale(Locale.getDefault());
+ textView.setTextLocale(
+ mDisplayLocale != null ? mDisplayLocale : Locale.getDefault());
break;
default:
// Covers both null, and "reusing" a wrong kind of view
diff --git a/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java b/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java
new file mode 100644
index 0000000..4ce6f60
--- /dev/null
+++ b/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.notification;
+
+import android.content.ComponentName;
+import android.content.Intent;
+
+public final class NotificationAccessConfirmationActivityContract {
+ private static final ComponentName COMPONENT_NAME = new ComponentName(
+ "com.android.settings",
+ "com.android.settings.notification.NotificationAccessConfirmationActivity");
+ public static final String EXTRA_USER_ID = "user_id";
+ public static final String EXTRA_COMPONENT_NAME = "component_name";
+ public static final String EXTRA_PACKAGE_TITLE = "package_title";
+
+ public static Intent launcherIntent(int userId, ComponentName component, String packageTitle) {
+ return new Intent()
+ .setComponent(COMPONENT_NAME)
+ .putExtra(EXTRA_USER_ID, userId)
+ .putExtra(EXTRA_COMPONENT_NAME, component)
+ .putExtra(EXTRA_PACKAGE_TITLE, packageTitle);
+ }
+}
diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java
index 287f68c..96b443d 100644
--- a/core/java/com/android/internal/util/CollectionUtils.java
+++ b/core/java/com/android/internal/util/CollectionUtils.java
@@ -16,6 +16,8 @@
package com.android.internal.util;
+import static com.android.internal.util.ArrayUtils.isEmpty;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -64,7 +66,7 @@
*/
public static @NonNull <I, O> List<O> map(@Nullable List<I> cur,
Function<? super I, ? extends O> f) {
- if (cur == null || cur.isEmpty()) return Collections.emptyList();
+ if (isEmpty(cur)) return Collections.emptyList();
final ArrayList<O> result = new ArrayList<>();
for (int i = 0; i < cur.size(); i++) {
result.add(f.apply(cur.get(i)));
@@ -73,6 +75,30 @@
}
/**
+ * {@link #map(List, Function)} + {@link #filter(List, java.util.function.Predicate)}
+ *
+ * Calling this is equivalent (but more memory efficient) to:
+ *
+ * {@code
+ * filter(
+ * map(cur, f),
+ * i -> { i != null })
+ * }
+ */
+ public static @NonNull <I, O> List<O> mapNotNull(@Nullable List<I> cur,
+ Function<? super I, ? extends O> f) {
+ if (isEmpty(cur)) return Collections.emptyList();
+ final ArrayList<O> result = new ArrayList<>();
+ for (int i = 0; i < cur.size(); i++) {
+ O transformed = f.apply(cur.get(i));
+ if (transformed != null) {
+ result.add(transformed);
+ }
+ }
+ return result;
+ }
+
+ /**
* Returns the given list, or an immutable empty list if the provided list is null
*
* This can be used to guaranty null-safety without paying the price of extra allocations
@@ -94,7 +120,7 @@
* Returns the elements of the given list that are of type {@code c}
*/
public static @NonNull <T> List<T> filter(@Nullable List<?> list, Class<T> c) {
- if (ArrayUtils.isEmpty(list)) return Collections.emptyList();
+ if (isEmpty(list)) return Collections.emptyList();
ArrayList<T> result = null;
for (int i = 0; i < list.size(); i++) {
final Object item = list.get(i);
@@ -120,11 +146,42 @@
*/
public static @Nullable <T> T find(@Nullable List<T> items,
java.util.function.Predicate<T> predicate) {
- if (ArrayUtils.isEmpty(items)) return null;
+ if (isEmpty(items)) return null;
for (int i = 0; i < items.size(); i++) {
final T item = items.get(i);
if (predicate.test(item)) return item;
}
return null;
}
+
+ /**
+ * Similar to {@link List#add}, but with support for list values of {@code null} and
+ * {@link Collections#emptyList}
+ */
+ public static @NonNull <T> List<T> add(@Nullable List<T> cur, T val) {
+ if (cur == null || cur == Collections.emptyList()) {
+ cur = new ArrayList<>();
+ }
+ cur.add(val);
+ return cur;
+ }
+
+ /**
+ * Similar to {@link List#remove}, but with support for list values of {@code null} and
+ * {@link Collections#emptyList}
+ */
+ public static @NonNull <T> List<T> remove(@Nullable List<T> cur, T val) {
+ if (isEmpty(cur)) {
+ return emptyIfNull(cur);
+ }
+ cur.remove(val);
+ return cur;
+ }
+
+ /**
+ * @return a list that will not be affected by mutations to the given original list.
+ */
+ public static @NonNull <T> List<T> copyOf(@Nullable List<T> cur) {
+ return isEmpty(cur) ? Collections.emptyList() : new ArrayList<>(cur);
+ }
}
diff --git a/core/java/com/android/internal/util/FunctionalUtils.java b/core/java/com/android/internal/util/FunctionalUtils.java
new file mode 100644
index 0000000..9aeb041
--- /dev/null
+++ b/core/java/com/android/internal/util/FunctionalUtils.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import java.util.function.Supplier;
+
+/**
+ * Utilities specific to functional programming
+ */
+public class FunctionalUtils {
+ private FunctionalUtils() {}
+
+ /**
+ * An equivalent of {@link Runnable} that allows throwing checked exceptions
+ *
+ * This can be used to specify a lambda argument without forcing all the checked exceptions
+ * to be handled within it
+ */
+ @FunctionalInterface
+ public interface ThrowingRunnable {
+ void run() throws Exception;
+ }
+
+ /**
+ * An equivalent of {@link Supplier} that allows throwing checked exceptions
+ *
+ * This can be used to specify a lambda argument without forcing all the checked exceptions
+ * to be handled within it
+ */
+ @FunctionalInterface
+ public interface ThrowingSupplier<T> {
+ T get() throws Exception;
+ }
+}
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index 4e6857a..e5d5716 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -49,6 +49,23 @@
}
/**
+ * Ensures that an expression checking an argument is true.
+ *
+ * @param expression the expression to check
+ * @param messageTemplate a printf-style message template to use if the check fails; will
+ * be converted to a string using {@link String#format(String, Object...)}
+ * @param messageArgs arguments for {@code messageTemplate}
+ * @throws IllegalArgumentException if {@code expression} is false
+ */
+ public static void checkArgument(boolean expression,
+ final String messageTemplate,
+ final Object... messageArgs) {
+ if (!expression) {
+ throw new IllegalArgumentException(String.format(messageTemplate, messageArgs));
+ }
+ }
+
+ /**
* Ensures that an string reference passed as a parameter to the calling
* method is not empty.
*
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 3a03af6..0e67d304 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -44,14 +44,6 @@
static jmethodID gBitmap_reinitMethodID;
static jmethodID gBitmap_getAllocationByteCountMethodID;
-static jfieldID gTransferParams_aFieldID;
-static jfieldID gTransferParams_bFieldID;
-static jfieldID gTransferParams_cFieldID;
-static jfieldID gTransferParams_dFieldID;
-static jfieldID gTransferParams_eFieldID;
-static jfieldID gTransferParams_fFieldID;
-static jfieldID gTransferParams_gFieldID;
-
namespace android {
class BitmapWrapper {
@@ -742,28 +734,8 @@
if (colorType != kN32_SkColorType || xyzD50 == nullptr || transferParameters == nullptr) {
colorSpace = GraphicsJNI::colorSpaceForType(colorType);
} else {
- SkColorSpaceTransferFn p;
- p.fA = (float) env->GetDoubleField(transferParameters, gTransferParams_aFieldID);
- p.fB = (float) env->GetDoubleField(transferParameters, gTransferParams_bFieldID);
- p.fC = (float) env->GetDoubleField(transferParameters, gTransferParams_cFieldID);
- p.fD = (float) env->GetDoubleField(transferParameters, gTransferParams_dFieldID);
- p.fE = (float) env->GetDoubleField(transferParameters, gTransferParams_eFieldID);
- p.fF = (float) env->GetDoubleField(transferParameters, gTransferParams_fFieldID);
- p.fG = (float) env->GetDoubleField(transferParameters, gTransferParams_gFieldID);
-
- SkMatrix44 xyzMatrix(SkMatrix44::kIdentity_Constructor);
- jfloat* array = env->GetFloatArrayElements(xyzD50, NULL);
- xyzMatrix.setFloat(0, 0, array[0]);
- xyzMatrix.setFloat(1, 0, array[1]);
- xyzMatrix.setFloat(2, 0, array[2]);
- xyzMatrix.setFloat(0, 1, array[3]);
- xyzMatrix.setFloat(1, 1, array[4]);
- xyzMatrix.setFloat(2, 1, array[5]);
- xyzMatrix.setFloat(0, 2, array[6]);
- xyzMatrix.setFloat(1, 2, array[7]);
- xyzMatrix.setFloat(2, 2, array[8]);
- env->ReleaseFloatArrayElements(xyzD50, array, 0);
-
+ SkColorSpaceTransferFn p = GraphicsJNI::getNativeTransferParameters(env, transferParameters);
+ SkMatrix44 xyzMatrix = GraphicsJNI::getNativeXYZMatrix(env, xyzD50);
colorSpace = SkColorSpace::MakeRGB(p, xyzMatrix);
}
@@ -1635,20 +1607,6 @@
}
///////////////////////////////////////////////////////////////////////////////
-static jclass make_globalref(JNIEnv* env, const char classname[])
-{
- jclass c = env->FindClass(classname);
- SkASSERT(c);
- return (jclass) env->NewGlobalRef(c);
-}
-
-static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
- const char fieldname[], const char type[])
-{
- jfieldID id = env->GetFieldID(clazz, fieldname, type);
- SkASSERT(id);
- return id;
-}
static const JNINativeMethod gBitmapMethods[] = {
{ "nativeCreate", "([IIIIIIZ[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/Bitmap;",
@@ -1706,20 +1664,11 @@
int register_android_graphics_Bitmap(JNIEnv* env)
{
- jclass transfer_params_class = FindClassOrDie(env, "android/graphics/ColorSpace$Rgb$TransferParameters");
- gTransferParams_aFieldID = GetFieldIDOrDie(env, transfer_params_class, "a", "D");
- gTransferParams_bFieldID = GetFieldIDOrDie(env, transfer_params_class, "b", "D");
- gTransferParams_cFieldID = GetFieldIDOrDie(env, transfer_params_class, "c", "D");
- gTransferParams_dFieldID = GetFieldIDOrDie(env, transfer_params_class, "d", "D");
- gTransferParams_eFieldID = GetFieldIDOrDie(env, transfer_params_class, "e", "D");
- gTransferParams_fFieldID = GetFieldIDOrDie(env, transfer_params_class, "f", "D");
- gTransferParams_gFieldID = GetFieldIDOrDie(env, transfer_params_class, "g", "D");
-
- gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
- gBitmap_nativePtr = getFieldIDCheck(env, gBitmap_class, "mNativePtr", "J");
- gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
- gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V");
- gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I");
+ gBitmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap"));
+ gBitmap_nativePtr = GetFieldIDOrDie(env, gBitmap_class, "mNativePtr", "J");
+ gBitmap_constructorMethodID = GetMethodIDOrDie(env, gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
+ gBitmap_reinitMethodID = GetMethodIDOrDie(env, gBitmap_class, "reinit", "(IIZ)V");
+ gBitmap_getAllocationByteCountMethodID = GetMethodIDOrDie(env, gBitmap_class, "getAllocationByteCount", "()I");
return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
NELEM(gBitmapMethods));
}
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index a38acd3..e714671 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -27,6 +27,7 @@
jfieldID gOptions_justBoundsFieldID;
jfieldID gOptions_sampleSizeFieldID;
jfieldID gOptions_configFieldID;
+jfieldID gOptions_colorSpaceFieldID;
jfieldID gOptions_premultipliedFieldID;
jfieldID gOptions_mutableFieldID;
jfieldID gOptions_ditherFieldID;
@@ -51,20 +52,6 @@
jclass gBitmapConfig_class;
jmethodID gBitmapConfig_nativeToConfigMethodID;
-jclass gColorSpace_class;
-jmethodID gColorSpace_getMethodID;
-jmethodID gColorSpace_matchMethodID;
-
-jclass gColorSpaceRGB_class;
-jmethodID gColorSpaceRGB_constructorMethodID;
-
-jclass gColorSpace_Named_class;
-jfieldID gColorSpace_Named_sRGBFieldID;
-jfieldID gColorSpace_Named_LinearExtendedSRGBFieldID;
-
-jclass gTransferParameters_class;
-jmethodID gTransferParameters_constructorMethodID;
-
using namespace android;
jstring encodedFormatToString(JNIEnv* env, SkEncodedImageFormat format) {
@@ -243,70 +230,6 @@
needsFineScale(fullSize.height(), decodedSize.height(), sampleSize);
}
-static jobject getColorSpace(JNIEnv* env,
- sk_sp<SkColorSpace>& decodeColorSpace, SkColorType decodeColorType) {
- jobject colorSpace = nullptr;
-
- // No need to match, we know what the output color space will be
- if (decodeColorType == kRGBA_F16_SkColorType) {
- jobject linearExtendedSRGB = env->GetStaticObjectField(
- gColorSpace_Named_class, gColorSpace_Named_LinearExtendedSRGBFieldID);
- colorSpace = env->CallStaticObjectMethod(gColorSpace_class,
- gColorSpace_getMethodID, linearExtendedSRGB);
- } else {
- // Same here, no need to match
- if (decodeColorSpace->isSRGB()) {
- jobject sRGB = env->GetStaticObjectField(
- gColorSpace_Named_class, gColorSpace_Named_sRGBFieldID);
- colorSpace = env->CallStaticObjectMethod(gColorSpace_class,
- gColorSpace_getMethodID, sRGB);
- } else if (decodeColorSpace.get() != nullptr) {
- // Try to match against known RGB color spaces using the CIE XYZ D50
- // conversion matrix and numerical transfer function parameters
- SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor);
- LOG_ALWAYS_FATAL_IF(!decodeColorSpace->toXYZD50(&xyzMatrix));
-
- SkColorSpaceTransferFn transferParams;
- // We can only handle numerical transfer functions at the moment
- LOG_ALWAYS_FATAL_IF(!decodeColorSpace->isNumericalTransferFn(&transferParams));
-
- jobject params = env->NewObject(gTransferParameters_class,
- gTransferParameters_constructorMethodID,
- transferParams.fA, transferParams.fB, transferParams.fC,
- transferParams.fD, transferParams.fE, transferParams.fF,
- transferParams.fG);
-
- jfloatArray xyzArray = env->NewFloatArray(9);
- jfloat xyz[9] = {
- xyzMatrix.getFloat(0, 0),
- xyzMatrix.getFloat(1, 0),
- xyzMatrix.getFloat(2, 0),
- xyzMatrix.getFloat(0, 1),
- xyzMatrix.getFloat(1, 1),
- xyzMatrix.getFloat(2, 1),
- xyzMatrix.getFloat(0, 2),
- xyzMatrix.getFloat(1, 2),
- xyzMatrix.getFloat(2, 2)
- };
- env->SetFloatArrayRegion(xyzArray, 0, 9, xyz);
-
- colorSpace = env->CallStaticObjectMethod(gColorSpace_class,
- gColorSpace_matchMethodID, xyzArray, params);
-
- if (colorSpace == nullptr) {
- // We couldn't find an exact match, let's create a new color space
- // instance with the 3x3 conversion matrix and transfer function
- colorSpace = env->NewObject(gColorSpaceRGB_class,
- gColorSpaceRGB_constructorMethodID,
- env->NewStringUTF("Unknown"), xyzArray, params);
- }
-
- env->DeleteLocalRef(xyzArray);
- }
- }
- return colorSpace;
-}
-
static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding, jobject options) {
// This function takes ownership of the input stream. Since the SkAndroidCodec
// will take ownership of the stream, we don't necessarily need to take ownership
@@ -323,6 +246,7 @@
float scale = 1.0f;
bool requireUnpremultiplied = false;
jobject javaBitmap = NULL;
+ sk_sp<SkColorSpace> prefColorSpace = nullptr;
// Update with options supplied by the client.
if (options != NULL) {
@@ -346,6 +270,8 @@
jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
prefColorType = GraphicsJNI::getNativeBitmapColorType(env, jconfig);
+ jobject jcolorSpace = env->GetObjectField(options, gOptions_colorSpaceFieldID);
+ prefColorSpace = GraphicsJNI::getNativeColorSpace(env, jcolorSpace);
isHardware = GraphicsJNI::isHardwareConfig(env, jconfig);
isMutable = env->GetBooleanField(options, gOptions_mutableFieldID);
requireUnpremultiplied = !env->GetBooleanField(options, gOptions_premultipliedFieldID);
@@ -399,7 +325,8 @@
// Set the decode colorType
SkColorType decodeColorType = codec->computeOutputColorType(prefColorType);
- sk_sp<SkColorSpace> decodeColorSpace = codec->computeOutputColorSpace(decodeColorType);
+ sk_sp<SkColorSpace> decodeColorSpace = codec->computeOutputColorSpace(
+ decodeColorType, prefColorSpace);
// Set the options and return if the client only wants the size.
if (options != NULL) {
@@ -427,7 +354,7 @@
env->SetObjectField(options, gOptions_outConfigFieldID, config);
env->SetObjectField(options, gOptions_outColorSpaceFieldID,
- getColorSpace(env, decodeColorSpace, decodeColorType));
+ GraphicsJNI::getColorSpace(env, decodeColorSpace, decodeColorType));
if (onlyDecodeSize) {
return nullptr;
@@ -795,6 +722,8 @@
gOptions_sampleSizeFieldID = GetFieldIDOrDie(env, options_class, "inSampleSize", "I");
gOptions_configFieldID = GetFieldIDOrDie(env, options_class, "inPreferredConfig",
"Landroid/graphics/Bitmap$Config;");
+ gOptions_colorSpaceFieldID = GetFieldIDOrDie(env, options_class, "inPreferredColorSpace",
+ "Landroid/graphics/ColorSpace;");
gOptions_premultipliedFieldID = GetFieldIDOrDie(env, options_class, "inPremultiplied", "Z");
gOptions_mutableFieldID = GetFieldIDOrDie(env, options_class, "inMutable", "Z");
gOptions_ditherFieldID = GetFieldIDOrDie(env, options_class, "inDither", "Z");
@@ -827,29 +756,6 @@
gBitmapConfig_nativeToConfigMethodID = GetStaticMethodIDOrDie(env, gBitmapConfig_class,
"nativeToConfig", "(I)Landroid/graphics/Bitmap$Config;");
- gColorSpace_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ColorSpace"));
- gColorSpace_getMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class,
- "get", "(Landroid/graphics/ColorSpace$Named;)Landroid/graphics/ColorSpace;");
- gColorSpace_matchMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class, "match",
- "([FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/ColorSpace;");
-
- gColorSpaceRGB_class = MakeGlobalRefOrDie(env,
- FindClassOrDie(env, "android/graphics/ColorSpace$Rgb"));
- gColorSpaceRGB_constructorMethodID = GetMethodIDOrDie(env, gColorSpaceRGB_class,
- "<init>", "(Ljava/lang/String;[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)V");
-
- gColorSpace_Named_class = MakeGlobalRefOrDie(env,
- FindClassOrDie(env, "android/graphics/ColorSpace$Named"));
- gColorSpace_Named_sRGBFieldID = GetStaticFieldIDOrDie(env,
- gColorSpace_Named_class, "SRGB", "Landroid/graphics/ColorSpace$Named;");
- gColorSpace_Named_LinearExtendedSRGBFieldID = GetStaticFieldIDOrDie(env,
- gColorSpace_Named_class, "LINEAR_EXTENDED_SRGB", "Landroid/graphics/ColorSpace$Named;");
-
- gTransferParameters_class = MakeGlobalRefOrDie(env, FindClassOrDie(env,
- "android/graphics/ColorSpace$Rgb$TransferParameters"));
- gTransferParameters_constructorMethodID = GetMethodIDOrDie(env, gTransferParameters_class,
- "<init>", "(DDDDDDD)V");
-
return android::RegisterMethodsOrDie(env, "android/graphics/BitmapFactory",
gMethods, NELEM(gMethods));
}
diff --git a/core/jni/android/graphics/BitmapFactory.h b/core/jni/android/graphics/BitmapFactory.h
index 76db41d..1ee49fa 100644
--- a/core/jni/android/graphics/BitmapFactory.h
+++ b/core/jni/android/graphics/BitmapFactory.h
@@ -8,6 +8,7 @@
extern jfieldID gOptions_justBoundsFieldID;
extern jfieldID gOptions_sampleSizeFieldID;
extern jfieldID gOptions_configFieldID;
+extern jfieldID gOptions_colorSpaceFieldID;
extern jfieldID gOptions_premultipliedFieldID;
extern jfieldID gOptions_ditherFieldID;
extern jfieldID gOptions_purgeableFieldID;
@@ -17,9 +18,14 @@
extern jfieldID gOptions_widthFieldID;
extern jfieldID gOptions_heightFieldID;
extern jfieldID gOptions_mimeFieldID;
+extern jfieldID gOptions_outConfigFieldID;
+extern jfieldID gOptions_outColorSpaceFieldID;
extern jfieldID gOptions_mCancelID;
extern jfieldID gOptions_bitmapFieldID;
+extern jclass gBitmapConfig_class;
+extern jmethodID gBitmapConfig_nativeToConfigMethodID;
+
jstring encodedFormatToString(JNIEnv* env, SkEncodedImageFormat format);
jobject decodeBitmap(JNIEnv* env, void* data, size_t size);
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index 3247851..5022b22 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -132,11 +132,14 @@
bool requireUnpremul = false;
jobject javaBitmap = NULL;
bool isHardware = false;
+ sk_sp<SkColorSpace> colorSpace = nullptr;
// Update the default options with any options supplied by the client.
if (NULL != options) {
sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
colorType = GraphicsJNI::getNativeBitmapColorType(env, jconfig);
+ jobject jcolorSpace = env->GetObjectField(options, gOptions_colorSpaceFieldID);
+ colorSpace = GraphicsJNI::getNativeColorSpace(env, jcolorSpace);
isHardware = GraphicsJNI::isHardwareConfig(env, jconfig);
requireUnpremul = !env->GetBooleanField(options, gOptions_premultipliedFieldID);
javaBitmap = env->GetObjectField(options, gOptions_bitmapFieldID);
@@ -148,8 +151,16 @@
env->SetIntField(options, gOptions_widthFieldID, -1);
env->SetIntField(options, gOptions_heightFieldID, -1);
env->SetObjectField(options, gOptions_mimeFieldID, 0);
+ env->SetObjectField(options, gOptions_outConfigFieldID, 0);
+ env->SetObjectField(options, gOptions_outColorSpaceFieldID, 0);
}
+ SkBitmapRegionDecoder* brd = reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle);
+
+ SkColorType decodeColorType = brd->computeOutputColorType(colorType);
+ sk_sp<SkColorSpace> decodeColorSpace = brd->computeOutputColorSpace(
+ decodeColorType, colorSpace);
+
// Recycle a bitmap if possible.
android::Bitmap* recycledBitmap = nullptr;
size_t recycledBytes = 0;
@@ -168,17 +179,16 @@
if (javaBitmap) {
allocator = &recycleAlloc;
// We are required to match the color type of the recycled bitmap.
- colorType = recycledBitmap->info().colorType();
+ decodeColorType = recycledBitmap->info().colorType();
} else {
allocator = &heapAlloc;
}
// Decode the region.
SkIRect subset = SkIRect::MakeXYWH(inputX, inputY, inputWidth, inputHeight);
- SkBitmapRegionDecoder* brd =
- reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle);
SkBitmap bitmap;
- if (!brd->decodeRegion(&bitmap, allocator, subset, sampleSize, colorType, requireUnpremul)) {
+ if (!brd->decodeRegion(&bitmap, allocator, subset, sampleSize,
+ decodeColorType, requireUnpremul, decodeColorSpace)) {
return nullObjectReturn("Failed to decode region.");
}
@@ -186,11 +196,23 @@
if (NULL != options) {
env->SetIntField(options, gOptions_widthFieldID, bitmap.width());
env->SetIntField(options, gOptions_heightFieldID, bitmap.height());
+
env->SetObjectField(options, gOptions_mimeFieldID,
encodedFormatToString(env, (SkEncodedImageFormat)brd->getEncodedFormat()));
if (env->ExceptionCheck()) {
return nullObjectReturn("OOM in encodedFormatToString()");
}
+
+ jint configID = GraphicsJNI::colorTypeToLegacyBitmapConfig(decodeColorType);
+ if (isHardware) {
+ configID = GraphicsJNI::kHardware_LegacyBitmapConfig;
+ }
+ jobject config = env->CallStaticObjectMethod(gBitmapConfig_class,
+ gBitmapConfig_nativeToConfigMethodID, configID);
+ env->SetObjectField(options, gOptions_outConfigFieldID, config);
+
+ env->SetObjectField(options, gOptions_outColorSpaceFieldID,
+ GraphicsJNI::getColorSpace(env, decodeColorSpace, decodeColorType));
}
// If we may have reused a bitmap, we need to indicate that the pixels have changed.
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index e66587a..452d0a9 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -6,6 +6,7 @@
#include "jni.h"
#include "JNIHelp.h"
#include "GraphicsJNI.h"
+#include "core_jni_helpers.h"
#include "SkCanvas.h"
#include "SkMath.h"
@@ -17,6 +18,8 @@
#include <Caches.h>
#include <TextureCache.h>
+using namespace android;
+
void doThrowNPE(JNIEnv* env) {
jniThrowNullPointerException(env, NULL);
}
@@ -178,6 +181,32 @@
static jmethodID gVMRuntime_newNonMovableArray;
static jmethodID gVMRuntime_addressOf;
+static jfieldID gTransferParams_aFieldID;
+static jfieldID gTransferParams_bFieldID;
+static jfieldID gTransferParams_cFieldID;
+static jfieldID gTransferParams_dFieldID;
+static jfieldID gTransferParams_eFieldID;
+static jfieldID gTransferParams_fFieldID;
+static jfieldID gTransferParams_gFieldID;
+
+static jclass gColorSpace_class;
+static jfieldID gColorSpace_IlluminantD50FieldID;
+static jmethodID gColorSpace_adaptMethodID;
+static jmethodID gColorSpace_getMethodID;
+static jmethodID gColorSpace_matchMethodID;
+
+static jclass gColorSpaceRGB_class;
+static jmethodID gColorSpaceRGB_getTransferParametersMethodID;
+static jmethodID gColorSpaceRGB_getTransformMethodID;
+static jmethodID gColorSpaceRGB_constructorMethodID;
+
+static jclass gColorSpace_Named_class;
+static jfieldID gColorSpace_Named_sRGBFieldID;
+static jfieldID gColorSpace_Named_LinearExtendedSRGBFieldID;
+
+static jclass gTransferParameters_class;
+static jmethodID gTransferParameters_constructorMethodID;
+
///////////////////////////////////////////////////////////////////////////////
void GraphicsJNI::get_jrect(JNIEnv* env, jobject obj, int* L, int* T, int* R, int* B)
@@ -328,7 +357,7 @@
}
void GraphicsJNI::getSkBitmap(JNIEnv* env, jobject bitmap, SkBitmap* outBitmap) {
- android::bitmap::toBitmap(env, bitmap).getSkBitmap(outBitmap);
+ bitmap::toBitmap(env, bitmap).getSkBitmap(outBitmap);
}
SkPixelRef* GraphicsJNI::refSkPixelRef(JNIEnv* env, jobject jbitmap) {
@@ -464,6 +493,125 @@
return colorSpace == nullptr || colorSpace->isSRGB();
}
+SkColorSpaceTransferFn GraphicsJNI::getNativeTransferParameters(JNIEnv* env, jobject transferParams) {
+ SkColorSpaceTransferFn p;
+ p.fA = (float) env->GetDoubleField(transferParams, gTransferParams_aFieldID);
+ p.fB = (float) env->GetDoubleField(transferParams, gTransferParams_bFieldID);
+ p.fC = (float) env->GetDoubleField(transferParams, gTransferParams_cFieldID);
+ p.fD = (float) env->GetDoubleField(transferParams, gTransferParams_dFieldID);
+ p.fE = (float) env->GetDoubleField(transferParams, gTransferParams_eFieldID);
+ p.fF = (float) env->GetDoubleField(transferParams, gTransferParams_fFieldID);
+ p.fG = (float) env->GetDoubleField(transferParams, gTransferParams_gFieldID);
+ return p;
+}
+
+SkMatrix44 GraphicsJNI::getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50) {
+ SkMatrix44 xyzMatrix(SkMatrix44::kIdentity_Constructor);
+ jfloat* array = env->GetFloatArrayElements(xyzD50, NULL);
+ xyzMatrix.setFloat(0, 0, array[0]);
+ xyzMatrix.setFloat(1, 0, array[1]);
+ xyzMatrix.setFloat(2, 0, array[2]);
+ xyzMatrix.setFloat(0, 1, array[3]);
+ xyzMatrix.setFloat(1, 1, array[4]);
+ xyzMatrix.setFloat(2, 1, array[5]);
+ xyzMatrix.setFloat(0, 2, array[6]);
+ xyzMatrix.setFloat(1, 2, array[7]);
+ xyzMatrix.setFloat(2, 2, array[8]);
+ env->ReleaseFloatArrayElements(xyzD50, array, 0);
+ return xyzMatrix;
+}
+
+sk_sp<SkColorSpace> GraphicsJNI::getNativeColorSpace(JNIEnv* env, jobject colorSpace) {
+ if (colorSpace == nullptr) return nullptr;
+ if (!env->IsInstanceOf(colorSpace, gColorSpaceRGB_class)) {
+ doThrowIAE(env, "The color space must be an RGB color space");
+ }
+
+ jobject transferParams = env->CallObjectMethod(colorSpace,
+ gColorSpaceRGB_getTransferParametersMethodID);
+ if (transferParams == nullptr) {
+ doThrowIAE(env, "The color space must use an ICC parametric transfer function");
+ }
+
+ jfloatArray illuminantD50 = (jfloatArray) env->GetStaticObjectField(gColorSpace_class,
+ gColorSpace_IlluminantD50FieldID);
+ jobject colorSpaceD50 = env->CallStaticObjectMethod(gColorSpace_class,
+ gColorSpace_adaptMethodID, colorSpace, illuminantD50);
+
+ jfloatArray xyzD50 = (jfloatArray) env->CallObjectMethod(colorSpaceD50,
+ gColorSpaceRGB_getTransformMethodID);
+
+ SkMatrix44 xyzMatrix = getNativeXYZMatrix(env, xyzD50);
+ SkColorSpaceTransferFn transferFunction = getNativeTransferParameters(env, transferParams);
+
+ return SkColorSpace::MakeRGB(transferFunction, xyzMatrix);
+}
+
+
+jobject GraphicsJNI::getColorSpace(JNIEnv* env, sk_sp<SkColorSpace>& decodeColorSpace,
+ SkColorType decodeColorType) {
+ jobject colorSpace = nullptr;
+
+ // No need to match, we know what the output color space will be
+ if (decodeColorType == kRGBA_F16_SkColorType) {
+ jobject linearExtendedSRGB = env->GetStaticObjectField(
+ gColorSpace_Named_class, gColorSpace_Named_LinearExtendedSRGBFieldID);
+ colorSpace = env->CallStaticObjectMethod(gColorSpace_class,
+ gColorSpace_getMethodID, linearExtendedSRGB);
+ } else {
+ // Same here, no need to match
+ if (decodeColorSpace->isSRGB()) {
+ jobject sRGB = env->GetStaticObjectField(
+ gColorSpace_Named_class, gColorSpace_Named_sRGBFieldID);
+ colorSpace = env->CallStaticObjectMethod(gColorSpace_class,
+ gColorSpace_getMethodID, sRGB);
+ } else if (decodeColorSpace.get() != nullptr) {
+ // Try to match against known RGB color spaces using the CIE XYZ D50
+ // conversion matrix and numerical transfer function parameters
+ SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor);
+ LOG_ALWAYS_FATAL_IF(!decodeColorSpace->toXYZD50(&xyzMatrix));
+
+ SkColorSpaceTransferFn transferParams;
+ // We can only handle numerical transfer functions at the moment
+ LOG_ALWAYS_FATAL_IF(!decodeColorSpace->isNumericalTransferFn(&transferParams));
+
+ jobject params = env->NewObject(gTransferParameters_class,
+ gTransferParameters_constructorMethodID,
+ transferParams.fA, transferParams.fB, transferParams.fC,
+ transferParams.fD, transferParams.fE, transferParams.fF,
+ transferParams.fG);
+
+ jfloatArray xyzArray = env->NewFloatArray(9);
+ jfloat xyz[9] = {
+ xyzMatrix.getFloat(0, 0),
+ xyzMatrix.getFloat(1, 0),
+ xyzMatrix.getFloat(2, 0),
+ xyzMatrix.getFloat(0, 1),
+ xyzMatrix.getFloat(1, 1),
+ xyzMatrix.getFloat(2, 1),
+ xyzMatrix.getFloat(0, 2),
+ xyzMatrix.getFloat(1, 2),
+ xyzMatrix.getFloat(2, 2)
+ };
+ env->SetFloatArrayRegion(xyzArray, 0, 9, xyz);
+
+ colorSpace = env->CallStaticObjectMethod(gColorSpace_class,
+ gColorSpace_matchMethodID, xyzArray, params);
+
+ if (colorSpace == nullptr) {
+ // We couldn't find an exact match, let's create a new color space
+ // instance with the 3x3 conversion matrix and transfer function
+ colorSpace = env->NewObject(gColorSpaceRGB_class,
+ gColorSpaceRGB_constructorMethodID,
+ env->NewStringUTF("Unknown"), xyzArray, params);
+ }
+
+ env->DeleteLocalRef(xyzArray);
+ }
+ }
+ return colorSpace;
+}
+
///////////////////////////////////////////////////////////////////////////////
bool HeapAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
mStorage = android::Bitmap::allocateHeapBitmap(bitmap, ctable);
@@ -577,74 +725,97 @@
////////////////////////////////////////////////////////////////////////////////
-static jclass make_globalref(JNIEnv* env, const char classname[])
-{
- jclass c = env->FindClass(classname);
- SkASSERT(c);
- return (jclass) env->NewGlobalRef(c);
-}
-
-static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
- const char fieldname[], const char type[])
-{
- jfieldID id = env->GetFieldID(clazz, fieldname, type);
- SkASSERT(id);
- return id;
-}
-
int register_android_graphics_Graphics(JNIEnv* env)
{
jmethodID m;
jclass c;
- gRect_class = make_globalref(env, "android/graphics/Rect");
- gRect_leftFieldID = getFieldIDCheck(env, gRect_class, "left", "I");
- gRect_topFieldID = getFieldIDCheck(env, gRect_class, "top", "I");
- gRect_rightFieldID = getFieldIDCheck(env, gRect_class, "right", "I");
- gRect_bottomFieldID = getFieldIDCheck(env, gRect_class, "bottom", "I");
+ gRect_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Rect"));
+ gRect_leftFieldID = GetFieldIDOrDie(env, gRect_class, "left", "I");
+ gRect_topFieldID = GetFieldIDOrDie(env, gRect_class, "top", "I");
+ gRect_rightFieldID = GetFieldIDOrDie(env, gRect_class, "right", "I");
+ gRect_bottomFieldID = GetFieldIDOrDie(env, gRect_class, "bottom", "I");
- gRectF_class = make_globalref(env, "android/graphics/RectF");
- gRectF_leftFieldID = getFieldIDCheck(env, gRectF_class, "left", "F");
- gRectF_topFieldID = getFieldIDCheck(env, gRectF_class, "top", "F");
- gRectF_rightFieldID = getFieldIDCheck(env, gRectF_class, "right", "F");
- gRectF_bottomFieldID = getFieldIDCheck(env, gRectF_class, "bottom", "F");
+ gRectF_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/RectF"));
+ gRectF_leftFieldID = GetFieldIDOrDie(env, gRectF_class, "left", "F");
+ gRectF_topFieldID = GetFieldIDOrDie(env, gRectF_class, "top", "F");
+ gRectF_rightFieldID = GetFieldIDOrDie(env, gRectF_class, "right", "F");
+ gRectF_bottomFieldID = GetFieldIDOrDie(env, gRectF_class, "bottom", "F");
- gPoint_class = make_globalref(env, "android/graphics/Point");
- gPoint_xFieldID = getFieldIDCheck(env, gPoint_class, "x", "I");
- gPoint_yFieldID = getFieldIDCheck(env, gPoint_class, "y", "I");
+ gPoint_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Point"));
+ gPoint_xFieldID = GetFieldIDOrDie(env, gPoint_class, "x", "I");
+ gPoint_yFieldID = GetFieldIDOrDie(env, gPoint_class, "y", "I");
- gPointF_class = make_globalref(env, "android/graphics/PointF");
- gPointF_xFieldID = getFieldIDCheck(env, gPointF_class, "x", "F");
- gPointF_yFieldID = getFieldIDCheck(env, gPointF_class, "y", "F");
+ gPointF_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/PointF"));
+ gPointF_xFieldID = GetFieldIDOrDie(env, gPointF_class, "x", "F");
+ gPointF_yFieldID = GetFieldIDOrDie(env, gPointF_class, "y", "F");
- gBitmapRegionDecoder_class = make_globalref(env, "android/graphics/BitmapRegionDecoder");
- gBitmapRegionDecoder_constructorMethodID = env->GetMethodID(gBitmapRegionDecoder_class, "<init>", "(J)V");
+ gBitmapRegionDecoder_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/BitmapRegionDecoder"));
+ gBitmapRegionDecoder_constructorMethodID = GetMethodIDOrDie(env, gBitmapRegionDecoder_class, "<init>", "(J)V");
- gBitmapConfig_class = make_globalref(env, "android/graphics/Bitmap$Config");
- gBitmapConfig_nativeInstanceID = getFieldIDCheck(env, gBitmapConfig_class,
- "nativeInt", "I");
+ gBitmapConfig_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap$Config"));
+ gBitmapConfig_nativeInstanceID = GetFieldIDOrDie(env, gBitmapConfig_class, "nativeInt", "I");
- gCanvas_class = make_globalref(env, "android/graphics/Canvas");
- gCanvas_nativeInstanceID = getFieldIDCheck(env, gCanvas_class, "mNativeCanvasWrapper", "J");
+ gCanvas_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Canvas"));
+ gCanvas_nativeInstanceID = GetFieldIDOrDie(env, gCanvas_class, "mNativeCanvasWrapper", "J");
- gPicture_class = make_globalref(env, "android/graphics/Picture");
- gPicture_nativeInstanceID = getFieldIDCheck(env, gPicture_class, "mNativePicture", "J");
+ gPicture_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Picture"));
+ gPicture_nativeInstanceID = GetFieldIDOrDie(env, gPicture_class, "mNativePicture", "J");
- gRegion_class = make_globalref(env, "android/graphics/Region");
- gRegion_nativeInstanceID = getFieldIDCheck(env, gRegion_class, "mNativeRegion", "J");
- gRegion_constructorMethodID = env->GetMethodID(gRegion_class, "<init>",
- "(JI)V");
+ gRegion_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Region"));
+ gRegion_nativeInstanceID = GetFieldIDOrDie(env, gRegion_class, "mNativeRegion", "J");
+ gRegion_constructorMethodID = GetMethodIDOrDie(env, gRegion_class, "<init>", "(JI)V");
c = env->FindClass("java/lang/Byte");
gByte_class = (jclass) env->NewGlobalRef(
env->GetStaticObjectField(c, env->GetStaticFieldID(c, "TYPE", "Ljava/lang/Class;")));
- gVMRuntime_class = make_globalref(env, "dalvik/system/VMRuntime");
+ gVMRuntime_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "dalvik/system/VMRuntime"));
m = env->GetStaticMethodID(gVMRuntime_class, "getRuntime", "()Ldalvik/system/VMRuntime;");
gVMRuntime = env->NewGlobalRef(env->CallStaticObjectMethod(gVMRuntime_class, m));
- gVMRuntime_newNonMovableArray = env->GetMethodID(gVMRuntime_class, "newNonMovableArray",
+ gVMRuntime_newNonMovableArray = GetMethodIDOrDie(env, gVMRuntime_class, "newNonMovableArray",
"(Ljava/lang/Class;I)Ljava/lang/Object;");
- gVMRuntime_addressOf = env->GetMethodID(gVMRuntime_class, "addressOf", "(Ljava/lang/Object;)J");
+ gVMRuntime_addressOf = GetMethodIDOrDie(env, gVMRuntime_class, "addressOf", "(Ljava/lang/Object;)J");
+
+ jclass transfer_params_class = FindClassOrDie(env, "android/graphics/ColorSpace$Rgb$TransferParameters");
+ gTransferParams_aFieldID = GetFieldIDOrDie(env, transfer_params_class, "a", "D");
+ gTransferParams_bFieldID = GetFieldIDOrDie(env, transfer_params_class, "b", "D");
+ gTransferParams_cFieldID = GetFieldIDOrDie(env, transfer_params_class, "c", "D");
+ gTransferParams_dFieldID = GetFieldIDOrDie(env, transfer_params_class, "d", "D");
+ gTransferParams_eFieldID = GetFieldIDOrDie(env, transfer_params_class, "e", "D");
+ gTransferParams_fFieldID = GetFieldIDOrDie(env, transfer_params_class, "f", "D");
+ gTransferParams_gFieldID = GetFieldIDOrDie(env, transfer_params_class, "g", "D");
+
+ gColorSpace_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ColorSpace"));
+ gColorSpace_IlluminantD50FieldID = GetStaticFieldIDOrDie(env,
+ gColorSpace_class, "ILLUMINANT_D50", "[F");
+ gColorSpace_adaptMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class, "adapt",
+ "(Landroid/graphics/ColorSpace;[F)Landroid/graphics/ColorSpace;");
+ gColorSpace_getMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class,
+ "get", "(Landroid/graphics/ColorSpace$Named;)Landroid/graphics/ColorSpace;");
+ gColorSpace_matchMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class, "match",
+ "([FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/ColorSpace;");
+
+ gColorSpaceRGB_class = MakeGlobalRefOrDie(env,
+ FindClassOrDie(env, "android/graphics/ColorSpace$Rgb"));
+ gColorSpaceRGB_constructorMethodID = GetMethodIDOrDie(env, gColorSpaceRGB_class,
+ "<init>", "(Ljava/lang/String;[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)V");
+ gColorSpaceRGB_getTransferParametersMethodID = GetMethodIDOrDie(env, gColorSpaceRGB_class,
+ "getTransferParameters", "()Landroid/graphics/ColorSpace$Rgb$TransferParameters;");
+ gColorSpaceRGB_getTransformMethodID = GetMethodIDOrDie(env, gColorSpaceRGB_class,
+ "getTransform", "()[F");
+
+ gColorSpace_Named_class = MakeGlobalRefOrDie(env,
+ FindClassOrDie(env, "android/graphics/ColorSpace$Named"));
+ gColorSpace_Named_sRGBFieldID = GetStaticFieldIDOrDie(env,
+ gColorSpace_Named_class, "SRGB", "Landroid/graphics/ColorSpace$Named;");
+ gColorSpace_Named_LinearExtendedSRGBFieldID = GetStaticFieldIDOrDie(env,
+ gColorSpace_Named_class, "LINEAR_EXTENDED_SRGB", "Landroid/graphics/ColorSpace$Named;");
+
+ gTransferParameters_class = MakeGlobalRefOrDie(env, FindClassOrDie(env,
+ "android/graphics/ColorSpace$Rgb$TransferParameters"));
+ gTransferParameters_constructorMethodID = GetMethodIDOrDie(env, gTransferParameters_class,
+ "<init>", "(DDDDDDD)V");
return 0;
}
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 7d7c881..7fbea25 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -10,6 +10,7 @@
#include "SkPoint.h"
#include "SkRect.h"
#include "SkColorSpace.h"
+#include "SkMatrix44.h"
#include <jni.h>
#include <hwui/Canvas.h>
#include <hwui/Bitmap.h>
@@ -112,6 +113,13 @@
static sk_sp<SkColorSpace> linearColorSpace();
static sk_sp<SkColorSpace> colorSpaceForType(SkColorType type);
static bool isColorSpaceSRGB(SkColorSpace* colorSpace);
+
+ static SkColorSpaceTransferFn getNativeTransferParameters(JNIEnv* env, jobject transferParams);
+ static SkMatrix44 getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50);
+ static sk_sp<SkColorSpace> getNativeColorSpace(JNIEnv* env, jobject colorSpace);
+
+ static jobject getColorSpace(JNIEnv* env, sk_sp<SkColorSpace>& decodeColorSpace,
+ SkColorType decodeColorType);
};
class HeapAllocator : public SkBRDAllocator {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 000c8c4..8869593 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3556,6 +3556,11 @@
android:process=":ui">
</activity>
+ <activity android:name="com.android.settings.notification.NotificationAccessConfirmationActivity"
+ android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.Alert"
+ android:excludeFromRecents="true">
+ </activity>
+
<receiver android:name="com.android.server.BootReceiver"
android:systemUserOnly="true">
<intent-filter android:priority="1000">
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 67f6d19..4fb21fa 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1371,6 +1371,22 @@
Corresponds to
{@link android.view.inputmethod.EditorInfo#IME_ACTION_PREVIOUS}. -->
<flag name="actionPrevious" value="0x00000007" />
+ <!-- Used to request that the IME should not update any personalized data such as typing
+ history and personalized language model based on what the user typed on this text
+ editing object. Typical use cases are:
+ <ul>
+ <li>When the application is in a special mode, where user's activities are expected
+ to be not recorded in the application's history. Some web browsers and chat
+ applications may have this kind of modes.</li>
+ <li>When storing typing history does not make much sense. Specifying this flag in
+ typing games may help to avoid typing history from being filled up with words that
+ the user is less likely to type in their daily life. Another example is that when
+ the application already knows that the expected input is not a valid word (e.g. a
+ promotion code that is not a valid word in any natural language).</li>
+ </ul>
+ <p>Applications need to be aware that the flag is not a guarantee, and some IMEs may
+ not respect it.</p> -->
+ <flag name="flagNoPersonalizedLearning" value="0x1000000" />
<!-- Used to request that the IME never go
into fullscreen mode. Applications need to be aware that the flag is not
a guarantee, and not all IMEs will respect it.
@@ -2304,18 +2320,7 @@
<enum name="auto" value="0x00000010" />
</attr>
- <!-- Controls the autofill behavior for this view. -->
- <attr name="autofillMode">
- <!-- Inherit the behavior from the parent. If there is no parent it is auto. This is the
- default value for this attribute.-->
- <enum name="inherit" value="0" />
- <!-- Allows this view to automatically trigger an autofill request when it get focus.
- -->
- <enum name="auto" value="1" />
- <!-- Do not trigger an autofill request when this view is focused. The user can still
- manually force an autofill request for this view. -->
- <enum name="manual" value="2" />
- </attr>
+ <attr name="__removed3" />
<!-- Describes the content of a view so that a autofill service can fill in the appropriate
data. Multiple hints can be combined in a comma separated list or an array of strings
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index d6ed178..213d6ca 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2797,7 +2797,7 @@
<public name="numericModifiers" />
<public name="fontProviderAuthority" />
<public name="fontProviderQuery" />
- <public name="autofillMode" />
+ <public name="__removed3" />
<public name="primaryContentAlpha" />
<public name="secondaryContentAlpha" />
<public name="requiredFeature" />
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 603e376..74cbe27 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -19,6 +19,9 @@
<!-- Private symbols that we need to reference from framework code. See
frameworks/base/core/res/MakeJavaSymbols.sed for how to easily generate
this.
+
+ Can be referenced in java code as: com.android.internal.R.<type>.<name>
+ and in layout xml as: "@*android:<type>/<name>"
-->
<java-symbol type="id" name="account_name" />
<java-symbol type="id" name="account_row_icon" />
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index ec653d0..7f07f03 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -40,6 +40,7 @@
<privapp-permissions package="com.android.defcontainer">
<permission name="android.permission.ACCESS_CACHE_FILESYSTEM"/>
+ <permission name="android.permission.ALLOCATE_AGGRESSIVE"/>
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.WRITE_MEDIA_STORAGE"/>
</privapp-permissions>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 91906850..7a8e487 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -916,9 +916,8 @@
* @param hasAlpha If the bitmap is ARGB_8888 or RGBA_16F this flag can be used to
* mark the bitmap as opaque. Doing so will clear the bitmap in black
* instead of transparent.
- * @param colorSpace The color space of the bitmap. If null,
- * {@link ColorSpace.Named#SRGB sRGB} is assumed. This argument is
- * ignored if the config is not {@link Config#ARGB_8888}.
+ * @param colorSpace The color space of the bitmap. If null or if the config is not
+ * {@link Config#ARGB_8888}, {@link ColorSpace.Named#SRGB sRGB} is assumed.
*
* @throws IllegalArgumentException if the width or height are <= 0, if
* Config is Config.HARDWARE (because hardware bitmaps are always
@@ -968,9 +967,8 @@
* @param hasAlpha If the bitmap is ARGB_8888 or RGBA_16F this flag can be used to
* mark the bitmap as opaque. Doing so will clear the bitmap in black
* instead of transparent.
- * @param colorSpace The color space of the bitmap. If null,
- * {@link ColorSpace.Named#SRGB sRGB} is assumed. This argument is
- * ignored if the config is not {@link Config#ARGB_8888}.
+ * @param colorSpace The color space of the bitmap. If null or if the config is not
+ * {@link Config#ARGB_8888}, {@link ColorSpace.Named#SRGB sRGB} is assumed.
*
* @throws IllegalArgumentException if the width or height are <= 0, if
* Config is Config.HARDWARE (because hardware bitmaps are always
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index ceedc1f..3b272c8 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -43,7 +43,6 @@
* the same result from the decoder as if null were passed.
*/
public Options() {
- inDither = false;
inScaled = true;
inPremultiplied = true;
}
@@ -114,8 +113,8 @@
/**
* If set to true, the decoder will return null (no bitmap), but
- * the out... fields will still be set, allowing the caller to query
- * the bitmap without having to allocate the memory for its pixels.
+ * the <code>out...</code> fields will still be set, allowing the caller to
+ * query the bitmap without having to allocate the memory for its pixels.
*/
public boolean inJustDecodeBounds;
@@ -144,6 +143,35 @@
public Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888;
/**
+ * <p>If this is non-null, the decoder will try to decode into this
+ * color space. If it is null, or the request cannot be met,
+ * the decoder will pick either the color space embedded in the image
+ * or the color space best suited for the requested image configuration
+ * (for instance {@link ColorSpace.Named#SRGB sRGB} for
+ * the {@link Bitmap.Config#ARGB_8888} configuration).</p>
+ *
+ * <p>{@link Bitmap.Config#RGBA_F16} always uses the
+ * {@link ColorSpace.Named#LINEAR_EXTENDED_SRGB scRGB} color space).
+ * Bitmaps in other configurations without an embedded color space are
+ * assumed to be in the {@link ColorSpace.Named#SRGB sRGB} color space.</p>
+ *
+ * <p class="note">Only {@link ColorSpace.Model#RGB} color spaces are
+ * currently supported. An <code>IllegalArgumentException</code> will
+ * be thrown by the decode methods when setting a non-RGB color space
+ * such as {@link ColorSpace.Named#CIE_LAB Lab}.</p>
+ *
+ * <p class="note">The specified color space's transfer function must be
+ * an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}. An
+ * <code>IllegalArgumentException</code> will be thrown by the decode methods
+ * if calling {@link ColorSpace.Rgb#getTransferParameters()} on the
+ * specified color space returns null.</p>
+ *
+ * <p>After decode, the bitmap's color space is stored in
+ * {@link #outColorSpace}.</p>
+ */
+ public ColorSpace inPreferredColorSpace = null;
+
+ /**
* If true (which is the default), the resulting bitmap will have its
* color channels pre-multipled by the alpha channel.
*
@@ -403,9 +431,22 @@
}
static void validate(Options opts) {
- if (opts != null && opts.inMutable && opts.inPreferredConfig == Bitmap.Config.HARDWARE) {
+ if (opts == null) return;
+
+ if (opts.inMutable && opts.inPreferredConfig == Bitmap.Config.HARDWARE) {
throw new IllegalArgumentException("Bitmaps with Config.HARWARE are always immutable");
}
+
+ if (opts.inPreferredColorSpace != null) {
+ if (!(opts.inPreferredColorSpace instanceof ColorSpace.Rgb)) {
+ throw new IllegalArgumentException("The destination color space must use the " +
+ "RGB color model");
+ }
+ if (((ColorSpace.Rgb) opts.inPreferredColorSpace).getTransferParameters() == null) {
+ throw new IllegalArgumentException("The destination color space must use an " +
+ "ICC parametric transfer function");
+ }
+ }
}
}
@@ -421,7 +462,9 @@
* size be returned (in opts.outWidth and opts.outHeight)
* @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
* is {@link android.graphics.Bitmap.Config#HARDWARE}
- * and {@link BitmapFactory.Options#inMutable} is set.
+ * and {@link BitmapFactory.Options#inMutable} is set, if the specified color space
+ * is not {@link ColorSpace.Model#RGB RGB}, or if the specified color space's transfer
+ * function is not an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
*/
public static Bitmap decodeFile(String pathName, Options opts) {
validate(opts);
@@ -463,7 +506,9 @@
* resources, which we pass to be able to scale the bitmap accordingly.
* @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
* is {@link android.graphics.Bitmap.Config#HARDWARE}
- * and {@link BitmapFactory.Options#inMutable} is set.
+ * and {@link BitmapFactory.Options#inMutable} is set, if the specified color space
+ * is not {@link ColorSpace.Model#RGB RGB}, or if the specified color space's transfer
+ * function is not an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
*/
public static Bitmap decodeResourceStream(Resources res, TypedValue value,
InputStream is, Rect pad, Options opts) {
@@ -501,7 +546,9 @@
* size be returned (in opts.outWidth and opts.outHeight)
* @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
* is {@link android.graphics.Bitmap.Config#HARDWARE}
- * and {@link BitmapFactory.Options#inMutable} is set.
+ * and {@link BitmapFactory.Options#inMutable} is set, if the specified color space
+ * is not {@link ColorSpace.Model#RGB RGB}, or if the specified color space's transfer
+ * function is not an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
*/
public static Bitmap decodeResource(Resources res, int id, Options opts) {
validate(opts);
@@ -559,7 +606,9 @@
* size be returned (in opts.outWidth and opts.outHeight)
* @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
* is {@link android.graphics.Bitmap.Config#HARDWARE}
- * and {@link BitmapFactory.Options#inMutable} is set.
+ * and {@link BitmapFactory.Options#inMutable} is set, if the specified color space
+ * is not {@link ColorSpace.Model#RGB RGB}, or if the specified color space's transfer
+ * function is not an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
*/
public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts) {
if ((offset | length) < 0 || data.length < offset + length) {
@@ -641,7 +690,9 @@
* size be returned (in opts.outWidth and opts.outHeight)
* @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
* is {@link android.graphics.Bitmap.Config#HARDWARE}
- * and {@link BitmapFactory.Options#inMutable} is set.
+ * and {@link BitmapFactory.Options#inMutable} is set, if the specified color space
+ * is not {@link ColorSpace.Model#RGB RGB}, or if the specified color space's transfer
+ * function is not an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
*
* <p class="note">Prior to {@link android.os.Build.VERSION_CODES#KITKAT},
* if {@link InputStream#markSupported is.markSupported()} returns true,
@@ -720,7 +771,9 @@
* @return the decoded bitmap, or null
* @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
* is {@link android.graphics.Bitmap.Config#HARDWARE}
- * and {@link BitmapFactory.Options#inMutable} is set.
+ * and {@link BitmapFactory.Options#inMutable} is set, if the specified color space
+ * is not {@link ColorSpace.Model#RGB RGB}, or if the specified color space's transfer
+ * function is not an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
*/
public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
validate(opts);
diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java
index 04abca1..2da27c7 100644
--- a/graphics/java/android/graphics/BitmapRegionDecoder.java
+++ b/graphics/java/android/graphics/BitmapRegionDecoder.java
@@ -180,7 +180,9 @@
* decoded.
* @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
* is {@link android.graphics.Bitmap.Config#HARDWARE}
- * and {@link BitmapFactory.Options#inMutable} is set.
+ * and {@link BitmapFactory.Options#inMutable} is set, if the specified color space
+ * is not {@link ColorSpace.Model#RGB RGB}, or if the specified color space's transfer
+ * function is not an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
*/
public Bitmap decodeRegion(Rect rect, BitmapFactory.Options options) {
BitmapFactory.Options.validate(options);
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
index 218b857c..8cbf921 100644
--- a/graphics/java/android/graphics/Color.java
+++ b/graphics/java/android/graphics/Color.java
@@ -538,7 +538,7 @@
/**
* Returns the value of the alpha component in the range \([0..1]\).
* Calling this method is equivalent to
- * <code>getComponent(getComponentCount())</code>.
+ * <code>getComponent(getComponentCount() - 1)</code>.
*
* @see #red()
* @see #green()
@@ -690,9 +690,8 @@
* Returns the color space encoded in the specified color long.
*
* @param color The color long whose color space to extract
- * @return A non-null color space instance. If the color long encodes
- * an unknown or invalid color space, the {@link ColorSpace.Named#SRGB sRGB}
- * color space is returned
+ * @return A non-null color space instance
+ * @throws IllegalArgumentException If the encoded color space is invalid or unknown
*
* @see #red(long)
* @see #green(long)
@@ -787,6 +786,7 @@
*
* @param color The color to test
* @return True if the color is in the sRGB color space, false otherwise
+ * @throws IllegalArgumentException If the encoded color space is invalid or unknown
*
* @see #isInColorSpace(long, ColorSpace)
* @see #isWideGamut(long)
@@ -802,6 +802,7 @@
*
* @param color The color to test
* @return True if the color is in a wide-gamut color space, false otherwise
+ * @throws IllegalArgumentException If the encoded color space is invalid or unknown
*
* @see #isInColorSpace(long, ColorSpace)
* @see #isSrgb(long)
@@ -831,6 +832,7 @@
* a color space conversion is applied if needed.
*
* @return An ARGB color in the sRGB color space
+ * @throws IllegalArgumentException If the encoded color space is invalid or unknown
*/
@ColorInt
public static int toArgb(@ColorLong long color) {
@@ -873,6 +875,7 @@
*
* @param color The color long to create a <code>Color</code> from
* @return A non-null instance of {@link Color}
+ * @throws IllegalArgumentException If the encoded color space is invalid or unknown
*/
@NonNull
public static Color valueOf(@ColorLong long color) {
@@ -1100,6 +1103,7 @@
* @param color The color long to convert
* @param colorSpace The destination color space
* @return A color long in the destination color space
+ * @throws IllegalArgumentException If the encoded color space is invalid or unknown
*/
@ColorLong
public static long convert(@ColorLong long color, @NonNull ColorSpace colorSpace) {
@@ -1206,7 +1210,7 @@
* @return A value between 0 (darkest black) and 1 (lightest white)
*
* @throws IllegalArgumentException If the specified color's color space
- * does not use the {@link ColorSpace.Model#RGB RGB} color model
+ * is unknown or does not use the {@link ColorSpace.Model#RGB RGB} color model
*/
public static float luminance(@ColorLong long color) {
ColorSpace colorSpace = colorSpace(color);
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 8f78319..67504cf 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -1338,9 +1338,8 @@
}
/**
- * <p>Returns an instance of {@link ColorSpace} whose ID matches the specified
- * ID. If the ID is < 0 or > {@link #MAX_ID}, calling this method is equivalent
- * to calling <code>get(Named.SRGB)</code>.</p>
+ * <p>Returns an instance of {@link ColorSpace} whose ID matches the
+ * specified ID.</p>
*
* <p>This method always returns the same instance for a given ID.</p>
*
@@ -1348,11 +1347,14 @@
*
* @param index An integer ID between {@link #MIN_ID} and {@link #MAX_ID}
* @return A non-null {@link ColorSpace} instance
+ * @throws IllegalArgumentException If the ID does not match the ID of one of the
+ * {@link Named named color spaces}
*/
@NonNull
static ColorSpace get(@IntRange(from = MIN_ID, to = MAX_ID) int index) {
if (index < 0 || index > Named.values().length) {
- return get(Named.SRGB);
+ throw new IllegalArgumentException("Invalid ID, must be in the range [0.." +
+ Named.values().length + "]");
}
return sNamedColorSpaces[index];
}
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 56f9cc7..97d3e5e 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -1135,6 +1135,7 @@
// Treat as system error since reaching here means that a system pre-installed font
// can't be used by our font stack.
Log.e(TAG, "Unable to load Family: " + family.getName() + ":" + family.getLanguage());
+ return null;
}
return fontFamily;
}
@@ -1160,7 +1161,10 @@
for (int i = 0; i < fontConfig.getFamilies().length; i++) {
FontConfig.Family f = fontConfig.getFamilies()[i];
if (i == 0 || f.getName() == null) {
- familyList.add(makeFamilyFromParsed(f, bufferForPath));
+ FontFamily family = makeFamilyFromParsed(f, bufferForPath);
+ if (family != null) {
+ familyList.add(family);
+ }
}
}
sFallbackFonts = familyList.toArray(new FontFamily[familyList.size()]);
@@ -1177,6 +1181,9 @@
typeface = sDefaultTypeface;
} else {
FontFamily fontFamily = makeFamilyFromParsed(f, bufferForPath);
+ if (fontFamily == null) {
+ continue;
+ }
FontFamily[] families = { fontFamily };
typeface = Typeface.createFromFamiliesWithDefault(families,
RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE);
diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
index 444705c..ece700d 100644
--- a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
+++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
@@ -100,8 +100,8 @@
int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
- Log.i(TAG, "Connected to GATT server.");
- Log.i(TAG, "Attempting to start service discovery:" +
+ Log.d(TAG, "Connected to GATT server.");
+ Log.d(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i(TAG, "Disconnected from GATT server.");
@@ -112,24 +112,24 @@
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
- List<BluetoothGattService> services = mBluetoothGatt.getServices();
- for (BluetoothGattService service : services) {
- if (MIDI_SERVICE.equals(service.getUuid())) {
- Log.d(TAG, "found MIDI_SERVICE");
- List<BluetoothGattCharacteristic> characteristics
- = service.getCharacteristics();
- for (BluetoothGattCharacteristic characteristic : characteristics) {
- if (MIDI_CHARACTERISTIC.equals(characteristic.getUuid())) {
- Log.d(TAG, "found MIDI_CHARACTERISTIC");
- mCharacteristic = characteristic;
+ BluetoothGattService service = gatt.getService(MIDI_SERVICE);
+ if (service != null) {
+ Log.d(TAG, "found MIDI_SERVICE");
+ BluetoothGattCharacteristic characteristic
+ = service.getCharacteristic(MIDI_CHARACTERISTIC);
+ if (characteristic != null) {
+ Log.d(TAG, "found MIDI_CHARACTERISTIC");
+ mCharacteristic = characteristic;
- // Specification says to read the characteristic first and then
- // switch to receiving notifications
- mBluetoothGatt.readCharacteristic(characteristic);
- break;
- }
- }
- break;
+ // Request a lower Connection Interval for better latency.
+ boolean result = gatt.requestConnectionPriority(
+ BluetoothGatt.CONNECTION_PRIORITY_HIGH);
+ Log.d(TAG, "requestConnectionPriority(CONNECTION_PRIORITY_HIGH):"
+ + result);
+
+ // Specification says to read the characteristic first and then
+ // switch to receiving notifications
+ mBluetoothGatt.readCharacteristic(characteristic);
}
}
} else {
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
index 76a64e5..b145290 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
@@ -34,6 +34,7 @@
import android.widget.TextView;
import com.android.companiondevicemanager.DeviceDiscoveryService.DeviceFilterPair;
+import com.android.internal.util.Preconditions;
public class DeviceChooserActivity extends Activity {
@@ -78,22 +79,35 @@
}
mPairButton = findViewById(R.id.button_pair);
- mPairButton.setOnClickListener((view) ->
- onPairTapped(getService().mSelectedDevice));
+ mPairButton.setOnClickListener(v -> onPairTapped(getService().mSelectedDevice));
updatePairButtonEnabled();
mCancelButton = findViewById(R.id.button_cancel);
- mCancelButton.setOnClickListener((view) -> {
- setResult(RESULT_CANCELED);
- finish();
- });
+ mCancelButton.setOnClickListener(v -> cancel());
+ }
+
+ private void cancel() {
+ getService().onCancel();
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (!isFinishing()) {
+ cancel();
+ }
}
private CharSequence getCallingAppName() {
try {
final PackageManager packageManager = getPackageManager();
+ String callingPackage = Preconditions.checkStringNotEmpty(
+ getCallingPackage(),
+ "This activity must be called for result");
return packageManager.getApplicationLabel(
- packageManager.getApplicationInfo(getCallingPackage(), 0));
+ packageManager.getApplicationInfo(callingPackage, 0));
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(e);
}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
index 1b6aca1..246bd2b 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -110,6 +110,11 @@
private final ScanCallback mBLEScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
+ if (DEBUG) {
+ Log.i(LOG_TAG,
+ "BLE.onScanResult(callbackType = " + callbackType + ", result = " + result
+ + ")");
+ }
final DeviceFilterPair<ScanResult> deviceFilterPair
= DeviceFilterPair.findMatch(result, mBLEFilters);
if (deviceFilterPair == null) return;
@@ -126,6 +131,10 @@
private BroadcastReceiver mBluetoothDeviceFoundBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ if (DEBUG) {
+ Log.i(LOG_TAG,
+ "BL.onReceive(context = " + context + ", intent = " + intent + ")");
+ }
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
final DeviceFilterPair<BluetoothDevice> deviceFilterPair
= DeviceFilterPair.findMatch(device, mBluetoothFilters);
@@ -191,7 +200,8 @@
mBLEScanFilters = CollectionUtils.map(mBLEFilters, BluetoothLEDeviceFilter::getScanFilter);
reset();
- }
+ } else if (DEBUG) Log.i(LOG_TAG, "startDiscovery: duplicate request: " + request);
+
if (!ArrayUtils.isEmpty(mDevicesFound)) {
onReadyToShowUI();
}
@@ -221,6 +231,7 @@
}
private void reset() {
+ if (DEBUG) Log.i(LOG_TAG, "reset()");
mDevicesFound.clear();
mSelectedDevice = null;
mDevicesAdapter.notifyDataSetChanged();
@@ -294,6 +305,14 @@
}
}
+ void onCancel() {
+ try {
+ mServiceCallback.onDeviceSelectionCancel();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
class DevicesAdapter extends ArrayAdapter<DeviceFilterPair> {
//TODO wifi icon
private Drawable BLUETOOTH_ICON = icon(android.R.drawable.stat_sys_data_bluetooth);
@@ -369,8 +388,15 @@
public static <T extends Parcelable> DeviceFilterPair<T> findMatch(
T dev, @Nullable List<? extends DeviceFilter<T>> filters) {
if (isEmpty(filters)) return new DeviceFilterPair<>(dev, null);
- final DeviceFilter<T> matchingFilter = CollectionUtils.find(filters, (f) -> f.matches(dev));
- return matchingFilter != null ? new DeviceFilterPair<>(dev, matchingFilter) : null;
+ final DeviceFilter<T> matchingFilter
+ = CollectionUtils.find(filters, f -> f.matches(dev));
+
+ DeviceFilterPair<T> result = matchingFilter != null
+ ? new DeviceFilterPair<>(dev, matchingFilter)
+ : null;
+ if (DEBUG) Log.i(LOG_TAG, "findMatch(dev = " + dev + ", filters = " + filters +
+ ") -> " + result);
+ return result;
}
public String getDisplayName() {
diff --git a/packages/DefaultContainerService/AndroidManifest.xml b/packages/DefaultContainerService/AndroidManifest.xml
index 55d000c..e399fb1 100644
--- a/packages/DefaultContainerService/AndroidManifest.xml
+++ b/packages/DefaultContainerService/AndroidManifest.xml
@@ -1,5 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.defcontainer" coreApp="true">
+ <uses-permission android:name="android.permission.ALLOCATE_AGGRESSIVE"/>
<uses-permission android:name="android.permission.ASEC_ACCESS"/>
<uses-permission android:name="android.permission.ASEC_CREATE"/>
<uses-permission android:name="android.permission.ASEC_DESTROY"/>
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 37a68e0..9347877 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -30,6 +30,7 @@
import android.content.pm.PackageParser.PackageParserException;
import android.content.res.ObbInfo;
import android.content.res.ObbScanner;
+import android.os.Binder;
import android.os.Environment;
import android.os.Environment.UserEnvironment;
import android.os.FileUtils;
@@ -179,6 +180,15 @@
return ret;
}
+ final int recommendedInstallLocation;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ recommendedInstallLocation = PackageHelper.resolveInstallLocation(context,
+ pkg.packageName, pkg.installLocation, sizeBytes, flags);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
ret.packageName = pkg.packageName;
ret.splitNames = pkg.splitNames;
ret.versionCode = pkg.versionCode;
@@ -186,8 +196,7 @@
ret.splitRevisionCodes = pkg.splitRevisionCodes;
ret.installLocation = pkg.installLocation;
ret.verifiers = pkg.verifiers;
- ret.recommendedInstallLocation = PackageHelper.resolveInstallLocation(context,
- pkg.packageName, pkg.installLocation, sizeBytes, flags);
+ ret.recommendedInstallLocation = recommendedInstallLocation;
ret.multiArch = pkg.multiArch;
return ret;
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_1.xml b/packages/SystemUI/res/drawable/ic_qs_signal_1.xml
deleted file mode 100644
index e055de7..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_1.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="32.0dp"
- android:height="32.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M10.0,14.6l-8.0,8.0l8.0,0.0l0,-8z"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
- android:fillAlpha="0.3"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
- android:fillColor="#FFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_2.xml b/packages/SystemUI/res/drawable/ic_qs_signal_2.xml
deleted file mode 100644
index 8a48817..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_2.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="32.0dp"
- android:height="32.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M14.0,10.6l-12.0,12.0l12.0,0.0L14.0,10.6z"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
- android:fillAlpha="0.3"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
- android:fillColor="#FFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_3.xml b/packages/SystemUI/res/drawable/ic_qs_signal_3.xml
deleted file mode 100644
index 39cc94c..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_3.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="32.0dp"
- android:height="32.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
- android:fillAlpha="0.3"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M14.1,14.1l2.9,0.0 0.0,-6.5 -15.0,15.0 12.1,0.0z"
- android:fillColor="#FFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_4.xml b/packages/SystemUI/res/drawable/ic_qs_signal_4.xml
deleted file mode 100644
index 012e95e..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_4.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="32.0dp"
- android:height="32.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
- android:fillColor="#FFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_carrier_network_change.xml b/packages/SystemUI/res/drawable/ic_qs_signal_carrier_network_change.xml
deleted file mode 100644
index 96e2fd4..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_carrier_network_change.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<!--
- Copyright (C) 2015 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="32dp"
- android:height="32dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:name="dot1"
- android:fillColor="#FFFFFFFF"
- android:pathData="M9.0,19.0l3.0,0.0l0.0,3.0l-3.0,0.0z"/>
- <path
- android:name="dot2"
- android:fillColor="#4DFFFFFF"
- android:pathData="M14.0,19.0l3.0,0.0l0.0,3.0l-3.0,0.0z"/>
- <path
- android:name="dot3"
- android:fillColor="#4DFFFFFF"
- android:pathData="M19.0,19.0l3.0,0.0l0.0,3.0l-3.0,0.0z"/>
- <path
- android:fillColor="#4DFFFFFF"
- android:pathData="M2.0,22.0l6.0,0.0 0.0,-4.0 14.0,0.0 0.0,-16.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_carrier_network_change_animation.xml b/packages/SystemUI/res/drawable/ic_qs_signal_carrier_network_change_animation.xml
deleted file mode 100644
index 2186aa8..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_carrier_network_change_animation.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
- Copyright (C) 2015 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.
--->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/ic_qs_signal_carrier_network_change" >
- <target
- android:name="dot1"
- android:animation="@anim/ic_qs_signal_blink_1"/>
- <target
- android:name="dot2"
- android:animation="@anim/ic_qs_signal_blink_2"/>
- <target
- android:name="dot3"
- android:animation="@anim/ic_qs_signal_blink_3"/>
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_full_0.xml b/packages/SystemUI/res/drawable/ic_qs_signal_full_0.xml
deleted file mode 100644
index 326373d..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_full_0.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 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:autoMirrored="true"
- android:width="32dp"
- android:height="32dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#4DFFFFFF"
- android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_full_1.xml b/packages/SystemUI/res/drawable/ic_qs_signal_full_1.xml
deleted file mode 100644
index 8baa4eb..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_full_1.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 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:autoMirrored="true"
- android:width="32dp"
- android:height="32dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#4DFFFFFF"
- android:pathData="M2.0,22.0l20.0,0.0 0.0,-20.0z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M10.1,13.9l-8.1,8.1 8.1,0.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_full_2.xml b/packages/SystemUI/res/drawable/ic_qs_signal_full_2.xml
deleted file mode 100644
index bf19a71..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_full_2.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 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:autoMirrored="true"
- android:width="32dp"
- android:height="32dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#4DFFFFFF"
- android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M14.000000,10.000000l-12.000000,12.000000 12.000000,0.000000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_full_3.xml b/packages/SystemUI/res/drawable/ic_qs_signal_full_3.xml
deleted file mode 100644
index 01839e85..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_full_3.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 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:autoMirrored="true"
- android:width="32dp"
- android:height="32dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#4DFFFFFF"
- android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M16.700001,7.300000l-14.700001,14.700000 14.700001,0.000000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_full_4.xml b/packages/SystemUI/res/drawable/ic_qs_signal_full_4.xml
deleted file mode 100644
index 48151ad..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_full_4.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 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:autoMirrored="true"
- android:width="32dp"
- android:height="32dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_0.xml b/packages/SystemUI/res/drawable/stat_sys_signal_0.xml
deleted file mode 100644
index 8bc872a..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_signal_0.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="17.0dp"
- android:height="17.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
- android:fillColor="?attr/backgroundColor"/>
- <path
- android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
- android:fillColor="?attr/fillColor"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_0_fully.xml b/packages/SystemUI/res/drawable/stat_sys_signal_0_fully.xml
deleted file mode 100644
index e267d25..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_signal_0_fully.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 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:autoMirrored="true"
- android:width="17dp"
- android:height="17dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="?attr/backgroundColor"
- android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_1.xml b/packages/SystemUI/res/drawable/stat_sys_signal_1.xml
deleted file mode 100644
index 8fa7630..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_signal_1.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="17.0dp"
- android:height="17.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M10.0,14.6l-8.0,8.0l8.0,0.0l0,-8z"
- android:fillColor="?attr/fillColor"/>
- <path
- android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
- android:fillColor="?attr/backgroundColor"/>
- <path
- android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
- android:fillColor="?attr/fillColor"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_1_fully.xml b/packages/SystemUI/res/drawable/stat_sys_signal_1_fully.xml
deleted file mode 100644
index 60822f4..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_signal_1_fully.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 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:autoMirrored="true"
- android:width="17dp"
- android:height="17dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="?attr/backgroundColor"
- android:pathData="M2.0,22.0l20.0,0.0 0.0,-20.0z"/>
- <path
- android:fillColor="?attr/fillColor"
- android:pathData="M10.1,13.9l-8.1,8.1 8.1,0.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_2.xml b/packages/SystemUI/res/drawable/stat_sys_signal_2.xml
deleted file mode 100644
index 2a660a3..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_signal_2.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="17.0dp"
- android:height="17.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M14.0,10.6l-12.0,12.0l12.0,0.0L14.0,10.6z"
- android:fillColor="?attr/fillColor"/>
- <path
- android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
- android:fillColor="?attr/backgroundColor"/>
- <path
- android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
- android:fillColor="?attr/fillColor"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_2_fully.xml b/packages/SystemUI/res/drawable/stat_sys_signal_2_fully.xml
deleted file mode 100644
index 5e68eed..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_signal_2_fully.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 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:autoMirrored="true"
- android:width="17dp"
- android:height="17dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="?attr/backgroundColor"
- android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/>
- <path
- android:fillColor="?attr/fillColor"
- android:pathData="M14.000000,10.000000l-12.000000,12.000000 12.000000,0.000000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_3.xml b/packages/SystemUI/res/drawable/stat_sys_signal_3.xml
deleted file mode 100644
index 9e0a433..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_signal_3.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="17.0dp"
- android:height="17.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
- android:fillColor="?attr/backgroundColor"/>
- <path
- android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
- android:fillColor="?attr/fillColor"/>
- <path
- android:pathData="M14.1,14.1l2.9,0.0 0.0,-6.5 -15.0,15.0 12.1,0.0z"
- android:fillColor="?attr/fillColor"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_3_fully.xml b/packages/SystemUI/res/drawable/stat_sys_signal_3_fully.xml
deleted file mode 100644
index 599b34a..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_signal_3_fully.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 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:autoMirrored="true"
- android:width="17dp"
- android:height="17dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="?attr/backgroundColor"
- android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/>
- <path
- android:fillColor="?attr/fillColor"
- android:pathData="M16.700001,7.300000l-14.700001,14.700000 14.700001,0.000000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_4.xml b/packages/SystemUI/res/drawable/stat_sys_signal_4.xml
deleted file mode 100644
index 01f6703..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_signal_4.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="17.0dp"
- android:height="17.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
- android:fillColor="?attr/fillColor"/>
- <path
- android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
- android:fillColor="?attr/fillColor"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_4_fully.xml b/packages/SystemUI/res/drawable/stat_sys_signal_4_fully.xml
deleted file mode 100644
index b66d89a..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_signal_4_fully.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 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:autoMirrored="true"
- android:width="17dp"
- android:height="17dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="?attr/singleToneColor"
- android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_carrier_network_change.xml b/packages/SystemUI/res/drawable/stat_sys_signal_carrier_network_change.xml
deleted file mode 100644
index f69ffe4..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_signal_carrier_network_change.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<!--
- Copyright (C) 2015 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="17dp"
- android:height="17dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:name="dot1"
- android:fillColor="?attr/fillColor"
- android:pathData="M9.0,19.0l3.0,0.0l0.0,3.0l-3.0,0.0z"/>
- <path
- android:name="dot2"
- android:fillColor="?attr/backgroundColor"
- android:pathData="M14.0,19.0l3.0,0.0l0.0,3.0l-3.0,0.0z"/>
- <path
- android:name="dot3"
- android:fillColor="?attr/backgroundColor"
- android:pathData="M19.0,19.0l3.0,0.0l0.0,3.0l-3.0,0.0z"/>
- <path
- android:fillColor="?attr/backgroundColor"
- android:pathData="M2.0,22.0l6.0,0.0 0.0,-4.0 14.0,0.0 0.0,-16.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_carrier_network_change_animation.xml b/packages/SystemUI/res/drawable/stat_sys_signal_carrier_network_change_animation.xml
deleted file mode 100644
index 275f037..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_signal_carrier_network_change_animation.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
- Copyright (C) 2015 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.
--->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/stat_sys_signal_carrier_network_change" >
- <target
- android:name="dot1"
- android:animation="@anim/ic_signal_blink_1"/>
- <target
- android:name="dot2"
- android:animation="@anim/ic_signal_blink_2"/>
- <target
- android:name="dot3"
- android:animation="@anim/ic_signal_blink_3"/>
-</animated-vector>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 6d8a077..9c7a6a0 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -760,4 +760,6 @@
<dimen name="default_gear_space">18dp</dimen>
<dimen name="cell_overlay_padding">18dp</dimen>
+ <dimen name="signal_icon_size">17dp</dimen>
+
</resources>
diff --git a/packages/SystemUI/res/values/styles_tv.xml b/packages/SystemUI/res/values/styles_tv.xml
index 3f0caab..0c4fd23 100644
--- a/packages/SystemUI/res/values/styles_tv.xml
+++ b/packages/SystemUI/res/values/styles_tv.xml
@@ -21,5 +21,6 @@
<style name="PipTheme" parent="@android:style/Theme.Translucent.NoTitleBar.Fullscreen">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:backgroundDimEnabled">false</item>
+ <item name="android:windowDisablePreview">true</item>
</style>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index f3fb1ef..ec56e15 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -33,6 +33,8 @@
boolean isPulsingBlocked();
void startPendingIntentDismissingKeyguard(PendingIntent intent);
+ void abortPulsing();
+ void extendPulse();
interface Callback {
default void onNotificationHeadsUp() {}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index f27521e..1cc5fb9 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -58,12 +58,15 @@
/** Pulse is done showing. Followed by transition to DOZE or DOZE_AOD. */
DOZE_PULSE_DONE,
/** Doze is done. DozeService is finished. */
- FINISH;
+ FINISH,
+ /** AOD, but the display is temporarily off. */
+ DOZE_AOD_PAUSED;
boolean canPulse() {
switch (this) {
case DOZE:
case DOZE_AOD:
+ case DOZE_AOD_PAUSED:
return true;
default:
return false;
@@ -85,6 +88,7 @@
case UNINITIALIZED:
case INITIALIZED:
case DOZE:
+ case DOZE_AOD_PAUSED:
return Display.STATE_OFF;
case DOZE_PULSING:
case DOZE_AOD:
@@ -241,6 +245,11 @@
if (mState == State.FINISH) {
return State.FINISH;
}
+ if ((mState == State.DOZE_AOD_PAUSED || mState == State.DOZE_AOD || mState == State.DOZE)
+ && requestedState == State.DOZE_PULSE_DONE) {
+ Log.i(TAG, "Dropping pulse done because current state is already done: " + mState);
+ return mState;
+ }
if (requestedState == State.DOZE_REQUEST_PULSE && !mState.canPulse()) {
Log.i(TAG, "Dropping pulse request because current state can't pulse: " + mState);
return mState;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 2ac0657..73f5222 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -22,6 +22,8 @@
import android.content.Context;
import android.database.ContentObserver;
import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.TriggerEvent;
import android.hardware.TriggerEventListener;
@@ -40,6 +42,7 @@
import java.io.PrintWriter;
import java.util.List;
+import java.util.function.Consumer;
public class DozeSensors {
@@ -55,18 +58,22 @@
private final DozeParameters mDozeParameters;
private final AmbientDisplayConfiguration mConfig;
private final WakeLock mWakeLock;
+ private final Consumer<Boolean> mProxCallback;
private final Callback mCallback;
private final Handler mHandler = new Handler();
+ private final ProxSensor mProxSensor;
public DozeSensors(Context context, SensorManager sensorManager, DozeParameters dozeParameters,
- AmbientDisplayConfiguration config, WakeLock wakeLock, Callback callback) {
+ AmbientDisplayConfiguration config, WakeLock wakeLock, Callback callback,
+ Consumer<Boolean> proxCallback) {
mContext = context;
mSensorManager = sensorManager;
mDozeParameters = dozeParameters;
mConfig = config;
mWakeLock = wakeLock;
+ mProxCallback = proxCallback;
mResolver = mContext.getContentResolver();
mSensors = new TriggerSensor[] {
@@ -86,6 +93,8 @@
true /* configured */,
DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP)
};
+
+ mProxSensor = new ProxSensor();
mCallback = callback;
}
@@ -129,6 +138,10 @@
}
}
+ public void setProxListening(boolean listen) {
+ mProxSensor.setRegistered(listen);
+ }
+
private final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
@@ -152,6 +165,43 @@
}
}
+ private class ProxSensor implements SensorEventListener {
+
+ boolean mRegistered;
+ Boolean mCurrentlyFar;
+
+ void setRegistered(boolean register) {
+ if (mRegistered == register) {
+ // Send an update even if we don't re-register.
+ mHandler.post(() -> {
+ if (mCurrentlyFar != null) {
+ mProxCallback.accept(mCurrentlyFar);
+ }
+ });
+ return;
+ }
+ if (register) {
+ mRegistered = mSensorManager.registerListener(this,
+ mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY),
+ SensorManager.SENSOR_DELAY_NORMAL, mHandler);
+ } else {
+ mSensorManager.unregisterListener(this);
+ mRegistered = false;
+ mCurrentlyFar = null;
+ }
+ }
+
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ mCurrentlyFar = event.values[0] >= event.sensor.getMaximumRange();
+ mProxCallback.accept(mCurrentlyFar);
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ }
+ }
+
private class TriggerSensor extends TriggerEventListener {
final Sensor mSensor;
final boolean mConfigured;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 1b9bf73..9b3593b 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -46,6 +46,7 @@
public class DozeTriggers implements DozeMachine.Part {
private static final String TAG = "DozeTriggers";
+ private static final boolean DEBUG = DozeService.DEBUG;
/** adb shell am broadcast -a com.android.systemui.doze.pulse com.android.systemui */
private static final String PULSE_ACTION = "com.android.systemui.doze.pulse";
@@ -81,7 +82,7 @@
mWakeLock = wakeLock;
mAllowPulseTriggers = allowPulseTriggers;
mDozeSensors = new DozeSensors(context, mSensorManager, dozeParameters, config,
- wakeLock, this::onSensor);
+ wakeLock, this::onSensor, this::onProximityFar);
mUiModeManager = mContext.getSystemService(UiModeManager.class);
}
@@ -113,6 +114,22 @@
}
}
+ private void onProximityFar(boolean far) {
+ final boolean near = !far;
+ DozeMachine.State state = mMachine.getState();
+ if (near && state == DozeMachine.State.DOZE_PULSING) {
+ if (DEBUG) Log.i(TAG, "Prox NEAR, ending pulse");
+ mMachine.requestState(DozeMachine.State.DOZE_PULSE_DONE);
+ }
+ if (far && state == DozeMachine.State.DOZE_AOD_PAUSED) {
+ if (DEBUG) Log.i(TAG, "Prox FAR, unpausing AOD");
+ mMachine.requestState(DozeMachine.State.DOZE_AOD);
+ } else if (near && state == DozeMachine.State.DOZE_AOD) {
+ if (DEBUG) Log.i(TAG, "Prox NEAR, pausing AOD");
+ mMachine.requestState(DozeMachine.State.DOZE_AOD_PAUSED);
+ }
+ }
+
private void onCarMode() {
mMachine.requestState(DozeMachine.State.FINISH);
}
@@ -131,15 +148,21 @@
break;
case DOZE:
case DOZE_AOD:
+ case DOZE_AOD_PAUSED:
+ mDozeSensors.setProxListening(newState != DozeMachine.State.DOZE);
mDozeSensors.setListening(true);
if (oldState != DozeMachine.State.INITIALIZED) {
mDozeSensors.reregisterAllSensors();
}
break;
+ case DOZE_PULSING:
+ mDozeSensors.setProxListening(true);
+ break;
case FINISH:
mBroadcastReceiver.unregister(mContext);
mDozeHost.removeCallback(mHostCallback);
mDozeSensors.setListening(false);
+ mDozeSensors.setProxListening(false);
break;
default:
}
@@ -156,6 +179,7 @@
private void requestPulse(final int reason, boolean performedProxCheck) {
Assert.isMainThread();
+ mDozeHost.extendPulse();
if (mPulsePending || !mAllowPulseTriggers || !canPulse()) {
return;
}
@@ -286,6 +310,8 @@
}
private class TriggerReceiver extends BroadcastReceiver {
+ private boolean mRegistered;
+
@Override
public void onReceive(Context context, Intent intent) {
if (PULSE_ACTION.equals(intent.getAction())) {
@@ -301,14 +327,22 @@
}
public void register(Context context) {
+ if (mRegistered) {
+ return;
+ }
IntentFilter filter = new IntentFilter(PULSE_ACTION);
filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE);
filter.addAction(Intent.ACTION_USER_SWITCHED);
context.registerReceiver(this, filter);
+ mRegistered = true;
}
public void unregister(Context context) {
+ if (!mRegistered) {
+ return;
+ }
context.unregisterReceiver(this);
+ mRegistered = false;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index f577654..6098a20 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -75,11 +75,14 @@
scheduleTimeTick();
break;
case DOZE:
+ case DOZE_AOD_PAUSED:
unscheduleTimeTick();
break;
case DOZE_REQUEST_PULSE:
pulseWhileDozing(DozeLog.PULSE_REASON_NOTIFICATION /* TODO */);
break;
+ case DOZE_PULSE_DONE:
+ mHost.abortPulsing();
case INITIALIZED:
mHost.startDozing();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 9c4f16b..ac06703 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -195,6 +195,7 @@
updateFromIntent(getIntent());
setTitle(R.string.pip_menu_title);
+ setDisablePreviewScreenshots(true);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 1151c8c..92ff17a1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -163,7 +163,6 @@
boolean enabled;
boolean wifiEnabled;
boolean airplaneModeEnabled;
- int mobileSignalIconId;
String signalContentDescription;
int dataTypeIconId;
String dataContentDescription;
@@ -193,7 +192,6 @@
return;
}
mInfo.enabled = qsIcon.visible;
- mInfo.mobileSignalIconId = qsIcon.icon;
mInfo.signalContentDescription = qsIcon.contentDescription;
mInfo.dataTypeIconId = qsType;
mInfo.dataContentDescription = typeContentDescription;
@@ -210,7 +208,6 @@
mInfo.noSim = show;
if (mInfo.noSim) {
// Make sure signal gets cleared out when no sims.
- mInfo.mobileSignalIconId = 0;
mInfo.dataTypeIconId = 0;
// Show a No SIMs description to avoid emergency calls message.
mInfo.enabled = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
index 2a1e063..fee24b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
@@ -306,6 +306,10 @@
}
private void snapBack(View animView, float velocity) {
+ if (mFadeAnimator != null) {
+ mFadeAnimator.cancel();
+ }
+ mHandler.removeCallbacks(mCheckForDrag);
mMenuSnappedTo = false;
mSnapping = true;
mSwipeHelper.snap(animView, 0 /* leftTarget */, velocity);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index d5f0e7c..dc254f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -42,6 +42,7 @@
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.SignalDrawable;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
@@ -192,7 +193,7 @@
mNoSimsCombo = findViewById(R.id.no_sims_combo);
mWifiAirplaneSpacer = findViewById(R.id.wifi_airplane_spacer);
mWifiSignalSpacer = findViewById(R.id.wifi_signal_spacer);
- mMobileSignalGroup = findViewById(R.id.mobile_signal_group);
+ mMobileSignalGroup = findViewById(R.id.mobile_signal_group);
maybeScaleVpnAndNoSimsIcons();
}
@@ -327,15 +328,6 @@
if (hasCorrectSubs(subs)) {
return;
}
- // Clear out all old subIds.
- for (PhoneState state : mPhoneStates) {
- if (state.mMobile != null) {
- state.maybeStopAnimatableDrawable(state.mMobile);
- }
- if (state.mMobileDark != null) {
- state.maybeStopAnimatableDrawable(state.mMobileDark);
- }
- }
mPhoneStates.clear();
if (mMobileSignalGroup != null) {
mMobileSignalGroup.removeAllViews();
@@ -428,16 +420,6 @@
}
for (PhoneState state : mPhoneStates) {
- if (state.mMobile != null) {
- state.maybeStopAnimatableDrawable(state.mMobile);
- state.mMobile.setImageDrawable(null);
- state.mLastMobileStrengthId = -1;
- }
- if (state.mMobileDark != null) {
- state.maybeStopAnimatableDrawable(state.mMobileDark);
- state.mMobileDark.setImageDrawable(null);
- state.mLastMobileStrengthId = -1;
- }
if (state.mMobileType != null) {
state.mMobileType.setImageDrawable(null);
state.mLastMobileTypeId = -1;
@@ -654,7 +636,6 @@
private int mMobileStrengthId = 0, mMobileTypeId = 0;
private int mLastMobileStrengthId = -1;
private int mLastMobileTypeId = -1;
- private int mLastMobileActivityId = -1;
private boolean mIsMobileTypeIconWide;
private String mMobileDescription, mMobileTypeDescription;
@@ -681,13 +662,18 @@
mMobileRoaming = root.findViewById(R.id.mobile_roaming);
mMobileActivityIn = root.findViewById(R.id.mobile_in);
mMobileActivityOut = root.findViewById(R.id.mobile_out);
+ // TODO: Remove the 2 instances because now the drawable can handle darkness.
+ mMobile.setImageDrawable(new SignalDrawable(mMobile.getContext()));
+ SignalDrawable drawable = new SignalDrawable(mMobileDark.getContext());
+ drawable.setDarkIntensity(1);
+ mMobileDark.setImageDrawable(drawable);
}
public boolean apply(boolean isSecondaryIcon) {
if (mMobileVisible && !mIsAirplaneMode) {
if (mLastMobileStrengthId != mMobileStrengthId) {
- updateAnimatableIcon(mMobile, mMobileStrengthId);
- updateAnimatableIcon(mMobileDark, mMobileStrengthId);
+ mMobile.getDrawable().setLevel(mMobileStrengthId);
+ mMobileDark.getDrawable().setLevel(mMobileStrengthId);
mLastMobileStrengthId = mMobileStrengthId;
}
@@ -724,49 +710,6 @@
return mMobileVisible;
}
- private void updateAnimatableIcon(ImageView view, int resId) {
- maybeStopAnimatableDrawable(view);
- setIconForView(view, resId);
- maybeStartAnimatableDrawable(view);
- }
-
- private void maybeStopAnimatableDrawable(ImageView view) {
- Drawable drawable = view.getDrawable();
-
- // Check if the icon has been scaled. If it has retrieve the actual drawable out of the
- // wrapper.
- if (drawable instanceof ScalingDrawableWrapper) {
- drawable = ((ScalingDrawableWrapper) drawable).getDrawable();
- }
-
- if (drawable instanceof Animatable) {
- Animatable ad = (Animatable) drawable;
- if (ad.isRunning()) {
- ad.stop();
- }
- }
- }
-
- private void maybeStartAnimatableDrawable(ImageView view) {
- Drawable drawable = view.getDrawable();
-
- // Check if the icon has been scaled. If it has retrieve the actual drawable out of the
- // wrapper.
- if (drawable instanceof ScalingDrawableWrapper) {
- drawable = ((ScalingDrawableWrapper) drawable).getDrawable();
- }
-
- if (drawable instanceof Animatable) {
- Animatable ad = (Animatable) drawable;
- if (ad instanceof AnimatedVectorDrawable) {
- ((AnimatedVectorDrawable) ad).forceAnimationOnUI();
- }
- if (!ad.isRunning()) {
- ad.start();
- }
- }
- }
-
public void populateAccessibilityEvent(AccessibilityEvent event) {
if (mMobileVisible && mMobileGroup != null
&& mMobileGroup.getContentDescription() != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
index 67f8426..677fa81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
@@ -11,6 +11,7 @@
import android.content.IntentFilter;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
+import android.telephony.SignalStrength;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
@@ -18,6 +19,7 @@
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.statusbar.ScalingDrawableWrapper;
+import com.android.systemui.statusbar.phone.SignalDrawable;
import com.android.systemui.statusbar.policy.BluetoothController;
import static com.android.systemui.statusbar.phone.StatusBar.DEBUG;
@@ -47,12 +49,12 @@
* Note that the icon is the same for 0 and 1.
*/
private static final int[] SIGNAL_STRENGTH_ICONS = {
- R.drawable.stat_sys_signal_0_fully,
- R.drawable.stat_sys_signal_0_fully,
- R.drawable.stat_sys_signal_1_fully,
- R.drawable.stat_sys_signal_2_fully,
- R.drawable.stat_sys_signal_3_fully,
- R.drawable.stat_sys_signal_4_fully,
+ 0,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
};
private static final int INVALID_SIGNAL = -1;
@@ -65,6 +67,7 @@
private final ImageView mNetworkSignalView;
private final float mIconScaleFactor;
+ private final SignalDrawable mSignalDrawable;
private BluetoothHeadsetClient mBluetoothHeadsetClient;
@@ -79,6 +82,9 @@
TypedValue typedValue = new TypedValue();
context.getResources().getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true);
mIconScaleFactor = typedValue.getFloat();
+ mSignalDrawable = new SignalDrawable(mNetworkSignalView.getContext());
+ mNetworkSignalView.setImageDrawable(
+ new ScalingDrawableWrapper(mSignalDrawable, mIconScaleFactor));
if (mAdapter == null) {
return;
@@ -187,14 +193,12 @@
}
}
- private void setNetworkSignalIcon(int iconId) {
+ private void setNetworkSignalIcon(int level) {
// Setting the icon on a child view of mSignalView, so toggle this container visible.
mSignalsView.setVisibility(View.VISIBLE);
- // Using mNetworkSignalView's context to get the Drawable in order to preserve the theme.
- Drawable icon = mNetworkSignalView.getContext().getDrawable(iconId);
-
- mNetworkSignalView.setImageDrawable(new ScalingDrawableWrapper(icon, mIconScaleFactor));
+ mSignalDrawable.setLevel(SignalDrawable.getState(level,
+ SignalStrength.NUM_SIGNAL_STRENGTH_BINS, false));
mNetworkSignalView.setVisibility(View.VISIBLE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index c3f8d97..40776ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -158,6 +158,10 @@
return sPickupSubtypePerformsProxMatcher.isIn(subType);
}
+ public int getPulseVisibleDurationExtended() {
+ return 2 * getPulseVisibleDuration();
+ }
+
/**
* Parses a spec of the form `1,2,3,!5,*`. The resulting object will match numbers that are
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index b78f748..c5f23c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -30,6 +30,7 @@
import com.android.systemui.Interpolators;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
+import com.android.systemui.doze.DozeTriggers;
/**
* Controller which handles all the doze animations of the scrims.
@@ -43,8 +44,6 @@
private final ScrimController mScrimController;
private final Context mContext;
- private final View mStackScroller;
- private final NotificationPanelView mNotificationPanelView;
private boolean mDozing;
private DozeHost.PulseCallback mPulseCallback;
@@ -53,24 +52,22 @@
private Animator mBehindAnimator;
private float mInFrontTarget;
private float mBehindTarget;
+ private boolean mDozingAborted;
- public DozeScrimController(ScrimController scrimController, Context context,
- View stackScroller, NotificationPanelView notificationPanelView) {
+ public DozeScrimController(ScrimController scrimController, Context context) {
mContext = context;
- mStackScroller = stackScroller;
mScrimController = scrimController;
mDozeParameters = new DozeParameters(context);
- mNotificationPanelView = notificationPanelView;
}
public void setDozing(boolean dozing, boolean animate) {
if (mDozing == dozing) return;
mDozing = dozing;
if (mDozing) {
+ mDozingAborted = false;
abortAnimations();
mScrimController.setDozeBehindAlpha(1f);
mScrimController.setDozeInFrontAlpha(mDozeParameters.getAlwaysOn() ? 0f : 1f);
- mNotificationPanelView.setDark(true);
} else {
cancelPulsing();
if (animate) {
@@ -85,8 +82,6 @@
mScrimController.setDozeBehindAlpha(0f);
mScrimController.setDozeInFrontAlpha(0f);
}
- // TODO: animate
- mNotificationPanelView.setDark(false);
}
}
@@ -116,10 +111,19 @@
cancelPulsing();
if (mDozing) {
mScrimController.setDozeBehindAlpha(1f);
- mScrimController.setDozeInFrontAlpha(1f);
+ mScrimController.setDozeInFrontAlpha(
+ mDozeParameters.getAlwaysOn() && !mDozingAborted ? 0f : 1f);
}
}
+ /**
+ * Aborts dozing immediately.
+ */
+ public void abortDoze() {
+ mDozingAborted = true;
+ abortPulsing();
+ }
+
public void onScreenTurnedOn() {
if (isPulsing()) {
final boolean pickupOrDoubleTap = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP
@@ -139,12 +143,17 @@
return mDozing;
}
+ public void extendPulse() {
+ mHandler.removeCallbacks(mPulseOut);
+ }
+
private void cancelPulsing() {
if (DEBUG) Log.d(TAG, "Cancel pulsing");
if (mPulseCallback != null) {
mHandler.removeCallbacks(mPulseIn);
mHandler.removeCallbacks(mPulseOut);
+ mHandler.removeCallbacks(mPulseOutExtended);
pulseFinished();
}
}
@@ -271,12 +280,23 @@
if (DEBUG) Log.d(TAG, "Pulse in finished, mDozing=" + mDozing);
if (!mDozing) return;
mHandler.postDelayed(mPulseOut, mDozeParameters.getPulseVisibleDuration());
+ mHandler.postDelayed(mPulseOutExtended,
+ mDozeParameters.getPulseVisibleDurationExtended());
+ }
+ };
+
+ private final Runnable mPulseOutExtended = new Runnable() {
+ @Override
+ public void run() {
+ mHandler.removeCallbacks(mPulseOut);
+ mPulseOut.run();
}
};
private final Runnable mPulseOut = new Runnable() {
@Override
public void run() {
+ mHandler.removeCallbacks(mPulseOutExtended);
if (DEBUG) Log.d(TAG, "Pulse out, mDozing=" + mDozing);
if (!mDozing) return;
startScrimAnimation(true /* inFront */, mDozeParameters.getAlwaysOn() ? 0 : 1,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
index 2bb3cbc..9206914 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
@@ -221,7 +221,7 @@
case MODE_WAKE_AND_UNLOCK:
Trace.beginSection("MODE_WAKE_AND_UNLOCK");
mStatusBarWindowManager.setStatusBarFocusable(false);
- mDozeScrimController.abortPulsing();
+ mDozeScrimController.abortDoze();
mKeyguardViewMediator.onWakeAndUnlocking();
mScrimController.setWakeAndUnlocking();
if (mStatusBar.getNavigationBarView() != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java
new file mode 100644
index 0000000..a9eb20b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.animation.ArgbEvaluator;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.Path;
+import android.graphics.Path.Direction;
+import android.graphics.Path.FillType;
+import android.graphics.Path.Op;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.util.Log;
+
+import com.android.settingslib.R;
+import com.android.settingslib.Utils;
+
+public class SignalDrawable extends Drawable {
+
+ private static final String TAG = "SignalDrawable";
+
+ private static final int NUM_DOTS = 3;
+
+ private static final float VIEWPORT = 24f;
+ private static final float PAD = 2f / VIEWPORT;
+ private static final float CUT_OUT = 7.9f / VIEWPORT;
+
+ private static final float DOT_SIZE = 3f / VIEWPORT;
+ private static final float DOT_PADDING = 1f / VIEWPORT;
+ private static final float DOT_CUT_WIDTH = (DOT_SIZE * 3) + (DOT_PADDING * 5);
+ private static final float DOT_CUT_HEIGHT = (DOT_SIZE * 1) + (DOT_PADDING * 1);
+
+ private static final float[] FIT = {2.26f, -3.02f, 1.76f};
+
+ // All of these are masks to push all of the drawable state into one int for easy callbacks
+ // and flow through sysui.
+ private static final int LEVEL_MASK = 0xff;
+ private static final int NUM_LEVEL_SHIFT = 8;
+ private static final int NUM_LEVEL_MASK = 0xff << NUM_LEVEL_SHIFT;
+ private static final int STATE_SHIFT = 16;
+ private static final int STATE_MASK = 0xff << STATE_SHIFT;
+ private static final int STATE_NONE = 0;
+ private static final int STATE_EMPTY = 1;
+ private static final int STATE_CUT = 2;
+ private static final int STATE_CARRIER_CHANGE = 3;
+
+ private static final long DOT_DELAY = 1000;
+
+ private static float[][] X_PATH = new float[][]{
+ {21.9f / VIEWPORT, 17.0f / VIEWPORT},
+ {-1.1f / VIEWPORT, -1.1f / VIEWPORT},
+ {-1.9f / VIEWPORT, 1.9f / VIEWPORT},
+ {-1.9f / VIEWPORT, -1.9f / VIEWPORT},
+ {-1.1f / VIEWPORT, 1.1f / VIEWPORT},
+ {1.9f / VIEWPORT, 1.9f / VIEWPORT},
+ {-1.9f / VIEWPORT, 1.9f / VIEWPORT},
+ {1.1f / VIEWPORT, 1.1f / VIEWPORT},
+ {1.9f / VIEWPORT, -1.9f / VIEWPORT},
+ {1.9f / VIEWPORT, 1.9f / VIEWPORT},
+ {1.1f / VIEWPORT, -1.1f / VIEWPORT},
+ {-1.9f / VIEWPORT, -1.9f / VIEWPORT},
+ };
+
+ private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private final Paint mForegroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private final int mDarkModeBackgroundColor;
+ private final int mDarkModeFillColor;
+ private final int mLightModeBackgroundColor;
+ private final int mLightModeFillColor;
+ private final Path mFullPath = new Path();
+ private final Path mForegroundPath = new Path();
+ private final Path mXPath = new Path();
+ private final int mIntrinsicSize;
+ private final Handler mHandler;
+ private float mOldDarkIntensity = -1;
+ private float mNumLevels = 1;
+ private int mLevel;
+ private int mState;
+ private boolean mVisible;
+ private boolean mAnimating;
+ private int mCurrentDot;
+
+ public SignalDrawable(Context context) {
+ mDarkModeBackgroundColor =
+ Utils.getDefaultColor(context, R.color.dark_mode_icon_color_dual_tone_background);
+ mDarkModeFillColor =
+ Utils.getDefaultColor(context, R.color.dark_mode_icon_color_dual_tone_fill);
+ mLightModeBackgroundColor =
+ Utils.getDefaultColor(context, R.color.light_mode_icon_color_dual_tone_background);
+ mLightModeFillColor =
+ Utils.getDefaultColor(context, R.color.light_mode_icon_color_dual_tone_fill);
+ mIntrinsicSize = context.getResources().getDimensionPixelSize(R.dimen.signal_icon_size);
+ mHandler = new Handler();
+ setDarkIntensity(0);
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mIntrinsicSize;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mIntrinsicSize;
+ }
+
+ public void setNumLevels(int levels) {
+ if (levels == mNumLevels) return;
+ mNumLevels = levels;
+ invalidateSelf();
+ }
+
+ private void setSignalState(int state) {
+ if (state == mState) return;
+ mState = state;
+ updateAnimation();
+ invalidateSelf();
+ }
+
+ private void updateAnimation() {
+ boolean shouldAnimate = (mState == STATE_CARRIER_CHANGE) && mVisible;
+ if (shouldAnimate == mAnimating) return;
+ mAnimating = shouldAnimate;
+ if (shouldAnimate) {
+ mChangeDot.run();
+ } else {
+ mHandler.removeCallbacks(mChangeDot);
+ }
+ }
+
+ @Override
+ protected boolean onLevelChange(int state) {
+ setNumLevels(getNumLevels(state));
+ setSignalState(getState(state));
+ int level = getLevel(state);
+ if (level != mLevel) {
+ mLevel = level;
+ invalidateSelf();
+ }
+ return true;
+ }
+
+ public void setDarkIntensity(float darkIntensity) {
+ if (darkIntensity == mOldDarkIntensity) {
+ return;
+ }
+ mPaint.setColor(getBackgroundColor(darkIntensity));
+ mForegroundPaint.setColor(getFillColor(darkIntensity));
+ mOldDarkIntensity = darkIntensity;
+ invalidateSelf();
+ }
+
+ private int getFillColor(float darkIntensity) {
+ return getColorForDarkIntensity(
+ darkIntensity, mLightModeFillColor, mDarkModeFillColor);
+ }
+
+ private int getBackgroundColor(float darkIntensity) {
+ return getColorForDarkIntensity(
+ darkIntensity, mLightModeBackgroundColor, mDarkModeBackgroundColor);
+ }
+
+ private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
+ return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ super.onBoundsChange(bounds);
+ invalidateSelf();
+ }
+
+ @Override
+ public void draw(@NonNull Canvas canvas) {
+ mFullPath.reset();
+ mFullPath.setFillType(FillType.WINDING);
+ float width = getBounds().width();
+ float height = getBounds().height();
+ float padding = (PAD * width);
+ mFullPath.moveTo(width - padding, height - padding);
+ mFullPath.lineTo(width - padding, padding);
+ mFullPath.lineTo(padding, height - padding);
+ mFullPath.lineTo(width - padding, height - padding);
+
+ if (mState == STATE_CARRIER_CHANGE) {
+ float cutWidth = (DOT_CUT_WIDTH * width);
+ float cutHeight = (DOT_CUT_HEIGHT * width);
+ float dotSize = (DOT_SIZE * height);
+ float dotPadding = (DOT_PADDING * height);
+
+ mFullPath.moveTo(width - padding, height - padding);
+ mFullPath.rLineTo(-cutWidth, 0);
+ mFullPath.rLineTo(0, -cutHeight);
+ mFullPath.rLineTo(cutWidth, 0);
+ mFullPath.rLineTo(0, cutHeight);
+ float dotSpacing = dotPadding * 2 + dotSize;
+ float x = width - padding - dotSize;
+ float y = height - padding - dotSize;
+ mForegroundPath.reset();
+ drawDot(mFullPath, mForegroundPath, x, y, dotSize, 2);
+ drawDot(mFullPath, mForegroundPath, x - dotSpacing, y, dotSize, 1);
+ drawDot(mFullPath, mForegroundPath, x - dotSpacing * 2, y, dotSize, 0);
+ } else if (mState == STATE_CUT) {
+ float cut = (CUT_OUT * width);
+ mFullPath.moveTo(width - padding, height - padding);
+ mFullPath.rLineTo(-cut, 0);
+ mFullPath.rLineTo(0, -cut);
+ mFullPath.rLineTo(cut, 0);
+ mFullPath.rLineTo(0, cut);
+ }
+
+ mPaint.setStyle(mState == STATE_EMPTY ? Style.STROKE : Style.FILL);
+ mForegroundPaint.setStyle(mState == STATE_EMPTY ? Style.STROKE : Style.FILL);
+
+ if (mState != STATE_CARRIER_CHANGE) {
+ mForegroundPath.reset();
+ int sigWidth = Math.round(calcFit(mLevel / (mNumLevels - 1)) * (width - 2 * padding));
+ mForegroundPath.addRect(padding, padding, padding + sigWidth, height - padding,
+ Direction.CW);
+ mForegroundPath.op(mFullPath, Op.INTERSECT);
+ }
+
+ canvas.drawPath(mFullPath, mPaint);
+ canvas.drawPath(mForegroundPath, mForegroundPaint);
+ if (mState == STATE_CUT) {
+ mXPath.reset();
+ mXPath.moveTo(X_PATH[0][0] * width, X_PATH[0][1] * height);
+ for (int i = 1; i < X_PATH.length; i++) {
+ mXPath.rLineTo(X_PATH[i][0] * width, X_PATH[i][1] * height);
+ }
+ canvas.drawPath(mXPath, mForegroundPaint);
+ }
+ }
+
+ private void drawDot(Path fullPath, Path foregroundPath, float x, float y, float dotSize,
+ int i) {
+ Path p = (i == mCurrentDot) ? foregroundPath : fullPath;
+ p.addRect(x, y, x + dotSize, y + dotSize, Direction.CW);
+ }
+
+ // This is a fit line based on previous values of provided in assets, but if
+ // you look at the a plot of this actual fit, it makes a lot of sense, what it does
+ // is compress the areas that are very visually easy to see changes (the middle sections)
+ // and spread out the sections that are hard to see (each end of the icon).
+ // The current fit is cubic, but pretty easy to change the way the code is written (just add
+ // terms to the end of FIT).
+ private float calcFit(float v) {
+ float ret = 0;
+ float t = v;
+ for (int i = 0; i < FIT.length; i++) {
+ ret += FIT[i] * t;
+ t *= v;
+ }
+ return ret;
+ }
+
+ @Override
+ public int getAlpha() {
+ return mPaint.getAlpha();
+ }
+
+ @Override
+ public void setAlpha(@IntRange(from = 0, to = 255) int alpha) {
+ mPaint.setAlpha(alpha);
+ mForegroundPaint.setAlpha(alpha);
+ }
+
+ @Override
+ public void setColorFilter(@Nullable ColorFilter colorFilter) {
+ mPaint.setColorFilter(colorFilter);
+ mForegroundPaint.setColorFilter(colorFilter);
+ }
+
+ @Override
+ public int getOpacity() {
+ return 255;
+ }
+
+ @Override
+ public boolean setVisible(boolean visible, boolean restart) {
+ mVisible = visible;
+ updateAnimation();
+ return super.setVisible(visible, restart);
+ }
+
+ private final Runnable mChangeDot = new Runnable() {
+ @Override
+ public void run() {
+ if (++mCurrentDot == NUM_DOTS) {
+ mCurrentDot = 0;
+ }
+ invalidateSelf();
+ mHandler.postDelayed(mChangeDot, DOT_DELAY);
+ }
+ };
+
+ public static int getLevel(int fullState) {
+ return fullState & LEVEL_MASK;
+ }
+
+ public static int getState(int fullState) {
+ return (fullState & STATE_MASK) >> STATE_SHIFT;
+ }
+
+ public static int getNumLevels(int fullState) {
+ return (fullState & NUM_LEVEL_MASK) >> NUM_LEVEL_SHIFT;
+ }
+
+ public static int getState(int level, int numLevels, boolean cutOut) {
+ return ((cutOut ? STATE_CUT : 0) << STATE_SHIFT)
+ | (numLevels << NUM_LEVEL_SHIFT)
+ | level;
+ }
+
+ public static int getCarrierChangeState(int numLevels) {
+ return (STATE_CARRIER_CHANGE << STATE_SHIFT) | (numLevels << NUM_LEVEL_SHIFT);
+ }
+
+ public static int getEmptyState(int numLevels) {
+ return (STATE_EMPTY << STATE_SHIFT) | (numLevels << NUM_LEVEL_SHIFT);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index d3cb6a4a8..fbf53e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1114,8 +1114,7 @@
}
mHeadsUpManager.addListener(mScrimController);
mStackScroller.setScrimController(mScrimController);
- mDozeScrimController = new DozeScrimController(mScrimController, context, mStackScroller,
- mNotificationPanel);
+ mDozeScrimController = new DozeScrimController(mScrimController, context);
// Other icons
mVolumeComponent = getComponent(VolumeComponent.class);
@@ -4332,6 +4331,7 @@
mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation);
mScrimController.setDozing(mDozing);
mKeyguardIndicationController.setDozing(mDozing);
+ mNotificationPanel.setDark(mDozing);
// Immediately abort the dozing from the doze scrim controller in case of wake-and-unlock
// for pulsing so the Keyguard fade-out animation scrim can take over.
@@ -4958,6 +4958,7 @@
mDozing = mDozingRequested && mState == StatusBarState.KEYGUARD
|| mFingerprintUnlockController.getMode()
== FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
+ mStatusBarWindowManager.setDozing(mDozing);
updateDozingState();
Trace.endSection();
}
@@ -5065,6 +5066,16 @@
StatusBar.this.startPendingIntentDismissingKeyguard(intent);
}
+ @Override
+ public void abortPulsing() {
+ mDozeScrimController.abortPulsing();
+ }
+
+ @Override
+ public void extendPulse() {
+ mDozeScrimController.extendPulse();
+ }
+
}
// Begin Extra BaseStatusBar methods.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index deb0070..0326e40 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -118,7 +118,7 @@
mLpChanged.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
}
- if (state.keyguardShowing && !state.backdropShowing) {
+ if (state.keyguardShowing && !state.backdropShowing && !state.dozing) {
mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
} else {
mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
@@ -357,6 +357,11 @@
apply(mCurrentState);
}
+ public void setDozing(boolean dozing) {
+ mCurrentState.dozing = dozing;
+ apply(mCurrentState);
+ }
+
public void setBarHeight(int barHeight) {
mBarHeight = barHeight;
apply(mCurrentState);
@@ -404,6 +409,7 @@
boolean remoteInputActive;
boolean forcePluginOpen;
+ boolean dozing;
private boolean isKeyguardShowingAndNotOccluded() {
return keyguardShowing && !keyguardOccluded;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 1848d4e..1a09d75 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -255,6 +255,9 @@
if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
mStackScrollLayout.closeControlsIfOutsideTouch(ev);
}
+ if (mService.isDozing()) {
+ mService.mDozeScrimController.extendPulse();
+ }
return super.dispatchTouchEvent(ev);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 91acf04..67b5596 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -36,6 +36,7 @@
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.cdma.EriInfo;
import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.SignalDrawable;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
@@ -233,6 +234,29 @@
mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_IWLAN, TelephonyIcons.WFC);
}
+ private int getNumLevels() {
+ return SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
+ }
+
+ @Override
+ public int getCurrentIconId() {
+ if (mCurrentState.iconGroup == TelephonyIcons.CARRIER_NETWORK_CHANGE) {
+ return SignalDrawable.getCarrierChangeState(getNumLevels());
+ } else if (mCurrentState.connected) {
+ return SignalDrawable.getState(mCurrentState.level, getNumLevels(),
+ mCurrentState.inetCondition == 0);
+ } else if (mCurrentState.enabled) {
+ return SignalDrawable.getEmptyState(getNumLevels());
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public int getQsCurrentIconId() {
+ return getCurrentIconId();
+ }
+
@Override
public void notifyListeners(SignalCallback callback) {
MobileIconGroup icons = getIcons();
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 bc3eec9..c21f444 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -32,6 +32,7 @@
import android.os.Looper;
import android.provider.Settings;
import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
@@ -872,11 +873,11 @@
if (args.containsKey("roam")) {
controller.getState().roaming = "show".equals(args.getString("roam"));
}
- int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH;
String level = args.getString("level");
if (level != null) {
controller.getState().level = level.equals("null") ? -1
- : Math.min(Integer.parseInt(level), icons[0].length - 1);
+ : Math.min(Integer.parseInt(level),
+ SignalStrength.NUM_SIGNAL_STRENGTH_BINS);
controller.getState().connected = controller.getState().level >= 0;
}
String activity = args.getString("activity");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index 6b2361e..aaa0568 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -20,196 +20,20 @@
import com.android.systemui.statusbar.policy.MobileSignalController.MobileIconGroup;
class TelephonyIcons {
- //***** Signal strength icons
-
- static final int TELEPHONY_NUM_LEVELS = 5;
-
- //GSM/UMTS
- static final int TELEPHONY_NO_NETWORK = R.drawable.stat_sys_signal_null;
-
- static final int[][] TELEPHONY_SIGNAL_STRENGTH = {
- { R.drawable.stat_sys_signal_0,
- R.drawable.stat_sys_signal_1,
- R.drawable.stat_sys_signal_2,
- R.drawable.stat_sys_signal_3,
- R.drawable.stat_sys_signal_4 },
- { R.drawable.stat_sys_signal_0_fully,
- R.drawable.stat_sys_signal_1_fully,
- R.drawable.stat_sys_signal_2_fully,
- R.drawable.stat_sys_signal_3_fully,
- R.drawable.stat_sys_signal_4_fully }
- };
-
- static final int QS_TELEPHONY_NO_NETWORK = R.drawable.ic_qs_signal_no_signal;
-
- static final int[][] QS_TELEPHONY_SIGNAL_STRENGTH = {
- { R.drawable.ic_qs_signal_0,
- R.drawable.ic_qs_signal_1,
- R.drawable.ic_qs_signal_2,
- R.drawable.ic_qs_signal_3,
- R.drawable.ic_qs_signal_4 },
- { R.drawable.ic_qs_signal_full_0,
- R.drawable.ic_qs_signal_full_1,
- R.drawable.ic_qs_signal_full_2,
- R.drawable.ic_qs_signal_full_3,
- R.drawable.ic_qs_signal_full_4 }
- };
-
- static final int[][] TELEPHONY_SIGNAL_STRENGTH_ROAMING = {
- { R.drawable.stat_sys_signal_0,
- R.drawable.stat_sys_signal_1,
- R.drawable.stat_sys_signal_2,
- R.drawable.stat_sys_signal_3,
- R.drawable.stat_sys_signal_4 },
- { R.drawable.stat_sys_signal_0_fully,
- R.drawable.stat_sys_signal_1_fully,
- R.drawable.stat_sys_signal_2_fully,
- R.drawable.stat_sys_signal_3_fully,
- R.drawable.stat_sys_signal_4_fully }
- };
-
- //CarrierNetworkChange
- static final int[][] TELEPHONY_CARRIER_NETWORK_CHANGE = {
- { R.drawable.stat_sys_signal_carrier_network_change_animation,
- R.drawable.stat_sys_signal_carrier_network_change_animation,
- R.drawable.stat_sys_signal_carrier_network_change_animation,
- R.drawable.stat_sys_signal_carrier_network_change_animation,
- R.drawable.stat_sys_signal_carrier_network_change_animation },
- { R.drawable.stat_sys_signal_carrier_network_change_animation,
- R.drawable.stat_sys_signal_carrier_network_change_animation,
- R.drawable.stat_sys_signal_carrier_network_change_animation,
- R.drawable.stat_sys_signal_carrier_network_change_animation,
- R.drawable.stat_sys_signal_carrier_network_change_animation }
- };
-
- static final int[][] QS_TELEPHONY_CARRIER_NETWORK_CHANGE = {
- { R.drawable.ic_qs_signal_carrier_network_change_animation,
- R.drawable.ic_qs_signal_carrier_network_change_animation,
- R.drawable.ic_qs_signal_carrier_network_change_animation,
- R.drawable.ic_qs_signal_carrier_network_change_animation,
- R.drawable.ic_qs_signal_carrier_network_change_animation },
- { R.drawable.ic_qs_signal_carrier_network_change_animation,
- R.drawable.ic_qs_signal_carrier_network_change_animation,
- R.drawable.ic_qs_signal_carrier_network_change_animation,
- R.drawable.ic_qs_signal_carrier_network_change_animation,
- R.drawable.ic_qs_signal_carrier_network_change_animation }
- };
-
//***** Data connection icons
- //GSM/UMTS
- static final int[][] DATA_G = {
- { R.drawable.stat_sys_data_fully_connected_g,
- R.drawable.stat_sys_data_fully_connected_g,
- R.drawable.stat_sys_data_fully_connected_g,
- R.drawable.stat_sys_data_fully_connected_g },
- { R.drawable.stat_sys_data_fully_connected_g,
- R.drawable.stat_sys_data_fully_connected_g,
- R.drawable.stat_sys_data_fully_connected_g,
- R.drawable.stat_sys_data_fully_connected_g }
- };
-
static final int QS_DATA_G = R.drawable.ic_qs_signal_g;
-
- static final int[][] DATA_3G = {
- { R.drawable.stat_sys_data_fully_connected_3g,
- R.drawable.stat_sys_data_fully_connected_3g,
- R.drawable.stat_sys_data_fully_connected_3g,
- R.drawable.stat_sys_data_fully_connected_3g },
- { R.drawable.stat_sys_data_fully_connected_3g,
- R.drawable.stat_sys_data_fully_connected_3g,
- R.drawable.stat_sys_data_fully_connected_3g,
- R.drawable.stat_sys_data_fully_connected_3g }
- };
-
static final int QS_DATA_3G = R.drawable.ic_qs_signal_3g;
-
- static final int[][] DATA_E = {
- { R.drawable.stat_sys_data_fully_connected_e,
- R.drawable.stat_sys_data_fully_connected_e,
- R.drawable.stat_sys_data_fully_connected_e,
- R.drawable.stat_sys_data_fully_connected_e },
- { R.drawable.stat_sys_data_fully_connected_e,
- R.drawable.stat_sys_data_fully_connected_e,
- R.drawable.stat_sys_data_fully_connected_e,
- R.drawable.stat_sys_data_fully_connected_e }
- };
-
static final int QS_DATA_E = R.drawable.ic_qs_signal_e;
-
- //3.5G
- static final int[][] DATA_H = {
- { R.drawable.stat_sys_data_fully_connected_h,
- R.drawable.stat_sys_data_fully_connected_h,
- R.drawable.stat_sys_data_fully_connected_h,
- R.drawable.stat_sys_data_fully_connected_h },
- { R.drawable.stat_sys_data_fully_connected_h,
- R.drawable.stat_sys_data_fully_connected_h,
- R.drawable.stat_sys_data_fully_connected_h,
- R.drawable.stat_sys_data_fully_connected_h }
- };
-
static final int QS_DATA_H = R.drawable.ic_qs_signal_h;
-
- //CDMA
- // Use 3G icons for EVDO data and 1x icons for 1XRTT data
- static final int[][] DATA_1X = {
- { R.drawable.stat_sys_data_fully_connected_1x,
- R.drawable.stat_sys_data_fully_connected_1x,
- R.drawable.stat_sys_data_fully_connected_1x,
- R.drawable.stat_sys_data_fully_connected_1x },
- { R.drawable.stat_sys_data_fully_connected_1x,
- R.drawable.stat_sys_data_fully_connected_1x,
- R.drawable.stat_sys_data_fully_connected_1x,
- R.drawable.stat_sys_data_fully_connected_1x }
- };
-
static final int QS_DATA_1X = R.drawable.ic_qs_signal_1x;
-
- // LTE and eHRPD
- static final int[][] DATA_4G = {
- { R.drawable.stat_sys_data_fully_connected_4g,
- R.drawable.stat_sys_data_fully_connected_4g,
- R.drawable.stat_sys_data_fully_connected_4g,
- R.drawable.stat_sys_data_fully_connected_4g },
- { R.drawable.stat_sys_data_fully_connected_4g,
- R.drawable.stat_sys_data_fully_connected_4g,
- R.drawable.stat_sys_data_fully_connected_4g,
- R.drawable.stat_sys_data_fully_connected_4g }
- };
-
static final int QS_DATA_4G = R.drawable.ic_qs_signal_4g;
-
- static final int[][] DATA_4G_PLUS = {
- { R.drawable.stat_sys_data_fully_connected_4g_plus,
- R.drawable.stat_sys_data_fully_connected_4g_plus,
- R.drawable.stat_sys_data_fully_connected_4g_plus,
- R.drawable.stat_sys_data_fully_connected_4g_plus },
- { R.drawable.stat_sys_data_fully_connected_4g_plus,
- R.drawable.stat_sys_data_fully_connected_4g_plus,
- R.drawable.stat_sys_data_fully_connected_4g_plus,
- R.drawable.stat_sys_data_fully_connected_4g_plus }
- };
-
static final int QS_DATA_4G_PLUS = R.drawable.ic_qs_signal_4g_plus;
-
- // LTE branded "LTE"
- static final int[][] DATA_LTE = {
- { R.drawable.stat_sys_data_fully_connected_lte,
- R.drawable.stat_sys_data_fully_connected_lte,
- R.drawable.stat_sys_data_fully_connected_lte,
- R.drawable.stat_sys_data_fully_connected_lte },
- { R.drawable.stat_sys_data_fully_connected_lte,
- R.drawable.stat_sys_data_fully_connected_lte,
- R.drawable.stat_sys_data_fully_connected_lte,
- R.drawable.stat_sys_data_fully_connected_lte }
- };
-
static final int QS_DATA_LTE = R.drawable.ic_qs_signal_lte;
static final int QS_DATA_LTE_PLUS = R.drawable.ic_qs_signal_lte_plus;
static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_airplane_mode;
- static final int ROAMING_ICON = R.drawable.stat_sys_roaming;
+
static final int ICON_LTE = R.drawable.stat_sys_data_fully_connected_lte;
static final int ICON_LTE_PLUS = R.drawable.stat_sys_data_fully_connected_lte_plus;
static final int ICON_G = R.drawable.stat_sys_data_fully_connected_g;
@@ -219,29 +43,19 @@
static final int ICON_4G = R.drawable.stat_sys_data_fully_connected_4g;
static final int ICON_4G_PLUS = R.drawable.stat_sys_data_fully_connected_4g_plus;
static final int ICON_1X = R.drawable.stat_sys_data_fully_connected_1x;
- static final int ICON_CARRIER_NETWORK_CHANGE =
- R.drawable.stat_sys_signal_carrier_network_change_animation;
static final int ICON_DATA_DISABLED = R.drawable.stat_sys_data_disabled;
- static final int QS_ICON_LTE = R.drawable.ic_qs_signal_lte;
- static final int QS_ICON_3G = R.drawable.ic_qs_signal_3g;
- static final int QS_ICON_4G = R.drawable.ic_qs_signal_4g;
- static final int QS_ICON_4G_PLUS = R.drawable.ic_qs_signal_4g_plus;
- static final int QS_ICON_1X = R.drawable.ic_qs_signal_1x;
- static final int QS_ICON_CARRIER_NETWORK_CHANGE =
- R.drawable.ic_qs_signal_carrier_network_change_animation;
-
static final int QS_ICON_DATA_DISABLED = R.drawable.ic_qs_data_disabled;
static final MobileIconGroup CARRIER_NETWORK_CHANGE = new MobileIconGroup(
"CARRIER_NETWORK_CHANGE",
- TelephonyIcons.TELEPHONY_CARRIER_NETWORK_CHANGE,
- TelephonyIcons.QS_TELEPHONY_CARRIER_NETWORK_CHANGE,
+ null,
+ null,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
0, 0,
- TelephonyIcons.ICON_CARRIER_NETWORK_CHANGE,
- TelephonyIcons.QS_ICON_CARRIER_NETWORK_CHANGE,
+ 0,
+ 0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
R.string.accessibility_carrier_network_change_mode,
0,
@@ -251,12 +65,12 @@
static final MobileIconGroup THREE_G = new MobileIconGroup(
"3G",
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+ null,
+ null,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
0, 0,
- TelephonyIcons.TELEPHONY_NO_NETWORK,
- TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+ 0,
+ 0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
R.string.accessibility_data_connection_3g,
TelephonyIcons.ICON_3G,
@@ -266,36 +80,36 @@
static final MobileIconGroup WFC = new MobileIconGroup(
"WFC",
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+ null,
+ null,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
0, 0,
- TelephonyIcons.TELEPHONY_NO_NETWORK,
- TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+ 0,
+ 0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
0, 0, false, 0
);
static final MobileIconGroup UNKNOWN = new MobileIconGroup(
"Unknown",
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+ null,
+ null,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
0, 0,
- TelephonyIcons.TELEPHONY_NO_NETWORK,
- TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+ 0,
+ 0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
0, 0, false, 0
);
static final MobileIconGroup E = new MobileIconGroup(
"E",
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+ null,
+ null,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
0, 0,
- TelephonyIcons.TELEPHONY_NO_NETWORK,
- TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+ 0,
+ 0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
R.string.accessibility_data_connection_edge,
TelephonyIcons.ICON_E,
@@ -305,12 +119,12 @@
static final MobileIconGroup ONE_X = new MobileIconGroup(
"1X",
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+ null,
+ null,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
0, 0,
- TelephonyIcons.TELEPHONY_NO_NETWORK,
- TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+ 0,
+ 0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
R.string.accessibility_data_connection_cdma,
TelephonyIcons.ICON_1X,
@@ -320,12 +134,12 @@
static final MobileIconGroup G = new MobileIconGroup(
"G",
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+ null,
+ null,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
0, 0,
- TelephonyIcons.TELEPHONY_NO_NETWORK,
- TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+ 0,
+ 0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
R.string.accessibility_data_connection_gprs,
TelephonyIcons.ICON_G,
@@ -335,12 +149,12 @@
static final MobileIconGroup H = new MobileIconGroup(
"H",
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+ null,
+ null,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
0, 0,
- TelephonyIcons.TELEPHONY_NO_NETWORK,
- TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+ 0,
+ 0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
R.string.accessibility_data_connection_3_5g,
TelephonyIcons.ICON_H,
@@ -350,12 +164,12 @@
static final MobileIconGroup FOUR_G = new MobileIconGroup(
"4G",
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+ null,
+ null,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
0, 0,
- TelephonyIcons.TELEPHONY_NO_NETWORK,
- TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+ 0,
+ 0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
R.string.accessibility_data_connection_4g,
TelephonyIcons.ICON_4G,
@@ -365,12 +179,12 @@
static final MobileIconGroup FOUR_G_PLUS = new MobileIconGroup(
"4G+",
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+ null,
+ null,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
0,0,
- TelephonyIcons.TELEPHONY_NO_NETWORK,
- TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+ 0,
+ 0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
R.string.accessibility_data_connection_4g_plus,
TelephonyIcons.ICON_4G_PLUS,
@@ -380,12 +194,12 @@
static final MobileIconGroup LTE = new MobileIconGroup(
"LTE",
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+ null,
+ null,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
0, 0,
- TelephonyIcons.TELEPHONY_NO_NETWORK,
- TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+ 0,
+ 0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
R.string.accessibility_data_connection_lte,
TelephonyIcons.ICON_LTE,
@@ -395,12 +209,12 @@
static final MobileIconGroup LTE_PLUS = new MobileIconGroup(
"LTE+",
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+ null,
+ null,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
0, 0,
- TelephonyIcons.TELEPHONY_NO_NETWORK,
- TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+ 0,
+ 0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
R.string.accessibility_data_connection_lte_plus,
TelephonyIcons.ICON_LTE_PLUS,
@@ -410,12 +224,12 @@
static final MobileIconGroup DATA_DISABLED = new MobileIconGroup(
"DataDisabled",
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+ null,
+ null,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
0, 0,
- TelephonyIcons.TELEPHONY_NO_NETWORK,
- TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+ 0,
+ 0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
R.string.accessibility_cell_data_off,
TelephonyIcons.ICON_DATA_DISABLED,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 19b4b17..505e1d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -31,6 +31,7 @@
import android.util.Log;
import com.android.internal.telephony.cdma.EriInfo;
import com.android.settingslib.net.DataUsageController;
+import com.android.systemui.statusbar.phone.SignalDrawable;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
@@ -66,12 +67,10 @@
public class NetworkControllerBaseTest extends SysuiTestCase {
private static final String TAG = "NetworkControllerBaseTest";
protected static final int DEFAULT_LEVEL = 2;
- protected static final int DEFAULT_SIGNAL_STRENGTH =
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL];
- protected static final int DEFAULT_QS_SIGNAL_STRENGTH =
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL];
+ protected static final int DEFAULT_SIGNAL_STRENGTH = DEFAULT_LEVEL;
+ protected static final int DEFAULT_QS_SIGNAL_STRENGTH = DEFAULT_LEVEL;
protected static final int DEFAULT_ICON = TelephonyIcons.ICON_3G;
- protected static final int DEFAULT_QS_ICON = TelephonyIcons.QS_ICON_3G;
+ protected static final int DEFAULT_QS_ICON = TelephonyIcons.QS_DATA_3G;
protected NetworkControllerImpl mNetworkController;
protected MobileSignalController mMobileSignalController;
@@ -315,8 +314,10 @@
typeIconArg.capture(), dataInArg.capture(), dataOutArg.capture(),
anyString(), anyString(), anyBoolean(), anyInt(), anyBoolean());
IconState iconState = iconArg.getValue();
+ int state = SignalDrawable.getState(icon, SignalStrength.NUM_SIGNAL_STRENGTH_BINS,
+ false);
assertEquals("Visibility in, quick settings", visible, iconState.visible);
- assertEquals("Signal icon in, quick settings", icon, iconState.icon);
+ assertEquals("Signal icon in, quick settings", state, iconState.icon);
assertEquals("Data icon in, quick settings", typeIcon, (int) typeIconArg.getValue());
assertEquals("Data direction in, in quick settings", dataIn,
(boolean) dataInArg.getValue());
@@ -330,6 +331,11 @@
protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon,
boolean roaming) {
+ verifyLastMobileDataIndicators(visible, icon, typeIcon, roaming, true);
+ }
+
+ protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon,
+ boolean roaming, boolean inet) {
ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class);
@@ -342,7 +348,9 @@
anyInt(), eq(roaming));
IconState iconState = iconArg.getValue();
- assertEquals("Signal icon in status bar", icon, iconState.icon);
+ int state = icon == -1 ? 0
+ : SignalDrawable.getState(icon, SignalStrength.NUM_SIGNAL_STRENGTH_BINS, !inet);
+ assertEquals("Signal icon in status bar", state, iconState.icon);
assertEquals("Data icon in status bar", typeIcon, (int) typeIconArg.getValue());
assertEquals("Visibility in status bar", visible, iconState.visible);
}
@@ -367,13 +375,15 @@
IconState iconState = iconArg.getValue();
+ int state = SignalDrawable.getState(icon, SignalStrength.NUM_SIGNAL_STRENGTH_BINS,
+ false);
assertEquals("Data icon in status bar", typeIcon, (int) typeIconArg.getValue());
- assertEquals("Signal icon in status bar", icon, iconState.icon);
+ assertEquals("Signal icon in status bar", state, iconState.icon);
assertEquals("Visibility in status bar", visible, iconState.visible);
iconState = qsIconArg.getValue();
assertEquals("Visibility in quick settings", qsVisible, iconState.visible);
- assertEquals("Signal icon in quick settings", qsIcon, iconState.icon);
+ assertEquals("Signal icon in quick settings", state, iconState.icon);
assertEquals("Data icon in quick settings", qsTypeIcon, (int) qsTypeIconArg.getValue());
assertEquals("Data direction in in quick settings", dataIn,
(boolean) dataInArg.getValue());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index e47f750..dfe00f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -24,7 +24,7 @@
public void test3gDataIcon() {
setupDefaultSignal();
- verifyDataIndicators(TelephonyIcons.DATA_3G[1][0 /* No direction */],
+ verifyDataIndicators(TelephonyIcons.ICON_3G,
TelephonyIcons.QS_DATA_3G);
}
@@ -34,7 +34,7 @@
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
TelephonyManager.NETWORK_TYPE_GSM);
- verifyDataIndicators(TelephonyIcons.DATA_G[1][0 /* No direction */],
+ verifyDataIndicators(TelephonyIcons.ICON_G,
TelephonyIcons.QS_DATA_G);
}
@@ -44,7 +44,7 @@
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
TelephonyManager.NETWORK_TYPE_CDMA);
- verifyDataIndicators(TelephonyIcons.DATA_1X[1][0 /* No direction */],
+ verifyDataIndicators(TelephonyIcons.ICON_1X,
TelephonyIcons.QS_DATA_1X);
}
@@ -54,7 +54,7 @@
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
TelephonyManager.NETWORK_TYPE_EDGE);
- verifyDataIndicators(TelephonyIcons.DATA_E[1][0 /* No direction */],
+ verifyDataIndicators(TelephonyIcons.ICON_E,
TelephonyIcons.QS_DATA_E);
}
@@ -64,7 +64,7 @@
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
TelephonyManager.NETWORK_TYPE_LTE);
- verifyDataIndicators(TelephonyIcons.DATA_LTE[1][0 /* No direction */],
+ verifyDataIndicators(TelephonyIcons.ICON_LTE,
TelephonyIcons.QS_DATA_LTE);
}
@@ -74,7 +74,7 @@
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
TelephonyManager.NETWORK_TYPE_HSPA);
- verifyDataIndicators(TelephonyIcons.DATA_H[1][0 /* No direction */],
+ verifyDataIndicators(TelephonyIcons.ICON_H,
TelephonyIcons.QS_DATA_H);
}
@@ -103,7 +103,7 @@
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
TelephonyManager.NETWORK_TYPE_LTE);
- verifyDataIndicators(TelephonyIcons.DATA_4G[1][0 /* No direction */],
+ verifyDataIndicators(TelephonyIcons.ICON_4G,
TelephonyIcons.QS_DATA_4G);
}
@@ -147,7 +147,7 @@
// the after work.
mNetworkController.handleConfigurationChanged();
- verifyDataIndicators(TelephonyIcons.DATA_4G[1][0 /* No direction */],
+ verifyDataIndicators(TelephonyIcons.ICON_4G,
TelephonyIcons.QS_DATA_4G);
}
@@ -157,13 +157,13 @@
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
TelephonyManager.NETWORK_TYPE_LTE);
- verifyDataIndicators(TelephonyIcons.DATA_LTE[1][0 /* No direction */],
+ verifyDataIndicators(TelephonyIcons.ICON_LTE,
TelephonyIcons.QS_DATA_LTE);
when(mServiceState.getDataNetworkType())
.thenReturn(TelephonyManager.NETWORK_TYPE_HSPA);
updateServiceState();
- verifyDataIndicators(TelephonyIcons.DATA_H[1][0 /* No direction */],
+ verifyDataIndicators(TelephonyIcons.ICON_H,
TelephonyIcons.QS_DATA_H);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index 1555856..1627925 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -30,6 +30,7 @@
import com.android.internal.telephony.TelephonyIntents;
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.SignalDrawable;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -60,7 +61,7 @@
mMockSubDefaults, mock(DeviceProvisionedController.class));
setupNetworkController();
- verifyLastMobileDataIndicators(false, 0, 0);
+ verifyLastMobileDataIndicators(false, -1, 0);
}
@Test
@@ -132,45 +133,45 @@
@Test
public void testSignalStrength() {
- for (int testStrength = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
- testStrength <= SignalStrength.SIGNAL_STRENGTH_GREAT; testStrength++) {
+ for (int testStrength = 0;
+ testStrength < SignalStrength.NUM_SIGNAL_STRENGTH_BINS; testStrength++) {
setupDefaultSignal();
setLevel(testStrength);
verifyLastMobileDataIndicators(true,
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][testStrength], DEFAULT_ICON);
+ testStrength, DEFAULT_ICON);
// Verify low inet number indexing.
setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, false, true);
verifyLastMobileDataIndicators(true,
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[0][testStrength], DEFAULT_ICON);
+ testStrength, DEFAULT_ICON, false, false);
}
}
@Test
public void testCdmaSignalStrength() {
- for (int testStrength = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
- testStrength <= SignalStrength.SIGNAL_STRENGTH_GREAT; testStrength++) {
+ for (int testStrength = 0;
+ testStrength < SignalStrength.NUM_SIGNAL_STRENGTH_BINS; testStrength++) {
setupDefaultSignal();
setCdma();
setLevel(testStrength);
verifyLastMobileDataIndicators(true,
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][testStrength],
- TelephonyIcons.DATA_1X[1][0 /* No direction */]);
+ testStrength,
+ TelephonyIcons.ICON_1X);
}
}
@Test
public void testSignalRoaming() {
- for (int testStrength = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
- testStrength <= SignalStrength.SIGNAL_STRENGTH_GREAT; testStrength++) {
+ for (int testStrength = 0;
+ testStrength < SignalStrength.NUM_SIGNAL_STRENGTH_BINS; testStrength++) {
setupDefaultSignal();
setGsmRoaming(true);
setLevel(testStrength);
verifyLastMobileDataIndicators(true,
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[1][testStrength],
+ testStrength,
DEFAULT_ICON, true);
}
}
@@ -185,8 +186,8 @@
setLevel(testStrength);
verifyLastMobileDataIndicators(true,
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[1][testStrength],
- TelephonyIcons.DATA_1X[1][0 /* No direction */], true);
+ testStrength,
+ TelephonyIcons.ICON_1X, true);
}
}
@@ -198,7 +199,7 @@
setLevel(testStrength);
verifyLastQsMobileDataIndicators(true,
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][testStrength],
+ testStrength,
DEFAULT_QS_ICON, false, false);
}
}
@@ -212,8 +213,8 @@
setLevel(testStrength);
verifyLastQsMobileDataIndicators(true,
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][testStrength],
- TelephonyIcons.QS_ICON_1X, false, false);
+ testStrength,
+ TelephonyIcons.QS_DATA_1X, false, false);
}
}
@@ -223,7 +224,7 @@
setConnectivity(mMobileSignalController.mTransportType, false, false);
setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, true, true);
- verifyLastMobileDataIndicators(true, TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][2], 0);
+ verifyLastMobileDataIndicators(true, DEFAULT_LEVEL, 0);
}
// Some tests of actual NetworkController code, just internals not display stuff
@@ -418,7 +419,7 @@
updateDataActivity(TelephonyManager.DATA_ACTIVITY_IN);
verifyLastQsMobileDataIndicators(true /* visible */,
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL] /* icon */,
+ DEFAULT_LEVEL /* icon */,
DEFAULT_QS_ICON /* typeIcon */,
true /* dataIn */,
false /* dataOut */);
@@ -432,11 +433,10 @@
updateDataActivity(TelephonyManager.DATA_ACTIVITY_OUT);
verifyLastQsMobileDataIndicators(true /* visible */,
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL] /* icon */,
+ DEFAULT_LEVEL /* icon */,
DEFAULT_QS_ICON /* typeIcon */,
false /* dataIn */,
true /* dataOut */);
-
}
@Test
@@ -446,7 +446,7 @@
updateDataActivity(TelephonyManager.DATA_ACTIVITY_INOUT);
verifyLastQsMobileDataIndicators(true /* visible */,
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL] /* icon */,
+ DEFAULT_LEVEL /* icon */,
DEFAULT_QS_ICON /* typeIcon */,
true /* dataIn */,
true /* dataOut */);
@@ -460,7 +460,7 @@
updateDataActivity(TelephonyManager.DATA_ACTIVITY_NONE);
verifyLastQsMobileDataIndicators(true /* visible */,
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL] /* icon */,
+ DEFAULT_LEVEL /* icon */,
DEFAULT_QS_ICON /* typeIcon */,
false /* dataIn */,
false /* dataOut */);
@@ -476,7 +476,7 @@
// Verify baseline
verifyLastMobileDataIndicators(true /* visible */,
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][strength] /* strengthIcon */,
+ strength /* strengthIcon */,
DEFAULT_ICON /* typeIcon */);
// API call is made
@@ -484,7 +484,7 @@
// Carrier network change is true, show special indicator
verifyLastMobileDataIndicators(true /* visible */,
- TelephonyIcons.TELEPHONY_CARRIER_NETWORK_CHANGE[0][0] /* strengthIcon */,
+ SignalDrawable.getCarrierChangeState(SignalStrength.NUM_SIGNAL_STRENGTH_BINS),
0 /* typeIcon */);
// Revert back
@@ -492,7 +492,7 @@
// Verify back in previous state
verifyLastMobileDataIndicators(true /* visible */,
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][strength] /* strengthIcon */,
+ strength /* strengthIcon */,
DEFAULT_ICON /* typeIcon */);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
index 483a837..73fa5aa1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
@@ -218,7 +218,7 @@
setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, true, true);
setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
verifyLastMobileDataIndicators(true,
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[1][DEFAULT_LEVEL],
+ DEFAULT_LEVEL,
0, true);
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 63bf373..57ef6d0 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -48,6 +48,7 @@
import android.provider.Settings;
import android.service.autofill.AutofillService;
import android.service.autofill.AutofillServiceInfo;
+import android.service.autofill.FillRequest;
import android.service.autofill.IAutoFillService;
import android.text.TextUtils;
import android.util.LocalLog;
@@ -169,7 +170,8 @@
structure.sanitizeForParceling(true);
// TODO(b/33197203): Need to pipe the bundle
- session.mRemoteFillService.onFillRequest(structure, null, session.mFlags);
+ FillRequest request = new FillRequest(structure, null, session.mFlags);
+ session.mRemoteFillService.onFillRequest(request);
}
};
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index dd520ac..3badcfc 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -20,12 +20,10 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.assist.AssistStructure;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.os.Bundle;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.ICancellationSignal;
@@ -33,10 +31,12 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.autofill.AutofillService;
+import android.service.autofill.FillRequest;
import android.service.autofill.FillResponse;
import android.service.autofill.IAutoFillService;
import android.service.autofill.IFillCallback;
import android.service.autofill.ISaveCallback;
+import android.service.autofill.SaveRequest;
import android.text.format.DateUtils;
import android.util.Slog;
@@ -88,7 +88,7 @@
public interface FillServiceCallbacks {
void onFillRequestSuccess(@Nullable FillResponse response,
- @NonNull String servicePackageName);
+ @NonNull String servicePackageName, int requestId);
void onFillRequestFailure(@Nullable CharSequence message,
@NonNull String servicePackageName);
void onSaveRequestSuccess(@NonNull String servicePackageName);
@@ -134,17 +134,16 @@
mCallbacks.onServiceDied(this);
}
- public void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle extras,
- int flags) {
+ public void onFillRequest(@NonNull FillRequest request) {
cancelScheduledUnbind();
- final PendingFillRequest request = new PendingFillRequest(structure, extras, this, flags);
- mHandler.obtainMessageO(MyHandler.MSG_ON_PENDING_REQUEST, request).sendToTarget();
+ final PendingFillRequest pendingRequest = new PendingFillRequest(request, this);
+ mHandler.obtainMessageO(MyHandler.MSG_ON_PENDING_REQUEST, pendingRequest).sendToTarget();
}
- public void onSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle extras) {
+ public void onSaveRequest(@NonNull SaveRequest request) {
cancelScheduledUnbind();
- final PendingSaveRequest request = new PendingSaveRequest(structure, extras, this);
- mHandler.obtainMessageO(MyHandler.MSG_ON_PENDING_REQUEST, request).sendToTarget();
+ final PendingSaveRequest pendingRequest = new PendingSaveRequest(request, this);
+ mHandler.obtainMessageO(MyHandler.MSG_ON_PENDING_REQUEST, pendingRequest).sendToTarget();
}
// Note: we are dumping without a lock held so this is a bit racy but
@@ -253,10 +252,11 @@
}
private void dispatchOnFillRequestSuccess(PendingRequest pendingRequest,
- FillResponse response) {
+ FillResponse response, int requestId) {
mHandler.getHandler().post(() -> {
if (handleResponseCallbackCommon(pendingRequest)) {
- mCallbacks.onFillRequestSuccess(response, mComponentName.getPackageName());
+ mCallbacks.onFillRequestSuccess(response, mComponentName.getPackageName(),
+ requestId);
}
});
}
@@ -392,18 +392,13 @@
private static final class PendingFillRequest extends PendingRequest {
private final Object mLock = new Object();
private final WeakReference<RemoteFillService> mWeakService;
- private final AssistStructure mStructure;
- private final Bundle mExtras;
+ private final FillRequest mRequest;
private final IFillCallback mCallback;
private ICancellationSignal mCancellation;
private boolean mCancelled;
- private int mFlags;
- public PendingFillRequest(AssistStructure structure,
- Bundle extras, RemoteFillService service, int flags) {
- mStructure = structure;
- mExtras = extras;
- mFlags = flags;
+ public PendingFillRequest(FillRequest request, RemoteFillService service) {
+ mRequest = request;
mWeakService = new WeakReference<>(service);
mCallback = new IFillCallback.Stub() {
@Override
@@ -425,11 +420,11 @@
}
@Override
- public void onSuccess(FillResponse response) {
+ public void onSuccess(FillResponse response, int requestId) {
RemoteFillService remoteService = mWeakService.get();
if (remoteService != null) {
remoteService.dispatchOnFillRequestSuccess(
- PendingFillRequest.this, response);
+ PendingFillRequest.this, response, requestId);
}
}
@@ -449,8 +444,7 @@
RemoteFillService remoteService = mWeakService.get();
if (remoteService != null) {
try {
- remoteService.mAutoFillService.onFillRequest(mStructure,
- mExtras, mCallback, mFlags);
+ remoteService.mAutoFillService.onFillRequest(mRequest, mCallback);
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Error calling on fill request", e);
cancel();
@@ -481,14 +475,12 @@
private static final class PendingSaveRequest extends PendingRequest {
private final WeakReference<RemoteFillService> mWeakService;
- private final AssistStructure mStructure;
- private final Bundle mExtras;
+ private final SaveRequest mRequest;
private final ISaveCallback mCallback;
- public PendingSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle extras,
+ public PendingSaveRequest(@NonNull SaveRequest request,
@NonNull RemoteFillService service) {
- mStructure = structure;
- mExtras = extras;
+ mRequest = request;
mWeakService = new WeakReference<>(service);
mCallback = new ISaveCallback.Stub() {
@Override
@@ -516,7 +508,7 @@
final RemoteFillService service = mWeakService.get();
if (service != null) {
try {
- service.mAutoFillService.onSaveRequest(mStructure, mExtras, mCallback);
+ service.mAutoFillService.onSaveRequest(mRequest, mCallback);
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Error calling on save request", e);
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 0b1381e..5feb81d 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -44,11 +44,15 @@
import android.os.RemoteException;
import android.service.autofill.AutofillService;
import android.service.autofill.Dataset;
+import android.service.autofill.FillContext;
+import android.service.autofill.FillRequest;
import android.service.autofill.FillResponse;
import android.service.autofill.SaveInfo;
+import android.service.autofill.SaveRequest;
import android.util.ArrayMap;
import android.util.DebugUtils;
import android.util.Slog;
+import android.util.SparseArray;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
@@ -125,7 +129,7 @@
RemoteFillService mRemoteFillService;
@GuardedBy("mLock")
- private ArrayList<FillResponse> mResponses;
+ private SparseArray<FillResponse> mResponses;
/**
* Response that requires a service authentitcation request.
@@ -156,7 +160,7 @@
* and used on subsequent {@code onFillRequest()} and {@code onSaveRequest()} calls.
*/
@GuardedBy("mLock")
- private Bundle mExtras;
+ private Bundle mClientState;
/**
* Flags used to start the session.
@@ -222,7 +226,7 @@
// FillServiceCallbacks
@Override
public void onFillRequestSuccess(@Nullable FillResponse response,
- @NonNull String servicePackageName) {
+ @NonNull String servicePackageName, int requestId) {
if (response == null) {
if ((mFlags & FLAG_MANUAL_REQUEST) != 0) {
getUiForShowing().showError(R.string.autofill_error_cannot_autofill);
@@ -243,7 +247,7 @@
// TODO(b/33197203 , b/35707731): make sure it's ignored if there is one already
mResponseWaitingAuth = response;
}
- processResponseLocked(response);
+ processResponseLocked(response, requestId);
}
final LogMaker log = (new LogMaker(MetricsEvent.AUTOFILL_REQUEST))
@@ -343,9 +347,8 @@
if (id.equals(mCurrentViewId)) {
try {
final ViewState view = mViewStates.get(id);
- mClient.requestShowFillUi(mWindowToken, id, width, height,
- view.getVirtualBounds(),
- presenter);
+ mClient.requestShowFillUi(this.id, mWindowToken, id, width, height,
+ view.getVirtualBounds(), presenter);
} catch (RemoteException e) {
Slog.e(TAG, "Error requesting to show fill UI", e);
}
@@ -363,7 +366,7 @@
public void requestHideFillUi(AutofillId id) {
synchronized (mLock) {
try {
- mClient.requestHideFillUi(mWindowToken, id);
+ mClient.requestHideFillUi(this.id, mWindowToken, id);
} catch (RemoteException e) {
Slog.e(TAG, "Error requesting to hide fill UI", e);
}
@@ -395,12 +398,18 @@
AutofillManager.EXTRA_AUTHENTICATION_RESULT);
if (result instanceof FillResponse) {
mMetricsLogger.action(MetricsEvent.AUTOFILL_AUTHENTICATED, mPackageName);
+ final int requestIndex = mResponses.indexOfValue(mResponseWaitingAuth);
mResponseWaitingAuth = null;
- processResponseLocked((FillResponse) result);
+ if (requestIndex >= 0) {
+ final int requestId = mResponses.keyAt(requestIndex);
+ processResponseLocked((FillResponse) result, requestId);
+ } else {
+ Slog.e(TAG, "Error cannot find id for auth response");
+ }
} else if (result instanceof Dataset) {
final Dataset dataset = (Dataset) result;
for (int i = 0; i < mResponses.size(); i++) {
- final FillResponse response = mResponses.get(i);
+ final FillResponse response = mResponses.valueAt(i);
final int index = response.getDatasets().indexOf(mDatasetWaitingAuth);
if (index >= 0) {
response.getDatasets().set(index, dataset);
@@ -441,12 +450,18 @@
return true;
}
- final FillResponse response = mResponses.get(mResponses.size() - 1);
+ final int lastResponseIdx = getLastResponseIndex();
+ if (lastResponseIdx < 0) {
+ Slog.d(TAG, "showSaveLocked(): mResponses=" + mResponses
+ + ", mViewStates=" + mViewStates);
+ return true;
+ }
+ final FillResponse response = mResponses.valueAt(lastResponseIdx);
final SaveInfo saveInfo = response.getSaveInfo();
if (DEBUG) {
- Slog.d(TAG,
- "showSaveLocked(): mResponses=" + mResponses + ", mViewStates=" + mViewStates);
+ Slog.d(TAG, "showSaveLocked(): mResponses=" + mResponses
+ + ", mViewStates=" + mViewStates);
}
/*
@@ -573,7 +588,15 @@
mStructure.dump();
}
- mRemoteFillService.onSaveRequest(mStructure, mExtras);
+ // TODO(b/33197203): Implement partitioning properly
+ final int lastResponseIdx = getLastResponseIndex();
+ final int requestId = mResponses.keyAt(lastResponseIdx);
+ final FillContext fillContext = new FillContext(requestId, mStructure);
+ final ArrayList fillContexts = new ArrayList(1);
+ fillContexts.add(fillContext);
+
+ final SaveRequest saveRequest = new SaveRequest(fillContexts, mClientState);
+ mRemoteFillService.onSaveRequest(saveRequest);
}
void updateLocked(AutofillId id, Rect virtualBounds, AutofillValue value, int flags) {
@@ -687,7 +710,9 @@
overlay.focused = id.equals(viewState.id);
node.setAutofillOverlay(overlay);
}
- mRemoteFillService.onFillRequest(mStructure, mExtras, 0);
+
+ FillRequest request = new FillRequest(mStructure, mClientState, 0);
+ mRemoteFillService.onFillRequest(request);
return newViewState;
}
@@ -716,7 +741,7 @@
}
if (!mHasCallback) return;
try {
- mClient.notifyNoFillUi(mWindowToken, mCurrentViewId);
+ mClient.notifyNoFillUi(id, mWindowToken, mCurrentViewId);
} catch (RemoteException e) {
Slog.e(TAG, "Error notifying client no fill UI: windowToken=" + mWindowToken
+ " id=" + mCurrentViewId, e);
@@ -724,17 +749,17 @@
}
}
- private void processResponseLocked(FillResponse response) {
+ private void processResponseLocked(FillResponse response, int requestId) {
if (DEBUG) {
Slog.d(TAG, "processResponseLocked(mCurrentViewId=" + mCurrentViewId + "):" + response);
}
if (mResponses == null) {
- mResponses = new ArrayList<>(4);
+ mResponses = new SparseArray<>(4);
}
- mResponses.add(response);
+ mResponses.put(requestId, response);
if (response != null) {
- mExtras = response.getExtras();
+ mClientState = response.getClientState();
}
setViewStatesLocked(response, ViewState.STATE_FILLABLE);
@@ -852,7 +877,7 @@
private void startAuthentication(IntentSender intent, Intent fillInIntent) {
try {
synchronized (mLock) {
- mClient.authenticate(intent, fillInIntent);
+ mClient.authenticate(id, intent, fillInIntent);
}
} catch (RemoteException e) {
Slog.e(TAG, "Error launching auth intent", e);
@@ -885,7 +910,8 @@
}
}
pw.print(prefix); pw.print("mHasCallback: "); pw.println(mHasCallback);
- pw.print(prefix); pw.print("mExtras: "); pw.println(Helper.bundleToString(mExtras));
+ pw.print(prefix); pw.print("mClientState: "); pw.println(
+ Helper.bundleToString(mClientState));
mRemoteFillService.dump(prefix, pw);
}
@@ -895,7 +921,7 @@
if (DEBUG) {
Slog.d(TAG, "autoFillApp(): the buck is on the app: " + dataset);
}
- mClient.autofill(mWindowToken, dataset.getFieldIds(), dataset.getFieldValues());
+ mClient.autofill(id, mWindowToken, dataset.getFieldIds(), dataset.getFieldValues());
setViewStatesLocked(null, dataset, ViewState.STATE_AUTOFILLED);
} catch (RemoteException e) {
Slog.w(TAG, "Error autofilling activity: " + e);
@@ -962,4 +988,20 @@
destroyLocked();
mService.removeSessionLocked(id);
}
+
+ private int getLastResponseIndex() {
+ // The response ids are monotonically increasing so
+ // we just find the largest id which is the last. We
+ // do not rely on the internal ordering in sparse
+ // array to avoid - wow this stopped working!?
+ int lastResponseIdx = -1;
+ int lastResponseId = -1;
+ final int responseCount = mResponses.size();
+ for (int i = 0; i < responseCount; i++) {
+ if (mResponses.keyAt(i) > lastResponseId) {
+ lastResponseIdx = i;
+ }
+ }
+ return lastResponseIdx;
+ }
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 4449da9..ab6a3a7 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -161,7 +161,8 @@
log.setType(MetricsProto.MetricsEvent.TYPE_DETAIL);
hideFillUiUiThread();
if (mCallback != null) {
- mCallback.authenticate(response.getAuthentication(), response.getExtras());
+ mCallback.authenticate(response.getAuthentication(),
+ response.getClientState());
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 50c0a12..45b0384 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -55,6 +55,7 @@
import android.net.Network;
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
+import android.net.MatchAllNetworkSpecifier;
import android.net.NetworkConfig;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
@@ -4044,11 +4045,8 @@
throw new IllegalArgumentException("Bad timeout specified");
}
- if (NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER
- .equals(networkCapabilities.getNetworkSpecifier())) {
- throw new IllegalArgumentException("Invalid network specifier - must not be '"
- + NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER + "'");
- }
+ MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(
+ networkCapabilities.getNetworkSpecifier());
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
nextNetworkRequestId(), type);
@@ -4117,6 +4115,9 @@
enforceMeteredApnPolicy(networkCapabilities);
ensureRequestableCapabilities(networkCapabilities);
+ MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(
+ networkCapabilities.getNetworkSpecifier());
+
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
nextNetworkRequestId(), NetworkRequest.Type.REQUEST);
NetworkRequestInfo nri = new NetworkRequestInfo(networkRequest, operation);
@@ -4178,6 +4179,9 @@
nc.addCapability(NET_CAPABILITY_FOREGROUND);
}
+ MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(
+ networkCapabilities.getNetworkSpecifier());
+
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder);
@@ -4195,6 +4199,9 @@
enforceAccessPermission();
}
+ MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(
+ networkCapabilities.getNetworkSpecifier());
+
NetworkRequest networkRequest = new NetworkRequest(
new NetworkCapabilities(networkCapabilities), TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2be5313..6b0a73b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -23885,6 +23885,15 @@
}
}
+ @Override
+ public long getActivityStartInitiatedTime(IBinder token) {
+ final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+ if (r != null) {
+ return r.mStartInitiatedTimeMs;
+ }
+ return 0;
+ }
+
void updateApplicationInfoLocked(@NonNull List<String> packagesToUpdate, int userId) {
final PackageManagerInternal packageManager = getPackageManagerInternalLocked();
final boolean updateFrameworkRes = packagesToUpdate.contains("android");
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 276b267..17c7dde 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -341,6 +341,12 @@
private final Rect mBounds = new Rect();
/**
+ * Denotes the timestamp at which this activity start was last initiated in the
+ * {@link SystemClock#uptimeMillis()} time base.
+ */
+ long mStartInitiatedTimeMs;
+
+ /**
* Temp configs used in {@link #ensureActivityConfigurationLocked(int, boolean)}
*/
private final Configuration mTmpConfig1 = new Configuration();
@@ -498,6 +504,8 @@
pw.print(" forceNewConfig="); pw.println(forceNewConfig);
pw.print(prefix); pw.print("mActivityType=");
pw.println(activityTypeToString(mActivityType));
+ pw.print(prefix); pw.print("mStartInitiatedTimeMs=");
+ TimeUtils.formatDuration(mStartInitiatedTimeMs, now, pw);
if (requestedVrComponent != null) {
pw.print(prefix);
pw.print("requestedVrComponent=");
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 56594d3..8f1c203 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -244,6 +244,7 @@
ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
TaskRecord inTask) {
+ final long activityStartTime = SystemClock.uptimeMillis();
int err = ActivityManager.START_SUCCESS;
ProcessRecord callerApp = null;
@@ -478,6 +479,7 @@
callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
mSupervisor, container, options, sourceRecord);
+ r.mStartInitiatedTimeMs = activityStartTime;
if (outActivity != null) {
outActivity[0] = r;
}
@@ -1029,6 +1031,7 @@
// so make sure the task now has the identity of the new intent.
top.getTask().setIntent(mStartActivity);
}
+ top.mStartInitiatedTimeMs = mStartActivity.mStartInitiatedTimeMs;
ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.getTask());
top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
mStartActivity.launchedFromPackage);
@@ -1052,6 +1055,7 @@
setTaskFromIntentActivity(reusedActivity);
if (!mAddingToTask && mReuseTask == null) {
+ reusedActivity.mStartInitiatedTimeMs = mStartActivity.mStartInitiatedTimeMs;
// We didn't do anything... but it was needed (a.k.a., client don't use that
// intent!) And for paranoia, make sure we have correctly resumed the top activity.
resumeTargetStackIfNeeded();
@@ -1084,6 +1088,7 @@
|| mLaunchSingleTop || mLaunchSingleTask);
if (dontStart) {
ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.getTask());
+ top.mStartInitiatedTimeMs = mStartActivity.mStartInitiatedTimeMs;
// For paranoia, make sure we have correctly resumed the top activity.
topStack.mLastPausedActivity = null;
if (mDoResume) {
@@ -1664,6 +1669,7 @@
// desires.
if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop)
&& intentActivity.realActivity.equals(mStartActivity.realActivity)) {
+ intentActivity.mStartInitiatedTimeMs = mStartActivity.mStartInitiatedTimeMs;
ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity,
intentActivity.getTask());
if (intentActivity.frontOfTask) {
diff --git a/services/print/java/com/android/server/print/CompanionDeviceManagerService.java b/services/print/java/com/android/server/print/CompanionDeviceManagerService.java
index d0dfc6c..122a954 100644
--- a/services/print/java/com/android/server/print/CompanionDeviceManagerService.java
+++ b/services/print/java/com/android/server/print/CompanionDeviceManagerService.java
@@ -17,12 +17,15 @@
package com.android.server.print;
+import static com.android.internal.util.CollectionUtils.size;
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.internal.util.Preconditions.checkState;
import android.Manifest;
import android.annotation.CheckResult;
import android.annotation.Nullable;
+import android.app.PendingIntent;
import android.companion.AssociationRequest;
import android.companion.CompanionDeviceManager;
import android.companion.ICompanionDeviceDiscoveryService;
@@ -46,13 +49,18 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.provider.Settings;
+import android.provider.SettingsStringUtil.ComponentNameSet;
+import android.text.BidiFormatter;
import android.util.AtomicFile;
import android.util.ExceptionUtils;
+import android.util.Log;
import android.util.Slog;
import android.util.Xml;
import com.android.internal.app.IAppOpsService;
import com.android.internal.content.PackageMonitor;
+import com.android.internal.notification.NotificationAccessConfirmationActivityContract;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.server.FgThread;
@@ -79,6 +87,7 @@
//TODO schedule stopScan on activity destroy(except if configuration change)
//TODO on associate called again after configuration change -> replace old callback with new
//TODO avoid leaking calling activity in IFindDeviceCallback (see PrintManager#print for example)
+//TODO check user-feature present in manifest on API calls
/** @hide */
public class CompanionDeviceManagerService extends SystemService implements Binder.DeathRecipient {
@@ -140,10 +149,10 @@
@Override
public void binderDied() {
- Handler.getMain().post(this::handleBinderDied);
+ Handler.getMain().post(this::cleanup);
}
- private void handleBinderDied() {
+ private void cleanup() {
mServiceConnection = unbind(mServiceConnection);
mFindDeviceCallback = unlinkToDeath(mFindDeviceCallback, this, 0);
}
@@ -207,7 +216,6 @@
}
}
-
@Override
public List<String> getAssociations(String callingPackage, int userId)
throws RemoteException {
@@ -217,12 +225,13 @@
a -> a.deviceAddress);
}
+ //TODO also revoke notification access
@Override
public void disassociate(String deviceMacAddress, String callingPackage)
throws RemoteException {
checkNotNull(deviceMacAddress);
checkCallerIsSystemOr(callingPackage);
- updateAssociations(associations -> ArrayUtils.remove(associations,
+ updateAssociations(associations -> CollectionUtils.remove(associations,
new Association(getCallingUserId(), deviceMacAddress, callingPackage)));
}
@@ -237,11 +246,49 @@
checkArgument(getCallingUserId() == userId,
"Must be called by either same user or system");
-
mAppOpsManager.checkPackage(Binder.getCallingUid(), pkg);
}
+
+ @Override
+ public PendingIntent requestNotificationAccess(ComponentName component)
+ throws RemoteException {
+ String callingPackage = component.getPackageName();
+ checkCanCallNotificationApi(callingPackage);
+ int userId = getCallingUserId();
+ String packageTitle = BidiFormatter.getInstance().unicodeWrap(
+ getPackageInfo(callingPackage, userId)
+ .applicationInfo
+ .loadSafeLabel(getContext().getPackageManager())
+ .toString());
+ long identity = Binder.clearCallingIdentity();
+ try {
+ return PendingIntent.getActivity(getContext(),
+ 0 /* request code */,
+ NotificationAccessConfirmationActivityContract.launcherIntent(
+ userId, component, packageTitle),
+ PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT
+ | PendingIntent.FLAG_CANCEL_CURRENT);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public boolean hasNotificationAccess(ComponentName component) throws RemoteException {
+ checkCanCallNotificationApi(component.getPackageName());
+ String setting = Settings.Secure.getString(getContext().getContentResolver(),
+ Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
+ return new ComponentNameSet(setting).contains(component);
+ }
+
+ private void checkCanCallNotificationApi(String callingPackage) throws RemoteException {
+ checkCallerIsSystemOr(callingPackage);
+ checkState(!ArrayUtils.isEmpty(readAllAssociations(getCallingUserId(), callingPackage)),
+ "App must have an association before calling this API");
+ }
}
+
private int getCallingUserId() {
return UserHandle.getUserId(Binder.getCallingUid());
}
@@ -263,7 +310,7 @@
mFindDeviceCallback.asBinder().linkToDeath(
CompanionDeviceManagerService.this, 0);
} catch (RemoteException e) {
- handleBinderDied();
+ cleanup();
return;
}
try {
@@ -291,10 +338,26 @@
return new ICompanionDeviceDiscoveryServiceCallback.Stub() {
@Override
+ public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ try {
+ return super.onTransact(code, data, reply, flags);
+ } catch (Throwable e) {
+ Slog.e(LOG_TAG, "Error during IPC", e);
+ throw ExceptionUtils.propagate(e, RemoteException.class);
+ }
+ }
+
+ @Override
public void onDeviceSelected(String packageName, int userId, String deviceAddress) {
- //TODO unbind
updateSpecialAccessPermissionForAssociatedPackage(packageName, userId);
recordAssociation(packageName, deviceAddress);
+ cleanup();
+ }
+
+ @Override
+ public void onDeviceSelectionCancel() {
+ cleanup();
}
};
}
@@ -345,22 +408,29 @@
}
private void recordAssociation(String priviledgedPackage, String deviceAddress) {
- updateAssociations((associations) -> ArrayUtils.add(associations,
- new Association(getCallingUserId(), deviceAddress, priviledgedPackage)));
+ if (DEBUG) {
+ Log.i(LOG_TAG, "recordAssociation(priviledgedPackage = " + priviledgedPackage
+ + ", deviceAddress = " + deviceAddress + ")");
+ }
+ int userId = getCallingUserId();
+ updateAssociations(associations -> CollectionUtils.add(associations,
+ new Association(userId, deviceAddress, priviledgedPackage)));
}
- private void updateAssociations(Function<ArrayList<Association>, List<Association>> update) {
+ private void updateAssociations(Function<List<Association>, List<Association>> update) {
updateAssociations(update, getCallingUserId());
}
- private void updateAssociations(Function<ArrayList<Association>, List<Association>> update,
+ private void updateAssociations(Function<List<Association>, List<Association>> update,
int userId) {
final AtomicFile file = getStorageFileForUser(userId);
synchronized (file) {
- final ArrayList<Association> old = readAllAssociations(userId);
- final List<Association> associations = update.apply(old);
- if (Objects.equals(old, associations)) return;
+ List<Association> associations = readAllAssociations(userId);
+ final List<Association> old = CollectionUtils.copyOf(associations);
+ associations = update.apply(associations);
+ if (size(old) == size(associations)) return;
+ List<Association> finalAssociations = associations;
file.write((out) -> {
XmlSerializer xml = Xml.newSerializer();
try {
@@ -369,8 +439,8 @@
xml.startDocument(null, true);
xml.startTag(null, XML_TAG_ASSOCIATIONS);
- for (int i = 0; i < CollectionUtils.size(associations); i++) {
- Association association = associations.get(i);
+ for (int i = 0; i < size(finalAssociations); i++) {
+ Association association = finalAssociations.get(i);
xml.startTag(null, XML_TAG_ASSOCIATION)
.attribute(null, XML_ATTR_PACKAGE, association.companionAppPackage)
.attribute(null, XML_ATTR_DEVICE, association.deviceAddress)
@@ -386,15 +456,6 @@
});
}
-
-
- //TODO Show dialog before recording notification access
-// final SettingStringHelper setting =
-// new SettingStringHelper(
-// getContext().getContentResolver(),
-// Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
-// getUserId());
-// setting.write(ColonDelimitedSet.OfStrings.add(setting.read(), priviledgedPackage));
}
private AtomicFile getStorageFileForUser(int uid) {
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index c562cb9..7c7a3f8 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -42,6 +42,7 @@
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.MatchAllNetworkSpecifier;
import android.net.Network;
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
@@ -51,7 +52,9 @@
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkMisc;
import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
import android.net.RouteInfo;
+import android.net.StringNetworkSpecifier;
import android.net.metrics.IpConnectivityLog;
import android.net.util.MultinetworkPolicyTracker;
import android.os.ConditionVariable;
@@ -64,12 +67,15 @@
import android.os.MessageQueue;
import android.os.Messenger;
import android.os.MessageQueue.IdleHandler;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.Process;
import android.os.SystemClock;
import android.provider.Settings;
import android.test.AndroidTestCase;
import android.test.mock.MockContentResolver;
import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
import android.util.Log;
import android.util.LogPrinter;
@@ -319,6 +325,11 @@
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
}
+ public void setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
+ mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
+ mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+ }
+
public void connectWithoutInternet() {
mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
@@ -1819,34 +1830,130 @@
captivePortalCallback.assertNoCallback();
}
- @SmallTest
- public void testInvalidNetworkSpecifier() {
- boolean execptionCalled = true;
+ private NetworkRequest.Builder newWifiRequestBuilder() {
+ return new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI);
+ }
- try {
- NetworkRequest.Builder builder = new NetworkRequest.Builder();
- builder.setNetworkSpecifier(MATCH_ALL_REQUESTS_NETWORK_SPECIFIER);
- execptionCalled = false;
- } catch (IllegalArgumentException e) {
- // do nothing - should get here
+ @SmallTest
+ public void testNetworkSpecifier() {
+ NetworkRequest rEmpty1 = newWifiRequestBuilder().build();
+ NetworkRequest rEmpty2 = newWifiRequestBuilder().setNetworkSpecifier((String) null).build();
+ NetworkRequest rEmpty3 = newWifiRequestBuilder().setNetworkSpecifier("").build();
+ NetworkRequest rEmpty4 = newWifiRequestBuilder().setNetworkSpecifier(
+ (NetworkSpecifier) null).build();
+ NetworkRequest rFoo = newWifiRequestBuilder().setNetworkSpecifier("foo").build();
+ NetworkRequest rBar = newWifiRequestBuilder().setNetworkSpecifier(
+ new StringNetworkSpecifier("bar")).build();
+
+ TestNetworkCallback cEmpty1 = new TestNetworkCallback();
+ TestNetworkCallback cEmpty2 = new TestNetworkCallback();
+ TestNetworkCallback cEmpty3 = new TestNetworkCallback();
+ TestNetworkCallback cEmpty4 = new TestNetworkCallback();
+ TestNetworkCallback cFoo = new TestNetworkCallback();
+ TestNetworkCallback cBar = new TestNetworkCallback();
+ TestNetworkCallback[] emptyCallbacks = new TestNetworkCallback[] {
+ cEmpty1, cEmpty2, cEmpty3 };
+
+ mCm.registerNetworkCallback(rEmpty1, cEmpty1);
+ mCm.registerNetworkCallback(rEmpty2, cEmpty2);
+ mCm.registerNetworkCallback(rEmpty3, cEmpty3);
+ mCm.registerNetworkCallback(rEmpty4, cEmpty4);
+ mCm.registerNetworkCallback(rFoo, cFoo);
+ mCm.registerNetworkCallback(rBar, cBar);
+
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(false);
+ cEmpty1.expectAvailableCallbacks(mWiFiNetworkAgent);
+ cEmpty2.expectAvailableCallbacks(mWiFiNetworkAgent);
+ cEmpty3.expectAvailableCallbacks(mWiFiNetworkAgent);
+ cEmpty4.expectAvailableCallbacks(mWiFiNetworkAgent);
+ assertNoCallbacks(cFoo, cBar);
+
+ mWiFiNetworkAgent.setNetworkSpecifier(new StringNetworkSpecifier("foo"));
+ cFoo.expectAvailableCallbacks(mWiFiNetworkAgent);
+ for (TestNetworkCallback c: emptyCallbacks) {
+ c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
+ }
+ cFoo.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
+ cFoo.assertNoCallback();
+
+ mWiFiNetworkAgent.setNetworkSpecifier(new StringNetworkSpecifier("bar"));
+ cFoo.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ cBar.expectAvailableCallbacks(mWiFiNetworkAgent);
+ for (TestNetworkCallback c: emptyCallbacks) {
+ c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
+ }
+ cBar.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
+ cBar.assertNoCallback();
+
+ mWiFiNetworkAgent.setNetworkSpecifier(null);
+ cBar.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ for (TestNetworkCallback c: emptyCallbacks) {
+ c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
}
- assertTrue("NetworkRequest builder with MATCH_ALL_REQUESTS_NETWORK_SPECIFIER",
- execptionCalled);
+ assertNoCallbacks(cEmpty1, cEmpty2, cEmpty3, cFoo, cBar);
+ }
+
+ @SmallTest
+ public void testInvalidNetworkSpecifier() {
+ try {
+ NetworkRequest.Builder builder = new NetworkRequest.Builder();
+ builder.setNetworkSpecifier(new MatchAllNetworkSpecifier());
+ fail("NetworkRequest builder with MatchAllNetworkSpecifier");
+ } catch (IllegalArgumentException expected) {
+ // expected
+ }
try {
NetworkCapabilities networkCapabilities = new NetworkCapabilities();
networkCapabilities.addTransportType(TRANSPORT_WIFI)
- .setNetworkSpecifier(NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER);
+ .setNetworkSpecifier(new MatchAllNetworkSpecifier());
mService.requestNetwork(networkCapabilities, null, 0, null,
ConnectivityManager.TYPE_WIFI);
- execptionCalled = false;
- } catch (IllegalArgumentException e) {
- // do nothing - should get here
+ fail("ConnectivityService requestNetwork with MatchAllNetworkSpecifier");
+ } catch (IllegalArgumentException expected) {
+ // expected
}
- assertTrue("ConnectivityService requestNetwork with MATCH_ALL_REQUESTS_NETWORK_SPECIFIER",
- execptionCalled);
+ class NonParcelableSpecifier extends NetworkSpecifier {
+ public boolean satisfiedBy(NetworkSpecifier other) { return false; }
+ };
+ class ParcelableSpecifier extends NonParcelableSpecifier implements Parcelable {
+ @Override public int describeContents() { return 0; }
+ @Override public void writeToParcel(Parcel p, int flags) {}
+ }
+ NetworkRequest.Builder builder;
+
+ builder = new NetworkRequest.Builder().addTransportType(TRANSPORT_ETHERNET);
+ try {
+ builder.setNetworkSpecifier(new NonParcelableSpecifier());
+ Parcel parcelW = Parcel.obtain();
+ builder.build().writeToParcel(parcelW, 0);
+ fail("Parceling a non-parcelable specifier did not throw an exception");
+ } catch (Exception e) {
+ // expected
+ }
+
+ builder = new NetworkRequest.Builder().addTransportType(TRANSPORT_ETHERNET);
+ builder.setNetworkSpecifier(new ParcelableSpecifier());
+ NetworkRequest nr = builder.build();
+ assertNotNull(nr);
+
+ try {
+ Parcel parcelW = Parcel.obtain();
+ nr.writeToParcel(parcelW, 0);
+ byte[] bytes = parcelW.marshall();
+ parcelW.recycle();
+
+ Parcel parcelR = Parcel.obtain();
+ parcelR.unmarshall(bytes, 0, bytes.length);
+ parcelR.setDataPosition(0);
+ NetworkRequest rereadNr = NetworkRequest.CREATOR.createFromParcel(parcelR);
+ fail("Unparceling a non-framework NetworkSpecifier did not throw an exception");
+ } catch (Exception e) {
+ // expected
+ }
}
@SmallTest