Merge "Allow system apps to define ephemeral permissions" into oc-dev
diff --git a/api/current.txt b/api/current.txt
index 862d541..0586d35 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -15,7 +15,6 @@
field public static final java.lang.String ACCESS_WIFI_STATE = "android.permission.ACCESS_WIFI_STATE";
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
- field public static final java.lang.String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
field public static final java.lang.String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
@@ -2877,7 +2876,8 @@
public static abstract class FingerprintGestureController.FingerprintGestureCallback {
ctor public FingerprintGestureController.FingerprintGestureCallback();
- method public void onGesture(int);
+ method public deprecated void onGesture(int);
+ method public void onGestureDetected(int);
method public void onGestureDetectionAvailabilityChanged(boolean);
}
@@ -3035,8 +3035,8 @@
field public static final java.lang.String KEY_PASSWORD = "password";
field public static final java.lang.String KEY_USERDATA = "userdata";
field public static final deprecated java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
- field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE = "android.accounts.key_legacy_not_visible";
- field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_VISIBLE = "android.accounts.key_legacy_visible";
+ field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE = "android:accounts:key_legacy_not_visible";
+ field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_VISIBLE = "android:accounts:key_legacy_visible";
field public static final int VISIBILITY_NOT_VISIBLE = 3; // 0x3
field public static final int VISIBILITY_UNDEFINED = 0; // 0x0
field public static final int VISIBILITY_USER_MANAGED_NOT_VISIBLE = 4; // 0x4
@@ -3943,7 +3943,7 @@
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 = 230; // 0xe6
- field public static final deprecated int IMPORTANCE_PERCEPTIBLE_DEPRECATED = 130; // 0x82
+ field public static final int IMPORTANCE_PERCEPTIBLE_PRE_26 = 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
@@ -4030,6 +4030,7 @@
method public static android.app.ActivityOptions makeTaskLaunchBehind();
method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
method public void requestUsageTimeReport(android.app.PendingIntent);
+ method public android.app.ActivityOptions setAppVerificationBundle(android.os.Bundle);
method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect);
method public android.app.ActivityOptions setLaunchDisplayId(int);
method public android.os.Bundle toBundle();
@@ -4817,6 +4818,7 @@
method public void onFragmentDetached(android.app.FragmentManager, android.app.Fragment);
method public void onFragmentPaused(android.app.FragmentManager, android.app.Fragment);
method public void onFragmentPreAttached(android.app.FragmentManager, android.app.Fragment, android.content.Context);
+ method public void onFragmentPreCreated(android.app.FragmentManager, android.app.Fragment, android.os.Bundle);
method public void onFragmentResumed(android.app.FragmentManager, android.app.Fragment);
method public void onFragmentSaveInstanceState(android.app.FragmentManager, android.app.Fragment, android.os.Bundle);
method public void onFragmentStarted(android.app.FragmentManager, android.app.Fragment);
@@ -4849,10 +4851,10 @@
method public abstract android.app.FragmentTransaction hide(android.app.Fragment);
method public abstract boolean isAddToBackStackAllowed();
method public abstract boolean isEmpty();
- method public abstract android.app.FragmentTransaction postOnCommit(java.lang.Runnable);
method public abstract android.app.FragmentTransaction remove(android.app.Fragment);
method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment);
method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment, java.lang.String);
+ method public abstract android.app.FragmentTransaction runOnCommit(java.lang.Runnable);
method public abstract android.app.FragmentTransaction setBreadCrumbShortTitle(int);
method public abstract android.app.FragmentTransaction setBreadCrumbShortTitle(java.lang.CharSequence);
method public abstract android.app.FragmentTransaction setBreadCrumbTitle(int);
@@ -4954,7 +4956,7 @@
method public final android.app.Activity getLastActivity();
method public final android.app.Instrumentation.ActivityResult getResult();
method public final boolean isBlocking();
- method public android.app.Instrumentation.ActivityResult onMatchIntent(android.content.Intent);
+ method public android.app.Instrumentation.ActivityResult onStartActivity(android.content.Intent);
method public final android.app.Activity waitForActivity();
method public final android.app.Activity waitForActivityWithTimeout(long);
}
@@ -4974,7 +4976,7 @@
public class KeyguardManager {
method public android.content.Intent createConfirmDeviceCredentialIntent(java.lang.CharSequence, java.lang.CharSequence);
- method public void dismissKeyguard(android.app.Activity, android.app.KeyguardManager.KeyguardDismissCallback, android.os.Handler);
+ method public deprecated void dismissKeyguard(android.app.Activity, android.app.KeyguardManager.KeyguardDismissCallback, android.os.Handler);
method public deprecated void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
method public boolean inKeyguardRestrictedInputMode();
method public boolean isDeviceLocked();
@@ -4982,6 +4984,7 @@
method public boolean isKeyguardLocked();
method public boolean isKeyguardSecure();
method public deprecated android.app.KeyguardManager.KeyguardLock newKeyguardLock(java.lang.String);
+ method public void requestDismissKeyguard(android.app.Activity, android.app.KeyguardManager.KeyguardDismissCallback);
}
public static abstract class KeyguardManager.KeyguardDismissCallback {
@@ -6112,17 +6115,6 @@
method public void onDetached();
}
- public final class WallpaperColors implements android.os.Parcelable {
- ctor public WallpaperColors(android.os.Parcel);
- ctor public WallpaperColors(java.util.List<android.util.Pair<android.graphics.Color, java.lang.Integer>>);
- ctor public WallpaperColors(java.util.List<android.util.Pair<android.graphics.Color, java.lang.Integer>>, boolean);
- method public int describeContents();
- method public java.util.List<android.util.Pair<android.graphics.Color, java.lang.Integer>> getColors();
- method public boolean supportsDarkText();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.app.WallpaperColors> CREATOR;
- }
-
public final class WallpaperInfo implements android.os.Parcelable {
ctor public WallpaperInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public int describeContents();
@@ -6145,8 +6137,6 @@
}
public class WallpaperManager {
- method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener);
- method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener, android.os.Handler);
method public void clear() throws java.io.IOException;
method public void clear(int) throws java.io.IOException;
method public void clearWallpaperOffsets(android.os.IBinder);
@@ -6161,7 +6151,6 @@
method public android.graphics.drawable.Drawable getDrawable();
method public android.graphics.drawable.Drawable getFastDrawable();
method public static android.app.WallpaperManager getInstance(android.content.Context);
- method public android.app.WallpaperColors getWallpaperColors(int);
method public android.os.ParcelFileDescriptor getWallpaperFile(int);
method public int getWallpaperId(int);
method public android.app.WallpaperInfo getWallpaperInfo();
@@ -6170,7 +6159,6 @@
method public boolean isWallpaperSupported();
method public android.graphics.drawable.Drawable peekDrawable();
method public android.graphics.drawable.Drawable peekFastDrawable();
- method public void removeOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener);
method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle);
method public void setBitmap(android.graphics.Bitmap) throws java.io.IOException;
method public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
@@ -6195,16 +6183,12 @@
field public static final java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
}
- public static abstract interface WallpaperManager.OnColorsChangedListener {
- method public abstract void onColorsChanged(android.app.WallpaperColors, int);
- }
-
}
package android.app.admin {
public final class ConnectEvent extends android.app.admin.NetworkEvent implements android.os.Parcelable {
- method public java.lang.String getIpAddress();
+ method public java.net.InetAddress getInetAddress();
method public int getPort();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.admin.ConnectEvent> CREATOR;
@@ -6509,7 +6493,7 @@
field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PROXY_PORT = "android.app.extra.PROVISIONING_WIFI_PROXY_PORT";
field public static final java.lang.String EXTRA_PROVISIONING_WIFI_SECURITY_TYPE = "android.app.extra.PROVISIONING_WIFI_SECURITY_TYPE";
field public static final java.lang.String EXTRA_PROVISIONING_WIFI_SSID = "android.app.extra.PROVISIONING_WIFI_SSID";
- field public static final int FLAG_EVICT_CE_KEY = 1; // 0x1
+ field public static final int FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY = 1; // 0x1
field public static final int FLAG_MANAGED_CAN_ACCESS_PARENT = 2; // 0x2
field public static final int FLAG_PARENT_CAN_ACCESS_MANAGED = 1; // 0x1
field public static final int KEYGUARD_DISABLE_FEATURES_ALL = 2147483647; // 0x7fffffff
@@ -6547,8 +6531,8 @@
public final class DnsEvent extends android.app.admin.NetworkEvent implements android.os.Parcelable {
method public java.lang.String getHostname();
- method public java.lang.String[] getIpAddresses();
- method public int getIpAddressesCount();
+ method public java.net.InetAddress[] getInetAddresses();
+ method public int getTotalResolvedAddressCount();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.admin.DnsEvent> CREATOR;
}
@@ -7007,8 +6991,8 @@
public final class StorageStats implements android.os.Parcelable {
method public int describeContents();
+ method public long getAppBytes();
method public long getCacheBytes();
- method public long getCodeBytes();
method public long getDataBytes();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.usage.StorageStats> CREATOR;
@@ -8216,8 +8200,10 @@
field public static final android.os.Parcelable.Creator<android.bluetooth.le.ScanResult> CREATOR;
field public static final int DATA_COMPLETE = 0; // 0x0
field public static final int DATA_TRUNCATED = 2; // 0x2
+ field public static final int PERIODIC_INTERVAL_NOT_PRESENT = 0; // 0x0
field public static final int PHY_UNUSED = 0; // 0x0
field public static final int SID_NOT_PRESENT = 255; // 0xff
+ field public static final int TX_POWER_NOT_PRESENT = 127; // 0x7f
}
public final class ScanSettings implements android.os.Parcelable {
@@ -8288,21 +8274,21 @@
method public android.companion.BluetoothDeviceFilter.Builder setNamePattern(java.util.regex.Pattern);
}
- public final class BluetoothLEDeviceFilter implements android.companion.DeviceFilter {
+ public final class BluetoothLeDeviceFilter implements android.companion.DeviceFilter {
method public int describeContents();
method public static int getRenamePrefixLengthLimit();
method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.companion.BluetoothLEDeviceFilter> CREATOR;
+ field public static final android.os.Parcelable.Creator<android.companion.BluetoothLeDeviceFilter> CREATOR;
}
- public static final class BluetoothLEDeviceFilter.Builder {
- ctor public BluetoothLEDeviceFilter.Builder();
- 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 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);
+ public static final class BluetoothLeDeviceFilter.Builder {
+ ctor public BluetoothLeDeviceFilter.Builder();
+ 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 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);
}
public final class CompanionDeviceManager {
@@ -8438,7 +8424,7 @@
ctor public ClipData(android.content.ClipDescription, android.content.ClipData.Item);
ctor public ClipData(android.content.ClipData);
method public void addItem(android.content.ClipData.Item);
- method public void addItem(android.content.ClipData.Item, android.content.ContentResolver);
+ method public void addItem(android.content.ContentResolver, android.content.ClipData.Item);
method public int describeContents();
method public android.content.ClipDescription getDescription();
method public android.content.ClipData.Item getItemAt(int);
@@ -13775,6 +13761,7 @@
method public void detachFromGLContext();
method public long getTimestamp();
method public void getTransformMatrix(float[]);
+ method public boolean isReleased();
method public void release();
method public void releaseTexImage();
method public void setDefaultBufferSize(int, int);
@@ -14507,7 +14494,7 @@
method public final void takePicture(android.hardware.Camera.ShutterCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback);
method public final void unlock();
field public static final java.lang.String ACTION_NEW_PICTURE = "android.hardware.action.NEW_PICTURE";
- field public static final deprecated java.lang.String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
+ field public static final java.lang.String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
field public static final int CAMERA_ERROR_EVICTED = 2; // 0x2
field public static final int CAMERA_ERROR_SERVER_DIED = 100; // 0x64
field public static final int CAMERA_ERROR_UNKNOWN = 1; // 0x1
@@ -14768,18 +14755,16 @@
field public static final int RGBX_8888 = 2; // 0x2
field public static final int RGB_565 = 4; // 0x4
field public static final int RGB_888 = 3; // 0x3
- field public static final long USAGE0_CPU_READ = 2L; // 0x2L
- field public static final long USAGE0_CPU_READ_OFTEN = 6L; // 0x6L
- field public static final long USAGE0_CPU_WRITE = 32L; // 0x20L
- field public static final long USAGE0_CPU_WRITE_OFTEN = 96L; // 0x60L
- field public static final long USAGE0_GPU_COLOR_OUTPUT = 2048L; // 0x800L
- field public static final long USAGE0_GPU_CUBEMAP = 8192L; // 0x2000L
- field public static final long USAGE0_GPU_DATA_BUFFER = 16384L; // 0x4000L
- field public static final long USAGE0_GPU_SAMPLED_IMAGE = 1024L; // 0x400L
- field public static final long USAGE0_GPU_STORAGE_IMAGE = 3072L; // 0xc00L
- field public static final long USAGE0_PROTECTED_CONTENT = 262144L; // 0x40000L
- field public static final long USAGE0_SENSOR_DIRECT_DATA = 536870912L; // 0x20000000L
- field public static final long USAGE0_VIDEO_ENCODE = 2097152L; // 0x200000L
+ field public static final long USAGE_CPU_READ_OFTEN = 3L; // 0x3L
+ field public static final long USAGE_CPU_READ_RARELY = 2L; // 0x2L
+ field public static final long USAGE_CPU_WRITE_OFTEN = 48L; // 0x30L
+ field public static final long USAGE_CPU_WRITE_RARELY = 32L; // 0x20L
+ field public static final long USAGE_GPU_COLOR_OUTPUT = 512L; // 0x200L
+ field public static final long USAGE_GPU_DATA_BUFFER = 16777216L; // 0x1000000L
+ field public static final long USAGE_GPU_SAMPLED_IMAGE = 256L; // 0x100L
+ field public static final long USAGE_PROTECTED_CONTENT = 16384L; // 0x4000L
+ field public static final long USAGE_SENSOR_DIRECT_DATA = 8388608L; // 0x800000L
+ field public static final long USAGE_VIDEO_ENCODE = 65536L; // 0x10000L
}
public final class Sensor {
@@ -25411,8 +25396,8 @@
method public boolean requestBandwidthUpdate(android.net.Network);
method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, android.os.Handler);
- method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback);
- method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback, android.os.Handler);
+ method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, int);
+ method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, android.os.Handler, int);
method public void requestNetwork(android.net.NetworkRequest, android.app.PendingIntent);
method public deprecated void setNetworkPreference(int);
method public static deprecated boolean setProcessDefaultNetwork(android.net.Network);
@@ -30691,7 +30676,6 @@
method public android.util.SizeF getSizeF(java.lang.String);
method public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
method public java.util.ArrayList<java.lang.String> getStringArrayList(java.lang.String);
- method public java.util.UUID getUuid(java.lang.String);
method public boolean hasFileDescriptors();
method public void putAll(android.os.Bundle);
method public void putBinder(java.lang.String, android.os.IBinder);
@@ -30716,7 +30700,6 @@
method public void putSizeF(java.lang.String, android.util.SizeF);
method public void putSparseParcelableArray(java.lang.String, android.util.SparseArray<? extends android.os.Parcelable>);
method public void putStringArrayList(java.lang.String, java.util.ArrayList<java.lang.String>);
- method public void putUuid(java.lang.String, java.util.UUID);
method public void readFromParcel(android.os.Parcel);
method public void setClassLoader(java.lang.ClassLoader);
method public void writeToParcel(android.os.Parcel, int);
@@ -31246,7 +31229,6 @@
method public final <T> void readTypedArray(T[], android.os.Parcelable.Creator<T>);
method public final <T> void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>);
method public final <T> T readTypedObject(android.os.Parcelable.Creator<T>);
- method public final java.util.UUID readUuid();
method public final java.lang.Object readValue(java.lang.ClassLoader);
method public final void recycle();
method public final void setDataCapacity(int);
@@ -31292,7 +31274,6 @@
method public final <T extends android.os.Parcelable> void writeTypedArray(T[], int);
method public final <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>);
method public final <T extends android.os.Parcelable> void writeTypedObject(T, int);
- method public final void writeUuid(java.util.UUID);
method public final void writeValue(java.lang.Object);
field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR;
}
@@ -31695,6 +31676,7 @@
field public static final java.lang.String DISALLOW_APPS_CONTROL = "no_control_apps";
field public static final java.lang.String DISALLOW_AUTOFILL = "no_autofill";
field public static final java.lang.String DISALLOW_BLUETOOTH = "no_bluetooth";
+ field public static final java.lang.String DISALLOW_BLUETOOTH_SHARING = "no_bluetooth_sharing";
field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
field public static final java.lang.String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
@@ -31923,9 +31905,9 @@
}
public class StorageManager {
- method public void allocateBytes(java.util.UUID, long, int) throws java.io.IOException;
- method public void allocateBytes(java.io.FileDescriptor, long, int) throws java.io.IOException;
- method public long getAllocatableBytes(java.util.UUID, int) throws java.io.IOException;
+ method public void allocateBytes(java.util.UUID, long) throws java.io.IOException;
+ method public void allocateBytes(java.io.FileDescriptor, long) throws java.io.IOException;
+ method public long getAllocatableBytes(java.util.UUID) throws java.io.IOException;
method public long getCacheQuotaBytes(java.util.UUID) throws java.io.IOException;
method public long getCacheSizeBytes(java.util.UUID) throws java.io.IOException;
method public java.lang.String getMountedObbPath(java.lang.String);
@@ -31938,7 +31920,6 @@
method public boolean isEncrypted(java.io.File);
method public boolean isObbMounted(java.lang.String);
method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
- method public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback) throws java.io.IOException;
method public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback, android.os.Handler) throws java.io.IOException;
method public void setCacheBehaviorGroup(java.io.File, boolean) throws java.io.IOException;
method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException;
@@ -31946,7 +31927,6 @@
field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
field public static final java.lang.String EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES";
field public static final java.lang.String EXTRA_UUID = "android.os.storage.extra.UUID";
- field public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1
field public static final java.util.UUID UUID_DEFAULT;
}
@@ -34437,7 +34417,6 @@
}
public class FontsContract {
- method public static android.graphics.Typeface buildTypeface(android.content.Context, android.os.CancellationSignal, android.provider.FontsContract.FontInfo[], int, boolean, java.lang.String);
method public static android.graphics.Typeface buildTypeface(android.content.Context, android.os.CancellationSignal, android.provider.FontsContract.FontInfo[]);
method public static android.provider.FontsContract.FontFamilyResult fetchFonts(android.content.Context, android.os.CancellationSignal, android.provider.FontRequest) throws android.content.pm.PackageManager.NameNotFoundException;
method public static void requestFonts(android.content.Context, android.provider.FontRequest, android.os.Handler, android.os.CancellationSignal, android.provider.FontsContract.FontRequestCallback);
@@ -37729,12 +37708,10 @@
method public int getDesiredMinimumHeight();
method public int getDesiredMinimumWidth();
method public android.view.SurfaceHolder getSurfaceHolder();
- method public void invalidateColors();
method public boolean isPreview();
method public boolean isVisible();
method public void onApplyWindowInsets(android.view.WindowInsets);
method public android.os.Bundle onCommand(java.lang.String, int, int, int, android.os.Bundle, boolean);
- method public android.app.WallpaperColors onComputeWallpaperColors();
method public void onCreate(android.view.SurfaceHolder);
method public void onDesiredSizeChanged(int, int);
method public void onDestroy();
@@ -45827,6 +45804,7 @@
field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
field public static final android.util.Property<android.view.View, java.lang.Float> ALPHA;
+ field public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 1; // 0x1
field public static final java.lang.String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = "creditCardExpirationDate";
field public static final java.lang.String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay";
field public static final java.lang.String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = "creditCardExpirationMonth";
@@ -46538,7 +46516,7 @@
public static abstract class ViewStructure.HtmlInfo {
ctor public ViewStructure.HtmlInfo();
- method public abstract java.util.ArrayList<android.util.Pair<java.lang.String, java.lang.String>> getAttributes();
+ method public abstract java.util.List<android.util.Pair<java.lang.String, java.lang.String>> getAttributes();
method public abstract java.lang.String getTag();
}
@@ -48935,7 +48913,6 @@
method public int getRendererRequestedPriority();
method public deprecated float getScale();
method public android.webkit.WebSettings getSettings();
- method public android.view.textclassifier.TextClassifier getTextClassifier();
method public java.lang.String getTitle();
method public java.lang.String getUrl();
method public android.webkit.WebChromeClient getWebChromeClient();
@@ -48952,7 +48929,6 @@
method public deprecated void onChildViewAdded(android.view.View, android.view.View);
method public deprecated void onChildViewRemoved(android.view.View, android.view.View);
method public deprecated void onGlobalFocusChanged(android.view.View, android.view.View);
- method public void onMovedToDisplay(int, android.content.res.Configuration);
method public void onPause();
method public void onResume();
method public deprecated boolean overlayHorizontalScrollbar();
@@ -48983,7 +48959,6 @@
method public void setNetworkAvailable(boolean);
method public deprecated void setPictureListener(android.webkit.WebView.PictureListener);
method public void setRendererPriorityPolicy(int, boolean);
- method public void setTextClassifier(android.view.textclassifier.TextClassifier);
method public deprecated void setVerticalScrollbarOverlay(boolean);
method public void setWebChromeClient(android.webkit.WebChromeClient);
method public static void setWebContentsDebuggingEnabled(boolean);
diff --git a/api/removed.txt b/api/removed.txt
index 13bccd6..8c81ef4 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -18,12 +18,17 @@
method public deprecated java.lang.String getDeviceInitializerApp();
method public deprecated android.content.ComponentName getDeviceInitializerComponent();
method public void setAffiliationIds(android.content.ComponentName, java.util.List<java.lang.String>);
+ field public static final deprecated int FLAG_EVICT_CE_KEY = 1; // 0x1
}
}
package android.app.usage {
+ public final class StorageStats implements android.os.Parcelable {
+ method public deprecated long getCodeBytes();
+ }
+
public class StorageStatsManager {
method public deprecated long getFreeBytes(java.lang.String) throws java.io.IOException;
method public deprecated long getTotalBytes(java.lang.String) throws java.io.IOException;
@@ -38,6 +43,10 @@
package android.content {
+ public class ClipData implements android.os.Parcelable {
+ method public deprecated void addItem(android.content.ClipData.Item, android.content.ContentResolver);
+ }
+
public abstract class Context {
method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
diff --git a/api/system-current.txt b/api/system-current.txt
index 89a2525..792796b 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3005,7 +3005,8 @@
public static abstract class FingerprintGestureController.FingerprintGestureCallback {
ctor public FingerprintGestureController.FingerprintGestureCallback();
- method public void onGesture(int);
+ method public deprecated void onGesture(int);
+ method public void onGestureDetected(int);
method public void onGestureDetectionAvailabilityChanged(boolean);
}
@@ -3164,8 +3165,8 @@
field public static final java.lang.String KEY_PASSWORD = "password";
field public static final java.lang.String KEY_USERDATA = "userdata";
field public static final deprecated java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
- field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE = "android.accounts.key_legacy_not_visible";
- field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_VISIBLE = "android.accounts.key_legacy_visible";
+ field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE = "android:accounts:key_legacy_not_visible";
+ field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_VISIBLE = "android:accounts:key_legacy_visible";
field public static final int VISIBILITY_NOT_VISIBLE = 3; // 0x3
field public static final int VISIBILITY_UNDEFINED = 0; // 0x0
field public static final int VISIBILITY_USER_MANAGED_NOT_VISIBLE = 4; // 0x4
@@ -4092,7 +4093,7 @@
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 = 230; // 0xe6
- field public static final deprecated int IMPORTANCE_PERCEPTIBLE_DEPRECATED = 130; // 0x82
+ field public static final int IMPORTANCE_PERCEPTIBLE_PRE_26 = 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
@@ -4179,6 +4180,7 @@
method public static android.app.ActivityOptions makeTaskLaunchBehind();
method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
method public void requestUsageTimeReport(android.app.PendingIntent);
+ method public android.app.ActivityOptions setAppVerificationBundle(android.os.Bundle);
method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect);
method public android.app.ActivityOptions setLaunchDisplayId(int);
method public android.os.Bundle toBundle();
@@ -4985,6 +4987,7 @@
method public void onFragmentDetached(android.app.FragmentManager, android.app.Fragment);
method public void onFragmentPaused(android.app.FragmentManager, android.app.Fragment);
method public void onFragmentPreAttached(android.app.FragmentManager, android.app.Fragment, android.content.Context);
+ method public void onFragmentPreCreated(android.app.FragmentManager, android.app.Fragment, android.os.Bundle);
method public void onFragmentResumed(android.app.FragmentManager, android.app.Fragment);
method public void onFragmentSaveInstanceState(android.app.FragmentManager, android.app.Fragment, android.os.Bundle);
method public void onFragmentStarted(android.app.FragmentManager, android.app.Fragment);
@@ -5017,10 +5020,10 @@
method public abstract android.app.FragmentTransaction hide(android.app.Fragment);
method public abstract boolean isAddToBackStackAllowed();
method public abstract boolean isEmpty();
- method public abstract android.app.FragmentTransaction postOnCommit(java.lang.Runnable);
method public abstract android.app.FragmentTransaction remove(android.app.Fragment);
method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment);
method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment, java.lang.String);
+ method public abstract android.app.FragmentTransaction runOnCommit(java.lang.Runnable);
method public abstract android.app.FragmentTransaction setBreadCrumbShortTitle(int);
method public abstract android.app.FragmentTransaction setBreadCrumbShortTitle(java.lang.CharSequence);
method public abstract android.app.FragmentTransaction setBreadCrumbTitle(int);
@@ -5134,7 +5137,7 @@
method public final android.app.Activity getLastActivity();
method public final android.app.Instrumentation.ActivityResult getResult();
method public final boolean isBlocking();
- method public android.app.Instrumentation.ActivityResult onMatchIntent(android.content.Intent);
+ method public android.app.Instrumentation.ActivityResult onStartActivity(android.content.Intent);
method public final android.app.Activity waitForActivity();
method public final android.app.Activity waitForActivityWithTimeout(long);
}
@@ -5154,7 +5157,7 @@
public class KeyguardManager {
method public android.content.Intent createConfirmDeviceCredentialIntent(java.lang.CharSequence, java.lang.CharSequence);
- method public void dismissKeyguard(android.app.Activity, android.app.KeyguardManager.KeyguardDismissCallback, android.os.Handler);
+ method public deprecated void dismissKeyguard(android.app.Activity, android.app.KeyguardManager.KeyguardDismissCallback, android.os.Handler);
method public deprecated void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
method public boolean inKeyguardRestrictedInputMode();
method public boolean isDeviceLocked();
@@ -5162,6 +5165,7 @@
method public boolean isKeyguardLocked();
method public boolean isKeyguardSecure();
method public deprecated android.app.KeyguardManager.KeyguardLock newKeyguardLock(java.lang.String);
+ method public void requestDismissKeyguard(android.app.Activity, android.app.KeyguardManager.KeyguardDismissCallback);
}
public static abstract class KeyguardManager.KeyguardDismissCallback {
@@ -6321,17 +6325,6 @@
method public void setPersistentVrModeEnabled(boolean);
}
- public final class WallpaperColors implements android.os.Parcelable {
- ctor public WallpaperColors(android.os.Parcel);
- ctor public WallpaperColors(java.util.List<android.util.Pair<android.graphics.Color, java.lang.Integer>>);
- ctor public WallpaperColors(java.util.List<android.util.Pair<android.graphics.Color, java.lang.Integer>>, boolean);
- method public int describeContents();
- method public java.util.List<android.util.Pair<android.graphics.Color, java.lang.Integer>> getColors();
- method public boolean supportsDarkText();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.app.WallpaperColors> CREATOR;
- }
-
public final class WallpaperInfo implements android.os.Parcelable {
ctor public WallpaperInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public int describeContents();
@@ -6354,8 +6347,6 @@
}
public class WallpaperManager {
- method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener);
- method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener, android.os.Handler);
method public void clear() throws java.io.IOException;
method public void clear(int) throws java.io.IOException;
method public void clearWallpaper();
@@ -6372,7 +6363,6 @@
method public android.graphics.drawable.Drawable getDrawable();
method public android.graphics.drawable.Drawable getFastDrawable();
method public static android.app.WallpaperManager getInstance(android.content.Context);
- method public android.app.WallpaperColors getWallpaperColors(int);
method public android.os.ParcelFileDescriptor getWallpaperFile(int);
method public int getWallpaperId(int);
method public android.app.WallpaperInfo getWallpaperInfo();
@@ -6381,7 +6371,6 @@
method public boolean isWallpaperSupported();
method public android.graphics.drawable.Drawable peekDrawable();
method public android.graphics.drawable.Drawable peekFastDrawable();
- method public void removeOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener);
method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle);
method public void setBitmap(android.graphics.Bitmap) throws java.io.IOException;
method public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
@@ -6409,16 +6398,12 @@
field public static final java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
}
- public static abstract interface WallpaperManager.OnColorsChangedListener {
- method public abstract void onColorsChanged(android.app.WallpaperColors, int);
- }
-
}
package android.app.admin {
public final class ConnectEvent extends android.app.admin.NetworkEvent implements android.os.Parcelable {
- method public java.lang.String getIpAddress();
+ method public java.net.InetAddress getInetAddress();
method public int getPort();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.admin.ConnectEvent> CREATOR;
@@ -6752,7 +6737,7 @@
field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PROXY_PORT = "android.app.extra.PROVISIONING_WIFI_PROXY_PORT";
field public static final java.lang.String EXTRA_PROVISIONING_WIFI_SECURITY_TYPE = "android.app.extra.PROVISIONING_WIFI_SECURITY_TYPE";
field public static final java.lang.String EXTRA_PROVISIONING_WIFI_SSID = "android.app.extra.PROVISIONING_WIFI_SSID";
- field public static final int FLAG_EVICT_CE_KEY = 1; // 0x1
+ field public static final int FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY = 1; // 0x1
field public static final int FLAG_MANAGED_CAN_ACCESS_PARENT = 2; // 0x2
field public static final int FLAG_PARENT_CAN_ACCESS_MANAGED = 1; // 0x1
field public static final int KEYGUARD_DISABLE_FEATURES_ALL = 2147483647; // 0x7fffffff
@@ -6795,8 +6780,8 @@
public final class DnsEvent extends android.app.admin.NetworkEvent implements android.os.Parcelable {
method public java.lang.String getHostname();
- method public java.lang.String[] getIpAddresses();
- method public int getIpAddressesCount();
+ method public java.net.InetAddress[] getInetAddresses();
+ method public int getTotalResolvedAddressCount();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.admin.DnsEvent> CREATOR;
}
@@ -7475,8 +7460,8 @@
public final class StorageStats implements android.os.Parcelable {
method public int describeContents();
+ method public long getAppBytes();
method public long getCacheBytes();
- method public long getCodeBytes();
method public long getDataBytes();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.usage.StorageStats> CREATOR;
@@ -8706,8 +8691,10 @@
field public static final android.os.Parcelable.Creator<android.bluetooth.le.ScanResult> CREATOR;
field public static final int DATA_COMPLETE = 0; // 0x0
field public static final int DATA_TRUNCATED = 2; // 0x2
+ field public static final int PERIODIC_INTERVAL_NOT_PRESENT = 0; // 0x0
field public static final int PHY_UNUSED = 0; // 0x0
field public static final int SID_NOT_PRESENT = 255; // 0xff
+ field public static final int TX_POWER_NOT_PRESENT = 127; // 0x7f
}
public final class ScanSettings implements android.os.Parcelable {
@@ -8787,21 +8774,21 @@
method public android.companion.BluetoothDeviceFilter.Builder setNamePattern(java.util.regex.Pattern);
}
- public final class BluetoothLEDeviceFilter implements android.companion.DeviceFilter {
+ public final class BluetoothLeDeviceFilter implements android.companion.DeviceFilter {
method public int describeContents();
method public static int getRenamePrefixLengthLimit();
method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.companion.BluetoothLEDeviceFilter> CREATOR;
+ field public static final android.os.Parcelable.Creator<android.companion.BluetoothLeDeviceFilter> CREATOR;
}
- public static final class BluetoothLEDeviceFilter.Builder {
- ctor public BluetoothLEDeviceFilter.Builder();
- 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 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);
+ public static final class BluetoothLeDeviceFilter.Builder {
+ ctor public BluetoothLeDeviceFilter.Builder();
+ 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 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);
}
public final class CompanionDeviceManager {
@@ -8937,7 +8924,7 @@
ctor public ClipData(android.content.ClipDescription, android.content.ClipData.Item);
ctor public ClipData(android.content.ClipData);
method public void addItem(android.content.ClipData.Item);
- method public void addItem(android.content.ClipData.Item, android.content.ContentResolver);
+ method public void addItem(android.content.ContentResolver, android.content.ClipData.Item);
method public int describeContents();
method public android.content.ClipDescription getDescription();
method public android.content.ClipData.Item getItemAt(int);
@@ -9892,6 +9879,7 @@
field public static final java.lang.String ACTION_FACTORY_TEST = "android.intent.action.FACTORY_TEST";
field public static final java.lang.String ACTION_GET_CONTENT = "android.intent.action.GET_CONTENT";
field public static final java.lang.String ACTION_GET_RESTRICTION_ENTRIES = "android.intent.action.GET_RESTRICTION_ENTRIES";
+ field public static final java.lang.String ACTION_GLOBAL_BUTTON = "android.intent.action.GLOBAL_BUTTON";
field public static final java.lang.String ACTION_GTALK_SERVICE_CONNECTED = "android.intent.action.GTALK_CONNECTED";
field public static final java.lang.String ACTION_GTALK_SERVICE_DISCONNECTED = "android.intent.action.GTALK_DISCONNECTED";
field public static final java.lang.String ACTION_HEADSET_PLUG = "android.intent.action.HEADSET_PLUG";
@@ -14552,6 +14540,7 @@
method public void detachFromGLContext();
method public long getTimestamp();
method public void getTransformMatrix(float[]);
+ method public boolean isReleased();
method public void release();
method public void releaseTexImage();
method public void setDefaultBufferSize(int, int);
@@ -15284,7 +15273,7 @@
method public final void takePicture(android.hardware.Camera.ShutterCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback);
method public final void unlock();
field public static final java.lang.String ACTION_NEW_PICTURE = "android.hardware.action.NEW_PICTURE";
- field public static final deprecated java.lang.String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
+ field public static final java.lang.String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
field public static final int CAMERA_ERROR_EVICTED = 2; // 0x2
field public static final int CAMERA_ERROR_SERVER_DIED = 100; // 0x64
field public static final int CAMERA_ERROR_UNKNOWN = 1; // 0x1
@@ -15545,18 +15534,16 @@
field public static final int RGBX_8888 = 2; // 0x2
field public static final int RGB_565 = 4; // 0x4
field public static final int RGB_888 = 3; // 0x3
- field public static final long USAGE0_CPU_READ = 2L; // 0x2L
- field public static final long USAGE0_CPU_READ_OFTEN = 6L; // 0x6L
- field public static final long USAGE0_CPU_WRITE = 32L; // 0x20L
- field public static final long USAGE0_CPU_WRITE_OFTEN = 96L; // 0x60L
- field public static final long USAGE0_GPU_COLOR_OUTPUT = 2048L; // 0x800L
- field public static final long USAGE0_GPU_CUBEMAP = 8192L; // 0x2000L
- field public static final long USAGE0_GPU_DATA_BUFFER = 16384L; // 0x4000L
- field public static final long USAGE0_GPU_SAMPLED_IMAGE = 1024L; // 0x400L
- field public static final long USAGE0_GPU_STORAGE_IMAGE = 3072L; // 0xc00L
- field public static final long USAGE0_PROTECTED_CONTENT = 262144L; // 0x40000L
- field public static final long USAGE0_SENSOR_DIRECT_DATA = 536870912L; // 0x20000000L
- field public static final long USAGE0_VIDEO_ENCODE = 2097152L; // 0x200000L
+ field public static final long USAGE_CPU_READ_OFTEN = 3L; // 0x3L
+ field public static final long USAGE_CPU_READ_RARELY = 2L; // 0x2L
+ field public static final long USAGE_CPU_WRITE_OFTEN = 48L; // 0x30L
+ field public static final long USAGE_CPU_WRITE_RARELY = 32L; // 0x20L
+ field public static final long USAGE_GPU_COLOR_OUTPUT = 512L; // 0x200L
+ field public static final long USAGE_GPU_DATA_BUFFER = 16777216L; // 0x1000000L
+ field public static final long USAGE_GPU_SAMPLED_IMAGE = 256L; // 0x100L
+ field public static final long USAGE_PROTECTED_CONTENT = 16384L; // 0x4000L
+ field public static final long USAGE_SENSOR_DIRECT_DATA = 8388608L; // 0x800000L
+ field public static final long USAGE_VIDEO_ENCODE = 65536L; // 0x10000L
}
public final class Sensor {
@@ -27285,6 +27272,7 @@
method public java.lang.Object getTaggedData(int);
method public long getTimestamp();
method public int getType();
+ method public int getUid();
method public boolean isLongCounterBucket();
method public boolean isSubsetOf(android.metrics.LogMaker);
method public boolean isValidValue(java.lang.Object);
@@ -27591,8 +27579,8 @@
method public boolean requestBandwidthUpdate(android.net.Network);
method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, android.os.Handler);
- method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback);
- method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback, android.os.Handler);
+ method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, int);
+ method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, android.os.Handler, int);
method public void requestNetwork(android.net.NetworkRequest, android.app.PendingIntent);
method public deprecated void setNetworkPreference(int);
method public static deprecated boolean setProcessDefaultNetwork(android.net.Network);
@@ -33451,7 +33439,6 @@
method public android.util.SizeF getSizeF(java.lang.String);
method public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
method public java.util.ArrayList<java.lang.String> getStringArrayList(java.lang.String);
- method public java.util.UUID getUuid(java.lang.String);
method public boolean hasFileDescriptors();
method public void putAll(android.os.Bundle);
method public void putBinder(java.lang.String, android.os.IBinder);
@@ -33476,7 +33463,6 @@
method public void putSizeF(java.lang.String, android.util.SizeF);
method public void putSparseParcelableArray(java.lang.String, android.util.SparseArray<? extends android.os.Parcelable>);
method public void putStringArrayList(java.lang.String, java.util.ArrayList<java.lang.String>);
- method public void putUuid(java.lang.String, java.util.UUID);
method public void readFromParcel(android.os.Parcel);
method public void setClassLoader(java.lang.ClassLoader);
method public void writeToParcel(android.os.Parcel, int);
@@ -34038,7 +34024,6 @@
method public final <T> void readTypedArray(T[], android.os.Parcelable.Creator<T>);
method public final <T> void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>);
method public final <T> T readTypedObject(android.os.Parcelable.Creator<T>);
- method public final java.util.UUID readUuid();
method public final java.lang.Object readValue(java.lang.ClassLoader);
method public final void recycle();
method public final void setDataCapacity(int);
@@ -34084,7 +34069,6 @@
method public final <T extends android.os.Parcelable> void writeTypedArray(T[], int);
method public final <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>);
method public final <T extends android.os.Parcelable> void writeTypedObject(T, int);
- method public final void writeUuid(java.util.UUID);
method public final void writeValue(java.lang.Object);
field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR;
}
@@ -34577,6 +34561,7 @@
field public static final java.lang.String DISALLOW_APPS_CONTROL = "no_control_apps";
field public static final java.lang.String DISALLOW_AUTOFILL = "no_autofill";
field public static final java.lang.String DISALLOW_BLUETOOTH = "no_bluetooth";
+ field public static final java.lang.String DISALLOW_BLUETOOTH_SHARING = "no_bluetooth_sharing";
field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
field public static final java.lang.String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
@@ -34821,8 +34806,11 @@
}
public class StorageManager {
+ method public void allocateBytes(java.util.UUID, long) throws java.io.IOException;
method public void allocateBytes(java.util.UUID, long, int) throws java.io.IOException;
+ method public void allocateBytes(java.io.FileDescriptor, long) throws java.io.IOException;
method public void allocateBytes(java.io.FileDescriptor, long, int) throws java.io.IOException;
+ method public long getAllocatableBytes(java.util.UUID) throws java.io.IOException;
method public long getAllocatableBytes(java.util.UUID, int) throws java.io.IOException;
method public long getCacheQuotaBytes(java.util.UUID) throws java.io.IOException;
method public long getCacheSizeBytes(java.util.UUID) throws java.io.IOException;
@@ -34836,7 +34824,6 @@
method public boolean isEncrypted(java.io.File);
method public boolean isObbMounted(java.lang.String);
method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
- method public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback) throws java.io.IOException;
method public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback, android.os.Handler) throws java.io.IOException;
method public void setCacheBehaviorGroup(java.io.File, boolean) throws java.io.IOException;
method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException;
@@ -37427,7 +37414,6 @@
}
public class FontsContract {
- method public static android.graphics.Typeface buildTypeface(android.content.Context, android.os.CancellationSignal, android.provider.FontsContract.FontInfo[], int, boolean, java.lang.String);
method public static android.graphics.Typeface buildTypeface(android.content.Context, android.os.CancellationSignal, android.provider.FontsContract.FontInfo[]);
method public static android.provider.FontsContract.FontFamilyResult fetchFonts(android.content.Context, android.os.CancellationSignal, android.provider.FontRequest) throws android.content.pm.PackageManager.NameNotFoundException;
method public static void requestFonts(android.content.Context, android.provider.FontRequest, android.os.Handler, android.os.CancellationSignal, android.provider.FontsContract.FontRequestCallback);
@@ -40987,12 +40973,10 @@
method public int getDesiredMinimumHeight();
method public int getDesiredMinimumWidth();
method public android.view.SurfaceHolder getSurfaceHolder();
- method public void invalidateColors();
method public boolean isPreview();
method public boolean isVisible();
method public void onApplyWindowInsets(android.view.WindowInsets);
method public android.os.Bundle onCommand(java.lang.String, int, int, int, android.os.Bundle, boolean);
- method public android.app.WallpaperColors onComputeWallpaperColors();
method public void onCreate(android.view.SurfaceHolder);
method public void onDesiredSizeChanged(int, int);
method public void onDestroy();
@@ -46759,6 +46743,7 @@
method public int getTag();
method public int getThreadId();
method public long getTimeNanos();
+ method public int getUid();
}
public deprecated class EventLogTags {
@@ -49411,6 +49396,7 @@
field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
field public static final android.util.Property<android.view.View, java.lang.Float> ALPHA;
+ field public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 1; // 0x1
field public static final java.lang.String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = "creditCardExpirationDate";
field public static final java.lang.String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay";
field public static final java.lang.String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = "creditCardExpirationMonth";
@@ -50122,7 +50108,7 @@
public static abstract class ViewStructure.HtmlInfo {
ctor public ViewStructure.HtmlInfo();
- method public abstract java.util.ArrayList<android.util.Pair<java.lang.String, java.lang.String>> getAttributes();
+ method public abstract java.util.List<android.util.Pair<java.lang.String, java.lang.String>> getAttributes();
method public abstract java.lang.String getTag();
}
@@ -52615,7 +52601,6 @@
method public int getRendererRequestedPriority();
method public deprecated float getScale();
method public android.webkit.WebSettings getSettings();
- method public android.view.textclassifier.TextClassifier getTextClassifier();
method public java.lang.String getTitle();
method public java.lang.String getUrl();
method public android.webkit.WebChromeClient getWebChromeClient();
@@ -52633,7 +52618,6 @@
method public deprecated void onChildViewAdded(android.view.View, android.view.View);
method public deprecated void onChildViewRemoved(android.view.View, android.view.View);
method public deprecated void onGlobalFocusChanged(android.view.View, android.view.View);
- method public void onMovedToDisplay(int, android.content.res.Configuration);
method public void onPause();
method public void onResume();
method public deprecated boolean overlayHorizontalScrollbar();
@@ -52664,7 +52648,6 @@
method public void setNetworkAvailable(boolean);
method public deprecated void setPictureListener(android.webkit.WebView.PictureListener);
method public void setRendererPriorityPolicy(int, boolean);
- method public void setTextClassifier(android.view.textclassifier.TextClassifier);
method public deprecated void setVerticalScrollbarOverlay(boolean);
method public void setWebChromeClient(android.webkit.WebChromeClient);
method public static void setWebContentsDebuggingEnabled(boolean);
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 2ef8690..659236d 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -16,12 +16,17 @@
method public deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
method public deprecated android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
method public void setAffiliationIds(android.content.ComponentName, java.util.List<java.lang.String>);
+ field public static final deprecated int FLAG_EVICT_CE_KEY = 1; // 0x1
}
}
package android.app.usage {
+ public final class StorageStats implements android.os.Parcelable {
+ method public deprecated long getCodeBytes();
+ }
+
public class StorageStatsManager {
method public deprecated long getFreeBytes(java.lang.String) throws java.io.IOException;
method public deprecated long getTotalBytes(java.lang.String) throws java.io.IOException;
@@ -36,6 +41,10 @@
package android.content {
+ public class ClipData implements android.os.Parcelable {
+ method public deprecated void addItem(android.content.ClipData.Item, android.content.ContentResolver);
+ }
+
public abstract class Context {
method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
diff --git a/api/test-current.txt b/api/test-current.txt
index 83128c8..65e3dc2 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -15,7 +15,6 @@
field public static final java.lang.String ACCESS_WIFI_STATE = "android.permission.ACCESS_WIFI_STATE";
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
- field public static final java.lang.String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
field public static final java.lang.String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
@@ -2877,7 +2876,8 @@
public static abstract class FingerprintGestureController.FingerprintGestureCallback {
ctor public FingerprintGestureController.FingerprintGestureCallback();
- method public void onGesture(int);
+ method public deprecated void onGesture(int);
+ method public void onGestureDetected(int);
method public void onGestureDetectionAvailabilityChanged(boolean);
}
@@ -3035,8 +3035,8 @@
field public static final java.lang.String KEY_PASSWORD = "password";
field public static final java.lang.String KEY_USERDATA = "userdata";
field public static final deprecated java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
- field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE = "android.accounts.key_legacy_not_visible";
- field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_VISIBLE = "android.accounts.key_legacy_visible";
+ field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE = "android:accounts:key_legacy_not_visible";
+ field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_VISIBLE = "android:accounts:key_legacy_visible";
field public static final int VISIBILITY_NOT_VISIBLE = 3; // 0x3
field public static final int VISIBILITY_UNDEFINED = 0; // 0x0
field public static final int VISIBILITY_USER_MANAGED_NOT_VISIBLE = 4; // 0x4
@@ -3953,7 +3953,7 @@
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 = 230; // 0xe6
- field public static final deprecated int IMPORTANCE_PERCEPTIBLE_DEPRECATED = 130; // 0x82
+ field public static final int IMPORTANCE_PERCEPTIBLE_PRE_26 = 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
@@ -4040,6 +4040,7 @@
method public static android.app.ActivityOptions makeTaskLaunchBehind();
method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
method public void requestUsageTimeReport(android.app.PendingIntent);
+ method public android.app.ActivityOptions setAppVerificationBundle(android.os.Bundle);
method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect);
method public android.app.ActivityOptions setLaunchDisplayId(int);
method public void setLaunchStackId(int);
@@ -4830,6 +4831,7 @@
method public void onFragmentDetached(android.app.FragmentManager, android.app.Fragment);
method public void onFragmentPaused(android.app.FragmentManager, android.app.Fragment);
method public void onFragmentPreAttached(android.app.FragmentManager, android.app.Fragment, android.content.Context);
+ method public void onFragmentPreCreated(android.app.FragmentManager, android.app.Fragment, android.os.Bundle);
method public void onFragmentResumed(android.app.FragmentManager, android.app.Fragment);
method public void onFragmentSaveInstanceState(android.app.FragmentManager, android.app.Fragment, android.os.Bundle);
method public void onFragmentStarted(android.app.FragmentManager, android.app.Fragment);
@@ -4862,10 +4864,10 @@
method public abstract android.app.FragmentTransaction hide(android.app.Fragment);
method public abstract boolean isAddToBackStackAllowed();
method public abstract boolean isEmpty();
- method public abstract android.app.FragmentTransaction postOnCommit(java.lang.Runnable);
method public abstract android.app.FragmentTransaction remove(android.app.Fragment);
method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment);
method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment, java.lang.String);
+ method public abstract android.app.FragmentTransaction runOnCommit(java.lang.Runnable);
method public abstract android.app.FragmentTransaction setBreadCrumbShortTitle(int);
method public abstract android.app.FragmentTransaction setBreadCrumbShortTitle(java.lang.CharSequence);
method public abstract android.app.FragmentTransaction setBreadCrumbTitle(int);
@@ -4967,7 +4969,7 @@
method public final android.app.Activity getLastActivity();
method public final android.app.Instrumentation.ActivityResult getResult();
method public final boolean isBlocking();
- method public android.app.Instrumentation.ActivityResult onMatchIntent(android.content.Intent);
+ method public android.app.Instrumentation.ActivityResult onStartActivity(android.content.Intent);
method public final android.app.Activity waitForActivity();
method public final android.app.Activity waitForActivityWithTimeout(long);
}
@@ -4987,7 +4989,7 @@
public class KeyguardManager {
method public android.content.Intent createConfirmDeviceCredentialIntent(java.lang.CharSequence, java.lang.CharSequence);
- method public void dismissKeyguard(android.app.Activity, android.app.KeyguardManager.KeyguardDismissCallback, android.os.Handler);
+ method public deprecated void dismissKeyguard(android.app.Activity, android.app.KeyguardManager.KeyguardDismissCallback, android.os.Handler);
method public deprecated void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
method public boolean inKeyguardRestrictedInputMode();
method public boolean isDeviceLocked();
@@ -4995,6 +4997,7 @@
method public boolean isKeyguardLocked();
method public boolean isKeyguardSecure();
method public deprecated android.app.KeyguardManager.KeyguardLock newKeyguardLock(java.lang.String);
+ method public void requestDismissKeyguard(android.app.Activity, android.app.KeyguardManager.KeyguardDismissCallback);
}
public static abstract class KeyguardManager.KeyguardDismissCallback {
@@ -6132,17 +6135,6 @@
method public void onDetached();
}
- public final class WallpaperColors implements android.os.Parcelable {
- ctor public WallpaperColors(android.os.Parcel);
- ctor public WallpaperColors(java.util.List<android.util.Pair<android.graphics.Color, java.lang.Integer>>);
- ctor public WallpaperColors(java.util.List<android.util.Pair<android.graphics.Color, java.lang.Integer>>, boolean);
- method public int describeContents();
- method public java.util.List<android.util.Pair<android.graphics.Color, java.lang.Integer>> getColors();
- method public boolean supportsDarkText();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.app.WallpaperColors> CREATOR;
- }
-
public final class WallpaperInfo implements android.os.Parcelable {
ctor public WallpaperInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public int describeContents();
@@ -6165,8 +6157,6 @@
}
public class WallpaperManager {
- method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener);
- method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener, android.os.Handler);
method public void clear() throws java.io.IOException;
method public void clear(int) throws java.io.IOException;
method public void clearWallpaperOffsets(android.os.IBinder);
@@ -6181,7 +6171,6 @@
method public android.graphics.drawable.Drawable getDrawable();
method public android.graphics.drawable.Drawable getFastDrawable();
method public static android.app.WallpaperManager getInstance(android.content.Context);
- method public android.app.WallpaperColors getWallpaperColors(int);
method public android.os.ParcelFileDescriptor getWallpaperFile(int);
method public int getWallpaperId(int);
method public android.app.WallpaperInfo getWallpaperInfo();
@@ -6190,7 +6179,6 @@
method public boolean isWallpaperSupported();
method public android.graphics.drawable.Drawable peekDrawable();
method public android.graphics.drawable.Drawable peekFastDrawable();
- method public void removeOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener);
method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle);
method public void setBitmap(android.graphics.Bitmap) throws java.io.IOException;
method public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
@@ -6215,16 +6203,12 @@
field public static final java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
}
- public static abstract interface WallpaperManager.OnColorsChangedListener {
- method public abstract void onColorsChanged(android.app.WallpaperColors, int);
- }
-
}
package android.app.admin {
public final class ConnectEvent extends android.app.admin.NetworkEvent implements android.os.Parcelable {
- method public java.lang.String getIpAddress();
+ method public java.net.InetAddress getInetAddress();
method public int getPort();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.admin.ConnectEvent> CREATOR;
@@ -6539,7 +6523,7 @@
field public static final java.lang.String EXTRA_PROVISIONING_WIFI_SECURITY_TYPE = "android.app.extra.PROVISIONING_WIFI_SECURITY_TYPE";
field public static final java.lang.String EXTRA_PROVISIONING_WIFI_SSID = "android.app.extra.PROVISIONING_WIFI_SSID";
field public static final java.lang.String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
- field public static final int FLAG_EVICT_CE_KEY = 1; // 0x1
+ field public static final int FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY = 1; // 0x1
field public static final int FLAG_MANAGED_CAN_ACCESS_PARENT = 2; // 0x2
field public static final int FLAG_PARENT_CAN_ACCESS_MANAGED = 1; // 0x1
field public static final int KEYGUARD_DISABLE_FEATURES_ALL = 2147483647; // 0x7fffffff
@@ -6577,8 +6561,8 @@
public final class DnsEvent extends android.app.admin.NetworkEvent implements android.os.Parcelable {
method public java.lang.String getHostname();
- method public java.lang.String[] getIpAddresses();
- method public int getIpAddressesCount();
+ method public java.net.InetAddress[] getInetAddresses();
+ method public int getTotalResolvedAddressCount();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.admin.DnsEvent> CREATOR;
}
@@ -7037,8 +7021,8 @@
public final class StorageStats implements android.os.Parcelable {
method public int describeContents();
+ method public long getAppBytes();
method public long getCacheBytes();
- method public long getCodeBytes();
method public long getDataBytes();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.usage.StorageStats> CREATOR;
@@ -8247,8 +8231,10 @@
field public static final android.os.Parcelable.Creator<android.bluetooth.le.ScanResult> CREATOR;
field public static final int DATA_COMPLETE = 0; // 0x0
field public static final int DATA_TRUNCATED = 2; // 0x2
+ field public static final int PERIODIC_INTERVAL_NOT_PRESENT = 0; // 0x0
field public static final int PHY_UNUSED = 0; // 0x0
field public static final int SID_NOT_PRESENT = 255; // 0xff
+ field public static final int TX_POWER_NOT_PRESENT = 127; // 0x7f
}
public final class ScanSettings implements android.os.Parcelable {
@@ -8319,21 +8305,21 @@
method public android.companion.BluetoothDeviceFilter.Builder setNamePattern(java.util.regex.Pattern);
}
- public final class BluetoothLEDeviceFilter implements android.companion.DeviceFilter {
+ public final class BluetoothLeDeviceFilter implements android.companion.DeviceFilter {
method public int describeContents();
method public static int getRenamePrefixLengthLimit();
method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.companion.BluetoothLEDeviceFilter> CREATOR;
+ field public static final android.os.Parcelable.Creator<android.companion.BluetoothLeDeviceFilter> CREATOR;
}
- public static final class BluetoothLEDeviceFilter.Builder {
- ctor public BluetoothLEDeviceFilter.Builder();
- 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 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);
+ public static final class BluetoothLeDeviceFilter.Builder {
+ ctor public BluetoothLeDeviceFilter.Builder();
+ 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 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);
}
public final class CompanionDeviceManager {
@@ -8469,7 +8455,7 @@
ctor public ClipData(android.content.ClipDescription, android.content.ClipData.Item);
ctor public ClipData(android.content.ClipData);
method public void addItem(android.content.ClipData.Item);
- method public void addItem(android.content.ClipData.Item, android.content.ContentResolver);
+ method public void addItem(android.content.ContentResolver, android.content.ClipData.Item);
method public int describeContents();
method public android.content.ClipDescription getDescription();
method public android.content.ClipData.Item getItemAt(int);
@@ -13817,6 +13803,7 @@
method public void detachFromGLContext();
method public long getTimestamp();
method public void getTransformMatrix(float[]);
+ method public boolean isReleased();
method public void release();
method public void releaseTexImage();
method public void setDefaultBufferSize(int, int);
@@ -14553,7 +14540,7 @@
method public final void takePicture(android.hardware.Camera.ShutterCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback);
method public final void unlock();
field public static final java.lang.String ACTION_NEW_PICTURE = "android.hardware.action.NEW_PICTURE";
- field public static final deprecated java.lang.String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
+ field public static final java.lang.String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
field public static final int CAMERA_ERROR_EVICTED = 2; // 0x2
field public static final int CAMERA_ERROR_SERVER_DIED = 100; // 0x64
field public static final int CAMERA_ERROR_UNKNOWN = 1; // 0x1
@@ -14814,18 +14801,16 @@
field public static final int RGBX_8888 = 2; // 0x2
field public static final int RGB_565 = 4; // 0x4
field public static final int RGB_888 = 3; // 0x3
- field public static final long USAGE0_CPU_READ = 2L; // 0x2L
- field public static final long USAGE0_CPU_READ_OFTEN = 6L; // 0x6L
- field public static final long USAGE0_CPU_WRITE = 32L; // 0x20L
- field public static final long USAGE0_CPU_WRITE_OFTEN = 96L; // 0x60L
- field public static final long USAGE0_GPU_COLOR_OUTPUT = 2048L; // 0x800L
- field public static final long USAGE0_GPU_CUBEMAP = 8192L; // 0x2000L
- field public static final long USAGE0_GPU_DATA_BUFFER = 16384L; // 0x4000L
- field public static final long USAGE0_GPU_SAMPLED_IMAGE = 1024L; // 0x400L
- field public static final long USAGE0_GPU_STORAGE_IMAGE = 3072L; // 0xc00L
- field public static final long USAGE0_PROTECTED_CONTENT = 262144L; // 0x40000L
- field public static final long USAGE0_SENSOR_DIRECT_DATA = 536870912L; // 0x20000000L
- field public static final long USAGE0_VIDEO_ENCODE = 2097152L; // 0x200000L
+ field public static final long USAGE_CPU_READ_OFTEN = 3L; // 0x3L
+ field public static final long USAGE_CPU_READ_RARELY = 2L; // 0x2L
+ field public static final long USAGE_CPU_WRITE_OFTEN = 48L; // 0x30L
+ field public static final long USAGE_CPU_WRITE_RARELY = 32L; // 0x20L
+ field public static final long USAGE_GPU_COLOR_OUTPUT = 512L; // 0x200L
+ field public static final long USAGE_GPU_DATA_BUFFER = 16777216L; // 0x1000000L
+ field public static final long USAGE_GPU_SAMPLED_IMAGE = 256L; // 0x100L
+ field public static final long USAGE_PROTECTED_CONTENT = 16384L; // 0x4000L
+ field public static final long USAGE_SENSOR_DIRECT_DATA = 8388608L; // 0x800000L
+ field public static final long USAGE_VIDEO_ENCODE = 65536L; // 0x10000L
}
public final class Sensor {
@@ -25519,8 +25504,8 @@
method public boolean requestBandwidthUpdate(android.net.Network);
method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, android.os.Handler);
- method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback);
- method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback, android.os.Handler);
+ method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, int);
+ method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, android.os.Handler, int);
method public void requestNetwork(android.net.NetworkRequest, android.app.PendingIntent);
method public deprecated void setNetworkPreference(int);
method public static deprecated boolean setProcessDefaultNetwork(android.net.Network);
@@ -30799,7 +30784,6 @@
method public android.util.SizeF getSizeF(java.lang.String);
method public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
method public java.util.ArrayList<java.lang.String> getStringArrayList(java.lang.String);
- method public java.util.UUID getUuid(java.lang.String);
method public boolean hasFileDescriptors();
method public void putAll(android.os.Bundle);
method public void putBinder(java.lang.String, android.os.IBinder);
@@ -30824,7 +30808,6 @@
method public void putSizeF(java.lang.String, android.util.SizeF);
method public void putSparseParcelableArray(java.lang.String, android.util.SparseArray<? extends android.os.Parcelable>);
method public void putStringArrayList(java.lang.String, java.util.ArrayList<java.lang.String>);
- method public void putUuid(java.lang.String, java.util.UUID);
method public void readFromParcel(android.os.Parcel);
method public void setClassLoader(java.lang.ClassLoader);
method public void writeToParcel(android.os.Parcel, int);
@@ -31375,7 +31358,6 @@
method public final <T> void readTypedArray(T[], android.os.Parcelable.Creator<T>);
method public final <T> void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>);
method public final <T> T readTypedObject(android.os.Parcelable.Creator<T>);
- method public final java.util.UUID readUuid();
method public final java.lang.Object readValue(java.lang.ClassLoader);
method public final void recycle();
method public final void setDataCapacity(int);
@@ -31421,7 +31403,6 @@
method public final <T extends android.os.Parcelable> void writeTypedArray(T[], int);
method public final <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>);
method public final <T extends android.os.Parcelable> void writeTypedObject(T, int);
- method public final void writeUuid(java.util.UUID);
method public final void writeValue(java.lang.Object);
field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR;
}
@@ -31828,6 +31809,7 @@
field public static final java.lang.String DISALLOW_APPS_CONTROL = "no_control_apps";
field public static final java.lang.String DISALLOW_AUTOFILL = "no_autofill";
field public static final java.lang.String DISALLOW_BLUETOOTH = "no_bluetooth";
+ field public static final java.lang.String DISALLOW_BLUETOOTH_SHARING = "no_bluetooth_sharing";
field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
field public static final java.lang.String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
@@ -32056,9 +32038,9 @@
}
public class StorageManager {
- method public void allocateBytes(java.util.UUID, long, int) throws java.io.IOException;
- method public void allocateBytes(java.io.FileDescriptor, long, int) throws java.io.IOException;
- method public long getAllocatableBytes(java.util.UUID, int) throws java.io.IOException;
+ method public void allocateBytes(java.util.UUID, long) throws java.io.IOException;
+ method public void allocateBytes(java.io.FileDescriptor, long) throws java.io.IOException;
+ method public long getAllocatableBytes(java.util.UUID) throws java.io.IOException;
method public long getCacheQuotaBytes(java.util.UUID) throws java.io.IOException;
method public long getCacheSizeBytes(java.util.UUID) throws java.io.IOException;
method public java.lang.String getMountedObbPath(java.lang.String);
@@ -32071,7 +32053,6 @@
method public boolean isEncrypted(java.io.File);
method public boolean isObbMounted(java.lang.String);
method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
- method public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback) throws java.io.IOException;
method public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback, android.os.Handler) throws java.io.IOException;
method public void setCacheBehaviorGroup(java.io.File, boolean) throws java.io.IOException;
method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException;
@@ -32079,7 +32060,6 @@
field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
field public static final java.lang.String EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES";
field public static final java.lang.String EXTRA_UUID = "android.os.storage.extra.UUID";
- field public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1
field public static final java.util.UUID UUID_DEFAULT;
}
@@ -34573,7 +34553,6 @@
}
public class FontsContract {
- method public static android.graphics.Typeface buildTypeface(android.content.Context, android.os.CancellationSignal, android.provider.FontsContract.FontInfo[], int, boolean, java.lang.String);
method public static android.graphics.Typeface buildTypeface(android.content.Context, android.os.CancellationSignal, android.provider.FontsContract.FontInfo[]);
method public static android.provider.FontsContract.FontFamilyResult fetchFonts(android.content.Context, android.os.CancellationSignal, android.provider.FontRequest) throws android.content.pm.PackageManager.NameNotFoundException;
method public static void requestFonts(android.content.Context, android.provider.FontRequest, android.os.Handler, android.os.CancellationSignal, android.provider.FontsContract.FontRequestCallback);
@@ -37924,12 +37903,10 @@
method public int getDesiredMinimumHeight();
method public int getDesiredMinimumWidth();
method public android.view.SurfaceHolder getSurfaceHolder();
- method public void invalidateColors();
method public boolean isPreview();
method public boolean isVisible();
method public void onApplyWindowInsets(android.view.WindowInsets);
method public android.os.Bundle onCommand(java.lang.String, int, int, int, android.os.Bundle, boolean);
- method public android.app.WallpaperColors onComputeWallpaperColors();
method public void onCreate(android.view.SurfaceHolder);
method public void onDesiredSizeChanged(int, int);
method public void onDestroy();
@@ -46198,6 +46175,7 @@
field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
field public static final android.util.Property<android.view.View, java.lang.Float> ALPHA;
+ field public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 1; // 0x1
field public static final java.lang.String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = "creditCardExpirationDate";
field public static final java.lang.String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay";
field public static final java.lang.String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = "creditCardExpirationMonth";
@@ -46913,7 +46891,7 @@
public static abstract class ViewStructure.HtmlInfo {
ctor public ViewStructure.HtmlInfo();
- method public abstract java.util.ArrayList<android.util.Pair<java.lang.String, java.lang.String>> getAttributes();
+ method public abstract java.util.List<android.util.Pair<java.lang.String, java.lang.String>> getAttributes();
method public abstract java.lang.String getTag();
}
@@ -49314,7 +49292,6 @@
method public int getRendererRequestedPriority();
method public deprecated float getScale();
method public android.webkit.WebSettings getSettings();
- method public android.view.textclassifier.TextClassifier getTextClassifier();
method public java.lang.String getTitle();
method public java.lang.String getUrl();
method public android.webkit.WebChromeClient getWebChromeClient();
@@ -49331,7 +49308,6 @@
method public deprecated void onChildViewAdded(android.view.View, android.view.View);
method public deprecated void onChildViewRemoved(android.view.View, android.view.View);
method public deprecated void onGlobalFocusChanged(android.view.View, android.view.View);
- method public void onMovedToDisplay(int, android.content.res.Configuration);
method public void onPause();
method public void onResume();
method public deprecated boolean overlayHorizontalScrollbar();
@@ -49362,7 +49338,6 @@
method public void setNetworkAvailable(boolean);
method public deprecated void setPictureListener(android.webkit.WebView.PictureListener);
method public void setRendererPriorityPolicy(int, boolean);
- method public void setTextClassifier(android.view.textclassifier.TextClassifier);
method public deprecated void setVerticalScrollbarOverlay(boolean);
method public void setWebChromeClient(android.webkit.WebChromeClient);
method public static void setWebContentsDebuggingEnabled(boolean);
diff --git a/api/test-removed.txt b/api/test-removed.txt
index 13bccd6..8c81ef4 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -18,12 +18,17 @@
method public deprecated java.lang.String getDeviceInitializerApp();
method public deprecated android.content.ComponentName getDeviceInitializerComponent();
method public void setAffiliationIds(android.content.ComponentName, java.util.List<java.lang.String>);
+ field public static final deprecated int FLAG_EVICT_CE_KEY = 1; // 0x1
}
}
package android.app.usage {
+ public final class StorageStats implements android.os.Parcelable {
+ method public deprecated long getCodeBytes();
+ }
+
public class StorageStatsManager {
method public deprecated long getFreeBytes(java.lang.String) throws java.io.IOException;
method public deprecated long getTotalBytes(java.lang.String) throws java.io.IOException;
@@ -38,6 +43,10 @@
package android.content {
+ public class ClipData implements android.os.Parcelable {
+ method public deprecated void addItem(android.content.ClipData.Item, android.content.ContentResolver);
+ }
+
public abstract class Context {
method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
diff --git a/core/java/android/accessibilityservice/AccessibilityButtonController.java b/core/java/android/accessibilityservice/AccessibilityButtonController.java
index c3a5dab..ee19768 100644
--- a/core/java/android/accessibilityservice/AccessibilityButtonController.java
+++ b/core/java/android/accessibilityservice/AccessibilityButtonController.java
@@ -23,6 +23,8 @@
import android.util.ArrayMap;
import android.util.Slog;
+import com.android.internal.util.Preconditions;
+
/**
* Controller for the accessibility button within the system's navigation area
* <p>
@@ -89,7 +91,7 @@
* @param callback the callback to add, must be non-null
*/
public void registerAccessibilityButtonCallback(@NonNull AccessibilityButtonCallback callback) {
- registerAccessibilityButtonCallback(callback, null);
+ registerAccessibilityButtonCallback(callback, new Handler());
}
/**
@@ -99,11 +101,12 @@
* {@code null}.
*
* @param callback the callback to add, must be non-null
- * @param handler the handler on which to callback should execute, or {@code null} to
- * execute on the service's main thread
+ * @param handler the handler on which the callback should execute, must be non-null
*/
public void registerAccessibilityButtonCallback(@NonNull AccessibilityButtonCallback callback,
- @Nullable Handler handler) {
+ @NonNull Handler handler) {
+ Preconditions.checkNotNull(callback);
+ Preconditions.checkNotNull(handler);
synchronized (mLock) {
if (mCallbacks == null) {
mCallbacks = new ArrayMap<>();
@@ -121,6 +124,7 @@
*/
public void unregisterAccessibilityButtonCallback(
@NonNull AccessibilityButtonCallback callback) {
+ Preconditions.checkNotNull(callback);
synchronized (mLock) {
if (mCallbacks == null) {
return;
@@ -154,12 +158,7 @@
for (int i = 0, count = entries.size(); i < count; i++) {
final AccessibilityButtonCallback callback = entries.keyAt(i);
final Handler handler = entries.valueAt(i);
- if (handler != null) {
- handler.post(() -> callback.onClicked(this));
- } else {
- // We're already on the main thread, just run the callback.
- callback.onClicked(this);
- }
+ handler.post(() -> callback.onClicked(this));
}
}
@@ -184,12 +183,7 @@
for (int i = 0, count = entries.size(); i < count; i++) {
final AccessibilityButtonCallback callback = entries.keyAt(i);
final Handler handler = entries.valueAt(i);
- if (handler != null) {
- handler.post(() -> callback.onAvailabilityChanged(this, available));
- } else {
- // We're already on the main thread, just run the callback.
- callback.onAvailabilityChanged(this, available);
- }
+ handler.post(() -> callback.onAvailabilityChanged(this, available));
}
}
diff --git a/core/java/android/accessibilityservice/FingerprintGestureController.java b/core/java/android/accessibilityservice/FingerprintGestureController.java
index e203c6d..db00fff 100644
--- a/core/java/android/accessibilityservice/FingerprintGestureController.java
+++ b/core/java/android/accessibilityservice/FingerprintGestureController.java
@@ -156,9 +156,9 @@
FingerprintGestureCallback callback = handlerMap.keyAt(i);
Handler handler = handlerMap.valueAt(i);
if (handler != null) {
- handler.post(() -> callback.onGesture(gesture));
+ handler.post(() -> callback.onGestureDetected(gesture));
} else {
- callback.onGesture(gesture);
+ callback.onGestureDetected(gesture);
}
}
}
@@ -180,6 +180,12 @@
* @param gesture The id of the gesture that was detected. For example,
* {@link #FINGERPRINT_GESTURE_SWIPE_RIGHT}.
*/
+ public void onGestureDetected(int gesture) {}
+
+ /**
+ * @deprecated Never called. Use onGestureDetected.
+ */
+ @Deprecated
public void onGesture(int gesture) {}
}
}
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 06b09c0..a5b37f3 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -376,7 +376,7 @@
* {@link #VISIBILITY_USER_MANAGED_NOT_VISIBLE} is used.
*/
public static final String PACKAGE_NAME_KEY_LEGACY_VISIBLE =
- "android.accounts.key_legacy_visible";
+ "android:accounts:key_legacy_visible";
/**
* Key to set visibility for applications which satisfy one of the following conditions:
@@ -395,7 +395,7 @@
* {@link #VISIBILITY_USER_MANAGED_VISIBLE} is used.
*/
public static final String PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE =
- "android.accounts.key_legacy_not_visible";
+ "android:accounts:key_legacy_not_visible";
/**
* @hide
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 6e7b750..2230472 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -3143,10 +3143,15 @@
* 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.
+ * <p>The system will return this value instead of {@link #IMPORTANCE_PERCEPTIBLE}
+ * on Android versions below {@link Build.VERSION_CODES#O}.
+ *
+ * <p>On Android version {@link Build.VERSION_CODES#O} and later, this value will still be
+ * returned for apps with the target API level below {@link Build.VERSION_CODES#O}.
+ * For apps targeting version {@link Build.VERSION_CODES#O} and later,
+ * the correct value {@link #IMPORTANCE_PERCEPTIBLE} will be returned.
*/
- @Deprecated
- public static final int IMPORTANCE_PERCEPTIBLE_DEPRECATED = 130;
+ public static final int IMPORTANCE_PERCEPTIBLE_PRE_26 = 130;
/**
* Constant for {@link #importance}: This process is not something the user
@@ -3160,11 +3165,17 @@
* 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.
+ * <p>The system will return this value instead of {@link #IMPORTANCE_CANT_SAVE_STATE}
+ * on Android versions below {@link Build.VERSION_CODES#O}.
+ *
+ * <p>On Android version {@link Build.VERSION_CODES#O} after, this value will still be
+ * returned for apps with the target API level below {@link Build.VERSION_CODES#O}.
+ * For apps targeting version {@link Build.VERSION_CODES#O} and later,
+ * the correct value {@link #IMPORTANCE_CANT_SAVE_STATE} will be returned.
+ *
* @hide
*/
- @Deprecated
- public static final int IMPORTANCE_CANT_SAVE_STATE_DEPRECATED = 170;
+ public static final int IMPORTANCE_CANT_SAVE_STATE_PRE_26 = 170;
/**
* Constant for {@link #importance}: This process is running an
@@ -3244,15 +3255,25 @@
*/
public static @Importance int procStateToImportanceForClient(int procState,
Context clientContext) {
+ return procStateToImportanceForTargetSdk(procState,
+ clientContext.getApplicationInfo().targetSdkVersion);
+ }
+
+ /**
+ * See {@link #procStateToImportanceForClient}.
+ * @hide
+ */
+ public static @Importance int procStateToImportanceForTargetSdk(int procState,
+ int targetSdkVersion) {
final int importance = procStateToImportance(procState);
// For pre O apps, convert to the old, wrong values.
- if (clientContext.getApplicationInfo().targetSdkVersion < VERSION_CODES.O) {
+ if (targetSdkVersion < VERSION_CODES.O) {
switch (importance) {
case IMPORTANCE_PERCEPTIBLE:
- return IMPORTANCE_PERCEPTIBLE_DEPRECATED;
+ return IMPORTANCE_PERCEPTIBLE_PRE_26;
case IMPORTANCE_CANT_SAVE_STATE:
- return IMPORTANCE_CANT_SAVE_STATE_DEPRECATED;
+ return IMPORTANCE_CANT_SAVE_STATE_PRE_26;
}
}
return importance;
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 63e8cc6..3eec596 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -211,6 +211,9 @@
private static final String KEY_USAGE_TIME_REPORT = "android:activity.usageTimeReport";
private static final String KEY_ROTATION_ANIMATION_HINT = "android:activity.rotationAnimationHint";
+ private static final String KEY_INSTANT_APP_VERIFICATION_BUNDLE
+ = "android:instantapps.installerbundle";
+
/** @hide */
public static final int ANIM_NONE = 0;
/** @hide */
@@ -264,6 +267,7 @@
private boolean mTaskOverlayCanResume;
private AppTransitionAnimationSpec mAnimSpecs[];
private int mRotationAnimationHint = -1;
+ private Bundle mAppVerificationBundle;
/**
* Create an ActivityOptions specifying a custom animation to run when
@@ -886,6 +890,7 @@
opts.getBinder(KEY_ANIMATION_FINISHED_LISTENER));
}
mRotationAnimationHint = opts.getInt(KEY_ROTATION_ANIMATION_HINT);
+ mAppVerificationBundle = opts.getBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE);
}
/**
@@ -1275,6 +1280,9 @@
b.putBinder(KEY_ANIMATION_FINISHED_LISTENER, mAnimationFinishedListener.asBinder());
}
b.putInt(KEY_ROTATION_ANIMATION_HINT, mRotationAnimationHint);
+ if (mAppVerificationBundle != null) {
+ b.putBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE, mAppVerificationBundle);
+ }
return b;
}
@@ -1342,6 +1350,30 @@
mRotationAnimationHint = hint;
}
+ /**
+ * Pop the extra verification bundle for the installer.
+ * This removes the bundle from the ActivityOptions to make sure the installer bundle
+ * is only available once.
+ * @hide
+ */
+ public Bundle popAppVerificationBundle() {
+ Bundle out = mAppVerificationBundle;
+ mAppVerificationBundle = null;
+ return out;
+ }
+
+ /**
+ * Set the {@link Bundle} that is provided to the app installer for additional verification
+ * if the call to {@link Context#startActivity} results in an app being installed.
+ *
+ * This Bundle is not provided to any other app besides the installer.
+ */
+ public ActivityOptions setAppVerificationBundle(Bundle bundle) {
+ mAppVerificationBundle = bundle;
+ return this;
+
+ }
+
/** @hide */
@Override
public String toString() {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 195ba24..dd9db8a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -670,6 +670,7 @@
IBinder requestToken;
int requestType;
int sessionId;
+ int flags;
}
static final class ActivityConfigChangeData {
@@ -1288,12 +1289,13 @@
@Override
public void requestAssistContextExtras(IBinder activityToken, IBinder requestToken,
- int requestType, int sessionId) {
+ int requestType, int sessionId, int flags) {
RequestAssistContextExtras cmd = new RequestAssistContextExtras();
cmd.activityToken = activityToken;
cmd.requestToken = requestToken;
cmd.requestType = requestType;
cmd.sessionId = sessionId;
+ cmd.flags = flags;
sendMessage(H.REQUEST_ASSIST_CONTEXT_EXTRAS, cmd);
}
@@ -3030,7 +3032,7 @@
referrer = r.activity.onProvideReferrer();
}
if (cmd.requestType == ActivityManager.ASSIST_CONTEXT_FULL || forAutofill) {
- structure = new AssistStructure(r.activity, forAutofill);
+ structure = new AssistStructure(r.activity, forAutofill, cmd.flags);
Intent activityIntent = r.activity.getIntent();
boolean notSecure = r.window == null ||
(r.window.getAttributes().flags
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 65c5b4f..46e6def 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -621,7 +621,7 @@
}
@Override
- public FragmentTransaction postOnCommit(Runnable runnable) {
+ public FragmentTransaction runOnCommit(Runnable runnable) {
if (runnable == null) {
throw new IllegalArgumentException("runnable cannot be null");
}
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index fdd1b7e..63c0ef3 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -452,6 +452,18 @@
public void onFragmentAttached(FragmentManager fm, Fragment f, Context context) {}
/**
+ * Called right before the fragment's {@link Fragment#onCreate(Bundle)} method is called.
+ * This is a good time to inject any required dependencies or perform other configuration
+ * for the fragment.
+ *
+ * @param fm Host FragmentManager
+ * @param f Fragment changing state
+ * @param savedInstanceState Saved instance bundle from a previous instance
+ */
+ public void onFragmentPreCreated(FragmentManager fm, Fragment f,
+ Bundle savedInstanceState) {}
+
+ /**
* Called after the fragment has returned from the FragmentManager's call to
* {@link Fragment#onCreate(Bundle)}. This will only happen once for any given
* fragment instance, though the fragment may be attached and detached multiple times.
@@ -1218,6 +1230,7 @@
dispatchOnFragmentAttached(f, mHost.getContext(), false);
if (!f.mRetaining) {
+ dispatchOnFragmentPreCreated(f, f.mSavedFragmentState, false);
f.performCreate(f.mSavedFragmentState);
dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
} else {
@@ -3274,6 +3287,25 @@
}
}
+ void dispatchOnFragmentPreCreated(Fragment f, Bundle savedInstanceState,
+ boolean onlyRecursive) {
+ if (mParent != null) {
+ FragmentManager parentManager = mParent.getFragmentManager();
+ if (parentManager instanceof FragmentManagerImpl) {
+ ((FragmentManagerImpl) parentManager)
+ .dispatchOnFragmentPreCreated(f, savedInstanceState, true);
+ }
+ }
+ if (mLifecycleCallbacks == null) {
+ return;
+ }
+ for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
+ if (!onlyRecursive || p.second) {
+ p.first.onFragmentPreCreated(this, f, savedInstanceState);
+ }
+ }
+ }
+
void dispatchOnFragmentCreated(Fragment f, Bundle savedInstanceState, boolean onlyRecursive) {
if (mParent != null) {
FragmentManager parentManager = mParent.getFragmentManager();
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index a0e5a4e..c910e90 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -315,14 +315,22 @@
* in this transaction may have been optimized out due to the presence of a subsequent
* fragment transaction in the batch.
*
- * <p><code>postOnCommit</code> may not be used with transactions
+ *
+ * <p>If a transaction is committed using {@link #commitAllowingStateLoss()} this runnable
+ * may be executed when the FragmentManager is in a state where new transactions may not
+ * be committed without allowing state loss.</p>
+ *
+ * <p><code>runOnCommit</code> may not be used with transactions
* {@link #addToBackStack(String) added to the back stack} as Runnables cannot be persisted
- * with back stack state.</p>
+ * with back stack state. {@link IllegalStateException} will be thrown if
+ * {@link #addToBackStack(String)} has been previously called for this transaction
+ * or if it is called after a call to <code>runOnCommit</code>.</p>
*
* @param runnable Runnable to add
* @return this FragmentTransaction
+ * @throws IllegalStateException if {@link #addToBackStack(String)} has been called
*/
- public abstract FragmentTransaction postOnCommit(Runnable runnable);
+ public abstract FragmentTransaction runOnCommit(Runnable runnable);
/**
* Schedules a commit of this transaction. The commit does
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 5ee8e0c..aeccf56 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -594,7 +594,7 @@
void unregisterTaskStackListener(ITaskStackListener listener);
void moveStackToDisplay(int stackId, int displayId);
boolean requestAutofillData(in IResultReceiver receiver, in Bundle receiverExtras,
- in IBinder activityToken);
+ in IBinder activityToken, int flags);
void dismissKeyguard(in IBinder token, in IKeyguardDismissCallback callback);
int restartUserInBackground(int userId);
@@ -605,7 +605,7 @@
void cancelTaskThumbnailTransition(int taskId);
/**
- * @param taskId the id of the task to retrieve the snapshots for
+ * @param taskId the id of the task to retrieve the sAutoapshots for
* @param reducedResolution if set, if the snapshot needs to be loaded from disk, this will load
* a reduced resolution of it, which is much faster
* @return a graphic buffer representing a screenshot of a task
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index 1b3c00b..b3521c0 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -135,7 +135,7 @@
void dumpDbInfo(in ParcelFileDescriptor fd, in String[] args);
void unstableProviderDied(IBinder provider);
void requestAssistContextExtras(IBinder activityToken, IBinder requestToken,
- int requestType, int sessionId);
+ int requestType, int sessionId, int flags);
void scheduleTranslucentConversionComplete(IBinder token, boolean timeout);
void setProcessState(int state);
void scheduleInstallProvider(in ProviderInfo provider);
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 9377d35..69ed439 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -543,10 +543,10 @@
* Create a new ActivityMonitor that can be used for intercepting any activity to be
* started.
*
- * <p> When an activity is started, {@link #onMatchIntent(Intent)} will be called on
+ * <p> When an activity is started, {@link #onStartActivity(Intent)} will be called on
* instances created using this constructor to see if it is a hit.
*
- * @see #onMatchIntent(Intent)
+ * @see #onStartActivity(Intent)
*/
public ActivityMonitor() {
mWhich = null;
@@ -558,7 +558,7 @@
/**
* @return true if this monitor is used for intercepting any started activity by calling
- * into {@link #onMatchIntent(Intent)}, false if this monitor is only used
+ * into {@link #onStartActivity(Intent)}, false if this monitor is only used
* for specific intents corresponding to the intent filter or activity class
* passed in the constructor.
*/
@@ -665,7 +665,7 @@
* @param intent The intent used for starting the activity.
* @return The {@link ActivityResult} that needs to be used in case of a match.
*/
- public ActivityResult onMatchIntent(Intent intent) {
+ public ActivityResult onStartActivity(Intent intent) {
return null;
}
@@ -1589,7 +1589,7 @@
final ActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result = null;
if (am.ignoreMatchingSpecificIntents()) {
- result = am.onMatchIntent(intent);
+ result = am.onStartActivity(intent);
}
if (result != null) {
am.mHits++;
@@ -1652,7 +1652,7 @@
final ActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result = null;
if (am.ignoreMatchingSpecificIntents()) {
- result = am.onMatchIntent(intents[0]);
+ result = am.onStartActivity(intents[0]);
}
if (result != null) {
am.mHits++;
@@ -1722,7 +1722,7 @@
final ActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result = null;
if (am.ignoreMatchingSpecificIntents()) {
- result = am.onMatchIntent(intent);
+ result = am.onStartActivity(intent);
}
if (result != null) {
am.mHits++;
@@ -1789,7 +1789,7 @@
final ActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result = null;
if (am.ignoreMatchingSpecificIntents()) {
- result = am.onMatchIntent(intent);
+ result = am.onStartActivity(intent);
}
if (result != null) {
am.mHits++;
@@ -1835,7 +1835,7 @@
final ActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result = null;
if (am.ignoreMatchingSpecificIntents()) {
- result = am.onMatchIntent(intent);
+ result = am.onStartActivity(intent);
}
if (result != null) {
am.mHits++;
@@ -1880,7 +1880,7 @@
final ActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result = null;
if (am.ignoreMatchingSpecificIntents()) {
- result = am.onMatchIntent(intent);
+ result = am.onStartActivity(intent);
}
if (result != null) {
am.mHits++;
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index b8a5f57..4de6e44 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -381,27 +381,58 @@
* or {@code null} if the caller isn't interested in knowing the result.
* @param handler The handler to invoke the callback on, or {@code null} to use the main
* handler.
+ *
+ * TO BE REMOVED
*/
+ @Deprecated
public void dismissKeyguard(@NonNull Activity activity,
@Nullable KeyguardDismissCallback callback, @Nullable Handler handler) {
+ requestDismissKeyguard(activity, callback);
+ }
+
+ /**
+ * If the device is currently locked (see {@link #isKeyguardLocked()}, requests the Keyguard to
+ * be dismissed.
+ * <p>
+ * If the Keyguard is not secure or the device is currently in a trusted state, calling this
+ * method will immediately dismiss the Keyguard without any user interaction.
+ * <p>
+ * If the Keyguard is secure and the device is not in a trusted state, this will bring up the
+ * UI so the user can enter their credentials.
+ *
+ * @param activity The activity requesting the dismissal. The activity must be either visible
+ * by using {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} or must be in a state in
+ * which it would be visible if Keyguard would not be hiding it. If that's not
+ * the case, the request will fail immediately and
+ * {@link KeyguardDismissCallback#onDismissError} will be invoked.
+ * @param callback The callback to be called if the request to dismiss Keyguard was successful
+ * or {@code null} if the caller isn't interested in knowing the result. The
+ * callback will not be invoked if the activity was destroyed before the
+ * callback was received.
+ */
+ public void requestDismissKeyguard(@NonNull Activity activity,
+ @Nullable KeyguardDismissCallback callback) {
try {
- final Handler actualHandler = handler != null
- ? handler
- : new Handler(Looper.getMainLooper());
mAm.dismissKeyguard(activity.getActivityToken(), new IKeyguardDismissCallback.Stub() {
@Override
public void onDismissError() throws RemoteException {
- actualHandler.post(callback::onDismissError);
+ if (callback != null && !activity.isDestroyed()) {
+ activity.mHandler.post(callback::onDismissError);
+ }
}
@Override
public void onDismissSucceeded() throws RemoteException {
- actualHandler.post(callback::onDismissSucceeded);
+ if (callback != null && !activity.isDestroyed()) {
+ activity.mHandler.post(callback::onDismissSucceeded);
+ }
}
@Override
public void onDismissCancelled() throws RemoteException {
- actualHandler.post(callback::onDismissCancelled);
+ if (callback != null && !activity.isDestroyed()) {
+ activity.mHandler.post(callback::onDismissCancelled);
+ }
}
});
} catch (RemoteException e) {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 00a8f46..28fe319 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -239,16 +239,11 @@
* The number of events that this notification represents. For example, in a new mail
* notification, this could be the number of unread messages.
*
- * The system may or may not use this field to modify the appearance of the notification. For
- * example, before {@link android.os.Build.VERSION_CODES#HONEYCOMB}, this number was
- * superimposed over the icon in the status bar. Starting with
- * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, the template used by
- * {@link Notification.Builder} has displayed the number in the expanded notification view.
+ * The system may or may not use this field to modify the appearance of the notification.
* Starting with {@link android.os.Build.VERSION_CODES#O}, the number may be displayed as a
* badge icon in Launchers that support badging.
- *
*/
- public int number = 1;
+ public int number = 0;
/**
* The intent to execute when the expanded status entry is clicked. If
@@ -1290,7 +1285,7 @@
* action is sent. These remote inputs are guaranteed to return true on a call to
* {@link RemoteInput#isDataOnly}.
*
- * May return null if no data-only remote inputs were added.
+ * Returns null if there are no data-only remote inputs.
*
* This method exists so that legacy RemoteInput collectors that pre-date the addition
* of non-textual RemoteInputs do not access these remote inputs.
@@ -2681,21 +2676,12 @@
private int mPrimaryTextColor = COLOR_INVALID;
private int mSecondaryTextColor = COLOR_INVALID;
private int mActionBarColor = COLOR_INVALID;
+ private int mBackgroundColor = COLOR_INVALID;
+ private int mForegroundColor = COLOR_INVALID;
/**
* Constructs a new Builder with the defaults:
*
-
- * <table>
- * <tr><th align=right>priority</th>
- * <td>{@link #PRIORITY_DEFAULT}</td></tr>
- * <tr><th align=right>when</th>
- * <td>now ({@link System#currentTimeMillis()})</td></tr>
- * <tr><th align=right>audio stream</th>
- * <td>{@link #STREAM_DEFAULT}</td></tr>
- * </table>
- *
-
* @param context
* A {@link Context} that will be used by the Builder to construct the
* RemoteViews. The Context will not be held past the lifetime of this Builder
@@ -3854,10 +3840,62 @@
|| mActionBarColor == COLOR_INVALID
|| mTextColorsAreForBackground != backgroundColor) {
mTextColorsAreForBackground = backgroundColor;
- mPrimaryTextColor = NotificationColorUtil.resolvePrimaryColor(
- mContext, backgroundColor);
- mSecondaryTextColor = NotificationColorUtil.resolveSecondaryColor(
- mContext, backgroundColor);
+ if (mForegroundColor == COLOR_INVALID || !isColorized()) {
+ mPrimaryTextColor = NotificationColorUtil.resolvePrimaryColor(mContext,
+ backgroundColor);
+ mSecondaryTextColor = NotificationColorUtil.resolveSecondaryColor(mContext,
+ backgroundColor);
+ } else {
+ double backLum = NotificationColorUtil.calculateLuminance(backgroundColor);
+ double textLum = NotificationColorUtil.calculateLuminance(mForegroundColor);
+ double contrast = NotificationColorUtil.calculateContrast(mForegroundColor,
+ backgroundColor);
+ boolean textDark = backLum > textLum;
+ if (contrast < 4.5f) {
+ if (textDark) {
+ mSecondaryTextColor = NotificationColorUtil.findContrastColor(
+ mForegroundColor,
+ backgroundColor,
+ true /* findFG */,
+ 4.5f);
+ mPrimaryTextColor = NotificationColorUtil.changeColorLightness(
+ mSecondaryTextColor, -20);
+ } else {
+ mSecondaryTextColor =
+ NotificationColorUtil.findContrastColorAgainstDark(
+ mForegroundColor,
+ backgroundColor,
+ true /* findFG */,
+ 4.5f);
+ mPrimaryTextColor = NotificationColorUtil.changeColorLightness(
+ mSecondaryTextColor, 10);
+ }
+ } else {
+ mPrimaryTextColor = mForegroundColor;
+ mSecondaryTextColor = NotificationColorUtil.changeColorLightness(
+ mPrimaryTextColor, textDark ? 10 : -20);
+ if (NotificationColorUtil.calculateContrast(mSecondaryTextColor,
+ backgroundColor) < 4.5f) {
+ // oh well the secondary is not good enough
+ if (textDark) {
+ mSecondaryTextColor = NotificationColorUtil.findContrastColor(
+ mSecondaryTextColor,
+ backgroundColor,
+ true /* findFG */,
+ 4.5f);
+ } else {
+ mSecondaryTextColor
+ = NotificationColorUtil.findContrastColorAgainstDark(
+ mSecondaryTextColor,
+ backgroundColor,
+ true /* findFG */,
+ 4.5f);
+ }
+ mPrimaryTextColor = NotificationColorUtil.changeColorLightness(
+ mSecondaryTextColor, textDark ? -20 : 10);
+ }
+ }
+ }
mActionBarColor = NotificationColorUtil.resolveActionBarColor(mContext,
backgroundColor);
}
@@ -4845,7 +4883,7 @@
private int getBackgroundColor() {
if (isColorized()) {
- return mN.color;
+ return mBackgroundColor != COLOR_INVALID ? mBackgroundColor : mN.color;
} else {
return COLOR_DEFAULT;
}
@@ -4863,6 +4901,21 @@
return targetSdkVersion > Build.VERSION_CODES.M
&& targetSdkVersion < Build.VERSION_CODES.O;
}
+
+ /**
+ * Set a color palette to be used as the background and textColors
+ *
+ * @param backgroundColor the color to be used as the background
+ * @param foregroundColor the color to be used as the foreground
+ *
+ * @hide
+ */
+ public void setColorPalette(int backgroundColor, int foregroundColor) {
+ mBackgroundColor = backgroundColor;
+ mForegroundColor = foregroundColor;
+ mTextColorsAreForBackground = COLOR_INVALID;
+ ensureColors();
+ }
}
/**
@@ -4899,6 +4952,18 @@
* @hide
*/
public boolean isColorized() {
+ if (isColorizedMedia()) {
+ return true;
+ }
+ return extras.getBoolean(EXTRA_COLORIZED) && isForegroundService();
+ }
+
+ /**
+ * @return true if this notification is colorized and it is a media notification
+ *
+ * @hide
+ */
+ public boolean isColorizedMedia() {
Class<? extends Style> style = getNotificationStyle();
if (MediaStyle.class.equals(style)) {
Boolean colorized = (Boolean) extras.get(EXTRA_COLORIZED);
@@ -4910,7 +4975,23 @@
return true;
}
}
- return extras.getBoolean(EXTRA_COLORIZED) && isForegroundService();
+ return false;
+ }
+
+
+ /**
+ * @return true if this is a media notification
+ *
+ * @hide
+ */
+ public boolean isMediaNotification() {
+ Class<? extends Style> style = getNotificationStyle();
+ if (MediaStyle.class.equals(style)) {
+ return true;
+ } else if (DecoratedMediaCustomViewStyle.class.equals(style)) {
+ return true;
+ }
+ return false;
}
private boolean hasLargeIcon() {
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 7c361b9..6c55548 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -422,7 +422,9 @@
* Creates a notification channel that notifications can be posted to.
*
* This can also be used to restore a deleted channel and to update an existing channel's
- * name and description. The name and description should only be changed if the locale changes
+ * name and description.
+ *
+ * <p>The name and description should only be changed if the locale changes
* or in response to the user renaming this channel. For example, if a user has a channel
* named 'John Doe' that represents messages from a 'John Doe', and 'John Doe' changes his name
* to 'John Smith,' the channel can be renamed to match.
@@ -454,6 +456,8 @@
/**
* Returns the notification channel settings for a given channel id.
+ *
+ * The channel must belong to your package, or it will not be returned.
*/
public NotificationChannel getNotificationChannel(String channelId) {
INotificationManager service = getService();
@@ -465,7 +469,7 @@
}
/**
- * Returns all notification channels belonging to the calling app.
+ * Returns all notification channels belonging to the calling package.
*/
public List<NotificationChannel> getNotificationChannels() {
INotificationManager service = getService();
@@ -478,6 +482,10 @@
/**
* Deletes the given notification channel.
+ *
+ * <p>If you {@link #createNotificationChannel(NotificationChannel) create} a new channel with
+ * this same id, the deleted channel will be un-deleted with all of the same settings it
+ * had before it was deleted.
*/
public void deleteNotificationChannel(String channelId) {
INotificationManager service = getService();
@@ -501,7 +509,8 @@
}
/**
- * Deletes the given notification channel group.
+ * Deletes the given notification channel group, and all notification channels that
+ * belong to it.
*/
public void deleteNotificationChannelGroup(String groupId) {
INotificationManager service = getService();
diff --git a/core/java/android/app/PictureInPictureParams.java b/core/java/android/app/PictureInPictureParams.java
index 875d592..e1df33b 100644
--- a/core/java/android/app/PictureInPictureParams.java
+++ b/core/java/android/app/PictureInPictureParams.java
@@ -238,7 +238,7 @@
*/
public void truncateActions(int size) {
if (hasSetActions()) {
- mUserActions = mUserActions.subList(0, size);
+ mUserActions = mUserActions.subList(0, Math.min(mUserActions.size(), size));
}
}
diff --git a/core/java/android/app/RemoteInput.java b/core/java/android/app/RemoteInput.java
index d1dc859..8ab19c0 100644
--- a/core/java/android/app/RemoteInput.java
+++ b/core/java/android/app/RemoteInput.java
@@ -118,6 +118,11 @@
return mChoices;
}
+ /**
+ * Get possible non-textual inputs that are accepted.
+ * This can be {@code null} if the input does not accept non-textual values.
+ * See {@link Builder#setAllowDataType}.
+ */
public Set<String> getAllowedDataTypes() {
return mAllowedDataTypes;
}
@@ -202,7 +207,9 @@
}
/**
- * Specifies whether the user can provide arbitrary values.
+ * Specifies whether the user can provide arbitrary values. This allows an input
+ * to accept non-textual values. Examples of usage are an input that wants audio
+ * or an image.
*
* @param mimeType A mime type that results are allowed to come in.
* Be aware that text results (see {@link #setAllowFreeFormInput}
@@ -374,7 +381,12 @@
}
/**
- * Same as {@link #addResultsToIntent} but for setting data results.
+ * Same as {@link #addResultsToIntent} but for setting data results. This is used
+ * for inputs that accept non-textual results (see {@link Builder#setAllowDataType}).
+ * Only one result can be provided for every mime type accepted by the RemoteInput.
+ * If multiple inputs of the same mime type are expected then multiple RemoteInputs
+ * should be used.
+ *
* @param remoteInput The remote input for which results are being provided
* @param intent The intent to add remote input results to. The {@link ClipData}
* field of the intent will be modified to contain the results.
diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java
deleted file mode 100644
index 5ed66ca..0000000
--- a/core/java/android/app/WallpaperColors.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.app;
-
-import android.graphics.Color;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import android.util.Pair;
-
-import java.util.List;
-
-/**
- * A class containing information about the colors of a wallpaper.
- */
-public final class WallpaperColors implements Parcelable {
-
- public WallpaperColors(Parcel parcel) {
- }
-
- /**
- * Wallpaper color details containing a list of colors and their weights,
- * as if it were an histogram.
- * This list can be extracted from a bitmap by the Palette API.
- *
- * Dark text support will be calculated internally based on the histogram.
- *
- * @param colors list of pairs where each pair contains a color
- * and number of occurrences/influence.
- */
- public WallpaperColors(List<Pair<Color, Integer>> colors) {
- }
-
- /**
- * Wallpaper color details containing a list of colors and their weights,
- * as if it were an histogram.
- * Explicit dark text support.
- *
- * @param colors list of pairs where each pair contains a color
- * and number of occurrences/influence.
- * @param supportsDarkText can have dark text on top or not
- */
- public WallpaperColors(List<Pair<Color, Integer>> colors, boolean supportsDarkText) {
- }
-
- public static final Creator<WallpaperColors> CREATOR = new Creator<WallpaperColors>() {
- @Override
- public WallpaperColors createFromParcel(Parcel in) {
- return new WallpaperColors(in);
- }
-
- @Override
- public WallpaperColors[] newArray(int size) {
- return new WallpaperColors[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- }
-
- /**
- * List of colors with their occurrences. The bigger the int, the more relevant the color.
- * @return list of colors paired with their weights.
- */
- public List<Pair<Color, Integer>> getColors() {
- return null;
- }
-
- /**
- * Whether or not dark text is legible on top of this wallpaper.
- *
- * @return true if dark text is supported
- */
- public boolean supportsDarkText() {
- return false;
- }
-}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 6d87de8..db2f937 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -17,8 +17,6 @@
package android.app;
import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.RawRes;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
@@ -746,43 +744,6 @@
return getWallpaperFile(which, mContext.getUserId());
}
-
- /**
- * Registers a listener to get notified when the wallpaper colors change.
- * Callback might be called from an arbitrary background thread.
- *
- * @param listener A listener to register
- */
- public void addOnColorsChangedListener(@NonNull OnColorsChangedListener listener) {
- }
-
- /**
- * Registers a listener to get notified when the wallpaper colors change
- * @param listener A listener to register
- * @param handler Where to call it from. Might be called from a background thread
- * if null.
- */
- public void addOnColorsChangedListener(@NonNull OnColorsChangedListener listener,
- @Nullable Handler handler) {
- }
-
- /**
- * Stop listening to color updates.
- * @param callback A callback to unsubscribe
- */
- public void removeOnColorsChangedListener(@NonNull OnColorsChangedListener callback) {
- }
-
- /**
- * Get the primary colors of a wallpaper
- * @param which wallpaper type. Must be either {@link #FLAG_SYSTEM} or
- * {@link #FLAG_LOCK}
- * @return a list of colors ordered by priority
- */
- public @Nullable WallpaperColors getWallpaperColors(int which) {
- return null;
- }
-
/**
* Version of {@link #getWallpaperFile(int)} that can access the wallpaper data
* for a given user. The caller must hold the INTERACT_ACROSS_USERS_FULL
@@ -1774,19 +1735,4 @@
mLatch.countDown();
}
}
-
- /**
- * Interface definition for a callback to be invoked when colors change on a wallpaper.
- */
- public interface OnColorsChangedListener {
- /**
- * Called when colors change.
- * A {@link android.app.WallpaperColors} object containing a simplified
- * color histogram will be given.
- *
- * @param colors Wallpaper color info
- * @param which A combination of {@link #FLAG_LOCK} and {@link #FLAG_SYSTEM}
- */
- void onColorsChanged(WallpaperColors colors, int which);
- }
}
diff --git a/core/java/android/app/admin/ConnectEvent.java b/core/java/android/app/admin/ConnectEvent.java
index 5111443..423ee52 100644
--- a/core/java/android/app/admin/ConnectEvent.java
+++ b/core/java/android/app/admin/ConnectEvent.java
@@ -19,6 +19,9 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
/**
* A class that represents a connect library call event.
*/
@@ -44,8 +47,14 @@
this.timestamp = in.readLong();
}
- public String getIpAddress() {
- return ipAddress;
+ public InetAddress getInetAddress() {
+ try {
+ // ipAddress is already an address, not a host name, no DNS resolution will happen.
+ return InetAddress.getByName(ipAddress);
+ } catch (UnknownHostException e) {
+ // Should never happen as we aren't passing a host name.
+ return InetAddress.getLoopbackAddress();
+ }
}
public int getPort() {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index f5df67b..8fcabce 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3030,17 +3030,24 @@
* keyring. The user's credential will need to be entered again in order to derive the
* credential encryption key that will be stored back in the keyring for future use.
* <p>
- * This flag can only be used by a profile owner when locking a managed profile on an FBE
- * device.
+ * This flag can only be used by a profile owner when locking a managed profile when
+ * {@link #getStorageEncryptionStatus} returns {@link #ENCRYPTION_STATUS_ACTIVE_PER_USER}.
* <p>
* In order to secure user data, the user will be stopped and restarted so apps should wait
* until they are next run to perform further actions.
*/
+ public static final int FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY = 1;
+
+ /**
+ * Instead use {@link #FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY}.
+ * @removed
+ */
+ @Deprecated
public static final int FLAG_EVICT_CE_KEY = 1;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag=true, value={FLAG_EVICT_CE_KEY})
+ @IntDef(flag=true, value={FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY})
public @interface LockNowFlag {}
/**
@@ -3072,15 +3079,17 @@
* This method can be called on the {@link DevicePolicyManager} instance returned by
* {@link #getParentProfileInstance(ComponentName)} in order to lock the parent profile.
*
- * @param flags May be 0 or {@link #FLAG_EVICT_CE_KEY}.
+ * @param flags May be 0 or {@link #FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY}.
* @throws SecurityException if the calling application does not own an active administrator
* that uses {@link DeviceAdminInfo#USES_POLICY_FORCE_LOCK} or the
- * {@link #FLAG_EVICT_CE_KEY} flag is passed by an application that is not a profile
+ * {@link #FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY} flag is passed by an application
+ * that is not a profile
* owner of a managed profile.
- * @throws IllegalArgumentException if the {@link #FLAG_EVICT_CE_KEY} flag is passed when
- * locking the parent profile.
- * @throws UnsupportedOperationException if the {@link #FLAG_EVICT_CE_KEY} flag is passed on a
- * non-FBE device.
+ * @throws IllegalArgumentException if the {@link #FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY} flag is
+ * passed when locking the parent profile.
+ * @throws UnsupportedOperationException if the {@link #FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY}
+ * flag is passed when {@link #getStorageEncryptionStatus} does not return
+ * {@link #ENCRYPTION_STATUS_ACTIVE_PER_USER}.
*/
public void lockNow(@LockNowFlag int flags) {
if (mService != null) {
diff --git a/core/java/android/app/admin/DnsEvent.java b/core/java/android/app/admin/DnsEvent.java
index a3a3f58..87f86b5 100644
--- a/core/java/android/app/admin/DnsEvent.java
+++ b/core/java/android/app/admin/DnsEvent.java
@@ -19,6 +19,9 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
/**
* A class that represents a DNS lookup event.
*/
@@ -59,15 +62,27 @@
}
/** Returns (possibly a subset of) the IP addresses returned. */
- public String[] getIpAddresses() {
- return ipAddresses;
+ public InetAddress[] getInetAddresses() {
+ final int length = ipAddresses != null ? ipAddresses.length : 0;
+ final InetAddress[] inetAddresses = new InetAddress[length];
+ for (int i = 0; i < length; i++) {
+ try {
+ // ipAddress is already an address, not a host name, no DNS resolution will happen.
+ inetAddresses[i] = InetAddress.getByName(ipAddresses[i]);
+ } catch (UnknownHostException e) {
+ // Should never happen as we aren't passing a host name.
+ inetAddresses[i] = InetAddress.getLoopbackAddress();
+ }
+ }
+ return inetAddresses;
}
/**
* Returns the number of IP addresses returned from the DNS lookup event. May be different from
- * the length of ipAddresses if there were too many addresses to log.
+ * the length of the array returned by {@link #getInetAddresses()} if there were too many
+ * addresses to log.
*/
- public int getIpAddressesCount() {
+ public int getTotalResolvedAddressCount() {
return ipAddressesCount;
}
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index d6b89a1..3353530 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -29,10 +29,12 @@
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
/**
* Assist data automatically created by the platform's implementation of Assist and Autofill.
@@ -62,6 +64,7 @@
ComponentName mActivityComponent;
private boolean mIsHomeActivity;
+ private int mFlags;
final ArrayList<WindowNode> mWindowNodes = new ArrayList<>();
@@ -184,6 +187,7 @@
mSanitizeOnWrite = as.mSanitizeOnWrite;
mWriteStructure = as.waitForReady();
ComponentName.writeToParcel(as.mActivityComponent, out);
+ out.writeInt(as.mFlags);
out.writeLong(as.mAcquisitionStartTime);
out.writeLong(as.mAcquisitionEndTime);
mNumWindows = as.mWindowNodes.size();
@@ -338,6 +342,7 @@
void go() {
fetchData();
mActivityComponent = ComponentName.readFromParcel(mCurParcel);
+ mFlags = mCurParcel.readInt();
mAcquisitionStartTime = mCurParcel.readLong();
mAcquisitionEndTime = mCurParcel.readLong();
final int N = mCurParcel.readInt();
@@ -473,7 +478,7 @@
final int mDisplayId;
final ViewNode mRoot;
- WindowNode(AssistStructure assist, ViewRootImpl root, boolean forAutoFill) {
+ WindowNode(AssistStructure assist, ViewRootImpl root, boolean forAutoFill, int flags) {
View view = root.getView();
Rect rect = new Rect();
view.getBoundsOnScreen(rect);
@@ -488,8 +493,9 @@
ViewNodeBuilder builder = new ViewNodeBuilder(assist, mRoot, false);
if ((root.getWindowFlags() & WindowManager.LayoutParams.FLAG_SECURE) != 0) {
if (forAutoFill) {
- // NOTE: flags are currently not supported, hence 0
- view.onProvideAutofillStructure(builder, 0);
+ final int autofillFlags = (flags & AutofillManager.FLAG_MANUAL_REQUEST) != 0
+ ? View.AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS : 0;
+ view.onProvideAutofillStructure(builder, autofillFlags);
} else {
// This is a secure window, so it doesn't want a screenshot, and that
// means we should also not copy out its view hierarchy for Assist
@@ -499,8 +505,9 @@
}
}
if (forAutoFill) {
- // NOTE: flags are currently not supported, hence 0
- view.dispatchProvideAutofillStructure(builder, 0);
+ final int autofillFlags = (flags & AutofillManager.FLAG_MANUAL_REQUEST) != 0
+ ? View.AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS : 0;
+ view.dispatchProvideAutofillStructure(builder, autofillFlags);
} else {
view.dispatchProvideStructure(builder);
}
@@ -1788,7 +1795,7 @@
}
@Override
- public ArrayList<Pair<String, String>> getAttributes() {
+ public List<Pair<String, String>> getAttributes() {
if (mAttributes == null && mNames != null) {
mAttributes = new ArrayList<>(mNames.length);
for (int i = 0; i < mNames.length; i++) {
@@ -1869,20 +1876,22 @@
}
/** @hide */
- public AssistStructure(Activity activity, boolean forAutoFill) {
+ public AssistStructure(Activity activity, boolean forAutoFill, int flags) {
mHaveData = true;
mActivityComponent = activity.getComponentName();
+ mFlags = flags;
ArrayList<ViewRootImpl> views = WindowManagerGlobal.getInstance().getRootViews(
activity.getActivityToken());
for (int i=0; i<views.size(); i++) {
ViewRootImpl root = views.get(i);
- mWindowNodes.add(new WindowNode(this, root, forAutoFill));
+ mWindowNodes.add(new WindowNode(this, root, forAutoFill, flags));
}
}
public AssistStructure() {
mHaveData = true;
mActivityComponent = null;
+ mFlags = 0;
}
/** @hide */
@@ -1909,6 +1918,7 @@
}
Log.i(TAG, "Activity: " + mActivityComponent.flattenToShortString());
Log.i(TAG, "Sanitize on write: " + mSanitizeOnWrite);
+ Log.i(TAG, "Flags: " + mFlags);
final int N = getWindowNodeCount();
for (int i=0; i<N; i++) {
WindowNode node = getWindowNodeAt(i);
@@ -2021,10 +2031,16 @@
return mActivityComponent;
}
+ /** @hide */
+ public int getFlags() {
+ return mFlags;
+ }
+
/**
* Returns whether the activity associated with this AssistStructure was the home activity
- * at the time the assist data was acquired.
+ * (Launcher) at the time the assist data was acquired.
* @return Whether the activity was the home activity.
+ * @see android.content.Intent#CATEGORY_HOME
*/
public boolean isHomeActivity() {
return mIsHomeActivity;
diff --git a/core/java/android/app/usage/ExternalStorageStats.java b/core/java/android/app/usage/ExternalStorageStats.java
index 10c9b5f..83ac779e 100644
--- a/core/java/android/app/usage/ExternalStorageStats.java
+++ b/core/java/android/app/usage/ExternalStorageStats.java
@@ -16,6 +16,7 @@
package android.app.usage;
+import android.annotation.BytesLong;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
@@ -37,7 +38,7 @@
* Return the total bytes used by all files in the shared/external storage
* hosted on this volume.
*/
- public long getTotalBytes() {
+ public @BytesLong long getTotalBytes() {
return totalBytes;
}
@@ -45,7 +46,7 @@
* Return the total bytes used by audio files in the shared/external storage
* hosted on this volume.
*/
- public long getAudioBytes() {
+ public @BytesLong long getAudioBytes() {
return audioBytes;
}
@@ -53,7 +54,7 @@
* Return the total bytes used by video files in the shared/external storage
* hosted on this volume.
*/
- public long getVideoBytes() {
+ public @BytesLong long getVideoBytes() {
return videoBytes;
}
@@ -61,7 +62,7 @@
* Return the total bytes used by image files in the shared/external storage
* hosted on this volume.
*/
- public long getImageBytes() {
+ public @BytesLong long getImageBytes() {
return imageBytes;
}
@@ -72,7 +73,7 @@
* This data is already accounted against individual apps as returned
* through {@link StorageStats}.
*/
- public long getAppBytes() {
+ public @BytesLong long getAppBytes() {
return appBytes;
}
diff --git a/core/java/android/app/usage/StorageStats.java b/core/java/android/app/usage/StorageStats.java
index 26c702c0..3a27751 100644
--- a/core/java/android/app/usage/StorageStats.java
+++ b/core/java/android/app/usage/StorageStats.java
@@ -16,6 +16,7 @@
package android.app.usage;
+import android.annotation.BytesLong;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
@@ -33,18 +34,24 @@
/** {@hide} */ public long cacheBytes;
/**
- * Return the size of all code. This includes {@code APK} files and
- * optimized compiler output.
+ * Return the size of app. This includes {@code APK} files, optimized
+ * compiler output, and unpacked native libraries.
* <p>
* If the primary external/shared storage is hosted on this storage device,
* then this includes files stored under {@link Context#getObbDir()}.
* <p>
* Code is shared between all users on a multiuser device.
*/
- public long getCodeBytes() {
+ public @BytesLong long getAppBytes() {
return codeBytes;
}
+ /** @removed */
+ @Deprecated
+ public long getCodeBytes() {
+ return getAppBytes();
+ }
+
/**
* Return the size of all data. This includes files stored under
* {@link Context#getDataDir()}, {@link Context#getCacheDir()},
@@ -58,7 +65,7 @@
* <p>
* Data is isolated for each user on a multiuser device.
*/
- public long getDataBytes() {
+ public @BytesLong long getDataBytes() {
return dataBytes;
}
@@ -72,7 +79,7 @@
* <p>
* Cached data is isolated for each user on a multiuser device.
*/
- public long getCacheBytes() {
+ public @BytesLong long getCacheBytes() {
return cacheBytes;
}
diff --git a/core/java/android/app/usage/StorageStatsManager.java b/core/java/android/app/usage/StorageStatsManager.java
index 5497d57..d9d958c 100644
--- a/core/java/android/app/usage/StorageStatsManager.java
+++ b/core/java/android/app/usage/StorageStatsManager.java
@@ -18,6 +18,7 @@
import static android.os.storage.StorageManager.convert;
+import android.annotation.BytesLong;
import android.annotation.NonNull;
import android.annotation.TestApi;
import android.annotation.WorkerThread;
@@ -37,13 +38,16 @@
import java.util.UUID;
/**
- * Provides access to detailed storage statistics.
+ * Access to detailed storage statistics. This provides a summary of how apps,
+ * users, and external/shared storage is utilizing disk space.
* <p class="note">
- * Note: this API requires the permission
- * {@code android.permission.PACKAGE_USAGE_STATS}, which is a system-level
- * permission that will not be granted to normal apps. However, declaring the
- * permission expresses your intention to use this API and an end user can then
- * choose to grant this permission through the Settings application.
+ * Note: no permissions are required when calling these APIs for your own
+ * package or UID. However, requesting details for any other package requires
+ * the {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which
+ * is a system-level permission that will not be granted to normal apps.
+ * Declaring that permission expresses your intention to use this API and an end
+ * user can then choose to grant this permission through the Settings
+ * application.
* </p>
*/
public class StorageStatsManager {
@@ -73,19 +77,22 @@
}
/**
- * Return the total size of the underlying media that is hosting this
- * storage volume.
+ * Return the total size of the underlying physical media that is hosting
+ * this storage volume.
* <p>
- * To reduce end user confusion, this value matches the total storage size
- * advertised in a retail environment, which is typically larger than the
- * actual usable partition space.
+ * This value is best suited for visual display to end users, since it's
+ * designed to reflect the total storage size advertised in a retail
+ * environment.
+ * <p>
+ * Apps making logical decisions about disk space should always use
+ * {@link File#getTotalSpace()} instead of this value.
*
* @param storageUuid the UUID of the storage volume you're interested in,
* such as {@link StorageManager#UUID_DEFAULT}.
* @throws IOException when the storage device isn't present.
*/
@WorkerThread
- public long getTotalBytes(@NonNull UUID storageUuid) throws IOException {
+ public @BytesLong long getTotalBytes(@NonNull UUID storageUuid) throws IOException {
try {
return mService.getTotalBytes(convert(storageUuid), mContext.getOpPackageName());
} catch (ParcelableException e) {
@@ -105,19 +112,20 @@
/**
* Return the free space on the requested storage volume.
* <p>
- * The free space is equivalent to {@link File#getUsableSpace()} plus the
- * size of any cached data that can be automatically deleted by the system
- * as additional space is needed.
+ * This value is best suited for visual display to end users, since it's
+ * designed to reflect both unused space <em>and</em> and cached space that
+ * could be reclaimed by the system.
* <p>
- * This method may take several seconds to calculate the requested values,
- * so it should only be called from a worker thread.
+ * Apps making logical decisions about disk space should always use
+ * {@link StorageManager#getAllocatableBytes(UUID, int)} instead of this
+ * value.
*
* @param storageUuid the UUID of the storage volume you're interested in,
* such as {@link StorageManager#UUID_DEFAULT}.
* @throws IOException when the storage device isn't present.
*/
@WorkerThread
- public long getFreeBytes(@NonNull UUID storageUuid) throws IOException {
+ public @BytesLong long getFreeBytes(@NonNull UUID storageUuid) throws IOException {
try {
return mService.getFreeBytes(convert(storageUuid), mContext.getOpPackageName());
} catch (ParcelableException e) {
@@ -137,9 +145,15 @@
/**
* Return storage statistics for a specific package on the requested storage
* volume.
- * <p>
- * This method may take several seconds to calculate the requested values,
- * so it should only be called from a worker thread.
+ * <p class="note">
+ * Note: no permissions are required when calling this API for your own
+ * package. However, requesting details for any other package requires the
+ * {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which
+ * is a system-level permission that will not be granted to normal apps.
+ * Declaring that permission expresses your intention to use this API and an
+ * end user can then choose to grant this permission through the Settings
+ * application.
+ * </p>
* <p class="note">
* Note: if the requested package uses the {@code android:sharedUserId}
* manifest feature, this call will be forced into a slower manual
@@ -158,8 +172,9 @@
* @see PackageInfo#packageName
*/
@WorkerThread
- public @NonNull StorageStats queryStatsForPackage(@NonNull UUID storageUuid, String packageName,
- UserHandle user) throws PackageManager.NameNotFoundException, IOException {
+ public @NonNull StorageStats queryStatsForPackage(@NonNull UUID storageUuid,
+ @NonNull String packageName, @NonNull UserHandle user)
+ throws PackageManager.NameNotFoundException, IOException {
try {
return mService.queryStatsForPackage(convert(storageUuid), packageName,
user.getIdentifier(), mContext.getOpPackageName());
@@ -182,9 +197,15 @@
/**
* Return storage statistics for a specific UID on the requested storage
* volume.
- * <p>
- * This method may take several seconds to calculate the requested values,
- * so it should only be called from a worker thread.
+ * <p class="note">
+ * Note: no permissions are required when calling this API for your own UID.
+ * However, requesting details for any other UID requires the
+ * {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which
+ * is a system-level permission that will not be granted to normal apps.
+ * Declaring that permission expresses your intention to use this API and an
+ * end user can then choose to grant this permission through the Settings
+ * application.
+ * </p>
*
* @param storageUuid the UUID of the storage volume you're interested in,
* such as {@link StorageManager#UUID_DEFAULT}.
@@ -194,7 +215,8 @@
* @see ApplicationInfo#uid
*/
@WorkerThread
- public StorageStats queryStatsForUid(@NonNull UUID storageUuid, int uid) throws IOException {
+ public @NonNull StorageStats queryStatsForUid(@NonNull UUID storageUuid, int uid)
+ throws IOException {
try {
return mService.queryStatsForUid(convert(storageUuid), uid,
mContext.getOpPackageName());
@@ -215,9 +237,14 @@
/**
* Return storage statistics for a specific {@link UserHandle} on the
* requested storage volume.
- * <p>
- * This method may take several seconds to calculate the requested values,
- * so it should only be called from a worker thread.
+ * <p class="note">
+ * Note: this API requires the
+ * {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which
+ * is a system-level permission that will not be granted to normal apps.
+ * Declaring that permission expresses your intention to use this API and an
+ * end user can then choose to grant this permission through the Settings
+ * application.
+ * </p>
*
* @param storageUuid the UUID of the storage volume you're interested in,
* such as {@link StorageManager#UUID_DEFAULT}.
@@ -226,8 +253,8 @@
* @see android.os.Process#myUserHandle()
*/
@WorkerThread
- public StorageStats queryStatsForUser(@NonNull UUID storageUuid, UserHandle user)
- throws IOException {
+ public @NonNull StorageStats queryStatsForUser(@NonNull UUID storageUuid,
+ @NonNull UserHandle user) throws IOException {
try {
return mService.queryStatsForUser(convert(storageUuid), user.getIdentifier(),
mContext.getOpPackageName());
@@ -248,9 +275,14 @@
/**
* Return shared/external storage statistics for a specific
* {@link UserHandle} on the requested storage volume.
- * <p>
- * This method may take several seconds to calculate the requested values,
- * so it should only be called from a worker thread.
+ * <p class="note">
+ * Note: this API requires the
+ * {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which
+ * is a system-level permission that will not be granted to normal apps.
+ * Declaring that permission expresses your intention to use this API and an
+ * end user can then choose to grant this permission through the Settings
+ * application.
+ * </p>
*
* @param storageUuid the UUID of the storage volume you're interested in,
* such as {@link StorageManager#UUID_DEFAULT}.
@@ -258,8 +290,8 @@
* @see android.os.Process#myUserHandle()
*/
@WorkerThread
- public ExternalStorageStats queryExternalStatsForUser(@NonNull UUID storageUuid,
- UserHandle user) throws IOException {
+ public @NonNull ExternalStorageStats queryExternalStatsForUser(@NonNull UUID storageUuid,
+ @NonNull UserHandle user) throws IOException {
try {
return mService.queryExternalStatsForUser(convert(storageUuid), user.getIdentifier(),
mContext.getOpPackageName());
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 713dbf4..0f01d62 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -159,8 +159,10 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- mCallback.onConnectionStateChange(BluetoothGatt.this, GATT_FAILURE,
- BluetoothProfile.STATE_DISCONNECTED);
+ if (mCallback != null) {
+ mCallback.onConnectionStateChange(BluetoothGatt.this, GATT_FAILURE,
+ BluetoothProfile.STATE_DISCONNECTED);
+ }
}
});
@@ -192,7 +194,9 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- mCallback.onPhyUpdate(BluetoothGatt.this, txPhy, rxPhy, status);
+ if (mCallback != null) {
+ mCallback.onPhyUpdate(BluetoothGatt.this, txPhy, rxPhy, status);
+ }
}
});
}
@@ -212,7 +216,9 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- mCallback.onPhyRead(BluetoothGatt.this, txPhy, rxPhy, status);
+ if (mCallback != null) {
+ mCallback.onPhyRead(BluetoothGatt.this, txPhy, rxPhy, status);
+ }
}
});
}
@@ -235,7 +241,10 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- mCallback.onConnectionStateChange(BluetoothGatt.this, status, profileState);
+ if (mCallback != null) {
+ mCallback.onConnectionStateChange(BluetoothGatt.this, status,
+ profileState);
+ }
}
});
@@ -294,7 +303,9 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- mCallback.onServicesDiscovered(BluetoothGatt.this, status);
+ if (mCallback != null) {
+ mCallback.onServicesDiscovered(BluetoothGatt.this, status);
+ }
}
});
}
@@ -344,7 +355,10 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- mCallback.onCharacteristicRead(BluetoothGatt.this, characteristic, status);
+ if (mCallback != null) {
+ mCallback.onCharacteristicRead(BluetoothGatt.this, characteristic,
+ status);
+ }
}
});
}
@@ -390,7 +404,10 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- mCallback.onCharacteristicWrite(BluetoothGatt.this, characteristic, status);
+ if (mCallback != null) {
+ mCallback.onCharacteristicWrite(BluetoothGatt.this, characteristic,
+ status);
+ }
}
});
}
@@ -416,7 +433,9 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- mCallback.onCharacteristicChanged(BluetoothGatt.this, characteristic);
+ if (mCallback != null) {
+ mCallback.onCharacteristicChanged(BluetoothGatt.this, characteristic);
+ }
}
});
}
@@ -461,7 +480,9 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- mCallback.onDescriptorRead(BluetoothGatt.this, descriptor, status);
+ if (mCallback != null) {
+ mCallback.onDescriptorRead(BluetoothGatt.this, descriptor, status);
+ }
}
});
}
@@ -505,7 +526,9 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- mCallback.onDescriptorWrite(BluetoothGatt.this, descriptor, status);
+ if (mCallback != null) {
+ mCallback.onDescriptorWrite(BluetoothGatt.this, descriptor, status);
+ }
}
});
}
@@ -529,7 +552,9 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- mCallback.onReliableWriteCompleted(BluetoothGatt.this, status);
+ if (mCallback != null) {
+ mCallback.onReliableWriteCompleted(BluetoothGatt.this, status);
+ }
}
});
}
@@ -548,7 +573,9 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- mCallback.onReadRemoteRssi(BluetoothGatt.this, rssi, status);
+ if (mCallback != null) {
+ mCallback.onReadRemoteRssi(BluetoothGatt.this, rssi, status);
+ }
}
});
}
@@ -568,7 +595,9 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- mCallback.onMtuChanged(BluetoothGatt.this, mtu, status);
+ if (mCallback != null) {
+ mCallback.onMtuChanged(BluetoothGatt.this, mtu, status);
+ }
}
});
}
@@ -590,8 +619,10 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- mCallback.onConnectionUpdated(BluetoothGatt.this, interval, latency,
- timeout, status);
+ if (mCallback != null) {
+ mCallback.onConnectionUpdated(BluetoothGatt.this, interval, latency,
+ timeout, status);
+ }
}
});
}
@@ -973,6 +1004,41 @@
}
/**
+ * Reads the characteristic using its UUID from the associated remote device.
+ *
+ * <p>This is an asynchronous operation. The result of the read operation
+ * is reported by the {@link BluetoothGattCallback#onCharacteristicRead}
+ * callback.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * @param uuid UUID of characteristic to read from the remote device
+ * @return true, if the read operation was initiated successfully
+ * @hide
+ */
+ public boolean readUsingCharacteristicUuid(UUID uuid, int startHandle, int endHandle) {
+ if (VDBG) Log.d(TAG, "readUsingCharacteristicUuid() - uuid: " + uuid);
+ if (mService == null || mClientIf == 0) return false;
+
+ synchronized(mDeviceBusy) {
+ if (mDeviceBusy) return false;
+ mDeviceBusy = true;
+ }
+
+ try {
+ mService.readUsingCharacteristicUuid(mClientIf, mDevice.getAddress(),
+ new ParcelUuid(uuid), startHandle, endHandle, AUTHENTICATION_NONE);
+ } catch (RemoteException e) {
+ Log.e(TAG,"",e);
+ mDeviceBusy = false;
+ return false;
+ }
+
+ return true;
+ }
+
+
+ /**
* Writes a given characteristic and its values to the associated remote device.
*
* <p>Once the write operation has been completed, the
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 12e9baa..e2d4f5b 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -59,6 +59,7 @@
in IAdvertisingSetCallback callback);
void stopAdvertisingSet(in IAdvertisingSetCallback callback);
+ void getOwnAddress(in int advertiserId);
void enableAdvertisingSet(in int advertiserId, in boolean enable, in int duration, in int maxExtAdvEvents);
void setAdvertisingData(in int advertiserId, in AdvertiseData data);
void setScanResponseData(in int advertiserId, in AdvertiseData data);
@@ -80,6 +81,8 @@
void refreshDevice(in int clientIf, in String address);
void discoverServices(in int clientIf, in String address);
void readCharacteristic(in int clientIf, in String address, in int handle, in int authReq);
+ void readUsingCharacteristicUuid(in int clientIf, in String address, in ParcelUuid uuid,
+ in int startHandle, in int endHandle, in int authReq);
void writeCharacteristic(in int clientIf, in String address, in int handle,
in int writeType, in int authReq, in byte[] value);
void readDescriptor(in int clientIf, in String address, in int handle, in int authReq);
diff --git a/core/java/android/bluetooth/le/AdvertisingSet.java b/core/java/android/bluetooth/le/AdvertisingSet.java
index 51571b2..3021be1 100644
--- a/core/java/android/bluetooth/le/AdvertisingSet.java
+++ b/core/java/android/bluetooth/le/AdvertisingSet.java
@@ -181,7 +181,23 @@
}
/**
- * Returns advertiserId associated with thsi advertising set.
+ * Returns address associated with this advertising set.
+ * This method is exposed only for Bluetooth PTS tests, no app or system service
+ * should ever use it.
+ *
+ * This method requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission.
+ * @hide
+ */
+ public void getOwnAddress(){
+ try {
+ gatt.getOwnAddress(this.advertiserId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote exception - ", e);
+ }
+ }
+
+ /**
+ * Returns advertiserId associated with this advertising set.
*
* @hide
*/
diff --git a/core/java/android/bluetooth/le/AdvertisingSetCallback.java b/core/java/android/bluetooth/le/AdvertisingSetCallback.java
index fe3b1cd..2c46e85 100644
--- a/core/java/android/bluetooth/le/AdvertisingSetCallback.java
+++ b/core/java/android/bluetooth/le/AdvertisingSetCallback.java
@@ -143,4 +143,15 @@
*/
public void onPeriodicAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable,
int status) {}
+
+ /**
+ * Callback triggered in response to {@link AdvertisingSet#getOwnAddress()}
+ * indicating result of the operation.
+ *
+ * @param advertisingSet The advertising set.
+ * @param addressType type of address.
+ * @param address advertising set bluetooth address.
+ * @hide
+ */
+ public void onOwnAddressRead(AdvertisingSet advertisingSet, int addressType, String address) {}
}
\ No newline at end of file
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index 0c7958d..67d56d5 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -544,6 +544,17 @@
}
@Override
+ public void onOwnAddressRead(int advertiserId, int addressType, String address) {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
+ callback.onOwnAddressRead(advertisingSet, addressType, address);
+ }
+ });
+ }
+
+ @Override
public void onAdvertisingSetStopped(int advertiserId) {
handler.post(new Runnable() {
@Override
diff --git a/core/java/android/bluetooth/le/IAdvertisingSetCallback.aidl b/core/java/android/bluetooth/le/IAdvertisingSetCallback.aidl
index 2c9f4ba..3628c77 100644
--- a/core/java/android/bluetooth/le/IAdvertisingSetCallback.aidl
+++ b/core/java/android/bluetooth/le/IAdvertisingSetCallback.aidl
@@ -21,6 +21,7 @@
*/
oneway interface IAdvertisingSetCallback {
void onAdvertisingSetStarted(in int advertiserId, in int tx_power, in int status);
+ void onOwnAddressRead(in int advertiserId, in int addressType, in String address);
void onAdvertisingSetStopped(in int advertiserId);
void onAdvertisingEnabled(in int advertiserId, in boolean enable, in int status);
void onAdvertisingDataSet(in int advertiserId, in int status);
diff --git a/core/java/android/bluetooth/le/ScanResult.java b/core/java/android/bluetooth/le/ScanResult.java
index 5b2fa40..e552398 100644
--- a/core/java/android/bluetooth/le/ScanResult.java
+++ b/core/java/android/bluetooth/le/ScanResult.java
@@ -52,6 +52,16 @@
public static final int SID_NOT_PRESENT = 0xFF;
/**
+ * TX power is not present in the packet.
+ */
+ public static final int TX_POWER_NOT_PRESENT = 0x7F;
+
+ /**
+ * Periodic advertising interval is not present in the packet.
+ */
+ public static final int PERIODIC_INTERVAL_NOT_PRESENT = 0x00;
+
+ /**
* Mask for checking whether event type represents legacy advertisement.
*/
private static final int ET_LEGACY_MASK = 0x10;
@@ -265,15 +275,16 @@
/**
* Returns the transmit power in dBm.
- * Valid range is [-127, 126]. A value of 127 indicates that the
- * advertisement did not indicate TX power.
+ * Valid range is [-127, 126]. A value of {@link ScanResult#TX_POWER_NOT_PRESENT}
+ * indicates that the TX power is not present.
*/
public int getTxPower() { return mTxPower; }
/**
* Returns the periodic advertising interval in units of 1.25ms.
- * Valid range is 6 (7.5ms) to 65536 (81918.75ms). A value of 0 means
- * periodic advertising is not used for this scan result.
+ * Valid range is 6 (7.5ms) to 65536 (81918.75ms). A value of
+ * {@link ScanResult#PERIODIC_INTERVAL_NOT_PRESENT} means periodic
+ * advertising interval is not present.
*/
public int getPeriodicAdvertisingInterval() {
return mPeriodicAdvertisingInterval;
diff --git a/core/java/android/companion/BluetoothLEDeviceFilter.java b/core/java/android/companion/BluetoothLeDeviceFilter.java
similarity index 95%
rename from core/java/android/companion/BluetoothLEDeviceFilter.java
rename to core/java/android/companion/BluetoothLeDeviceFilter.java
index e5ea4e9..7a9ba1c 100644
--- a/core/java/android/companion/BluetoothLEDeviceFilter.java
+++ b/core/java/android/companion/BluetoothLeDeviceFilter.java
@@ -47,10 +47,10 @@
*
* @see ScanFilter
*/
-public final class BluetoothLEDeviceFilter implements DeviceFilter<ScanResult> {
+public final class BluetoothLeDeviceFilter implements DeviceFilter<ScanResult> {
private static final boolean DEBUG = false;
- private static final String LOG_TAG = "BluetoothLEDeviceFilter";
+ private static final String LOG_TAG = "BluetoothLeDeviceFilter";
private static final int RENAME_PREFIX_LENGTH_LIMIT = 10;
@@ -66,7 +66,7 @@
private final int mRenameNameTo;
private final boolean mRenameBytesReverseOrder;
- private BluetoothLEDeviceFilter(Pattern namePattern, ScanFilter scanFilter,
+ private BluetoothLeDeviceFilter(Pattern namePattern, ScanFilter scanFilter,
byte[] rawDataFilter, byte[] rawDataFilterMask, String renamePrefix,
String renameSuffix, int renameBytesFrom, int renameBytesTo,
int renameNameFrom, int renameNameTo, boolean renameBytesReverseOrder) {
@@ -186,7 +186,7 @@
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
- BluetoothLEDeviceFilter that = (BluetoothLEDeviceFilter) o;
+ BluetoothLeDeviceFilter that = (BluetoothLeDeviceFilter) o;
return mRenameBytesFrom == that.mRenameBytesFrom &&
mRenameBytesTo == that.mRenameBytesTo &&
mRenameBytesReverseOrder == that.mRenameBytesReverseOrder &&
@@ -242,10 +242,10 @@
'}';
}
- public static final Creator<BluetoothLEDeviceFilter> CREATOR
- = new Creator<BluetoothLEDeviceFilter>() {
+ public static final Creator<BluetoothLeDeviceFilter> CREATOR
+ = new Creator<BluetoothLeDeviceFilter>() {
@Override
- public BluetoothLEDeviceFilter createFromParcel(Parcel in) {
+ public BluetoothLeDeviceFilter createFromParcel(Parcel in) {
Builder builder = new Builder()
.setNamePattern(patternFromString(in.readString()))
.setScanFilter(in.readParcelable(null));
@@ -273,8 +273,8 @@
}
@Override
- public BluetoothLEDeviceFilter[] newArray(int size) {
- return new BluetoothLEDeviceFilter[size];
+ public BluetoothLeDeviceFilter[] newArray(int size) {
+ return new BluetoothLeDeviceFilter[size];
}
};
@@ -283,9 +283,9 @@
}
/**
- * Builder for {@link BluetoothLEDeviceFilter}
+ * Builder for {@link BluetoothLeDeviceFilter}
*/
- public static final class Builder extends OneTimeUseBuilder<BluetoothLEDeviceFilter> {
+ public static final class Builder extends OneTimeUseBuilder<BluetoothLeDeviceFilter> {
private ScanFilter mScanFilter;
private Pattern mNamePattern;
private byte[] mRawDataFilter;
@@ -418,9 +418,9 @@
/** @inheritDoc */
@Override
@NonNull
- public BluetoothLEDeviceFilter build() {
+ public BluetoothLeDeviceFilter build() {
markUsed();
- return new BluetoothLEDeviceFilter(mNamePattern, mScanFilter,
+ return new BluetoothLeDeviceFilter(mNamePattern, mScanFilter,
mRawDataFilter, mRawDataFilterMask,
mRenamePrefix, mRenameSuffix,
mRenameBytesFrom, mRenameBytesTo,
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 6703bd4..5bc1f18 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -846,7 +846,7 @@
* Add a new Item to the overall ClipData container.
* <p> This method will <em>not</em> update the list of available MIME types in the
* {@link ClipDescription}. It should be used only when adding items which do not add new
- * MIME types to this clip. If this is not the case, use {@link #addItem(Item, ContentResolver)}
+ * MIME types to this clip. If this is not the case, use {@link #addItem(ContentResolver, Item)}
* or call {@link #ClipData(CharSequence, String[], Item)} with a complete list of MIME types.
* @param item Item to be added.
*/
@@ -857,15 +857,21 @@
mItems.add(item);
}
+ /** @removed use #addItem(ContentResolver, Item) instead */
+ @Deprecated
+ public void addItem(Item item, ContentResolver resolver) {
+ addItem(resolver, item);
+ }
+
/**
* Add a new Item to the overall ClipData container.
* <p> Unlike {@link #addItem(Item)}, this method will update the list of available MIME types
* in the {@link ClipDescription}.
- * @param item Item to be added.
* @param resolver ContentResolver used to get information about the URI possibly contained in
* the item.
+ * @param item Item to be added.
*/
- public void addItem(Item item, ContentResolver resolver) {
+ public void addItem(ContentResolver resolver, Item item) {
addItem(item);
if (item.getHtmlText() != null) {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 5f7947f..d746377 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3228,6 +3228,7 @@
* caused the broadcast.
* @hide
*/
+ @SystemApi
public static final String ACTION_GLOBAL_BUTTON = "android.intent.action.GLOBAL_BUTTON";
/**
@@ -4422,6 +4423,21 @@
public static final String EXTRA_VERSION_CODE = "android.intent.extra.VERSION_CODE";
/**
+ * The app that triggered the ephemeral installation.
+ * @hide
+ */
+ public static final String EXTRA_CALLING_PACKAGE
+ = "android.intent.extra.CALLING_PACKAGE";
+
+ /**
+ * Optional calling app provided bundle containing additional launch information the
+ * installer may use.
+ * @hide
+ */
+ public static final String EXTRA_VERIFICATION_BUNDLE
+ = "android.intent.extra.VERIFICATION_BUNDLE";
+
+ /**
* A Bundle forming a mapping of potential target package names to different extras Bundles
* to add to the default intent extras in {@link #EXTRA_INTENT} when used with
* {@link #ACTION_CHOOSER}. Each key should be a package name. The package need not
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 6c5d26a..06f7916 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1205,7 +1205,8 @@
dest.writeInt(largestWidthLimitDp);
if (storageUuid != null) {
dest.writeInt(1);
- dest.writeUuid(storageUuid);
+ dest.writeLong(storageUuid.getMostSignificantBits());
+ dest.writeLong(storageUuid.getLeastSignificantBits());
} else {
dest.writeInt(0);
}
@@ -1271,7 +1272,7 @@
compatibleWidthLimitDp = source.readInt();
largestWidthLimitDp = source.readInt();
if (source.readInt() != 0) {
- storageUuid = source.readUuid();
+ storageUuid = new UUID(source.readLong(), source.readLong());
volumeUuid = StorageManager.convert(storageUuid);
}
scanSourceDir = source.readString();
diff --git a/core/java/android/content/pm/InstantAppRequest.java b/core/java/android/content/pm/InstantAppRequest.java
index b45169d..27d2828 100644
--- a/core/java/android/content/pm/InstantAppRequest.java
+++ b/core/java/android/content/pm/InstantAppRequest.java
@@ -17,6 +17,7 @@
package android.content.pm;
import android.content.Intent;
+import android.os.Bundle;
/**
* Information needed to make an instant application resolution request.
@@ -33,13 +34,18 @@
public final String callingPackage;
/** ID of the user requesting the instant application */
public final int userId;
+ /**
+ * Optional extra bundle provided by the source application to the installer for additional
+ * verification. */
+ public final Bundle verificationBundle;
public InstantAppRequest(AuxiliaryResolveInfo responseObj, Intent origIntent,
- String resolvedType, String callingPackage, int userId) {
+ String resolvedType, String callingPackage, int userId, Bundle verificationBundle) {
this.responseObj = responseObj;
this.origIntent = origIntent;
this.resolvedType = resolvedType;
this.callingPackage = callingPackage;
this.userId = userId;
+ this.verificationBundle = verificationBundle;
}
-}
\ No newline at end of file
+}
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 7bfde75..426f3cf 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -19,6 +19,7 @@
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
import android.util.SparseArray;
import java.util.List;
@@ -215,11 +216,13 @@
* @param origIntent The original intent that triggered ephemeral resolution
* @param resolvedType The resolved type of the intent
* @param callingPackage The name of the package requesting the ephemeral application
+ * @param verificationBundle Optional bundle to pass to the installer for additional
+ * verification
* @param userId The ID of the user that triggered ephemeral resolution
*/
public abstract void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
Intent origIntent, String resolvedType, String callingPackage,
- int userId);
+ Bundle verificationBundle, int userId);
/**
* Grants access to the package metadata for an ephemeral application.
@@ -333,4 +336,9 @@
* @param isolatedUid isolated uid that is no longer being used.
*/
public abstract void removeIsolatedUid(int isolatedUid);
+
+ /**
+ * Return the taget SDK version for the app with the given UID.
+ */
+ public abstract int getUidTargetSdkVersion(int uid);
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index e4db0f0..a05f11b 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -547,6 +547,8 @@
*/
public interface Callback {
boolean hasFeature(String feature);
+ String[] getOverlayPaths(String targetPackageName, String targetPath);
+ String[] getOverlayApks(String targetPackageName);
}
/**
@@ -563,6 +565,14 @@
@Override public boolean hasFeature(String feature) {
return mPm.hasSystemFeature(feature);
}
+
+ @Override public String[] getOverlayPaths(String targetPackageName, String targetPath) {
+ return null;
+ }
+
+ @Override public String[] getOverlayApks(String targetPackageName) {
+ return null;
+ }
}
/**
@@ -1054,7 +1064,19 @@
try {
final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath());
- return fromCacheEntry(bytes);
+ Package p = fromCacheEntry(bytes);
+ if (mCallback != null) {
+ String[] overlayApks = mCallback.getOverlayApks(p.packageName);
+ if (overlayApks != null && overlayApks.length > 0) {
+ for (String overlayApk : overlayApks) {
+ // If a static RRO is updated, return null.
+ if (!isCacheUpToDate(new File(overlayApk), cacheFile)) {
+ return null;
+ }
+ }
+ }
+ }
+ return p;
} catch (Exception e) {
Slog.w(TAG, "Error reading package cache: ", e);
@@ -1238,7 +1260,7 @@
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
final String[] outError = new String[1];
- final Package pkg = parseBaseApk(res, parser, flags, outError);
+ final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
if (pkg == null) {
throw new PackageParserException(mParseError,
apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
@@ -1938,6 +1960,7 @@
* need to consider whether they should be supported by split APKs and child
* packages.
*
+ * @param apkPath The package apk file path
* @param res The resources from which to resolve values
* @param parser The manifest parser
* @param flags Flags how to parse
@@ -1947,7 +1970,7 @@
* @throws XmlPullParserException
* @throws IOException
*/
- private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
+ private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags,
String[] outError) throws XmlPullParserException, IOException {
final String splitName;
final String pkgName;
@@ -1967,6 +1990,15 @@
return null;
}
+ if (mCallback != null) {
+ String[] overlayPaths = mCallback.getOverlayPaths(pkgName, apkPath);
+ if (overlayPaths != null && overlayPaths.length > 0) {
+ for (String overlayPath : overlayPaths) {
+ res.getAssets().addOverlayPath(overlayPath);
+ }
+ }
+ }
+
final Package pkg = new Package(pkgName);
TypedArray sa = res.obtainAttributes(parser,
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 061346c..aa35a66 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -189,7 +189,7 @@
*
* <p>In {@link android.os.Build.VERSION_CODES#O Android O} this broadcast has been brought
* back, but only for <em>registered</em> receivers. Apps that are actively running can
- * against listen to the broadcast if they want an immediate clear signal about a picture
+ * again listen to the broadcast if they want an immediate clear signal about a picture
* being taken, however anything doing heavy work (or needing to be launched) as a result of
* this should still use JobScheduler.</p>
*/
@@ -208,12 +208,11 @@
*
* <p>In {@link android.os.Build.VERSION_CODES#O Android O} this broadcast has been brought
* back, but only for <em>registered</em> receivers. Apps that are actively running can
- * against listen to the broadcast if they want an immediate clear signal about a video
+ * again listen to the broadcast if they want an immediate clear signal about a video
* being taken, however anything doing heavy work (or needing to be launched) as a result of
* this should still use JobScheduler.</p>
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @Deprecated
public static final String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
/**
diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java
index 9d217d3..7049628 100644
--- a/core/java/android/hardware/HardwareBuffer.java
+++ b/core/java/android/hardware/HardwareBuffer.java
@@ -70,37 +70,34 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, value = {USAGE0_CPU_READ, USAGE0_CPU_READ_OFTEN, USAGE0_CPU_WRITE,
- USAGE0_CPU_WRITE_OFTEN, USAGE0_GPU_SAMPLED_IMAGE, USAGE0_GPU_COLOR_OUTPUT,
- USAGE0_GPU_STORAGE_IMAGE, USAGE0_GPU_CUBEMAP, USAGE0_GPU_DATA_BUFFER,
- USAGE0_PROTECTED_CONTENT, USAGE0_SENSOR_DIRECT_DATA, USAGE0_VIDEO_ENCODE})
- public @interface Usage0 {};
+ @IntDef(flag = true, value = {USAGE_CPU_READ_RARELY, USAGE_CPU_READ_OFTEN,
+ USAGE_CPU_WRITE_RARELY, USAGE_CPU_WRITE_OFTEN, USAGE_GPU_SAMPLED_IMAGE,
+ USAGE_GPU_COLOR_OUTPUT, USAGE_PROTECTED_CONTENT, USAGE_VIDEO_ENCODE,
+ USAGE_GPU_DATA_BUFFER, USAGE_SENSOR_DIRECT_DATA})
+ public @interface Usage {};
- /** Usage0: the buffer will sometimes be read by the CPU */
- public static final long USAGE0_CPU_READ = (1 << 1);
- /** Usage0: the buffer will often be read by the CPU*/
- public static final long USAGE0_CPU_READ_OFTEN = (1 << 2 | USAGE0_CPU_READ);
- /** Usage0: the buffer will sometimes be written to by the CPU */
- public static final long USAGE0_CPU_WRITE = (1 << 5);
- /** Usage0: the buffer will often be written to by the CPU */
- public static final long USAGE0_CPU_WRITE_OFTEN = (1 << 6 | USAGE0_CPU_WRITE);
- /** Usage0: the buffer will be read from by the GPU */
- public static final long USAGE0_GPU_SAMPLED_IMAGE = (1 << 10);
- /** Usage0: the buffer will be written to by the GPU */
- public static final long USAGE0_GPU_COLOR_OUTPUT = (1 << 11);
- /** Usage0: the buffer will be read from and written to by the GPU */
- public static final long USAGE0_GPU_STORAGE_IMAGE = (USAGE0_GPU_SAMPLED_IMAGE |
- USAGE0_GPU_COLOR_OUTPUT);
- /** Usage0: the buffer will be used as a cubemap texture */
- public static final long USAGE0_GPU_CUBEMAP = (1 << 13);
- /** Usage0: the buffer will be used as a shader storage or uniform buffer object*/
- public static final long USAGE0_GPU_DATA_BUFFER = (1 << 14);
- /** Usage0: the buffer must not be used outside of a protected hardware path */
- public static final long USAGE0_PROTECTED_CONTENT = (1 << 18);
- /** Usage0: the buffer will be used for sensor direct data */
- public static final long USAGE0_SENSOR_DIRECT_DATA = (1 << 29);
- /** Usage0: the buffer will be read by a hardware video encoder */
- public static final long USAGE0_VIDEO_ENCODE = (1 << 21);
+ /** Usage: The buffer will sometimes be read by the CPU */
+ public static final long USAGE_CPU_READ_RARELY = 2;
+ /** Usage: The buffer will often be read by the CPU */
+ public static final long USAGE_CPU_READ_OFTEN = 3;
+
+ /** Usage: The buffer will sometimes be written to by the CPU */
+ public static final long USAGE_CPU_WRITE_RARELY = 2 << 4;
+ /** Usage: The buffer will often be written to by the CPU */
+ public static final long USAGE_CPU_WRITE_OFTEN = 3 << 4;
+
+ /** Usage: The buffer will be read from by the GPU */
+ public static final long USAGE_GPU_SAMPLED_IMAGE = 1 << 8;
+ /** Usage: The buffer will be written to by the GPU */
+ public static final long USAGE_GPU_COLOR_OUTPUT = 1 << 9;
+ /** Usage: The buffer must not be used outside of a protected hardware path */
+ public static final long USAGE_PROTECTED_CONTENT = 1 << 14;
+ /** Usage: The buffer will be read by a hardware video encoder */
+ public static final long USAGE_VIDEO_ENCODE = 1 << 16;
+ /** Usage: The buffer will be used for sensor direct data */
+ public static final long USAGE_SENSOR_DIRECT_DATA = 1 << 23;
+ /** Usage: The buffer will be used as a shader storage or uniform buffer object */
+ public static final long USAGE_GPU_DATA_BUFFER = 1 << 24;
// The approximate size of a native AHardwareBuffer object.
private static final long NATIVE_HARDWARE_BUFFER_SIZE = 232;
@@ -116,13 +113,11 @@
* {@link #RGBX_8888}, {@link #RGB_565}, {@link #RGB_888}, {@link #RGBA_1010102}, {@link #BLOB}
* @param layers The number of layers in the buffer
* @param usage Flags describing how the buffer will be used, one of
- * {@link #USAGE0_CPU_READ}, {@link #USAGE0_CPU_READ_OFTEN}, {@link #USAGE0_CPU_WRITE},
- * {@link #USAGE0_CPU_WRITE_OFTEN}, {@link #USAGE0_GPU_SAMPLED_IMAGE},
- * {@link #USAGE0_GPU_COLOR_OUTPUT},{@link #USAGE0_GPU_STORAGE_IMAGE},
- * {@link #USAGE0_GPU_CUBEMAP}, {@link #USAGE0_GPU_DATA_BUFFER},
- * {@link #USAGE0_PROTECTED_CONTENT}, {@link #USAGE0_SENSOR_DIRECT_DATA},
- * {@link #USAGE0_VIDEO_ENCODE}
- *
+ * {@link #USAGE_CPU_READ_RARELY}, {@link #USAGE_CPU_READ_OFTEN},
+ * {@link #USAGE_CPU_WRITE_RARELY}, {@link #USAGE_CPU_WRITE_OFTEN},
+ * {@link #USAGE_GPU_SAMPLED_IMAGE}, {@link #USAGE_GPU_COLOR_OUTPUT},
+ * {@link #USAGE_GPU_DATA_BUFFER}, {@link #USAGE_PROTECTED_CONTENT},
+ * {@link #USAGE_SENSOR_DIRECT_DATA}, {@link #USAGE_VIDEO_ENCODE}
* @return A <code>HardwareBuffer</code> instance if successful, or throws an
* IllegalArgumentException if the dimensions passed are invalid (either zero, negative, or
* too large to allocate), if the format is not supported, if the requested number of layers
@@ -130,7 +125,7 @@
*/
@NonNull
public static HardwareBuffer create(int width, int height, @Format int format, int layers,
- @Usage0 long usage) {
+ @Usage long usage) {
if (!HardwareBuffer.isSupportedFormat(format)) {
throw new IllegalArgumentException("Invalid pixel format " + format);
}
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 80cbde7..0dab5d7 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -589,9 +589,9 @@
"Width if HaradwareBuffer must be greater than "
+ MIN_DIRECT_CHANNEL_BUFFER_SIZE);
}
- if ((hardwareBuffer.getUsage() & HardwareBuffer.USAGE0_SENSOR_DIRECT_DATA) == 0) {
+ if ((hardwareBuffer.getUsage() & HardwareBuffer.USAGE_SENSOR_DIRECT_DATA) == 0) {
throw new IllegalArgumentException(
- "HardwareBuffer must set usage flag USAGE0_SENSOR_DIRECT_DATA");
+ "HardwareBuffer must set usage flag USAGE_SENSOR_DIRECT_DATA");
}
size = hardwareBuffer.getWidth();
id = nativeCreateDirectChannel(
diff --git a/core/java/android/metrics/LogMaker.java b/core/java/android/metrics/LogMaker.java
index 3c6baa7..2bb43bd 100644
--- a/core/java/android/metrics/LogMaker.java
+++ b/core/java/android/metrics/LogMaker.java
@@ -170,6 +170,27 @@
}
/**
+ * This will be set by the system when the log is persisted.
+ * Client-supplied values will be ignored.
+ *
+ * @param uid to replace the existing setting.
+ * @hide
+ */
+ public LogMaker setUid(int uid) {
+ entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_UID, uid);
+ return this;
+ }
+
+ /**
+ * Remove the UID property.
+ * @hide
+ */
+ public LogMaker clearUid() {
+ entries.remove(MetricsEvent.RESERVED_FOR_LOGBUILDER_UID);
+ return this;
+ }
+
+ /**
* The name of the counter or histogram.
* Only useful for counter or histogram category objects.
* @param name to replace the existing setting.
@@ -319,6 +340,16 @@
}
}
+ /** @return the UID of the log, or -1. */
+ public int getUid() {
+ Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_UID);
+ if (obj instanceof Integer) {
+ return (Integer) obj;
+ } else {
+ return -1;
+ }
+ }
+
/** @return the name of the counter, or null. */
public String getCounterName() {
Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_NAME);
diff --git a/core/java/android/metrics/MetricsReader.java b/core/java/android/metrics/MetricsReader.java
index 5be977a..5f356ca 100644
--- a/core/java/android/metrics/MetricsReader.java
+++ b/core/java/android/metrics/MetricsReader.java
@@ -93,6 +93,7 @@
}
final LogMaker log = new LogMaker(objects)
.setTimestamp(eventTimestampMs)
+ .setUid(event.getUid())
.setProcessId(event.getProcessId());
if (log.getCategory() == MetricsEvent.METRICS_CHECKPOINT) {
if (log.getSubtype() == mCheckpointTag) {
@@ -155,11 +156,13 @@
public static class Event {
long mTimeMillis;
int mPid;
+ int mUid;
Object mData;
- public Event(long timeMillis, int pid, Object data) {
+ public Event(long timeMillis, int pid, int uid, Object data) {
mTimeMillis = timeMillis;
mPid = pid;
+ mUid = uid;
mData = data;
}
@@ -167,6 +170,7 @@
mTimeMillis = TimeUnit.MILLISECONDS.convert(
nativeEvent.getTimeNanos(), TimeUnit.NANOSECONDS);
mPid = nativeEvent.getProcessId();
+ mUid = nativeEvent.getUid();
mData = nativeEvent.getData();
}
@@ -178,6 +182,10 @@
return mPid;
}
+ public int getUid() {
+ return mUid;
+ }
+
public Object getData() {
return mData;
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index b854cbf..2f2e79a 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2974,50 +2974,6 @@
}
/**
- * Note: this is a deprecated version of
- * {@link #requestNetwork(NetworkRequest, int, NetworkCallback)} - please transition code to use
- * the unhidden version of the function.
- * TODO: replace all callers with the new version of the API
- *
- * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited
- * by a timeout.
- *
- * This function behaves identically to the non-timed-out version
- * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, but if a suitable network
- * is not found within the given time (in milliseconds) the
- * {@link NetworkCallback#onUnavailable()} callback is called. The request can still be
- * released normally by calling {@link #unregisterNetworkCallback(NetworkCallback)} but does
- * not have to be released if timed-out (it is automatically released). Unregistering a
- * request that timed out is not an error.
- *
- * <p>Do not use this method to poll for the existence of specific networks (e.g. with a small
- * timeout) - the {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} is provided
- * for that purpose. Calling this method will attempt to bring up the requested network.
- *
- * <p>This method requires the caller to hold either the
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
- * or the ability to modify system settings as determined by
- * {@link android.provider.Settings.System#canWrite}.</p>
- *
- * @param request {@link NetworkRequest} describing this request.
- * @param networkCallback The callbacks to be utilized for this request. Note
- * the callbacks must not be shared - they uniquely specify
- * this request.
- * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
- * before {@link NetworkCallback#onUnavailable()} is called. The timeout must
- * be a positive value (i.e. >0).
- * @hide
- */
- public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
- int timeoutMs) {
- if (timeoutMs <= 0) {
- throw new IllegalArgumentException("Non-positive timeoutMs: " + timeoutMs);
- }
- int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
- requestNetwork(request, networkCallback, timeoutMs, legacyType, getDefaultHandler());
- }
-
- /**
* Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited
* by a timeout.
*
@@ -3039,14 +2995,14 @@
* {@link android.provider.Settings.System#canWrite}.</p>
*
* @param request {@link NetworkRequest} describing this request.
+ * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
+ * the callback must not be shared - it uniquely specifies this request.
* @param timeoutMs The time in milliseconds to attempt looking for a suitable network
* before {@link NetworkCallback#onUnavailable()} is called. The timeout must
* be a positive value (i.e. >0).
- * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
- * the callback must not be shared - it uniquely specifies this request.
*/
- public void requestNetwork(NetworkRequest request, int timeoutMs,
- NetworkCallback networkCallback) {
+ public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
+ int timeoutMs) {
if (timeoutMs <= 0) {
throw new IllegalArgumentException("Non-positive timeoutMs: " + timeoutMs);
}
@@ -3076,14 +3032,14 @@
* {@link android.provider.Settings.System#canWrite}.</p>
*
* @param request {@link NetworkRequest} describing this request.
- * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
- * before {@link NetworkCallback#onUnavailable} is called.
* @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
* the callback must not be shared - it uniquely specifies this request.
* @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+ * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
+ * before {@link NetworkCallback#onUnavailable} is called.
*/
- public void requestNetwork(NetworkRequest request, int timeoutMs,
- NetworkCallback networkCallback, Handler handler) {
+ public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
+ Handler handler, int timeoutMs) {
if (timeoutMs <= 0) {
throw new IllegalArgumentException("Non-positive timeoutMs");
}
@@ -3402,8 +3358,8 @@
/**
* It is acceptable to briefly use multipath data to provide seamless connectivity for
* time-sensitive user-facing operations when the system default network is temporarily
- * unresponsive. The amount of data should be limited (less than one megabyte), and the
- * operation should be infrequent to ensure that data usage is limited.
+ * unresponsive. The amount of data should be limited (less than one megabyte for every call to
+ * this method), and the operation should be infrequent to ensure that data usage is limited.
*
* An example of such an operation might be a time-sensitive foreground activity, such as a
* voice command, that the user is performing while walking out of range of a Wi-Fi network.
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 167c46d..9b5ff29 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -25,7 +25,6 @@
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
-import java.util.UUID;
/**
* A mapping from String keys to various {@link Parcelable} values.
@@ -477,18 +476,6 @@
}
/**
- * Inserts a UUID value into the mapping of this Bundle, replacing
- * any existing value for the given key. Either key or value may be null.
- *
- * @param key a String, or null
- * @param value a UUID object, or null
- */
- public void putUuid(@Nullable String key, @Nullable UUID value) {
- unparcel();
- mMap.put(key, value);
- }
-
- /**
* Inserts an array of Parcelable values into the mapping of this Bundle,
* replacing any existing value for the given key. Either key or value may
* be null.
@@ -871,26 +858,6 @@
* value is explicitly associated with the key.
*
* @param key a String, or null
- * @return a UUID value, or null
- */
- @Nullable
- public UUID getUuid(@Nullable String key) {
- unparcel();
- final Object o = mMap.get(key);
- try {
- return (UUID) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "UUID", e);
- return null;
- }
- }
-
- /**
- * Returns the value associated with the given key, or null if
- * no mapping of the desired type exists for the given key or a null
- * value is explicitly associated with the key.
- *
- * @param key a String, or null
* @return a Bundle value, or null
*/
@Nullable
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index c1647c7..28bdacf 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -50,7 +50,6 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.UUID;
/**
* Container for a message (data and object references) that can
@@ -242,7 +241,6 @@
private static final int VAL_SIZE = 26;
private static final int VAL_SIZEF = 27;
private static final int VAL_DOUBLEARRAY = 28;
- private static final int VAL_UUID = 29;
// The initial int32 in a Binder call's reply Parcel header:
// Keep these in sync with libbinder's binder/Status.h.
@@ -831,15 +829,6 @@
}
/**
- * Flatten a UUID into the parcel at the current dataPosition(),
- * growing dataCapacity() if needed.
- */
- public final void writeUuid(UUID val) {
- writeLong(val.getMostSignificantBits());
- writeLong(val.getLeastSignificantBits());
- }
-
- /**
* Flatten a List into the parcel at the current dataPosition(), growing
* dataCapacity() if needed. The List values are written using
* {@link #writeValue} and must follow the specification there.
@@ -1687,9 +1676,6 @@
} else if (v instanceof double[]) {
writeInt(VAL_DOUBLEARRAY);
writeDoubleArray((double[]) v);
- } else if (v instanceof UUID) {
- writeInt(VAL_UUID);
- writeUuid((UUID) v);
} else {
Class<?> clazz = v.getClass();
if (clazz.isArray() && clazz.getComponentType() == Object.class) {
@@ -2194,13 +2180,6 @@
}
/**
- * Read a UUID from the parcel at the current dataPosition().
- */
- public final UUID readUuid() {
- return new UUID(readLong(), readLong());
- }
-
- /**
* Read and return a byte[] object from the parcel.
*/
public final byte[] createByteArray() {
@@ -2750,9 +2729,6 @@
case VAL_DOUBLEARRAY:
return createDoubleArray();
- case VAL_UUID:
- return readUuid();
-
default:
int off = dataPosition() - 4;
throw new RuntimeException(
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index f95a34c..52b2f52 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -64,7 +64,7 @@
*/
public class UserManager {
- private static String TAG = "UserManager";
+ private static final String TAG = "UserManager";
private final IUserManager mService;
private final Context mContext;
@@ -218,6 +218,23 @@
public static final String DISALLOW_BLUETOOTH = "no_bluetooth";
/**
+ * Specifies if outgoing bluetooth sharing is disallowed on the device. Device owner and profile
+ * owner can set this restriction. When it is set by device owner, all users on this device will
+ * be affected.
+ *
+ * <p>Default is <code>true</code> for managed profiles and false for otherwise. When a device
+ * upgrades to {@link android.os.Build.VERSION_CODES#O}, the system sets it for all existing
+ * managed profiles.
+ *
+ * <p>Key for user restrictions.
+ * <p>Type: Boolean
+ * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+ * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_BLUETOOTH_SHARING = "no_bluetooth_sharing";
+
+ /**
* Specifies if a user is disallowed from transferring files over
* USB. This can only be set by device owners and profile owners on the primary user.
* The default value is <code>false</code>.
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index baa29b0..bd43d6a 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -19,14 +19,18 @@
import static android.net.TrafficStats.GB_IN_BYTES;
import static android.net.TrafficStats.MB_IN_BYTES;
+import android.annotation.BytesLong;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.annotation.WorkerThread;
import android.app.ActivityThread;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.PackageManager;
@@ -135,6 +139,7 @@
* thus it cannot be used to uniquely identify a particular physical device.
*
* @see #getUuidForPath(File)
+ * @see ApplicationInfo#storageUuid
*/
public static final UUID UUID_DEFAULT = UUID
.fromString("41217664-9172-527a-b3d5-edabb50a7d69");
@@ -166,6 +171,7 @@
* @see #ACTION_MANAGE_STORAGE
* @see #UUID_DEFAULT
* @see #getUuidForPath(File)
+ * @see Intent#putExtra(String, java.io.Serializable)
*/
public static final String EXTRA_UUID = "android.os.storage.extra.UUID";
@@ -1414,6 +1420,7 @@
public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
int mode, ProxyFileDescriptorCallback callback, Handler handler, ThreadFactory factory)
throws IOException {
+ Preconditions.checkNotNull(callback);
MetricsLogger.count(mContext, "storage_open_proxy_file_descriptor", 1);
// Retry is needed because the mount point mFuseAppLoop is using may be unmounted before
// invoking StorageManagerService#openProxyFileDescriptor. In this case, we need to re-mount
@@ -1460,19 +1467,7 @@
}
}
- /**
- * Opens seekable ParcelFileDescriptor that routes file operation requests to
- * ProxyFileDescriptorCallback.
- *
- * @param mode The desired access mode, must be one of
- * {@link ParcelFileDescriptor#MODE_READ_ONLY},
- * {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, or
- * {@link ParcelFileDescriptor#MODE_READ_WRITE}
- * @param callback Callback to process file operation requests issued on returned file
- * descriptor.
- * @return Seekable ParcelFileDescriptor.
- * @throws IOException
- */
+ /** {@hide} */
public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
int mode, ProxyFileDescriptorCallback callback)
throws IOException {
@@ -1496,6 +1491,7 @@
public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
int mode, ProxyFileDescriptorCallback callback, Handler handler)
throws IOException {
+ Preconditions.checkNotNull(handler);
return openProxyFileDescriptor(mode, callback, handler, null);
}
@@ -1533,7 +1529,8 @@
* doesn't support cache quotas.
* @see #getCacheSizeBytes(UUID)
*/
- public long getCacheQuotaBytes(@NonNull UUID storageUuid) throws IOException {
+ @WorkerThread
+ public @BytesLong long getCacheQuotaBytes(@NonNull UUID storageUuid) throws IOException {
try {
final ApplicationInfo app = mContext.getApplicationInfo();
return mStorageManager.getCacheQuotaBytes(convert(storageUuid), app.uid);
@@ -1573,7 +1570,8 @@
* doesn't support cache quotas.
* @see #getCacheQuotaBytes(UUID)
*/
- public long getCacheSizeBytes(@NonNull UUID storageUuid) throws IOException {
+ @WorkerThread
+ public @BytesLong long getCacheSizeBytes(@NonNull UUID storageUuid) throws IOException {
try {
final ApplicationInfo app = mContext.getApplicationInfo();
return mStorageManager.getCacheSizeBytes(convert(storageUuid), app.uid);
@@ -1631,8 +1629,10 @@
* @see #getAllocatableBytes(UUID, int)
* @see #allocateBytes(UUID, long, int)
* @see #allocateBytes(FileDescriptor, long, int)
+ * @hide
*/
@RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE)
+ @SystemApi
public static final int FLAG_ALLOCATE_AGGRESSIVE = 1;
/** @hide */
@@ -1656,7 +1656,7 @@
* the returned value will fail.
* <p>
* If the returned value is not large enough for the data you'd like to
- * store, you can launch {@link #ACTION_MANAGE_STORAGE} with the
+ * persist, you can launch {@link #ACTION_MANAGE_STORAGE} with the
* {@link #EXTRA_UUID} and {@link #EXTRA_REQUESTED_BYTES} options to help
* involve the user in freeing up disk space.
* <p class="note">
@@ -1670,13 +1670,19 @@
* vary widely depending on the underlying storage device. The
* UUID for a specific path can be obtained using
* {@link #getUuidForPath(File)}.
- * @param flags to apply to the request.
* @return the maximum number of new bytes that the calling app can allocate
* using {@link #allocateBytes(UUID, long, int)} or
* {@link #allocateBytes(FileDescriptor, long, int)}.
* @throws IOException when the storage device isn't present, or when it
* doesn't support allocating space.
*/
+ public @BytesLong long getAllocatableBytes(@NonNull UUID storageUuid)
+ throws IOException {
+ return getAllocatableBytes(storageUuid, 0);
+ }
+
+ /** @hide */
+ @SystemApi
public long getAllocatableBytes(@NonNull UUID storageUuid, @AllocateFlags int flags)
throws IOException {
try {
@@ -1713,14 +1719,20 @@
* allocate disk space. The UUID for a specific path can be
* obtained using {@link #getUuidForPath(File)}.
* @param bytes the number of bytes to allocate.
- * @param flags to apply to the request.
* @throws IOException when the storage device isn't present, or when it
* doesn't support allocating space, or if the device had
* trouble allocating the requested space.
* @see #getAllocatableBytes(UUID, int)
*/
- public void allocateBytes(@NonNull UUID storageUuid, long bytes, @AllocateFlags int flags)
+ public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes)
throws IOException {
+ allocateBytes(storageUuid, bytes, 0);
+ }
+
+ /** @hide */
+ @SystemApi
+ public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes,
+ @AllocateFlags int flags) throws IOException {
try {
mStorageManager.allocateBytes(convert(storageUuid), bytes, flags);
} catch (ParcelableException e) {
@@ -1732,7 +1744,7 @@
/** @removed */
@Deprecated
- public void allocateBytes(@NonNull File path, long bytes, @AllocateFlags int flags)
+ public void allocateBytes(@NonNull File path, @BytesLong long bytes, @AllocateFlags int flags)
throws IOException {
allocateBytes(getUuidForPath(path), bytes, flags);
}
@@ -1756,14 +1768,19 @@
* requested size, it will be extended without modifying any
* existing contents. If the open file is larger than this
* requested size, it will be truncated.
- * @param flags to apply to the request.
* @throws IOException when the storage device isn't present, or when it
* doesn't support allocating space, or if the device had
* trouble allocating the requested space.
* @see #getAllocatableBytes(UUID, int)
* @see Environment#isExternalStorageEmulated(File)
*/
- public void allocateBytes(FileDescriptor fd, long bytes, @AllocateFlags int flags)
+ public void allocateBytes(FileDescriptor fd, @BytesLong long bytes) throws IOException {
+ allocateBytes(fd, bytes, 0);
+ }
+
+ /** @hide */
+ @SystemApi
+ public void allocateBytes(FileDescriptor fd, @BytesLong long bytes, @AllocateFlags int flags)
throws IOException {
final File file = ParcelFileDescriptor.getFile(fd);
for (int i = 0; i < 3; i++) {
diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java
index 6c038c78..1013b0f 100644
--- a/core/java/android/provider/FontsContract.java
+++ b/core/java/android/provider/FontsContract.java
@@ -607,43 +607,6 @@
}
/**
- * Build a Typeface from an array of {@link FontInfo}. Results that are marked as not ready
- * will be skipped.
- *
- * @param context A {@link Context} that will be used to fetch the font contents.
- * @param cancellationSignal A signal to cancel the operation in progress, or null if none. If
- * the operation is canceled, then {@link
- * android.os.OperationCanceledException} will be thrown.
- * @param fonts An array of {@link FontInfo} to be used to create a Typeface.
- * @param weight A weight value to be used for selecting a font from a font family.
- * @param italic {@code true} if this font is of italic style. This will be used for font
- * selection from a font family.
- * @param fallbackFontName A fallback font name used if this method fails to create the
- * Typeface. By passing {@code null}, this method returns {@code null}
- * if typeface creation fails.
- * @return A Typeface object. May return {@code null} if that is the value passed to {@code
- * fallBackFontName}.
- */
- public static Typeface buildTypeface(@NonNull Context context,
- @Nullable CancellationSignal cancellationSignal, @NonNull FontInfo[] fonts,
- int weight, boolean italic, @Nullable String fallbackFontName) {
- if (context.isRestricted()) {
- // TODO: Should we allow if the peer process is system or myself?
- return null;
- }
- final Map<Uri, ByteBuffer> uriBuffer =
- prepareFontData(context, fonts, cancellationSignal);
- if (uriBuffer.isEmpty()) {
- return null;
- }
- return new Typeface.Builder(fonts, uriBuffer)
- .setFallback(fallbackFontName)
- .setWeight(weight)
- .setItalic(italic)
- .build();
- }
-
- /**
* Build a Typeface from an array of {@link FontInfo}
*
* Results that are marked as not ready will be skipped.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cbd41c3..89c0963 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7065,6 +7065,12 @@
INSTANT_APP_SETTINGS.add(ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR);
INSTANT_APP_SETTINGS.add(ACCESSIBILITY_CAPTIONING_TYPEFACE);
INSTANT_APP_SETTINGS.add(ACCESSIBILITY_CAPTIONING_FONT_SCALE);
+ INSTANT_APP_SETTINGS.add(ACCESSIBILITY_CAPTIONING_WINDOW_COLOR);
+ INSTANT_APP_SETTINGS.add(ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED);
+ INSTANT_APP_SETTINGS.add(ACCESSIBILITY_DISPLAY_DALTONIZER);
+ INSTANT_APP_SETTINGS.add(ACCESSIBILITY_AUTOCLICK_DELAY);
+ INSTANT_APP_SETTINGS.add(ACCESSIBILITY_AUTOCLICK_ENABLED);
+ INSTANT_APP_SETTINGS.add(ACCESSIBILITY_LARGE_POINTER_ICON);
INSTANT_APP_SETTINGS.add(DEFAULT_INPUT_METHOD);
INSTANT_APP_SETTINGS.add(ENABLED_INPUT_METHODS);
@@ -7717,7 +7723,22 @@
public static final String LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST =
"location_background_throttle_package_whitelist";
- /**
+ /**
+ * The interval in milliseconds at which wifi scan requests will be throttled when they are
+ * coming from the background.
+ * @hide
+ */
+ public static final String WIFI_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS =
+ "wifi_scan_background_throttle_interval_ms";
+
+ /**
+ * Packages that are whitelisted to be exempt for wifi background throttling.
+ * @hide
+ */
+ public static final String WIFI_SCAN_BACKGROUND_THROTTLE_PACKAGE_WHITELIST =
+ "wifi_scan_background_throttle_package_whitelist";
+
+ /**
* Whether TV will switch to MHL port when a mobile device is plugged in.
* (0 = false, 1 = true)
* @hide
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index e04fae7..69f3f67 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -16,7 +16,7 @@
package android.service.autofill;
-import static android.view.autofill.Helper.DEBUG;
+import static android.view.autofill.Helper.sDebug;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -24,7 +24,6 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.view.autofill.AutofillId;
-import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
import android.widget.RemoteViews;
import com.android.internal.util.Preconditions;
@@ -90,7 +89,7 @@
@Override
public String toString() {
- if (!DEBUG) return super.toString();
+ if (!sDebug) return super.toString();
return new StringBuilder("Dataset " + mId + " [")
.append("fieldIds=").append(mFieldIds)
diff --git a/core/java/android/service/autofill/FillContext.java b/core/java/android/service/autofill/FillContext.java
index 8a28c45..d6616bf 100644
--- a/core/java/android/service/autofill/FillContext.java
+++ b/core/java/android/service/autofill/FillContext.java
@@ -16,7 +16,7 @@
package android.service.autofill;
-import static android.view.autofill.Helper.DEBUG;
+import static android.view.autofill.Helper.sDebug;
import android.annotation.NonNull;
import android.app.assist.AssistStructure;
@@ -74,11 +74,9 @@
@Override
public String toString() {
- if (!DEBUG) {
- return super.toString();
- } else {
- return "FillContext [mRequestId=" + mRequestId + "]";
- }
+ if (!sDebug) return super.toString();
+
+ return "FillContext [reqId=" + mRequestId + "]";
}
@Override
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index 5c8f3ce..42c0151 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -17,7 +17,7 @@
package android.service.autofill;
import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
-import static android.view.autofill.Helper.DEBUG;
+import static android.view.autofill.Helper.sDebug;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -394,7 +394,7 @@
/////////////////////////////////////
@Override
public String toString() {
- if (!DEBUG) return super.toString();
+ if (!sDebug) return super.toString();
return new StringBuilder(
"FillResponse : [mRequestId=" + mRequestId)
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 94e5e3e..277c622 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -16,7 +16,7 @@
package android.service.autofill;
-import static android.view.autofill.Helper.DEBUG;
+import static android.view.autofill.Helper.sDebug;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -387,7 +387,7 @@
/////////////////////////////////////
@Override
public String toString() {
- if (!DEBUG) return super.toString();
+ if (!sDebug) return super.toString();
return new StringBuilder("SaveInfo: [type=")
.append(DebugUtils.flagsToString(SaveInfo.class, "SAVE_DATA_TYPE_", mType))
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 00bd304..76c96bd 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1094,9 +1094,9 @@
/**
* Request that the service be unbound.
*
- * <p>This will no longer receive updates until
- * {@link #requestRebind(ComponentName)} is called.
- * The service will likely be kiled by the system after this call.
+ * <p>Once this is called, you will no longer receive updates and no method calls are
+ * guaranteed to be successful, until you next receive the {@link #onListenerConnected()} event.
+ * The service will likely be killed by the system after this call.
*
* <p>The service should wait for the {@link #onListenerConnected()} event
* before performing this operation. I know it's tempting, but you must wait.
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 98780a7..6bbb0ff 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -16,8 +16,6 @@
package android.service.wallpaper;
-import android.annotation.Nullable;
-import android.app.WallpaperColors;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.util.MergedConfiguration;
@@ -544,24 +542,6 @@
*/
public void onSurfaceDestroyed(SurfaceHolder holder) {
}
-
- /**
- * Notifies the engine that wallpaper colors changed significantly.
- * This will trigger a {@link #onComputeWallpaperColors()} call.
- */
- public void invalidateColors() {
- }
-
- /**
- * Notifies the system about what colors the wallpaper is using.
- * You might return null if no color information is available at the moment. In that case
- * you might want to call {@link #invalidateColors()} in a near future.
- *
- * @return List of wallpaper colors and their weights.
- */
- public @Nullable WallpaperColors onComputeWallpaperColors() {
- return null;
- }
protected void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) {
out.print(prefix); out.print("mInitializing="); out.print(mInitializing);
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index 6d4281b..92f218b 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -68,6 +68,7 @@
private static final int THREAD_OFFSET = 8;
private static final int SECONDS_OFFSET = 12;
private static final int NANOSECONDS_OFFSET = 16;
+ private static final int UID_OFFSET = 24;
// Layout for event log v1 format, v2 and v3 use HEADER_SIZE_OFFSET
private static final int V1_PAYLOAD_START = 20;
@@ -91,6 +92,20 @@
return mBuffer.getInt(PROCESS_OFFSET);
}
+ /**
+ * @return the UID which wrote the log entry
+ * @hide
+ */
+ @SystemApi
+ public int getUid() {
+ try {
+ return mBuffer.getInt(UID_OFFSET);
+ } catch (IndexOutOfBoundsException e) {
+ // buffer won't contain the UID if the caller doesn't have permission.
+ return -1;
+ }
+ }
+
/** @return the thread ID which wrote the log entry */
public int getThreadId() {
return mBuffer.getInt(THREAD_OFFSET);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a18381b..4029a42 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1173,6 +1173,18 @@
*/
public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 0x8;
+ /** @hide */
+ @IntDef(
+ flag = true,
+ value = {AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AutofillFlags {}
+
+ /**
+ * Flag requesting you to add views not-important for autofill to the assist data.
+ */
+ public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x1;
+
/**
* This view is enabled. Interpretation varies by subclass.
* Use with ENABLED_MASK when calling setFlags.
@@ -2745,8 +2757,7 @@
* 1 PFLAG3_IS_AUTOFILLED
* 1 PFLAG3_FINGER_DOWN
* 1 PFLAG3_FOCUSED_BY_DEFAULT
- * __ unused
- * 11 PFLAG3_IMPORTANT_FOR_AUTOFILL
+ * 1111 PFLAG3_IMPORTANT_FOR_AUTOFILL
* 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE
* 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED
* 1 PFLAG3_TEMPORARY_DETACH
@@ -2978,14 +2989,16 @@
* Shift for the bits in {@link #mPrivateFlags3} related to the
* "importantForAutofill" attribute.
*/
- static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT = 21;
+ static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT = 19;
/**
* Mask for obtaining the bits which specify how to determine
* whether a view is important for autofill.
*/
static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK = (IMPORTANT_FOR_AUTOFILL_AUTO
- | IMPORTANT_FOR_AUTOFILL_YES | IMPORTANT_FOR_AUTOFILL_NO)
+ | IMPORTANT_FOR_AUTOFILL_YES | IMPORTANT_FOR_AUTOFILL_NO
+ | IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS
+ | IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS)
<< PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT;
/**
@@ -7292,7 +7305,9 @@
*
* @param structure Fill in with structured view data. The default implementation
* fills in all data that can be inferred from the view itself.
- * @param flags optional flags (currently {@code 0}).
+ * @param flags optional flags.
+ *
+ * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
*/
public void onProvideAutofillStructure(ViewStructure structure, int flags) {
onProvideStructureForAssistOrAutofill(structure, true);
@@ -7546,6 +7561,17 @@
/**
* Sets the mode for determining whether this View is important for autofill.
*
+ * <p>This property controls how this view is presented to the autofill components
+ * which help users to fill credentials, addresses, etc. For example, views
+ * that contain labels and input fields are useful for autofill components to
+ * determine the user context and provide values for the inputs. Note that the
+ * user can always override this by manually triggering autotill which would
+ * expose the view to the autofill provider.
+ *
+ * <p>The platform determines the importance for autofill automatically but you
+ * can use this method to customize the behavior. See the autofill modes below
+ * for more details.
+ *
* <p>See {@link #setImportantForAutofill(int)} for more info about this mode.
*
* @param mode {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, {@link #IMPORTANT_FOR_AUTOFILL_YES},
@@ -7599,24 +7625,40 @@
*
* @return whether the view is considered important for autofill.
*
+ * @see #setImportantForAutofill(int)
* @see #IMPORTANT_FOR_AUTOFILL_AUTO
* @see #IMPORTANT_FOR_AUTOFILL_YES
* @see #IMPORTANT_FOR_AUTOFILL_NO
+ * @see #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS
+ * @see #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS
*/
public final boolean isImportantForAutofill() {
- final int flag = getImportantForAutofill();
+ // Check parent mode to ensure we're not hidden.
+ ViewParent parent = mParent;
+ while (parent instanceof View) {
+ final int parentImportance = ((View) parent).getImportantForAutofill();
+ if (parentImportance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS
+ || parentImportance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS) {
+ return false;
+ }
+ parent = parent.getParent();
+ }
- // First, check if view explicity set it to YES or NO
- if ((flag & IMPORTANT_FOR_AUTOFILL_YES) != 0) {
+ final int importance = getImportantForAutofill();
+
+ // First, check the explicit states.
+ if (importance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS
+ || importance == IMPORTANT_FOR_AUTOFILL_YES) {
return true;
}
- if ((flag & IMPORTANT_FOR_AUTOFILL_NO) != 0) {
+ if (importance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS
+ || importance == IMPORTANT_FOR_AUTOFILL_NO) {
return false;
}
// Then use some heuristics to handle AUTO.
- // Always include views that have a explicity resource id.
+ // Always include views that have an explicit resource id.
final int id = mID;
if (id != NO_ID && !isViewIdGenerated(id)) {
final Resources res = getResources();
@@ -7642,9 +7684,8 @@
return mContext.getSystemService(AutofillManager.class);
}
- /** @hide */
- public boolean isAutofillable() {
- return getAutofillType() != AUTOFILL_TYPE_NONE && !isAutofillBlocked();
+ private boolean isAutofillable() {
+ return getAutofillType() != AUTOFILL_TYPE_NONE && isImportantForAutofill();
}
private void populateVirtualStructure(ViewStructure structure,
@@ -7728,26 +7769,33 @@
* set the {@link AutofillId} in the structure (for example, by calling
* {@code structure.setAutofillId(getAutofillId())}).
*
+ * <p>When providing your implementation you need to decide how to handle
+ * the {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag which instructs you
+ * to report all views to the structure regardless if {@link #isImportantForAutofill()}
+ * returns true. We encourage you respect the importance property for a better
+ * user experience in your app. If the flag is not set then you should filter out
+ * not important views to optimize autofill performance in your app.
+ *
* @param structure Fill in with structured view data.
- * @param flags optional flags (currently {@code 0}).
+ * @param flags optional flags.
+ *
+ * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
*/
- public void dispatchProvideAutofillStructure(@NonNull ViewStructure structure, int flags) {
+ public void dispatchProvideAutofillStructure(@NonNull ViewStructure structure,
+ @AutofillFlags int flags) {
dispatchProvideStructureForAssistOrAutofill(structure, true);
}
private void dispatchProvideStructureForAssistOrAutofill(ViewStructure structure,
boolean forAutofill) {
- boolean blocked = forAutofill ? isAutofillBlocked() : isAssistBlocked();
- if (!blocked) {
- if (forAutofill) {
- structure.setAutofillId(getAutofillId());
- // NOTE: flags are not currently supported, hence 0
- onProvideAutofillStructure(structure, 0);
- onProvideAutofillVirtualStructure(structure, 0);
- } else {
- onProvideStructure(structure);
- onProvideVirtualStructure(structure);
- }
+ if (forAutofill) {
+ structure.setAutofillId(getAutofillId());
+ // NOTE: flags are not currently supported, hence 0
+ onProvideAutofillStructure(structure, 0);
+ onProvideAutofillVirtualStructure(structure, 0);
+ } else if (!isAssistBlocked()) {
+ onProvideStructure(structure);
+ onProvideVirtualStructure(structure);
} else {
structure.setClassName(getAccessibilityClassName().toString());
structure.setAssistBlocked(true);
@@ -9585,22 +9633,6 @@
/**
* @hide
- * Indicates whether this view will participate in data collection through
- * {@link ViewStructure} for autofill purposes.
- *
- * <p>If {@code true}, it will not provide any data for itself or its children.
- * <p>If {@code false}, the normal data collection will be allowed.
- *
- * @return Returns {@code false} if assist data collection for autofill is not blocked,
- * else {@code true}.
- */
- public boolean isAutofillBlocked() {
- // TODO(b/36171235): properly implement it using isImportantForAutofill()
- return false;
- }
-
- /**
- * @hide
* Controls whether assist data collection from this view and its children is enabled
* (that is, whether {@link #onProvideStructure} and
* {@link #onProvideVirtualStructure} will be called). The default value is false,
@@ -21085,7 +21117,7 @@
*/
@Nullable
public final <T extends View> T findViewById(@IdRes int id) {
- if (id < 0) {
+ if (id == NO_ID) {
return null;
}
return findViewTraversal(id);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index b7834823..18c1b8c 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -57,7 +57,6 @@
import android.view.animation.AnimationUtils;
import android.view.animation.LayoutAnimationController;
import android.view.animation.Transformation;
-
import com.android.internal.R;
import java.util.ArrayList;
@@ -3442,12 +3441,13 @@
* default {@link View} implementation.
*/
@Override
- public void dispatchProvideAutofillStructure(ViewStructure structure, int flags) {
+ public void dispatchProvideAutofillStructure(ViewStructure structure,
+ @AutofillFlags int flags) {
super.dispatchProvideAutofillStructure(structure, flags);
- if (isAutofillBlocked() || structure.getChildCount() != 0) {
+ if (structure.getChildCount() != 0) {
return;
}
- final ChildListForAutoFill children = getChildrenForAutofill();
+ final ChildListForAutoFill children = getChildrenForAutofill(flags);
final int childrenCount = children.size();
structure.setChildCount(childrenCount);
for (int i = 0; i < childrenCount; i++) {
@@ -3463,14 +3463,14 @@
* level descendants that are important for autofill. The returned
* child list object is pooled and the caller must recycle it once done.
* @hide */
- private @NonNull ChildListForAutoFill getChildrenForAutofill() {
+ private @NonNull ChildListForAutoFill getChildrenForAutofill(@AutofillFlags int flags) {
final ChildListForAutoFill children = ChildListForAutoFill.obtain();
- populateChildrenForAutofill(children);
+ populateChildrenForAutofill(children, flags);
return children;
}
/** @hide */
- private void populateChildrenForAutofill(ArrayList<View> list) {
+ private void populateChildrenForAutofill(ArrayList<View> list, @AutofillFlags int flags) {
final int childrenCount = mChildrenCount;
if (childrenCount <= 0) {
return;
@@ -3482,10 +3482,11 @@
final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
final View child = (preorderedList == null)
? mChildren[childIndex] : preorderedList.get(childIndex);
- if (child.isImportantForAutofill()) {
+ if ((flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0
+ || child.isImportantForAutofill()) {
list.add(child);
} else if (child instanceof ViewGroup) {
- ((ViewGroup) child).populateChildrenForAutofill(list);
+ ((ViewGroup) child).populateChildrenForAutofill(list, flags);
}
}
}
@@ -5413,6 +5414,9 @@
if (mDefaultFocus != null) {
clearDefaultFocus(mDefaultFocus);
}
+ if (mFocusedInCluster != null) {
+ clearFocusedInCluster(mFocusedInCluster);
+ }
if (clearChildFocus) {
clearChildFocus(focused);
if (!rootViewRequestFocus()) {
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index fb910b83..f71589c 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -26,7 +26,7 @@
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
-import java.util.ArrayList;
+import java.util.List;
/**
* Container for storing additional per-view data generated by {@link View#onProvideStructure
@@ -429,7 +429,7 @@
* @return list of key/value pairs; could contain pairs with the same keys.
*/
@Nullable
- public abstract ArrayList<Pair<String, String>> getAttributes();
+ public abstract List<Pair<String, String>> getAttributes();
/**
* Builder for {@link HtmlInfo} objects.
diff --git a/core/java/android/view/autofill/AutofillId.java b/core/java/android/view/autofill/AutofillId.java
index 268f7f3..1cee529 100644
--- a/core/java/android/view/autofill/AutofillId.java
+++ b/core/java/android/view/autofill/AutofillId.java
@@ -15,8 +15,6 @@
*/
package android.view.autofill;
-import static android.view.autofill.Helper.DEBUG;
-
import android.os.Parcel;
import android.os.Parcelable;
import android.view.View;
@@ -92,11 +90,9 @@
@Override
public String toString() {
- if (!DEBUG) return super.toString();
-
final StringBuilder builder = new StringBuilder().append(mViewId);
if (mVirtual) {
- builder.append(":").append(mVirtualId);
+ builder.append(':').append(mVirtualId);
}
return builder.toString();
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 9ee0cb1..ab30a04 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -16,8 +16,8 @@
package android.view.autofill;
-import static android.view.autofill.Helper.DEBUG;
-import static android.view.autofill.Helper.VERBOSE;
+import static android.view.autofill.Helper.sDebug;
+import static android.view.autofill.Helper.sVerbose;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -107,11 +107,15 @@
@Deprecated
public static final int FLAG_MANUAL_REQUEST = 0x1;
- // TODO(b/37563972): start from 0x1 once FLAG_MANUAL_REQUEST is gone
- /** @hide */ public static final int FLAG_START_SESSION = 0x80000000;
- /** @hide */ public static final int FLAG_VIEW_ENTERED = 0x40000000;
- /** @hide */ public static final int FLAG_VIEW_EXITED = 0x20000000;
- /** @hide */ public static final int FLAG_VALUE_CHANGED = 0x10000000;
+ /** @hide */ public static final int ACTION_START_SESSION = 1;
+ /** @hide */ public static final int ACTION_VIEW_ENTERED = 2;
+ /** @hide */ public static final int ACTION_VIEW_EXITED = 3;
+ /** @hide */ public static final int ACTION_VALUE_CHANGED = 4;
+
+
+ /** @hide */ public static final int FLAG_ADD_CLIENT_ENABLED = 0x1;
+ /** @hide */ public static final int FLAG_ADD_CLIENT_DEBUG = 0x2;
+ /** @hide */ public static final int FLAG_ADD_CLIENT_VERBOSE = 0x4;
private final MetricsLogger mMetricsLogger = new MetricsLogger();
@@ -239,7 +243,7 @@
Log.w(TAG, "Session " + mSessionId + " could not be restored");
mSessionId = NO_SESSION;
} else {
- if (DEBUG) {
+ if (sDebug) {
Log.d(TAG, "session " + mSessionId + " was restored");
}
@@ -356,21 +360,7 @@
* @param view view requesting the new autofill context.
*/
public void requestAutofill(@NonNull View view) {
- if (!hasAutofillFeature()) {
- return;
- }
- synchronized (mLock) {
- ensureServiceClientAddedIfNeededLocked();
-
- if (!mEnabled) {
- return;
- }
-
- final AutofillId id = getAutofillId(view);
- final AutofillValue value = view.getAutofillValue();
-
- startSessionLocked(id, view.getWindowToken(), null, value, FLAG_MANUAL_REQUEST);
- }
+ notifyViewEntered(view, FLAG_MANUAL_REQUEST);
}
/**
@@ -385,19 +375,7 @@
* @param bounds child boundaries, relative to the top window.
*/
public void requestAutofill(@NonNull View view, int childId, @NonNull Rect bounds) {
- if (!hasAutofillFeature()) {
- return;
- }
- synchronized (mLock) {
- ensureServiceClientAddedIfNeededLocked();
-
- if (!mEnabled) {
- return;
- }
-
- final AutofillId id = getAutofillId(view, childId);
- startSessionLocked(id, view.getWindowToken(), bounds, null, FLAG_MANUAL_REQUEST);
- }
+ notifyViewEntered(view, childId, bounds, FLAG_MANUAL_REQUEST);
}
/**
@@ -406,6 +384,10 @@
* @param view {@link View} that was entered.
*/
public void notifyViewEntered(@NonNull View view) {
+ notifyViewEntered(view, 0);
+ }
+
+ private void notifyViewEntered(@NonNull View view, int flags) {
if (!hasAutofillFeature()) {
return;
}
@@ -423,10 +405,10 @@
if (mSessionId == NO_SESSION) {
// Starts new session.
- startSessionLocked(id, view.getWindowToken(), null, value, 0);
+ startSessionLocked(id, view.getWindowToken(), null, value, flags);
} else {
// Update focus on existing session.
- updateSessionLocked(id, null, value, FLAG_VIEW_ENTERED);
+ updateSessionLocked(id, null, value, ACTION_VIEW_ENTERED, flags);
}
}
}
@@ -452,7 +434,7 @@
final AutofillId id = getAutofillId(view);
// Update focus on existing session.
- updateSessionLocked(id, null, null, FLAG_VIEW_EXITED);
+ updateSessionLocked(id, null, null, ACTION_VIEW_EXITED, 0);
}
}
}
@@ -481,6 +463,10 @@
* @param bounds child boundaries, relative to the top window.
*/
public void notifyViewEntered(@NonNull View view, int childId, @NonNull Rect bounds) {
+ notifyViewEntered(view, childId, bounds, 0);
+ }
+
+ private void notifyViewEntered(View view, int childId, Rect bounds, int flags) {
if (!hasAutofillFeature()) {
return;
}
@@ -497,10 +483,10 @@
if (mSessionId == NO_SESSION) {
// Starts new session.
- startSessionLocked(id, view.getWindowToken(), bounds, null, 0);
+ startSessionLocked(id, view.getWindowToken(), bounds, null, flags);
} else {
// Update focus on existing session.
- updateSessionLocked(id, bounds, null, FLAG_VIEW_ENTERED);
+ updateSessionLocked(id, bounds, null, ACTION_VIEW_ENTERED, flags);
}
}
}
@@ -528,7 +514,7 @@
final AutofillId id = getAutofillId(view, childId);
// Update focus on existing session.
- updateSessionLocked(id, null, null, FLAG_VIEW_EXITED);
+ updateSessionLocked(id, null, null, ACTION_VIEW_EXITED, 0);
}
}
}
@@ -580,7 +566,7 @@
value = view.getAutofillValue();
}
- updateSessionLocked(id, null, value, FLAG_VALUE_CHANGED);
+ updateSessionLocked(id, null, value, ACTION_VALUE_CHANGED, 0);
}
}
@@ -601,7 +587,7 @@
}
final AutofillId id = getAutofillId(view, childId);
- updateSessionLocked(id, null, value, FLAG_VALUE_CHANGED);
+ updateSessionLocked(id, null, value, ACTION_VALUE_CHANGED, 0);
}
}
@@ -708,7 +694,7 @@
// set the EXTRA_AUTHENTICATION_RESULT extra, but it could cause weird results if the
// service set the extra and returned RESULT_CANCELED...
- if (DEBUG) Log.d(TAG, "onAuthenticationResult(): d=" + data);
+ if (sDebug) Log.d(TAG, "onAuthenticationResult(): d=" + data);
synchronized (mLock) {
if (mSessionId == NO_SESSION || data == null) {
@@ -735,8 +721,8 @@
private void startSessionLocked(@NonNull AutofillId id, @NonNull IBinder windowToken,
@NonNull Rect bounds, @NonNull AutofillValue value, int flags) {
- if (DEBUG) {
- Log.d(TAG, "startSessionLocked(): id=" + id + ", bounds=" + bounds + ", value=" + value
+ if (sVerbose) {
+ Log.v(TAG, "startSessionLocked(): id=" + id + ", bounds=" + bounds + ", value=" + value
+ ", flags=" + flags);
}
@@ -744,7 +730,7 @@
mSessionId = mService.startSession(mContext.getActivityToken(), windowToken,
mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
mCallback != null, flags, mContext.getOpPackageName());
- AutofillClient client = getClientLocked();
+ final AutofillClient client = getClientLocked();
if (client != null) {
client.autofillCallbackResetableStateAvailable();
}
@@ -754,9 +740,7 @@
}
private void finishSessionLocked() {
- if (DEBUG) {
- Log.d(TAG, "finishSessionLocked()");
- }
+ if (sVerbose) Log.v(TAG, "finishSessionLocked()");
try {
mService.finishSession(mSessionId, mContext.getUserId());
@@ -769,9 +753,7 @@
}
private void cancelSessionLocked() {
- if (DEBUG) {
- Log.d(TAG, "cancelSessionLocked()");
- }
+ if (sVerbose) Log.v(TAG, "cancelSessionLocked()");
try {
mService.cancelSession(mSessionId, mContext.getUserId());
@@ -787,16 +769,16 @@
mTrackedViews = null;
}
- private void updateSessionLocked(AutofillId id, Rect bounds, AutofillValue value, int flags) {
- if (DEBUG) {
- if (VERBOSE || (flags & FLAG_VIEW_EXITED) != 0) {
- Log.d(TAG, "updateSessionLocked(): id=" + id + ", bounds=" + bounds
- + ", value=" + value + ", flags=" + flags);
- }
+ private void updateSessionLocked(AutofillId id, Rect bounds, AutofillValue value, int action,
+ int flags) {
+ if (sVerbose && action != ACTION_VIEW_EXITED) {
+ Log.v(TAG, "updateSessionLocked(): id=" + id + ", bounds=" + bounds
+ + ", value=" + value + ", action=" + action + ", flags=" + flags);
}
try {
- mService.updateSession(mSessionId, id, bounds, value, flags, mContext.getUserId());
+ mService.updateSession(mSessionId, id, bounds, value, action, flags,
+ mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -810,7 +792,10 @@
if (mServiceClient == null) {
mServiceClient = new AutofillManagerClient(this);
try {
- mEnabled = mService.addClient(mServiceClient, mContext.getUserId());
+ final int flags = mService.addClient(mServiceClient, mContext.getUserId());
+ mEnabled = (flags & FLAG_ADD_CLIENT_ENABLED) != 0;
+ sDebug = (flags & FLAG_ADD_CLIENT_DEBUG) != 0;
+ sVerbose = (flags & FLAG_ADD_CLIENT_VERBOSE) != 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1192,8 +1177,8 @@
}
}
- if (DEBUG) {
- Log.d(TAG, "TrackedViews(trackedIds=" + trackedIds + "): "
+ if (sVerbose) {
+ Log.v(TAG, "TrackedViews(trackedIds=" + trackedIds + "): "
+ " mVisibleTrackedIds=" + mVisibleTrackedIds
+ " mInvisibleTrackedIds=" + mInvisibleTrackedIds);
}
@@ -1213,7 +1198,7 @@
AutofillId id = getAutofillId(view);
AutofillClient client = getClientLocked();
- if (DEBUG) {
+ if (sDebug) {
Log.d(TAG, "notifyViewVisibilityChange(): id=" + id + " isVisible="
+ isVisible);
}
@@ -1254,8 +1239,8 @@
if (client.getViewVisibility(id.getViewId())) {
updatedVisibleTrackedIds = addToSet(updatedVisibleTrackedIds, id);
- if (DEBUG) {
- Log.i(TAG, "onVisibleForAutofill() " + id + " became visible");
+ if (sDebug) {
+ Log.d(TAG, "onVisibleForAutofill() " + id + " became visible");
}
} else {
updatedInvisibleTrackedIds = addToSet(updatedInvisibleTrackedIds, id);
@@ -1270,8 +1255,8 @@
} else {
updatedInvisibleTrackedIds = addToSet(updatedInvisibleTrackedIds, id);
- if (DEBUG) {
- Log.i(TAG, "onVisibleForAutofill() " + id + " became invisible");
+ if (sDebug) {
+ Log.d(TAG, "onVisibleForAutofill() " + id + " became invisible");
}
}
}
diff --git a/core/java/android/view/autofill/AutofillValue.java b/core/java/android/view/autofill/AutofillValue.java
index b1a9d90..b57dab5 100644
--- a/core/java/android/view/autofill/AutofillValue.java
+++ b/core/java/android/view/autofill/AutofillValue.java
@@ -20,8 +20,7 @@
import static android.view.View.AUTOFILL_TYPE_LIST;
import static android.view.View.AUTOFILL_TYPE_TEXT;
import static android.view.View.AUTOFILL_TYPE_TOGGLE;
-import static android.view.autofill.Helper.DEBUG;
-import static android.view.autofill.Helper.VERBOSE;
+import static android.view.autofill.Helper.sDebug;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -171,12 +170,17 @@
@Override
public String toString() {
- if (!DEBUG) return super.toString();
+ if (!sDebug) return super.toString();
- final String sanitizedValue = isText() && !VERBOSE
- ? ((CharSequence) mValue).length() + "_chars" : mValue.toString();
-
- return "[type=" + mType + ", value=" + sanitizedValue + "]";
+ final StringBuilder string = new StringBuilder()
+ .append("[type=").append(mType)
+ .append(", value=");
+ if (isText()) {
+ string.append(((CharSequence) mValue).length()).append("_chars");
+ } else {
+ string.append(mValue);
+ }
+ return string.append(']').toString();
}
/////////////////////////////////////
diff --git a/core/java/android/view/autofill/Helper.java b/core/java/android/view/autofill/Helper.java
index 2b25ae7..829e7f3 100644
--- a/core/java/android/view/autofill/Helper.java
+++ b/core/java/android/view/autofill/Helper.java
@@ -25,15 +25,16 @@
/** @hide */
public final class Helper {
- // TODO(b/36141126): set to false and remove guard from places that should always be on
- public static final boolean DEBUG = true;
- public static final boolean VERBOSE = false;
+ // Debug-level flags are defined when service is bound.
+ public static boolean sDebug = false;
+ public static boolean sVerbose = false;
+
public static final String REDACTED = "[REDACTED]";
static StringBuilder append(StringBuilder builder, Bundle bundle) {
- if (bundle == null) {
+ if (bundle == null || !sDebug) {
builder.append("N/A");
- } else if (!VERBOSE) {
+ } else if (!sVerbose) {
builder.append(REDACTED);
} else {
final Set<String> keySet = bundle.keySet();
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index 9417bd0..f28d8ba 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -30,7 +30,8 @@
* {@hide}
*/
interface IAutoFillManager {
- boolean addClient(in IAutoFillManagerClient client, int userId);
+ // Returns flags: FLAG_ADD_CLIENT_ENABLED | FLAG_ADD_CLIENT_DEBUG | FLAG_ADD_CLIENT_VERBOSE
+ int addClient(in IAutoFillManagerClient client, int userId);
int startSession(IBinder activityToken, IBinder windowToken, in IBinder appCallback,
in AutofillId autoFillId, in Rect bounds, in AutofillValue value, int userId,
boolean hasCallback, int flags, String packageName);
@@ -38,7 +39,7 @@
boolean restoreSession(int sessionId, in IBinder activityToken, in IBinder appCallback);
void setWindow(int sessionId, in IBinder windowToken);
void updateSession(int sessionId, in AutofillId id, in Rect bounds,
- in AutofillValue value, int flags, int userId);
+ in AutofillValue value, int action, int flags, int userId);
void finishSession(int sessionId, int userId);
void cancelSession(int sessionId, int userId);
void setAuthenticationResult(in Bundle data, int sessionId, int userId);
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 6213a63..52c82a7 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2255,6 +2255,7 @@
/**
* Sets the {@link TextClassifier} for this WebView.
+ * @hide
*/
public void setTextClassifier(@Nullable TextClassifier textClassifier) {
mProvider.setTextClassifier(textClassifier);
@@ -2263,6 +2264,7 @@
/**
* Returns the {@link TextClassifier} used by this WebView.
* If no TextClassifier has been set, this WebView uses the default set by the system.
+ * @hide
*/
@NonNull
public TextClassifier getTextClassifier() {
@@ -2506,6 +2508,7 @@
super.onDetachedFromWindowInternal();
}
+ /** @hide */
@Override
public void onMovedToDisplay(int displayId, Configuration config) {
mProvider.getViewDelegate().onMovedToDisplay(displayId, config);
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 4ae3510..27e3fe5 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -3836,9 +3836,11 @@
}
if (mTextView.canRequestAutofill()) {
+ final int mode = mTextView.getText().length() <= 0
+ ? MenuItem.SHOW_AS_ACTION_IF_ROOM : MenuItem.SHOW_AS_ACTION_NEVER;
menu.add(Menu.NONE, TextView.ID_AUTOFILL, MENU_ITEM_ORDER_AUTOFILL,
com.android.internal.R.string.autofill)
- .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+ .setShowAsAction(mode);
}
updateSelectAllItem(menu);
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index ff3c85c..88c3c5b 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -258,9 +258,9 @@
mUseLargestChild = a.getBoolean(R.styleable.LinearLayout_measureWithLargestChild, false);
- setDividerDrawable(a.getDrawable(R.styleable.LinearLayout_divider));
mShowDividers = a.getInt(R.styleable.LinearLayout_showDividers, SHOW_DIVIDER_NONE);
mDividerPadding = a.getDimensionPixelSize(R.styleable.LinearLayout_dividerPadding, 0);
+ setDividerDrawable(a.getDrawable(R.styleable.LinearLayout_divider));
final int version = context.getApplicationInfo().targetSdkVersion;
mAllowInconsistentMeasurement = version <= Build.VERSION_CODES.M;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 99b9bd2bfb..492010c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -126,6 +126,7 @@
import android.view.DragEvent;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
+import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -395,6 +396,14 @@
private TextClassifier mTextClassifier;
+ // A flag to prevent repeated movements from escaping the enclosing text view. The idea here is
+ // that if a user is holding down a movement key to traverse text, we shouldn't also traverse
+ // the view hierarchy. On the other hand, if the user is using the movement key to traverse
+ // views (i.e. the first movement was to traverse out of this view, or this view was traversed
+ // into by the user holding the movement key down) then we shouldn't prevent the focus from
+ // changing.
+ private boolean mPreventDefaultMovement;
+
private TextUtils.TruncateAt mEllipsize;
static class Drawables {
@@ -7155,6 +7164,15 @@
return KEY_EVENT_NOT_HANDLED;
}
+ // If this is the initial keydown, we don't want to prevent a movement away from this view.
+ // While this shouldn't be necessary because any time we're preventing default movement we
+ // should be restricting the focus to remain within this view, thus we'll also receive
+ // the key up event, occasionally key up events will get dropped and we don't want to
+ // prevent the user from traversing out of this on the next key down.
+ if (event.getRepeatCount() == 0 && !KeyEvent.isModifierKey(keyCode)) {
+ mPreventDefaultMovement = false;
+ }
+
switch (keyCode) {
case KeyEvent.KEYCODE_ENTER:
if (event.hasNoModifiers()) {
@@ -7286,16 +7304,23 @@
}
if (doDown) {
if (mMovement.onKeyDown(this, (Spannable) mText, keyCode, event)) {
+ if (event.getRepeatCount() == 0 && !KeyEvent.isModifierKey(keyCode)) {
+ mPreventDefaultMovement = true;
+ }
return KEY_DOWN_HANDLED_BY_MOVEMENT_METHOD;
}
}
- // Consume arrows to prevent focus leaving the editor.
- if (isDirectionalNavigationKey(keyCode)) {
+ // Consume arrows from keyboard devices to prevent focus leaving the editor.
+ // DPAD/JOY devices (Gamepads, TV remotes) often lack a TAB key so allow those
+ // to move focus with arrows.
+ if (event.getSource() == InputDevice.SOURCE_KEYBOARD
+ && isDirectionalNavigationKey(keyCode)) {
return KEY_EVENT_HANDLED;
}
}
- return KEY_EVENT_NOT_HANDLED;
+ return mPreventDefaultMovement && !KeyEvent.isModifierKey(keyCode)
+ ? KEY_EVENT_HANDLED : KEY_EVENT_NOT_HANDLED;
}
/**
@@ -7328,6 +7353,10 @@
return super.onKeyUp(keyCode, event);
}
+ if (!KeyEvent.isModifierKey(keyCode)) {
+ mPreventDefaultMovement = false;
+ }
+
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
if (event.hasNoModifiers()) {
@@ -9304,6 +9333,8 @@
}
private void notifyAutoFillManagerAfterTextChangedIfNeeded() {
+ // It is important to not check whether the view is important for autofill
+ // since the user can trigger autofill manually on not important views.
if (!isAutofillable()) {
return;
}
@@ -9316,6 +9347,12 @@
}
}
+ private boolean isAutofillable() {
+ // It is important to not check whether the view is important for autofill
+ // since the user can trigger autofill manually on not important views.
+ return getAutofillType() != AUTOFILL_TYPE_NONE;
+ }
+
void updateAfterEdit() {
invalidate();
int curs = getSelectionStart();
@@ -10192,6 +10229,9 @@
}
boolean canRequestAutofill() {
+ if (!isAutofillable()) {
+ return false;
+ }
final AutofillManager afm = mContext.getSystemService(AutofillManager.class);
if (afm != null) {
return afm.isEnabled();
diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java
index c6b6a7fb..d2e9789 100644
--- a/core/java/com/android/internal/content/PackageMonitor.java
+++ b/core/java/com/android/internal/content/PackageMonitor.java
@@ -65,6 +65,7 @@
int mChangeType;
int mChangeUserId = UserHandle.USER_NULL;
boolean mSomePackagesChanged;
+ String[] mModifiedComponents;
String[] mTempArray = new String[1];
@@ -269,6 +270,18 @@
}
return false;
}
+
+ public boolean isComponentModified(String className) {
+ if (className == null || mModifiedComponents == null) {
+ return false;
+ }
+ for (int i = mModifiedComponents.length - 1; i >= 0; i--) {
+ if (className.equals(mModifiedComponents[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
public void onSomePackagesChanged() {
}
@@ -301,6 +314,7 @@
mDisappearingPackages = mAppearingPackages = null;
mSomePackagesChanged = false;
+ mModifiedComponents = null;
String action = intent.getAction();
if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
@@ -358,13 +372,13 @@
} else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
String pkg = getPackageName(intent);
int uid = intent.getIntExtra(Intent.EXTRA_UID, 0);
- String[] components = intent.getStringArrayExtra(
+ mModifiedComponents = intent.getStringArrayExtra(
Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
if (pkg != null) {
mModifiedPackages = mTempArray;
mTempArray[0] = pkg;
mChangeType = PACKAGE_PERMANENT_CHANGE;
- if (onPackageChanged(pkg, uid, components)) {
+ if (onPackageChanged(pkg, uid, mModifiedComponents)) {
mSomePackagesChanged = true;
}
onPackageModified(pkg);
diff --git a/core/java/com/android/internal/util/NotificationColorUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
index 5cb66e5..2c97f8b 100644
--- a/core/java/com/android/internal/util/NotificationColorUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -257,7 +257,7 @@
* @return a color with the same hue as {@param color}, potentially darkened to meet the
* contrast ratio.
*/
- private static int findContrastColor(int color, int other, boolean findFg, double minRatio) {
+ public static int findContrastColor(int color, int other, boolean findFg, double minRatio) {
int fg = findFg ? color : other;
int bg = findFg ? other : color;
if (ColorUtilsFromCompat.calculateContrast(fg, bg) >= minRatio) {
@@ -402,16 +402,17 @@
}
/**
- * Lighten a color by a specified value
+ * Change a color by a specified value
* @param baseColor the base color to lighten
* @param amount the amount to lighten the color from 0 to 100. This corresponds to the L
- * increase in the LAB color space.
- * @return the lightened color
+ * increase in the LAB color space. A negative value will darken the color and
+ * a positive will lighten it.
+ * @return the changed color
*/
- public static int lightenColor(int baseColor, int amount) {
+ public static int changeColorLightness(int baseColor, int amount) {
final double[] result = ColorUtilsFromCompat.getTempDouble3Array();
ColorUtilsFromCompat.colorToLAB(baseColor, result);
- result[0] = Math.min(100, result[0] + amount);
+ result[0] = Math.max(Math.min(100, result[0] + amount), 0);
return ColorUtilsFromCompat.LABToColor(result[0], result[1], result[2]);
}
@@ -491,6 +492,15 @@
return useDark;
}
+ public static double calculateLuminance(int backgroundColor) {
+ return ColorUtilsFromCompat.calculateLuminance(backgroundColor);
+ }
+
+
+ public static double calculateContrast(int foregroundColor, int backgroundColor) {
+ return ColorUtilsFromCompat.calculateContrast(foregroundColor, backgroundColor);
+ }
+
/**
* Framework copy of functions needed from android.support.v4.graphics.ColorUtils.
*/
diff --git a/core/java/com/android/internal/widget/MediaNotificationView.java b/core/java/com/android/internal/widget/MediaNotificationView.java
index afb2a5e..bbebcc2 100644
--- a/core/java/com/android/internal/widget/MediaNotificationView.java
+++ b/core/java/com/android/internal/widget/MediaNotificationView.java
@@ -23,7 +23,6 @@
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
-import android.widget.RelativeLayout;
import android.widget.RemoteViews;
/**
@@ -34,8 +33,7 @@
@RemoteViews.RemoteView
public class MediaNotificationView extends FrameLayout {
- private final int mMaxImageSize;
- private final int mImageMinTopMargin;
+ private final int mSmallImageSize;
private final int mNotificationContentMarginEnd;
private final int mNotificationContentImageMarginEnd;
private ImageView mRightIcon;
@@ -57,72 +55,68 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int mode = MeasureSpec.getMode(widthMeasureSpec);
boolean hasIcon = mRightIcon.getVisibility() != GONE;
+ if (!hasIcon) {
+ resetHeaderIndention();
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ int mode = MeasureSpec.getMode(widthMeasureSpec);
+ boolean reMeasure = false;
if (hasIcon && mode != MeasureSpec.UNSPECIFIED) {
- measureChild(mActions, widthMeasureSpec, heightMeasureSpec);
int size = MeasureSpec.getSize(widthMeasureSpec);
size = size - mActions.getMeasuredWidth();
ViewGroup.MarginLayoutParams layoutParams =
(MarginLayoutParams) mRightIcon.getLayoutParams();
int imageEndMargin = layoutParams.getMarginEnd();
size -= imageEndMargin;
- size = Math.min(size, mMaxImageSize);
- size = Math.max(size, mRightIcon.getMinimumWidth());
- layoutParams.width = size;
- layoutParams.height = size;
- mRightIcon.setLayoutParams(layoutParams);
-
- // lets ensure that the main column doesn't run into the image
- ViewGroup.MarginLayoutParams mainParams
- = (MarginLayoutParams) mMainColumn.getLayoutParams();
- int marginEnd = size + imageEndMargin + mNotificationContentMarginEnd;
- if (marginEnd != mainParams.getMarginEnd()) {
- mainParams.setMarginEnd(marginEnd);
- mMainColumn.setLayoutParams(mainParams);
+ int fullHeight = getMeasuredHeight();
+ if (size < fullHeight) {
+ size = mSmallImageSize;
+ } else {
+ size = fullHeight;
}
-
- }
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- ViewGroup.MarginLayoutParams iconParams =
- (MarginLayoutParams) mRightIcon.getLayoutParams();
- int topMargin = getMeasuredHeight() - mRightIcon.getMeasuredHeight()
- - iconParams.bottomMargin;
- // If the topMargin is high enough we can also remove the header constraint!
- boolean reMeasure = false;
- if (!hasIcon || topMargin >= mImageMinTopMargin) {
- reMeasure = resetHeaderIndention();
- } else {
- int paddingEnd = mNotificationContentImageMarginEnd;
- ViewGroup.MarginLayoutParams headerParams =
- (MarginLayoutParams) mHeader.getLayoutParams();
- int newMarginEnd = mRightIcon.getMeasuredWidth() + iconParams.getMarginEnd();
- if (headerParams.getMarginEnd() != newMarginEnd) {
- headerParams.setMarginEnd(newMarginEnd);
- mHeader.setLayoutParams(headerParams);
+ if (layoutParams.width != size || layoutParams.height != size) {
+ layoutParams.width = size;
+ layoutParams.height = size;
+ mRightIcon.setLayoutParams(layoutParams);
reMeasure = true;
}
- if (mHeader.getPaddingEnd() != paddingEnd) {
+
+ // lets ensure that the main column doesn't run into the image
+ ViewGroup.MarginLayoutParams params
+ = (MarginLayoutParams) mMainColumn.getLayoutParams();
+ int marginEnd = size + imageEndMargin + mNotificationContentMarginEnd;
+ if (marginEnd != params.getMarginEnd()) {
+ params.setMarginEnd(marginEnd);
+ mMainColumn.setLayoutParams(params);
+ reMeasure = true;
+ }
+ int headerMarginEnd = size + imageEndMargin;
+ params = (MarginLayoutParams) mHeader.getLayoutParams();
+ if (params.getMarginEnd() != headerMarginEnd) {
+ params.setMarginEnd(headerMarginEnd);
+ mHeader.setLayoutParams(params);
+ reMeasure = true;
+ }
+ if (mHeader.getPaddingEnd() != mNotificationContentImageMarginEnd) {
mHeader.setPaddingRelative(mHeader.getPaddingStart(),
mHeader.getPaddingTop(),
- paddingEnd,
+ mNotificationContentImageMarginEnd,
mHeader.getPaddingBottom());
reMeasure = true;
}
}
if (reMeasure) {
- measureChildWithMargins(mHeader, widthMeasureSpec, 0, heightMeasureSpec, 0);
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
- private boolean resetHeaderIndention() {
- boolean remeasure = false;
+ private void resetHeaderIndention() {
if (mHeader.getPaddingEnd() != mNotificationContentMarginEnd) {
mHeader.setPaddingRelative(mHeader.getPaddingStart(),
mHeader.getPaddingTop(),
mNotificationContentMarginEnd,
mHeader.getPaddingBottom());
- remeasure = true;
}
ViewGroup.MarginLayoutParams headerParams =
(MarginLayoutParams) mHeader.getLayoutParams();
@@ -130,19 +124,14 @@
if (headerParams.getMarginEnd() != 0) {
headerParams.setMarginEnd(0);
mHeader.setLayoutParams(headerParams);
- remeasure = true;
}
- return remeasure;
}
public MediaNotificationView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- mMaxImageSize = context.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.media_notification_expanded_image_max_size);
- mImageMinTopMargin = (int) (context.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.notification_content_margin_top)
- + getResources().getDisplayMetrics().density * 2);
+ mSmallImageSize = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.media_notification_expanded_image_small_size);
mNotificationContentMarginEnd = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.notification_content_margin_end);
mNotificationContentImageMarginEnd = context.getResources().getDimensionPixelSize(
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index 292454b..d3d6882 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -26,6 +26,7 @@
#include "SkPath.h"
#include "SkPathOps.h"
+#include "SkGeometry.h" // WARNING: Internal Skia Header
#include <Caches.h>
#include <vector>
@@ -355,8 +356,9 @@
}
}
- static void createVerbSegments(SkPath::Verb verb, const SkPoint* points,
- std::vector<SkPoint>& segmentPoints, std::vector<float>& lengths, float errorSquared) {
+ static void createVerbSegments(const SkPath::Iter& pathIter, SkPath::Verb verb,
+ const SkPoint* points, std::vector<SkPoint>& segmentPoints,
+ std::vector<float>& lengths, float errorSquared, float errorConic) {
switch (verb) {
case SkPath::kMove_Verb:
addMove(segmentPoints, lengths, points[0]);
@@ -375,8 +377,27 @@
addBezier(points, cubicBezierCalculation, segmentPoints, lengths,
errorSquared, true);
break;
+ case SkPath::kConic_Verb: {
+ SkAutoConicToQuads converter;
+ const SkPoint* quads = converter.computeQuads(
+ points, pathIter.conicWeight(), errorConic);
+ for (int i = 0; i < converter.countQuads(); i++) {
+ // Note: offset each subsequent quad by 2, since end points are shared
+ const SkPoint* quad = quads + i * 2;
+ addBezier(quad, quadraticBezierCalculation, segmentPoints, lengths,
+ errorConic, false);
+ }
+ break;
+ }
default:
- // Leave element as NULL, Conic sections are not supported.
+ static_assert(SkPath::kMove_Verb == 0
+ && SkPath::kLine_Verb == 1
+ && SkPath::kQuad_Verb == 2
+ && SkPath::kConic_Verb == 3
+ && SkPath::kCubic_Verb == 4
+ && SkPath::kClose_Verb == 5
+ && SkPath::kDone_Verb == 6,
+ "Path enum changed, new types may have been added.");
break;
}
}
@@ -398,9 +419,11 @@
std::vector<SkPoint> segmentPoints;
std::vector<float> lengths;
float errorSquared = acceptableError * acceptableError;
+ float errorConic = acceptableError / 2; // somewhat arbitrary
while ((verb = pathIter.next(points, false)) != SkPath::kDone_Verb) {
- createVerbSegments(verb, points, segmentPoints, lengths, errorSquared);
+ createVerbSegments(pathIter, verb, points, segmentPoints, lengths,
+ errorSquared, errorConic);
}
if (segmentPoints.empty()) {
diff --git a/core/jni/android_hardware_HardwareBuffer.cpp b/core/jni/android_hardware_HardwareBuffer.cpp
index 4b31c91..ba23450 100644
--- a/core/jni/android_hardware_HardwareBuffer.cpp
+++ b/core/jni/android_hardware_HardwareBuffer.cpp
@@ -80,14 +80,10 @@
}
return NULL;
}
- uint64_t producerUsage = 0;
- uint64_t consumerUsage = 0;
- android_hardware_HardwareBuffer_convertToGrallocUsageBits(
- &producerUsage, &consumerUsage, usage, 0);
+ uint64_t grallocUsage = AHardwareBuffer_convertToGrallocUsageBits(usage);
sp<GraphicBuffer> buffer = new GraphicBuffer(width, height, pixelFormat, layers,
- android_convertGralloc1To0Usage(producerUsage, consumerUsage),
- std::string("HardwareBuffer pid [") + std::to_string(getpid()) +"]");
+ grallocUsage, std::string("HardwareBuffer pid [") + std::to_string(getpid()) +"]");
status_t error = buffer->initCheck();
if (error < 0) {
if (kDebugGraphicBuffer) {
@@ -145,11 +141,7 @@
static jlong android_hardware_HardwareBuffer_getUsage(JNIEnv* env,
jobject clazz, jlong nativeObject) {
GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject);
- uint64_t usage0 = 0;
- uint64_t usage1 = 0;
- android_hardware_HardwareBuffer_convertFromGrallocUsageBits(&usage0, &usage1,
- buffer->getUsage(), buffer->getUsage());
- return usage0;
+ return AHardwareBuffer_convertFromGrallocUsageBits(buffer->getUsage());
}
// ----------------------------------------------------------------------------
@@ -221,14 +213,8 @@
return AHardwareBuffer_convertToPixelFormat(format);
}
-void android_hardware_HardwareBuffer_convertToGrallocUsageBits(uint64_t* outProducerUsage,
- uint64_t* outConsumerUsage, uint64_t usage0, uint64_t usage1) {
- AHardwareBuffer_convertToGrallocUsageBits(outProducerUsage, outConsumerUsage, usage0, usage1);
-}
-
-void android_hardware_HardwareBuffer_convertFromGrallocUsageBits(uint64_t* outUsage0,
- uint64_t* outUsage1, uint64_t producerUsage, uint64_t consumerUsage) {
- AHardwareBuffer_convertFromGrallocUsageBits(outUsage0, outUsage1, producerUsage, consumerUsage);
+uint64_t android_hardware_HardwareBuffer_convertToGrallocUsageBits(uint64_t usage) {
+ return AHardwareBuffer_convertToGrallocUsageBits(usage);
}
} // namespace android
diff --git a/core/jni/include/android_runtime/android_hardware_HardwareBuffer.h b/core/jni/include/android_runtime/android_hardware_HardwareBuffer.h
index 3545c56..c452b74 100644
--- a/core/jni/include/android_runtime/android_hardware_HardwareBuffer.h
+++ b/core/jni/include/android_runtime/android_hardware_HardwareBuffer.h
@@ -32,22 +32,19 @@
JNIEnv* env, AHardwareBuffer* hardwareBuffer);
/* Convert from HAL_PIXEL_FORMAT values to AHARDWAREBUFFER_FORMAT values. */
-extern uint32_t android_hardware_HardwareBuffer_convertFromPixelFormat(
- uint32_t format);
+extern uint32_t android_hardware_HardwareBuffer_convertFromPixelFormat(uint32_t format);
/* Convert from AHARDWAREBUFFER_FORMAT values to HAL_PIXEL_FORMAT values. */
-extern uint32_t android_hardware_HardwareBuffer_convertToPixelFormat(
- uint32_t format);
+extern uint32_t android_hardware_HardwareBuffer_convertToPixelFormat(uint32_t format);
/* Convert from AHARDWAREBUFFER_USAGE* flags to to gralloc usage flags. */
-extern void android_hardware_HardwareBuffer_convertToGrallocUsageBits(
- uint64_t* outProducerUsage, uint64_t* outConsumerUsage, uint64_t usage0,
- uint64_t usage1);
+extern uint64_t android_hardware_HardwareBuffer_convertToGrallocUsageBits(uint64_t usage);
-/* Convert from gralloc usage flags to to AHARDWAREBUFFER_USAGE0* flags. */
-extern void android_hardware_HardwareBuffer_convertFromGrallocUsageBits(
- uint64_t* outUsage0, uint64_t* outUsage1, uint64_t producerUsage,
- uint64_t consumerUsage);
+inline void android_hardware_HardwareBuffer_convertToGrallocUsageBits(
+ uint64_t* outProducerUsage, uint64_t* outConsumerUsage, uint64_t usage, uint64_t) {
+ outProducerUsage[0] = outConsumerUsage[0] =
+ android_hardware_HardwareBuffer_convertToGrallocUsageBits(usage);
+}
} // namespace android
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index eacb02f..8bf96e3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1697,7 +1697,8 @@
<permission android:name="android.permission.CACHE_CONTENT"
android:protectionLevel="signature" />
- <!-- Allows an application to aggressively allocate disk space.
+ <!-- @SystemApi @hide
+ Allows an application to aggressively allocate disk space.
<p>Not for use by third-party applications.
-->
<permission android:name="android.permission.ALLOCATE_AGGRESSIVE"
diff --git a/core/res/res/layout/notification_template_material_big_media.xml b/core/res/res/layout/notification_template_material_big_media.xml
index 04ea12d..532f28e 100644
--- a/core/res/res/layout/notification_template_material_big_media.xml
+++ b/core/res/res/layout/notification_template_material_big_media.xml
@@ -23,6 +23,13 @@
android:background="#00000000"
android:tag="bigMediaNarrow"
>
+ <!-- The size will actually be determined at runtime -->
+ <ImageView android:id="@+id/right_icon"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_gravity="top|end"
+ android:scaleType="centerCrop"
+ />
<include layout="@layout/notification_template_header"
android:layout_width="match_parent"
android:layout_height="53dp"
@@ -60,14 +67,4 @@
<!-- media buttons will be added here -->
</LinearLayout>
</LinearLayout>
-
- <ImageView android:id="@+id/right_icon"
- android:layout_width="@dimen/media_notification_expanded_image_max_size"
- android:layout_height="@dimen/media_notification_expanded_image_max_size"
- android:minWidth="40dp"
- android:layout_marginEnd="16dp"
- android:layout_marginBottom="20dp"
- android:layout_gravity="bottom|end"
- android:scaleType="centerCrop"
- />
</com.android.internal.widget.MediaNotificationView>
diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml
index 4c64207..4be53e0 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -23,6 +23,13 @@
android:background="#00000000"
android:tag="media"
>
+ <ImageView android:id="@+id/right_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:adjustViewBounds="true"
+ android:layout_gravity="top|end"
+ android:scaleType="centerCrop"
+ />
<include layout="@layout/notification_template_header"
android:layout_width="fill_parent"
android:layout_height="53dp" />
@@ -61,5 +68,4 @@
<!-- media buttons will be added here -->
</LinearLayout>
</LinearLayout>
- <include layout="@layout/notification_template_right_icon" />
</FrameLayout>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index c5316c6..ef6c21f 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -208,8 +208,8 @@
<!-- The minimum height of the content if there are at least two lines or a picture-->
<dimen name="notification_min_content_height">41dp</dimen>
- <!-- The maximum size of the image in the expanded media notification -->
- <dimen name="media_notification_expanded_image_max_size">94dp</dimen>
+ <!-- The small size of the image if the height drawing doesn't work anymore -->
+ <dimen name="media_notification_expanded_image_small_size">72dp</dimen>
<!-- The maximum size of the image in the expanded media notification -->
<dimen name="media_notification_expanded_image_margin_bottom">20dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 63a5cfd7..0ea9b39 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -598,11 +598,9 @@
<java-symbol type="string" name="badPin" />
<java-symbol type="string" name="badPuk" />
<java-symbol type="string" name="byteShort" />
- <java-symbol type="string" name="capability_desc_canRequestEnhancedWebAccessibility" />
<java-symbol type="string" name="capability_title_canRequestFilterKeyEvents" />
<java-symbol type="string" name="capability_desc_canRequestTouchExploration" />
<java-symbol type="string" name="capability_desc_canRetrieveWindowContent" />
- <java-symbol type="string" name="capability_title_canRequestEnhancedWebAccessibility" />
<java-symbol type="string" name="capability_desc_canRequestFilterKeyEvents" />
<java-symbol type="string" name="capability_title_canRequestTouchExploration" />
<java-symbol type="string" name="capability_title_canRetrieveWindowContent" />
@@ -2616,7 +2614,7 @@
<java-symbol type="string" name="new_sms_notification_title" />
<java-symbol type="string" name="new_sms_notification_content" />
- <java-symbol type="dimen" name="media_notification_expanded_image_max_size" />
+ <java-symbol type="dimen" name="media_notification_expanded_image_small_size" />
<java-symbol type="dimen" name="media_notification_expanded_image_margin_bottom" />
<java-symbol type="dimen" name="notification_content_image_margin_end" />
diff --git a/core/tests/coretests/src/android/metrics/LogMakerTest.java b/core/tests/coretests/src/android/metrics/LogMakerTest.java
index 63c1f87..ada59cd 100644
--- a/core/tests/coretests/src/android/metrics/LogMakerTest.java
+++ b/core/tests/coretests/src/android/metrics/LogMakerTest.java
@@ -179,6 +179,14 @@
assertEquals(-1, builder.getProcessId());
}
+ public void testSetAndClearUid() {
+ LogMaker builder = new LogMaker(0);
+ builder.setUid(1);
+ assertEquals(1, builder.getUid());
+ builder.clearUid();
+ assertEquals(-1, builder.getUid());
+ }
+
public void testGiantLogOmitted() {
LogMaker badBuilder = new LogMaker(0);
StringBuilder b = new StringBuilder();
diff --git a/core/tests/coretests/src/android/metrics/MetricsReaderTest.java b/core/tests/coretests/src/android/metrics/MetricsReaderTest.java
index d06f522..d10b351 100644
--- a/core/tests/coretests/src/android/metrics/MetricsReaderTest.java
+++ b/core/tests/coretests/src/android/metrics/MetricsReaderTest.java
@@ -26,6 +26,8 @@
public class MetricsReaderTest extends TestCase {
private static final int FULL_N = 10;
private static final int CHECKPOINTED_N = 4;
+ private static final int PID = 1;
+ private static final int UID = 2;
class FakeLogReader extends MetricsReader.LogReader {
MetricsReader.Event[] mEvents;
@@ -36,7 +38,8 @@
for (int i = 0; i < FULL_N; i++) {
mEvents[i] = new MetricsReader.Event(
1000L + i,
- 1,
+ PID,
+ UID,
new LogMaker(i).serialize());
}
}
@@ -88,6 +91,13 @@
}
}
+ public void testPidUid() {
+ mReader.read(0);
+ LogMaker log = mReader.next();
+ assertEquals(PID, log.getProcessId());
+ assertEquals(UID, log.getUid());
+ }
+
public void testBlockingRead_readResetsHorizon() {
mReader.read(1000);
assertEquals(1000, mLogReader.mHorizonMs);
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index 3631373..098cdc6 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -16,8 +16,10 @@
package android.graphics;
+import android.annotation.FloatRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.Size;
import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;
@@ -805,7 +807,12 @@
* the error is less than half a pixel.
* @return An array of components for points approximating the Path.
*/
- public float[] approximate(float acceptableError) {
+ @NonNull
+ @Size(min = 6, multiple = 3)
+ public float[] approximate(@FloatRange(from = 0) float acceptableError) {
+ if (acceptableError < 0) {
+ throw new IllegalArgumentException("AcceptableError must be greater than or equal to 0");
+ }
return nApproximate(mNativePath, acceptableError);
}
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index 24fb673..97edf22 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -16,14 +16,14 @@
package android.graphics;
-import java.lang.ref.WeakReference;
-
import android.annotation.Nullable;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.Surface;
+import java.lang.ref.WeakReference;
+
/**
* Captures frames from an image stream as an OpenGL ES texture.
*
@@ -345,14 +345,17 @@
* Always call this method when you are done with SurfaceTexture. Failing
* to do so may delay resource deallocation for a significant amount of
* time.
+ *
+ * @see #isReleased()
*/
public void release() {
nativeRelease();
}
/**
- * Returns true if the SurfaceTexture was released
- * @hide
+ * Returns true if the SurfaceTexture was released.
+ *
+ * @see #release()
*/
public boolean isReleased() {
return nativeIsReleased();
@@ -400,7 +403,6 @@
private native void nativeReleaseTexImage();
private native int nativeDetachFromGLContext();
private native int nativeAttachToGLContext(int texName);
- private native int nativeGetQueuedCount();
private native void nativeRelease();
private native boolean nativeIsReleased();
}
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 09840a5..f661f29b 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -6664,6 +6664,10 @@
return NO_ERROR;
}
+void DynamicRefTable::addMapping(uint8_t buildPackageId, uint8_t runtimePackageId) {
+ mLookupTable[buildPackageId] = runtimePackageId;
+}
+
status_t DynamicRefTable::lookupResourceId(uint32_t* resId) const {
uint32_t res = *resId;
size_t packageId = Res_GETPACKAGE(res) + 1;
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 306ff9a..7a6e37d 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1610,6 +1610,8 @@
// the given package.
status_t addMapping(const String16& packageName, uint8_t packageId);
+ void addMapping(uint8_t buildPackageId, uint8_t runtimePackageId);
+
// Performs the actual conversion of build-time resource ID to run-time
// resource ID.
status_t lookupResourceId(uint32_t* resId) const;
diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp
index 9246237..64b2c45 100644
--- a/libs/hwui/PathTessellator.cpp
+++ b/libs/hwui/PathTessellator.cpp
@@ -1005,6 +1005,14 @@
break;
}
default:
+ static_assert(SkPath::kMove_Verb == 0
+ && SkPath::kLine_Verb == 1
+ && SkPath::kQuad_Verb == 2
+ && SkPath::kConic_Verb == 3
+ && SkPath::kCubic_Verb == 4
+ && SkPath::kClose_Verb == 5
+ && SkPath::kDone_Verb == 6,
+ "Path enum changed, new types may have been added");
break;
}
}
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 0c7bb60..dd45786 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -88,7 +88,8 @@
}; \
INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, OpenGL); \
INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaGL); \
- INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); \
+ /* Temporarily disabling Vulkan until we can figure out a way to stub out the driver */ \
+ /* INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); */ \
void test_case_name##_##test_name##_RenderThreadTest::doTheThing(renderthread::RenderThread& renderThread)
/**
@@ -111,7 +112,8 @@
static void doTheThing(renderthread::RenderThread& renderThread); \
}; \
INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaGL); \
- INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); \
+ /* Temporarily disabling Vulkan until we can figure out a way to stub out the driver */ \
+ /* INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); */ \
void test_case_name##_##test_name##_RenderThreadTest::doTheThing(renderthread::RenderThread& renderThread)
/**
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 06555c1..ccdf5ae 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -728,15 +728,15 @@
if (format == ImageFormat.PRIVATE) {
// Usage need to be either USAGE0_GPU_SAMPLED_IMAGE or USAGE0_VIDEO_ENCODE or combined.
- boolean isAllowed = (usage == HardwareBuffer.USAGE0_GPU_SAMPLED_IMAGE);
- isAllowed = isAllowed || (usage == HardwareBuffer.USAGE0_VIDEO_ENCODE);
+ boolean isAllowed = (usage == HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
+ isAllowed = isAllowed || (usage == HardwareBuffer.USAGE_VIDEO_ENCODE);
isAllowed = isAllowed || (usage ==
- (HardwareBuffer.USAGE0_VIDEO_ENCODE | HardwareBuffer.USAGE0_GPU_SAMPLED_IMAGE));
+ (HardwareBuffer.USAGE_VIDEO_ENCODE | HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE));
return isAllowed;
} else {
// Usage need to make the buffer CPU readable for explicit format.
- return ((usage == HardwareBuffer.USAGE0_CPU_READ) ||
- (usage == HardwareBuffer.USAGE0_CPU_READ_OFTEN));
+ return ((usage == HardwareBuffer.USAGE_CPU_READ_RARELY) ||
+ (usage == HardwareBuffer.USAGE_CPU_READ_OFTEN));
}
}
diff --git a/packages/CarrierDefaultApp/AndroidManifest.xml b/packages/CarrierDefaultApp/AndroidManifest.xml
index e450283..2ef1cf5 100644
--- a/packages/CarrierDefaultApp/AndroidManifest.xml
+++ b/packages/CarrierDefaultApp/AndroidManifest.xml
@@ -33,6 +33,7 @@
<receiver android:name="com.android.carrierdefaultapp.CarrierDefaultBroadcastReceiver">
<intent-filter>
<action android:name="com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED" />
+ <action android:name="com.android.internal.telephony.CARRIER_SIGNAL_RESET" />
</intent-filter>
</receiver>
<service android:name="com.android.carrierdefaultapp.ProvisionObserver"
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java
index e1125d9..d5d0b79 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java
@@ -91,6 +91,10 @@
arg1 = intent.getStringExtra(TelephonyIntents.EXTRA_APN_TYPE_KEY);
arg2 = intent.getStringExtra(TelephonyIntents.EXTRA_ERROR_CODE_KEY);
break;
+ case TelephonyIntents.ACTION_CARRIER_SIGNAL_RESET:
+ configs = b.getStringArray(CarrierConfigManager
+ .KEY_CARRIER_DEFAULT_ACTIONS_ON_RESET);
+ break;
default:
Rlog.e(TAG, "load carrier config failure with un-configured key: " +
intent.getAction());
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
index 11c858f..2a4ab0f 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -35,7 +35,7 @@
import android.bluetooth.le.ScanSettings;
import android.companion.AssociationRequest;
import android.companion.BluetoothDeviceFilter;
-import android.companion.BluetoothLEDeviceFilter;
+import android.companion.BluetoothLeDeviceFilter;
import android.companion.DeviceFilter;
import android.companion.ICompanionDeviceDiscoveryService;
import android.companion.ICompanionDeviceDiscoveryServiceCallback;
@@ -79,7 +79,7 @@
private ScanSettings mDefaultScanSettings = new ScanSettings.Builder().build();
private List<DeviceFilter<?>> mFilters;
- private List<BluetoothLEDeviceFilter> mBLEFilters;
+ private List<BluetoothLeDeviceFilter> mBLEFilters;
private List<BluetoothDeviceFilter> mBluetoothFilters;
private List<WifiDeviceFilter> mWifiFilters;
private List<ScanFilter> mBLEScanFilters;
@@ -144,8 +144,8 @@
mFilters = request.getDeviceFilters();
mWifiFilters = CollectionUtils.filter(mFilters, WifiDeviceFilter.class);
mBluetoothFilters = CollectionUtils.filter(mFilters, BluetoothDeviceFilter.class);
- mBLEFilters = CollectionUtils.filter(mFilters, BluetoothLEDeviceFilter.class);
- mBLEScanFilters = CollectionUtils.map(mBLEFilters, BluetoothLEDeviceFilter::getScanFilter);
+ mBLEFilters = CollectionUtils.filter(mFilters, BluetoothLeDeviceFilter.class);
+ mBLEScanFilters = CollectionUtils.map(mBLEFilters, BluetoothLeDeviceFilter::getScanFilter);
reset();
} else if (DEBUG) Log.i(LOG_TAG, "startDiscovery: duplicate request: " + request);
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 2f52227..1efa3a8 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -102,6 +102,9 @@
<string name="keyguard_widget_12_hours_format" translatable="false">h\uee01mm</string>
<!-- Time format strings for fall-back clock widget -->
<string name="keyguard_widget_24_hours_format" translatable="false">kk\uee01mm</string>
+ <!-- The character used in keyguard_widget_12_hours_format and keyguard_widget_24_hours_format
+ to represent a ":". -->
+ <string name="keyguard_fancy_colon" translatable="false">\uee01</string>
<!-- Accessibility description of the PIN password view. [CHAR_LIMIT=none] -->
<string name="keyguard_accessibility_pin_area">PIN area</string>
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 0c9858d..6fe00c0 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -74,8 +74,9 @@
android:orientation="horizontal">
<!-- Channel Text -->
<LinearLayout
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:layout_weight="1"
android:orientation="vertical">
<!-- Channel Name -->
<TextView
@@ -113,7 +114,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
- android:layout_weight="1"
android:contentDescription="@string/notification_channel_switch_accessibility"
android:background="@null" />
</LinearLayout>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockAccessibilityDelegate.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockAccessibilityDelegate.java
new file mode 100644
index 0000000..80509a6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockAccessibilityDelegate.java
@@ -0,0 +1,67 @@
+/*
+ * 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.keyguard;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.TextView;
+
+/**
+ * Replaces fancy colons with regular colons. Only works on TextViews.
+ */
+class KeyguardClockAccessibilityDelegate extends View.AccessibilityDelegate {
+ private final String mFancyColon;
+
+ public KeyguardClockAccessibilityDelegate(Context context) {
+ mFancyColon = context.getString(R.string.keyguard_fancy_colon);
+ }
+
+ @Override
+ public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
+ super.onInitializeAccessibilityEvent(host, event);
+ CharSequence text = event.getContentDescription();
+ if (!TextUtils.isEmpty(text)) {
+ event.setContentDescription(replaceFancyColon(text));
+ }
+ }
+
+ @Override
+ public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
+ CharSequence text = ((TextView) host).getText();
+ if (!TextUtils.isEmpty(text)) {
+ event.getText().add(replaceFancyColon(text));
+ }
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ if (!TextUtils.isEmpty(info.getText())) {
+ info.setText(replaceFancyColon(info.getText()));
+ }
+ if (!TextUtils.isEmpty(info.getContentDescription())) {
+ info.setContentDescription(replaceFancyColon(info.getContentDescription()));
+ }
+ }
+
+ private CharSequence replaceFancyColon(CharSequence text) {
+ return text.toString().replace(mFancyColon, ":");
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 162faa5..d4d69ff 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -38,7 +38,6 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.ChargingView;
-import java.util.Arrays;
import java.util.Locale;
public class KeyguardStatusView extends GridLayout {
@@ -121,6 +120,7 @@
mClockView = findViewById(R.id.clock_view);
mDateView.setShowCurrentUserTime(true);
mClockView.setShowCurrentUserTime(true);
+ mClockView.setAccessibilityDelegate(new KeyguardClockAccessibilityDelegate(mContext));
mOwnerInfo = findViewById(R.id.owner_info);
mBatteryDoze = findViewById(R.id.battery_doze);
mVisibleInDoze = new View[]{mBatteryDoze, mClockView};
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 7a6ac57..67a2989 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -197,6 +197,11 @@
private int mFingerprintRunningState = FINGERPRINT_STATE_STOPPED;
private LockPatternUtils mLockPatternUtils;
+ // If FP daemon dies, keyguard should retry after a short delay
+ private int mHardwareUnavailableRetryCount = 0;
+ private static final int HW_UNAVAILABLE_TIMEOUT = 3000; // ms
+ private static final int HW_UNAVAILABLE_RETRY_MAX = 3;
+
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -471,6 +476,15 @@
}
}
+ private Runnable mRetryFingerprintAuthentication = new Runnable() {
+ @Override
+ public void run() {
+ Log.w(TAG, "Retrying fingerprint after HW unavailable, attempt " +
+ mHardwareUnavailableRetryCount);
+ updateFingerprintListeningState();
+ }
+ };
+
private void handleFingerprintError(int msgId, String errString) {
if (msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED
&& mFingerprintRunningState == FINGERPRINT_STATE_CANCELLING_RESTARTING) {
@@ -479,6 +493,15 @@
} else {
setFingerprintRunningState(FINGERPRINT_STATE_STOPPED);
}
+
+ if (msgId == FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE) {
+ if (mHardwareUnavailableRetryCount < HW_UNAVAILABLE_RETRY_MAX) {
+ mHardwareUnavailableRetryCount++;
+ mHandler.removeCallbacks(mRetryFingerprintAuthentication);
+ mHandler.postDelayed(mRetryFingerprintAuthentication, HW_UNAVAILABLE_TIMEOUT);
+ }
+ }
+
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -940,6 +963,7 @@
}
private void handleScreenTurnedOff() {
+ mHardwareUnavailableRetryCount = 0;
final int count = mCallbacks.size();
for (int i = 0; i < count; i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -1072,6 +1096,7 @@
}
private void updateFingerprintListeningState() {
+ mHandler.removeCallbacks(mRetryFingerprintAuthentication);
boolean shouldListenForFingerprint = shouldListenForFingerprint();
if (mFingerprintRunningState == FINGERPRINT_STATE_RUNNING && !shouldListenForFingerprint) {
stopListeningForFingerprint();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index 0b4498c..802cb831 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -161,50 +161,7 @@
// If we've stopped the loader, then fall through to the above logic to wait on
// the load thread
if (ssp != null) {
- // Load the next item from the queue
- final Task t = mLoadQueue.nextTask();
- if (t != null) {
- Drawable cachedIcon = mIconCache.get(t.key);
-
- // Load the icon if it is stale or we haven't cached one yet
- if (cachedIcon == null) {
- cachedIcon = ssp.getBadgedTaskDescriptionIcon(t.taskDescription,
- t.key.userId, mContext.getResources());
-
- if (cachedIcon == null) {
- ActivityInfo info = ssp.getActivityInfo(
- t.key.getComponent(), t.key.userId);
- if (info != null) {
- if (DEBUG) Log.d(TAG, "Loading icon: " + t.key);
- cachedIcon = ssp.getBadgedActivityIcon(info, t.key.userId);
- }
- }
-
- if (cachedIcon == null) {
- cachedIcon = mDefaultIcon;
- }
-
- // At this point, even if we can't load the icon, we will set the
- // default icon.
- mIconCache.put(t.key, cachedIcon);
- }
-
- if (DEBUG) Log.d(TAG, "Loading thumbnail: " + t.key);
- ThumbnailData cachedThumbnailData = ssp.getTaskThumbnail(t.key.id,
- true /* reducedResolution */);
-
- if (cachedThumbnailData.thumbnail == null) {
- cachedThumbnailData.thumbnail = mDefaultThumbnail;
- }
-
- if (!mCancelled) {
- // Notify that the task data has changed
- final Drawable newIcon = cachedIcon;
- final ThumbnailData newThumbnailData = cachedThumbnailData;
- mMainThreadHandler.post(
- () -> t.notifyTaskDataLoaded(newThumbnailData, newIcon));
- }
- }
+ processLoadQueueItem(ssp);
}
// If there are no other items in the list, then just wait until something is added
@@ -222,6 +179,57 @@
}
}
}
+
+ /**
+ * This needs to be in a separate method to work around an surprising interpreter behavior:
+ * The register will keep the local reference to cachedThumbnailData even if it falls out of
+ * scope. Putting it into a method fixes this issue.
+ */
+ private void processLoadQueueItem(SystemServicesProxy ssp) {
+ // Load the next item from the queue
+ final Task t = mLoadQueue.nextTask();
+ if (t != null) {
+ Drawable cachedIcon = mIconCache.get(t.key);
+
+ // Load the icon if it is stale or we haven't cached one yet
+ if (cachedIcon == null) {
+ cachedIcon = ssp.getBadgedTaskDescriptionIcon(t.taskDescription,
+ t.key.userId, mContext.getResources());
+
+ if (cachedIcon == null) {
+ ActivityInfo info = ssp.getActivityInfo(
+ t.key.getComponent(), t.key.userId);
+ if (info != null) {
+ if (DEBUG) Log.d(TAG, "Loading icon: " + t.key);
+ cachedIcon = ssp.getBadgedActivityIcon(info, t.key.userId);
+ }
+ }
+
+ if (cachedIcon == null) {
+ cachedIcon = mDefaultIcon;
+ }
+
+ // At this point, even if we can't load the icon, we will set the
+ // default icon.
+ mIconCache.put(t.key, cachedIcon);
+ }
+
+ if (DEBUG) Log.d(TAG, "Loading thumbnail: " + t.key);
+ final ThumbnailData cachedThumbnailData = ssp.getTaskThumbnail(t.key.id,
+ true /* reducedResolution */);
+
+ if (cachedThumbnailData.thumbnail == null) {
+ cachedThumbnailData.thumbnail = mDefaultThumbnail;
+ }
+
+ if (!mCancelled) {
+ // Notify that the task data has changed
+ final Drawable finalIcon = cachedIcon;
+ mMainThreadHandler.post(
+ () -> t.notifyTaskDataLoaded(cachedThumbnailData, finalIcon));
+ }
+ }
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 469f3ad..d7eab97 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -172,6 +172,11 @@
private int mOverrideTint;
private float mOverrideAmount;
private boolean mShadowHidden;
+ private boolean mWasActivatedOnDown;
+ /**
+ * Similar to mDimmed but is also true if it's not dimmable but should be
+ */
+ private boolean mNeedsDimming;
public ActivatableNotificationView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -223,7 +228,7 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
- if (mDimmed && !mActivated && ev.getActionMasked() == MotionEvent.ACTION_DOWN
+ if (mNeedsDimming && !mActivated && ev.getActionMasked() == MotionEvent.ACTION_DOWN
&& disallowSingleClick(ev) && !isTouchExplorationEnabled()) {
return true;
}
@@ -245,7 +250,10 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean result;
- if (mDimmed && !isTouchExplorationEnabled() && isInteractive()) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ mWasActivatedOnDown = mActivated;
+ }
+ if ((mNeedsDimming && !mActivated) && !isTouchExplorationEnabled() && isInteractive()) {
boolean wasActivated = mActivated;
result = handleTouchEventDimmed(event);
if (wasActivated && result && event.getAction() == MotionEvent.ACTION_UP) {
@@ -282,9 +290,21 @@
}
private boolean handleTouchEventDimmed(MotionEvent event) {
+ if (mNeedsDimming && !mDimmed) {
+ // We're actually dimmed, but our content isn't dimmable, let's ensure we have a ripple
+ super.onTouchEvent(event);
+ }
return mDoubleTapHelper.onTouchEvent(event, getActualHeight());
}
+ @Override
+ public boolean performClick() {
+ if (mWasActivatedOnDown || !mNeedsDimming) {
+ return super.performClick();
+ }
+ return false;
+ }
+
private void makeActive() {
mFalsingManager.onNotificationActive();
startActivateAnimation(false /* reverse */);
@@ -298,6 +318,9 @@
if (!isAttachedToWindow()) {
return;
}
+ if (!isDimmable()) {
+ return;
+ }
int widthHalf = mBackgroundNormal.getWidth()/2;
int heightHalf = mBackgroundNormal.getActualHeight()/2;
float radius = (float) Math.sqrt(widthHalf*widthHalf + heightHalf*heightHalf);
@@ -371,6 +394,8 @@
}
public void setDimmed(boolean dimmed, boolean fade) {
+ mNeedsDimming = dimmed;
+ dimmed &= isDimmable();
if (mDimmed != dimmed) {
mDimmed = dimmed;
resetBackgroundAlpha();
@@ -382,6 +407,10 @@
}
}
+ public boolean isDimmable() {
+ return true;
+ }
+
public void setDark(boolean dark, boolean fade, long delay) {
super.setDark(dark, fade, delay);
if (mDark == dark) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index dff09bd..8c1b334 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar;
-import static com.android.systemui.statusbar.notification.NotificationInflater.InflationExceptionHandler;
+import static com.android.systemui.statusbar.notification.NotificationInflater.InflationCallback;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -47,6 +47,7 @@
import android.widget.ImageView;
import android.widget.RemoteViews;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.NotificationColorUtil;
@@ -61,7 +62,6 @@
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
import com.android.systemui.statusbar.NotificationGuts.GutsContent;
import com.android.systemui.statusbar.notification.HybridNotificationView;
-import com.android.systemui.statusbar.notification.InflationException;
import com.android.systemui.statusbar.notification.NotificationInflater;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
@@ -314,14 +314,13 @@
}
}
- public void updateNotification(NotificationData.Entry entry) throws InflationException {
+ public void updateNotification(NotificationData.Entry entry) {
mEntry = entry;
mStatusBarNotification = entry.notification;
mNotificationInflater.inflateNotificationViews();
- onNotificationUpdated();
}
- private void onNotificationUpdated() {
+ public void onNotificationUpdated() {
for (NotificationContentView l : mLayouts) {
l.onNotificationUpdated(mEntry);
}
@@ -361,6 +360,14 @@
expandedIcon.setStaticDrawableColor(color);
}
+ @Override
+ public boolean isDimmable() {
+ if (!getShowingLayout().isDimmable()) {
+ return false;
+ }
+ return super.isDimmable();
+ }
+
private void updateLimits() {
for (NotificationContentView l : mLayouts) {
updateLimitsForView(l);
@@ -482,9 +489,7 @@
boolean childInGroup = StatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
mNotificationParent = childInGroup ? parent : null;
mPrivateLayout.setIsChildInGroup(childInGroup);
- if (mNotificationInflater.setIsChildInGroup(childInGroup)) {
- onNotificationUpdated();
- }
+ mNotificationInflater.setIsChildInGroup(childInGroup);
resetBackgroundAlpha();
updateBackgroundForGroupState();
updateClickAndFocus();
@@ -1111,14 +1116,19 @@
mNotificationInflater.setRemoteViewClickHandler(remoteViewClickHandler);
}
- public void setInflateExceptionHandler(InflationExceptionHandler inflateExceptionHandler) {
- mNotificationInflater.setInflateExceptionHandler(inflateExceptionHandler);
+ public void setInflationCallback(InflationCallback callback) {
+ mNotificationInflater.setInflationCallback(callback);
}
public void setNeedsRedaction(boolean needsRedaction) {
mNotificationInflater.setRedactAmbient(needsRedaction);
}
+ @VisibleForTesting
+ public NotificationInflater getNotificationInflater() {
+ return mNotificationInflater;
+ }
+
public interface ExpansionLogger {
public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 6098565..e7bf983 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -1363,4 +1363,11 @@
public void setIsLowPriority(boolean isLowPriority) {
mIsLowPriority = isLowPriority;
}
+
+ public boolean isDimmable() {
+ if (!mContractedWrapper.isDimmable()) {
+ return false;
+ }
+ return true;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 90e908b..4d47e6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -24,6 +24,7 @@
import android.content.pm.PackageManager;
import android.content.Context;
import android.graphics.drawable.Icon;
+import android.os.AsyncTask;
import android.os.RemoteException;
import android.os.SystemClock;
import android.service.notification.NotificationListenerService;
@@ -32,6 +33,7 @@
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.view.View;
import android.widget.ImageView;
import android.widget.RemoteViews;
@@ -41,6 +43,7 @@
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.statusbar.notification.InflationException;
+import com.android.systemui.statusbar.notification.NotificationInflater;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -83,6 +86,7 @@
public List<SnoozeCriterion> snoozeCriteria;
private int mCachedContrastColor = COLOR_INVALID;
private int mCachedContrastColorIsFor = COLOR_INVALID;
+ private ArraySet<AsyncTask> mRunningTasks = new ArraySet();
public Entry(StatusBarNotification n) {
this.key = n.getKey();
@@ -210,6 +214,29 @@
mCachedContrastColor = contrasted;
return mCachedContrastColor;
}
+
+ /**
+ * Abort all existing inflation tasks
+ */
+ public void abortInflation() {
+ for (AsyncTask task : mRunningTasks) {
+ task.cancel(true /* mayInterruptIfRunning */);
+ }
+ mRunningTasks.clear();
+ }
+
+ public void addInflationTask(AsyncTask asyncInflationTask) {
+ mRunningTasks.add(asyncInflationTask);
+ }
+
+ public void onInflationTaskFinished(AsyncTask asyncInflationTask) {
+ mRunningTasks.remove(asyncInflationTask);
+ }
+
+ @VisibleForTesting
+ public ArraySet<AsyncTask> getRunningTasks() {
+ return mRunningTasks;
+ }
}
private final ArrayMap<String, Entry> mEntries = new ArrayMap<>();
@@ -302,12 +329,12 @@
return mEntries.get(key);
}
- public void add(Entry entry, RankingMap ranking) {
+ public void add(Entry entry) {
synchronized (mEntries) {
mEntries.put(entry.notification.getKey(), entry);
}
mGroupManager.onEntryAdded(entry);
- updateRankingAndSort(ranking);
+ filterAndSort();
}
public Entry remove(String key, RankingMap ranking) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageGradientColorizer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageGradientColorizer.java
new file mode 100644
index 0000000..82910b8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageGradientColorizer.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 com.android.systemui.statusbar.notification;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Shader;
+import android.graphics.Xfermode;
+import android.graphics.drawable.Drawable;
+
+/**
+ * A utility class to colorize bitmaps with a color gradient and a special blending mode
+ */
+public class ImageGradientColorizer {
+ public Bitmap colorize(Drawable drawable, int backgroundColor) {
+ int width = drawable.getIntrinsicWidth();
+ int height = drawable.getIntrinsicHeight();
+ int size = Math.min(width, height);
+ int widthInset = (width - size) / 2;
+ int heightInset = (height - size) / 2;
+ drawable = drawable.mutate();
+ drawable.setBounds(- widthInset, - heightInset, width - widthInset, height - heightInset);
+ Bitmap newBitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(newBitmap);
+
+ // Values to calculate the luminance of a color
+ float lr = 0.2126f;
+ float lg = 0.7152f;
+ float lb = 0.0722f;
+
+ // Extract the red, green, blue components of the color extraction color in
+ // float and int form
+ int tri = Color.red(backgroundColor);
+ int tgi = Color.green(backgroundColor);
+ int tbi = Color.blue(backgroundColor);
+
+ float tr = tri / 255f;
+ float tg = tgi / 255f;
+ float tb = tbi / 255f;
+
+ // Calculate the luminance of the color extraction color
+ float cLum = (tr * lr + tg * lg + tb * lb) * 255;
+
+ ColorMatrix m = new ColorMatrix(new float[] {
+ lr, lg, lb, 0, tri - cLum,
+ lr, lg, lb, 0, tgi - cLum,
+ lr, lg, lb, 0, tbi - cLum,
+ 0, 0, 0, 1, 0,
+ });
+
+ drawable.setColorFilter(new ColorMatrixColorFilter(m));
+ drawable.draw(canvas);
+ Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ LinearGradient linearGradient = new LinearGradient(0, 0, size, 0,
+ new int[] {0, Color.argb(0.5f, 1, 1, 1), Color.BLACK},
+ new float[] {0.0f, 0.4f, 1.0f}, Shader.TileMode.CLAMP);
+ paint.setShader(linearGradient);
+ Bitmap fadeIn = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+ Canvas fadeInCanvas = new Canvas(fadeIn);
+ drawable.clearColorFilter();
+ drawable.draw(fadeInCanvas);
+ paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
+ fadeInCanvas.drawPaint(paint);
+ canvas.drawBitmap(fadeIn, 0, 0, null);
+
+ linearGradient = new LinearGradient(0, 0, size, 0,
+ new int[] {backgroundColor, Color.argb(0.5f, tr, tg, tb), 0},
+ new float[] {0.0f, 0.6f, 1.0f}, Shader.TileMode.CLAMP);
+ paint.setShader(linearGradient);
+ paint.setXfermode(null);
+ canvas.drawPaint(paint);
+ return newBitmap;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
new file mode 100644
index 0000000..cef225b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
@@ -0,0 +1,259 @@
+/*
+ * 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.notification;
+
+import android.app.Notification;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.support.v4.graphics.ColorUtils;
+import android.support.v7.graphics.Palette;
+
+import com.android.systemui.R;
+
+import java.util.List;
+
+/**
+ * A class the processes media notifications and extracts the right text and background colors.
+ */
+public class MediaNotificationProcessor {
+
+ /**
+ * The fraction below which we select the vibrant instead of the light/dark vibrant color
+ */
+ private static final float POPULATION_FRACTION_FOR_MORE_VIBRANT = 0.75f;
+ private static final float POPULATION_FRACTION_FOR_WHITE_OR_BLACK = 2.5f;
+ private static final float BLACK_MAX_LIGHTNESS = 0.08f;
+ private static final float WHITE_MIN_LIGHTNESS = 0.92f;
+ private static final int RESIZE_BITMAP_AREA = 150 * 150;
+ private final ImageGradientColorizer mColorizer;
+ private final Context mContext;
+ private float[] mFilteredBackgroundHsl = null;
+ private Palette.Filter mBlackWhiteFilter = (rgb, hsl) -> !isWhiteOrBlack(hsl);
+
+ /**
+ * The context of the notification. This is the app context of the package posting the
+ * notification.
+ */
+ private final Context mPackageContext;
+ private boolean mIsLowPriority;
+
+ public MediaNotificationProcessor(Context context, Context packageContext) {
+ mContext = context;
+ mPackageContext = packageContext;
+ mColorizer = new ImageGradientColorizer();
+ }
+
+ /**
+ * Processes a builder of a media notification and calculates the appropriate colors that should
+ * be used.
+ *
+ * @param notification the notification that is being processed
+ * @param builder the recovered builder for the notification. this will be modified
+ */
+ public void processNotification(Notification notification, Notification.Builder builder) {
+ Icon largeIcon = notification.getLargeIcon();
+ Bitmap bitmap = null;
+ Drawable drawable = null;
+ if (largeIcon != null) {
+ drawable = largeIcon.loadDrawable(mPackageContext);
+ int backgroundColor = 0;
+ if (notification.isColorizedMedia()) {
+ int width = drawable.getIntrinsicWidth();
+ int height = drawable.getIntrinsicHeight();
+ int area = width * height;
+ if (area > RESIZE_BITMAP_AREA) {
+ double factor = Math.sqrt((float) RESIZE_BITMAP_AREA / area);
+ width = (int) (factor * width);
+ height = (int) (factor * height);
+ }
+ bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ drawable.setBounds(0, 0, width, height);
+ drawable.draw(canvas);
+
+ // for the background we only take the left side of the image to ensure
+ // a smooth transition
+ Palette.Builder paletteBuilder = Palette.from(bitmap)
+ .setRegion(0, 0, bitmap.getWidth() / 2, bitmap.getHeight())
+ .clearFilters() // we want all colors, red / white / black ones too!
+ .resizeBitmapArea(RESIZE_BITMAP_AREA);
+ Palette palette = paletteBuilder.generate();
+ backgroundColor = findBackgroundColorAndFilter(palette);
+ // we want the full region again
+ paletteBuilder.setRegion(0, 0, bitmap.getWidth(), bitmap.getHeight());
+ if (mFilteredBackgroundHsl != null) {
+ paletteBuilder.addFilter((rgb, hsl) -> {
+ // at least 10 degrees hue difference
+ float diff = Math.abs(hsl[0] - mFilteredBackgroundHsl[0]);
+ return diff > 10 && diff < 350;
+ });
+ }
+ paletteBuilder.addFilter(mBlackWhiteFilter);
+ palette = paletteBuilder.generate();
+ int foregroundColor;
+ if (ColorUtils.calculateLuminance(backgroundColor) > 0.5) {
+ Palette.Swatch first = palette.getDarkVibrantSwatch();
+ Palette.Swatch second = palette.getVibrantSwatch();
+ if (first != null && second != null) {
+ int firstPopulation = first.getPopulation();
+ int secondPopulation = second.getPopulation();
+ if (firstPopulation / secondPopulation
+ < POPULATION_FRACTION_FOR_MORE_VIBRANT) {
+ foregroundColor = second.getRgb();
+ } else {
+ foregroundColor = first.getRgb();
+ }
+ } else if (first != null) {
+ foregroundColor = first.getRgb();
+ } else if (second != null) {
+ foregroundColor = second.getRgb();
+ } else {
+ first = palette.getMutedSwatch();
+ second = palette.getDarkMutedSwatch();
+ if (first != null && second != null) {
+ float firstSaturation = first.getHsl()[1];
+ float secondSaturation = second.getHsl()[1];
+ if (firstSaturation > secondSaturation) {
+ foregroundColor = first.getRgb();
+ } else {
+ foregroundColor = second.getRgb();
+ }
+ } else if (first != null) {
+ foregroundColor = first.getRgb();
+ } else if (second != null) {
+ foregroundColor = second.getRgb();
+ } else {
+ foregroundColor = Color.BLACK;
+ }
+ }
+ } else {
+ Palette.Swatch first = palette.getLightVibrantSwatch();
+ Palette.Swatch second = palette.getVibrantSwatch();
+ if (first != null && second != null) {
+ int firstPopulation = first.getPopulation();
+ int secondPopulation = second.getPopulation();
+ if (firstPopulation / secondPopulation
+ < POPULATION_FRACTION_FOR_MORE_VIBRANT) {
+ foregroundColor = second.getRgb();
+ } else {
+ foregroundColor = first.getRgb();
+ }
+ } else if (first != null) {
+ foregroundColor = first.getRgb();
+ } else if (second != null) {
+ foregroundColor = second.getRgb();
+ } else {
+ first = palette.getMutedSwatch();
+ second = palette.getLightMutedSwatch();
+ if (first != null && second != null) {
+ float firstSaturation = first.getHsl()[1];
+ float secondSaturation = second.getHsl()[1];
+ if (firstSaturation > secondSaturation) {
+ foregroundColor = first.getRgb();
+ } else {
+ foregroundColor = second.getRgb();
+ }
+ } else if (first != null) {
+ foregroundColor = first.getRgb();
+ } else if (second != null) {
+ foregroundColor = second.getRgb();
+ } else {
+ foregroundColor = Color.WHITE;
+ }
+ }
+ }
+ builder.setColorPalette(backgroundColor, foregroundColor);
+ } else {
+ int id = mIsLowPriority
+ ? R.color.notification_material_background_low_priority_color
+ : R.color.notification_material_background_color;
+ backgroundColor = mContext.getColor(id);
+ }
+ Bitmap colorized = mColorizer.colorize(drawable, backgroundColor);
+ builder.setLargeIcon(Icon.createWithBitmap(colorized));
+ }
+ }
+
+ private int findBackgroundColorAndFilter(Palette palette) {
+ // by default we use the dominant palette
+ Palette.Swatch dominantSwatch = palette.getDominantSwatch();
+ if (dominantSwatch == null) {
+ // We're not filtering on white or black
+ mFilteredBackgroundHsl = null;
+ return Color.WHITE;
+ }
+
+ if (!isWhiteOrBlack(dominantSwatch.getHsl())) {
+ mFilteredBackgroundHsl = dominantSwatch.getHsl();
+ return dominantSwatch.getRgb();
+ }
+ // Oh well, we selected black or white. Lets look at the second color!
+ List<Palette.Swatch> swatches = palette.getSwatches();
+ float highestNonWhitePopulation = -1;
+ Palette.Swatch second = null;
+ for (Palette.Swatch swatch: swatches) {
+ if (swatch != dominantSwatch
+ && swatch.getPopulation() > highestNonWhitePopulation
+ && !isWhiteOrBlack(swatch.getHsl())) {
+ second = swatch;
+ highestNonWhitePopulation = swatch.getPopulation();
+ }
+ }
+ if (second == null) {
+ // We're not filtering on white or black
+ mFilteredBackgroundHsl = null;
+ return dominantSwatch.getRgb();
+ }
+ if (dominantSwatch.getPopulation() / highestNonWhitePopulation
+ > POPULATION_FRACTION_FOR_WHITE_OR_BLACK) {
+ // The dominant swatch is very dominant, lets take it!
+ // We're not filtering on white or black
+ mFilteredBackgroundHsl = null;
+ return dominantSwatch.getRgb();
+ } else {
+ mFilteredBackgroundHsl = second.getHsl();
+ return second.getRgb();
+ }
+ }
+
+ private boolean isWhiteOrBlack(float[] hsl) {
+ return isBlack(hsl) || isWhite(hsl);
+ }
+
+
+ /**
+ * @return true if the color represents a color which is close to black.
+ */
+ private boolean isBlack(float[] hslColor) {
+ return hslColor[2] <= BLACK_MAX_LIGHTNESS;
+ }
+
+ /**
+ * @return true if the color represents a color which is close to white.
+ */
+ private boolean isWhite(float[] hslColor) {
+ return hslColor[2] >= WHITE_MIN_LIGHTNESS;
+ }
+
+ public void setIsLowPriority(boolean isLowPriority) {
+ mIsLowPriority = isLowPriority;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
index 2e34f24..7cfc767 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
@@ -18,11 +18,10 @@
import android.app.Notification;
import android.content.Context;
+import android.os.AsyncTask;
import android.service.notification.StatusBarNotification;
import android.util.Log;
import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
import android.widget.RemoteViews;
import com.android.internal.annotations.VisibleForTesting;
@@ -39,7 +38,8 @@
@VisibleForTesting
static final int FLAG_REINFLATE_ALL = ~0;
private static final int FLAG_REINFLATE_CONTENT_VIEW = 1<<0;
- private static final int FLAG_REINFLATE_EXPANDED_VIEW = 1<<1;
+ @VisibleForTesting
+ static final int FLAG_REINFLATE_EXPANDED_VIEW = 1<<1;
private static final int FLAG_REINFLATE_HEADS_UP_VIEW = 1<<2;
private static final int FLAG_REINFLATE_PUBLIC_VIEW = 1<<3;
private static final int FLAG_REINFLATE_AMBIENT_VIEW = 1<<4;
@@ -50,7 +50,7 @@
private boolean mUsesIncreasedHeadsUpHeight;
private RemoteViews.OnClickHandler mRemoteViewClickHandler;
private boolean mIsChildInGroup;
- private InflationExceptionHandler mInflateExceptionHandler;
+ private InflationCallback mCallback;
private boolean mRedactAmbient;
public NotificationInflater(ExpandableNotificationRow row) {
@@ -66,21 +66,14 @@
*
* @return whether the view was re-inflated
*/
- public boolean setIsChildInGroup(boolean childInGroup) {
+ public void setIsChildInGroup(boolean childInGroup) {
if (childInGroup != mIsChildInGroup) {
mIsChildInGroup = childInGroup;
if (mIsLowPriority) {
- try {
- int flags = FLAG_REINFLATE_CONTENT_VIEW | FLAG_REINFLATE_EXPANDED_VIEW;
- inflateNotificationViews(flags);
- } catch (InflationException e) {
- mInflateExceptionHandler.handleInflationException(
- mRow.getStatusBarNotification(), e);
- }
+ int flags = FLAG_REINFLATE_CONTENT_VIEW | FLAG_REINFLATE_EXPANDED_VIEW;
+ inflateNotificationViews(flags);
}
- return true;
- }
- return false;
+ } ;
}
public void setUsesIncreasedHeight(boolean usesIncreasedHeight) {
@@ -101,39 +94,29 @@
if (mRow.getEntry() == null) {
return;
}
- try {
- inflateNotificationViews(FLAG_REINFLATE_AMBIENT_VIEW);
- } catch (InflationException e) {
- mInflateExceptionHandler.handleInflationException(
- mRow.getStatusBarNotification(), e);
- }
+ inflateNotificationViews(FLAG_REINFLATE_AMBIENT_VIEW);
}
}
- public void inflateNotificationViews() throws InflationException {
+ /**
+ * Inflate all views of this notification on a background thread. This is asynchronous and will
+ * notify the callback once it's finished.
+ */
+ public void inflateNotificationViews() {
inflateNotificationViews(FLAG_REINFLATE_ALL);
}
/**
- * reinflate all views for the specified flags
+ * Reinflate all views for the specified flags on a background thread. This is asynchronous and
+ * will notify the callback once it's finished.
+ *
* @param reInflateFlags flags which views should be reinflated. Use {@link #FLAG_REINFLATE_ALL}
* to reinflate all of views.
- * @throws InflationException
*/
- private void inflateNotificationViews(int reInflateFlags)
- throws InflationException {
+ @VisibleForTesting
+ void inflateNotificationViews(int reInflateFlags) {
StatusBarNotification sbn = mRow.getEntry().notification;
- try {
- final Notification.Builder recoveredBuilder
- = Notification.Builder.recoverBuilder(mRow.getContext(), sbn.getNotification());
- Context packageContext = sbn.getPackageContext(mRow.getContext());
- inflateNotificationViews(reInflateFlags, recoveredBuilder, packageContext);
-
- } catch (RuntimeException e) {
- final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
- Log.e(StatusBar.TAG, "couldn't inflate view for notification " + ident, e);
- throw new InflationException("Couldn't inflate contentViews");
- }
+ new AsyncInflationTask(mRow.getContext(), sbn, reInflateFlags).execute();
}
@VisibleForTesting
@@ -284,12 +267,13 @@
&& a.getLayoutId() == b.getLayoutId());
}
- public void setInflateExceptionHandler(InflationExceptionHandler inflateExceptionHandler) {
- mInflateExceptionHandler = inflateExceptionHandler;
+ public void setInflationCallback(InflationCallback callback) {
+ mCallback = callback;
}
- public interface InflationExceptionHandler {
+ public interface InflationCallback {
void handleInflationException(StatusBarNotification notification, InflationException e);
+ void onAsyncInflationFinished(NotificationData.Entry entry);
}
public void onDensityOrFontScaleChanged() {
@@ -299,12 +283,75 @@
entry.cachedContentView = null;
entry.cachedHeadsUpContentView = null;
entry.cachedPublicContentView = null;
- try {
- inflateNotificationViews();
- } catch (InflationException e) {
- mInflateExceptionHandler.handleInflationException(
- mRow.getStatusBarNotification(), e);
+ inflateNotificationViews();
+ }
+
+ private class AsyncInflationTask extends AsyncTask<Void, Void, Notification.Builder> {
+
+ private final StatusBarNotification mSbn;
+ private final Context mContext;
+ private final int mReInflateFlags;
+ private Context mPackageContext = null;
+ private Exception mError;
+
+ private AsyncInflationTask(Context context, StatusBarNotification notification,
+ int reInflateFlags) {
+ mSbn = notification;
+ mContext = context;
+ mReInflateFlags = reInflateFlags;
+ mRow.getEntry().addInflationTask(this);
+ }
+
+ @Override
+ protected Notification.Builder doInBackground(Void... params) {
+ try {
+ final Notification.Builder recoveredBuilder
+ = Notification.Builder.recoverBuilder(mContext,
+ mSbn.getNotification());
+ mPackageContext = mSbn.getPackageContext(mContext);
+ Notification notification = mSbn.getNotification();
+ if (notification.isMediaNotification()) {
+ MediaNotificationProcessor processor = new MediaNotificationProcessor(mContext,
+ mPackageContext);
+ processor.setIsLowPriority(mIsLowPriority);
+ processor.processNotification(notification, recoveredBuilder);
+ }
+ return recoveredBuilder;
+ } catch (Exception e) {
+ mError = e;
+ return null;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Notification.Builder builder) {
+ mRow.getEntry().onInflationTaskFinished(this);
+ if (mError == null) {
+ finishInflation(mReInflateFlags, builder, mPackageContext);
+ } else {
+ handleError(mError);
+ }
}
}
+ private void finishInflation(int reinflationFlags, Notification.Builder builder,
+ Context context) {
+ try {
+ inflateNotificationViews(reinflationFlags, builder, context);
+ } catch (RuntimeException e){
+ handleError(e);
+ return;
+ }
+ mRow.onNotificationUpdated();
+ mCallback.onAsyncInflationFinished(mRow.getEntry());
+ }
+
+ private void handleError(Exception e) {
+ StatusBarNotification sbn = mRow.getStatusBarNotification();
+ final String ident = sbn.getPackageName() + "/0x"
+ + Integer.toHexString(sbn.getId());
+ Log.e(StatusBar.TAG, "couldn't inflate view for notification " + ident, e);
+ mCallback.handleInflationException(sbn,
+ new InflationException("Couldn't inflate contentViews" + e));
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
index ef5a25c..8596cb3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
@@ -56,4 +56,9 @@
mActions);
}
}
+
+ @Override
+ public boolean isDimmable() {
+ return false;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index f4db9a1..5cc39cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -178,4 +178,8 @@
public void setIsChildInGroup(boolean isChildInGroup) {
}
+
+ public boolean isDimmable() {
+ return true;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 46d6415..c1859fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -22,7 +22,7 @@
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.windowStateToString;
-import static com.android.systemui.statusbar.notification.NotificationInflater.InflationExceptionHandler;
+import static com.android.systemui.statusbar.notification.NotificationInflater.InflationCallback;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
@@ -257,7 +257,7 @@
OnHeadsUpChangedListener, VisualStabilityManager.Callback, CommandQueue.Callbacks,
ActivatableNotificationView.OnActivatedListener,
ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment,
- ExpandableNotificationRow.OnExpandClickListener {
+ ExpandableNotificationRow.OnExpandClickListener, InflationCallback {
public static final boolean MULTIUSER_DEBUG = false;
public static final boolean ENABLE_REMOTE_INPUT =
@@ -713,8 +713,8 @@
private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
private NotificationIconAreaController mNotificationIconAreaController;
private ConfigurationListener mConfigurationListener;
- private InflationExceptionHandler mInflationExceptionHandler = this::handleInflationException;
private boolean mReinflateNotificationsOnUserSwitched;
+ private HashMap<String, Entry> mPendingNotifications = new HashMap<>();
private void recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array) {
final int N = array.size();
@@ -1544,29 +1544,24 @@
return new UserHandle(mCurrentUserId);
}
- public void addNotification(StatusBarNotification notification, RankingMap ranking,
- Entry oldEntry) throws InflationException {
- if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey());
+ public void addNotification(StatusBarNotification notification, RankingMap ranking)
+ throws InflationException {
+ String key = notification.getKey();
+ if (DEBUG) Log.d(TAG, "addNotification key=" + key);
mNotificationData.updateRanking(ranking);
Entry shadeEntry = createNotificationViews(notification);
boolean isHeadsUped = shouldPeek(shadeEntry);
- if (isHeadsUped) {
- mHeadsUpManager.showNotification(shadeEntry);
- // Mark as seen immediately
- setNotificationShown(notification);
- }
-
if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) {
- if (shouldSuppressFullScreenIntent(notification.getKey())) {
+ if (shouldSuppressFullScreenIntent(key)) {
if (DEBUG) {
- Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + notification.getKey());
+ Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + key);
}
- } else if (mNotificationData.getImportance(notification.getKey())
+ } else if (mNotificationData.getImportance(key)
< NotificationManager.IMPORTANCE_HIGH) {
if (DEBUG) {
Log.d(TAG, "No Fullscreen intent: not important enough: "
- + notification.getKey());
+ + key);
}
} else {
// Stop screensaver if the notification has a full-screen intent.
@@ -1578,7 +1573,7 @@
Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
try {
EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
- notification.getKey());
+ key);
notification.getNotification().fullScreenIntent.send();
shadeEntry.notifyFullScreenIntentLaunched();
mMetricsLogger.count("note_fullscreen", 1);
@@ -1586,15 +1581,47 @@
}
}
}
- addNotificationViews(shadeEntry, ranking);
+ abortExistingInflation(key);
+ mPendingNotifications.put(key, shadeEntry);
+ }
+
+ private void abortExistingInflation(String key) {
+ if (mPendingNotifications.containsKey(key)) {
+ Entry entry = mPendingNotifications.get(key);
+ entry.abortInflation();
+ mPendingNotifications.remove(key);
+ }
+ Entry addedEntry = mNotificationData.get(key);
+ if (addedEntry != null) {
+ addedEntry.abortInflation();
+ }
+ }
+
+ private void addEntry(Entry shadeEntry) {
+ boolean isHeadsUped = shouldPeek(shadeEntry);
+ if (isHeadsUped) {
+ mHeadsUpManager.showNotification(shadeEntry);
+ // Mark as seen immediately
+ setNotificationShown(shadeEntry.notification);
+ }
+ addNotificationViews(shadeEntry);
// Recalculate the position of the sliding windows and the titles.
setAreThereNotifications();
}
+ @Override
public void handleInflationException(StatusBarNotification notification, InflationException e) {
handleNotificationError(notification, e.getMessage());
}
+ @Override
+ public void onAsyncInflationFinished(Entry entry) {
+ mPendingNotifications.remove(entry.key);
+ if (mNotificationData.get(entry.key) == null) {
+ addEntry(entry);
+ }
+ }
+
private boolean shouldSuppressFullScreenIntent(String key) {
if (isDeviceInVrMode()) {
return true;
@@ -1614,6 +1641,7 @@
public void removeNotification(String key, RankingMap ranking) {
boolean deferRemoval = false;
+ abortExistingInflation(key);
if (mHeadsUpManager.isHeadsUp(key)) {
// A cancel() in repsonse to a remote input shouldn't be delayed, as it makes the
// sending look longer than it takes.
@@ -3295,6 +3323,14 @@
+ " scroll " + mStackScroller.getScrollX()
+ "," + mStackScroller.getScrollY());
}
+ pw.print(" mPendingNotifications=");
+ if (mPendingNotifications.size() == 0) {
+ pw.println("null");
+ } else {
+ for (Entry entry : mPendingNotifications.values()) {
+ pw.println(entry.notification);
+ }
+ }
pw.print(" mInteractingWindows="); pw.println(mInteractingWindows);
pw.print(" mStatusBarWindowState=");
@@ -5531,7 +5567,7 @@
public void run() {
for (StatusBarNotification sbn : notifications) {
try {
- addNotification(sbn, currentRanking, null /* oldEntry */);
+ addNotification(sbn, currentRanking);
} catch (InflationException e) {
handleInflationException(sbn, e);
}
@@ -5574,7 +5610,7 @@
if (isUpdate) {
updateNotification(sbn, rankingMap);
} else {
- addNotification(sbn, rankingMap, null /* oldEntry */);
+ addNotification(sbn, rankingMap);
}
} catch (InflationException e) {
handleInflationException(sbn, e);
@@ -6132,8 +6168,7 @@
}
}
- protected void inflateViews(Entry entry, ViewGroup parent) throws
- InflationException {
+ protected void inflateViews(Entry entry, ViewGroup parent) {
PackageManager pmUser = getPackageManagerForUser(mContext,
entry.notification.getUser().getIdentifier());
@@ -6154,7 +6189,7 @@
row.setRemoteInputController(mRemoteInputController);
row.setOnExpandClickListener(this);
row.setRemoteViewClickHandler(mOnClickHandler);
- row.setInflateExceptionHandler(mInflationExceptionHandler);
+ row.setInflationCallback(this);
// Get the app name.
// Note that Notification.Builder#bindHeaderAppName has similar logic
@@ -6552,12 +6587,12 @@
return entry;
}
- protected void addNotificationViews(Entry entry, RankingMap ranking) {
+ protected void addNotificationViews(Entry entry) {
if (entry == null) {
return;
}
// Add the expanded view and icon.
- mNotificationData.add(entry, ranking);
+ mNotificationData.add(entry);
updateNotifications();
}
@@ -6675,6 +6710,7 @@
if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
final String key = notification.getKey();
+ abortExistingInflation(key);
Entry entry = mNotificationData.get(key);
if (entry == null) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/util/Assert.java b/packages/SystemUI/src/com/android/systemui/util/Assert.java
index af447f3..0f7c9a4 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Assert.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Assert.java
@@ -28,4 +28,10 @@
throw new IllegalStateException("should be called from the main thread.");
}
}
+
+ public static void isNotMainThread() {
+ if (Looper.getMainLooper().isCurrentThread()) {
+ throw new IllegalStateException("should not be called from the main thread.");
+ }
+ }
}
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 8eedf31..5e8b3f9 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -42,6 +42,7 @@
android-support-v7-preference \
android-support-v7-appcompat \
android-support-v7-mediarouter \
+ android-support-v7-palette \
android-support-v14-preference \
android-support-v17-leanback
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockAccessibilityDelegateTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockAccessibilityDelegateTest.java
new file mode 100644
index 0000000..1c9f813
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockAccessibilityDelegateTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.keyguard;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.text.TextUtils;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.TextView;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.List;
+
+public class KeyguardClockAccessibilityDelegateTest {
+
+ private Context mContext;
+ private TextView mView;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getContext();
+ mView = new TextView(mContext);
+ mView.setText(R.string.keyguard_widget_12_hours_format);
+ mView.setContentDescription(mContext.getString(R.string.keyguard_widget_12_hours_format));
+ mView.setAccessibilityDelegate(new KeyguardClockAccessibilityDelegate(mContext));
+ }
+
+ @Test
+ public void onInitializeAccessibilityEvent_producesNonEmptyAsciiContentDesc() throws Exception {
+ AccessibilityEvent ev = AccessibilityEvent.obtain();
+ mView.onInitializeAccessibilityEvent(ev);
+
+ assertFalse(TextUtils.isEmpty(ev.getContentDescription()));
+ assertTrue(isAscii(ev.getContentDescription()));
+ }
+
+ @Test
+ public void onPopulateAccessibilityEvent_producesNonEmptyAsciiText() throws Exception {
+ AccessibilityEvent ev = AccessibilityEvent.obtain();
+ mView.onPopulateAccessibilityEvent(ev);
+
+ assertFalse(isEmpty(ev.getText()));
+ assertTrue(isAscii(ev.getText()));
+ }
+
+ @Test
+ public void onInitializeAccessibilityNodeInfo_producesNonEmptyAsciiText() throws Exception {
+ AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+ // Usually done in View.onInitializeAccessibilityNodeInfoInternal, but only when attached.
+ info.setContentDescription(mView.getContentDescription());
+ mView.onInitializeAccessibilityNodeInfo(info);
+
+ assertFalse(TextUtils.isEmpty(info.getText()));
+ assertTrue(isAscii(info.getText()));
+
+ assertFalse(TextUtils.isEmpty(info.getContentDescription()));
+ assertTrue(isAscii(info.getContentDescription()));
+ }
+
+ private boolean isAscii(CharSequence text) {
+ return text.chars().allMatch((i) -> i < 128);
+ }
+
+ private boolean isAscii(List<CharSequence> texts) {
+ return texts.stream().allMatch(this::isAscii);
+ }
+
+ private boolean isEmpty(List<CharSequence> texts) {
+ return texts.stream().allMatch(TextUtils::isEmpty);
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java
index 1b5d4a4..aa840989 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java
@@ -43,12 +43,13 @@
private ExpandHelper.Callback mCallback;
@Before
- @UiThreadTest
- public void setUp() {
+ public void setUp() throws Exception {
Context context = getContext();
mRow = new NotificationTestHelper(context).createRow();
mCallback = mock(ExpandHelper.Callback.class);
- mExpandHelper = new ExpandHelper(context, mCallback, 10, 100);
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(
+ () -> mExpandHelper = new ExpandHelper(context, mCallback, 10, 100));
+
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
index 3db2440..5cd092b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
@@ -39,8 +39,7 @@
private NotificationTestHelper mNotificationTestHelper;
@Before
- @UiThreadTest
- public void setUp() {
+ public void setUp() throws Exception {
mContext = InstrumentationRegistry.getTargetContext();
mNotificationTestHelper = new NotificationTestHelper(mContext);
mGroup = mNotificationTestHelper.createGroup();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index c91b269..cb238dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -17,15 +17,18 @@
package com.android.systemui.statusbar;
import android.app.ActivityManager;
+import android.app.Instrumentation;
import android.app.Notification;
import android.content.Context;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
+import android.support.test.InstrumentationRegistry;
import android.view.LayoutInflater;
import android.widget.RemoteViews;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.InflationException;
+import com.android.systemui.statusbar.notification.NotificationInflaterTest;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
/**
@@ -34,14 +37,18 @@
public class NotificationTestHelper {
private final Context mContext;
+ private final Instrumentation mInstrumentation;
private int mId;
private final NotificationGroupManager mGroupManager = new NotificationGroupManager();
+ private ExpandableNotificationRow mRow;
+ private InflationException mException;
public NotificationTestHelper(Context context) {
mContext = context;
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
}
- public ExpandableNotificationRow createRow() {
+ public ExpandableNotificationRow createRow() throws Exception {
Notification publicVersion = new Notification.Builder(mContext).setSmallIcon(
R.drawable.ic_person)
.setCustomContentView(new RemoteViews(mContext.getPackageName(),
@@ -56,12 +63,15 @@
return createRow(notification);
}
- public ExpandableNotificationRow createRow(Notification notification) {
+ public ExpandableNotificationRow createRow(Notification notification) throws Exception {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
mContext.LAYOUT_INFLATER_SERVICE);
- ExpandableNotificationRow row = (ExpandableNotificationRow) inflater.inflate(
- R.layout.status_bar_notification_row,
- null, false);
+ mInstrumentation.runOnMainSync(() -> {
+ mRow = (ExpandableNotificationRow) inflater.inflate(
+ R.layout.status_bar_notification_row,
+ null, false);
+ });
+ ExpandableNotificationRow row = mRow;
row.setGroupManager(mGroupManager);
UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
StatusBarNotification sbn = new StatusBarNotification("com.android.systemui",
@@ -69,16 +79,13 @@
2000, notification, mUser, null, System.currentTimeMillis());
NotificationData.Entry entry = new NotificationData.Entry(sbn);
entry.row = row;
- try {
- entry.createIcons(mContext, sbn);
- row.updateNotification(entry);
- } catch (InflationException e) {
- throw new RuntimeException(e.getMessage());
- }
+ entry.createIcons(mContext, sbn);
+ NotificationInflaterTest.runThenWaitForInflation(() -> row.updateNotification(entry),
+ row.getNotificationInflater());
return row;
}
- public ExpandableNotificationRow createGroup() {
+ public ExpandableNotificationRow createGroup() throws Exception {
ExpandableNotificationRow row = createRow();
row.addChildNotification(createRow());
row.addChildNotification(createRow());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java
new file mode 100644
index 0000000..fbb25e5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java
@@ -0,0 +1,176 @@
+/*
+ * 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.notification;
+
+import static com.android.systemui.statusbar.notification.NotificationInflater.FLAG_REINFLATE_ALL;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.Notification;
+import android.content.Context;
+import android.service.notification.StatusBarNotification;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.widget.RemoteViews;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.NotificationTestHelper;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.function.Function;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NotificationInflaterTest {
+
+ private Context mContext;
+ private NotificationInflater mNotificationInflater;
+ private Notification.Builder mBuilder;
+ private ExpandableNotificationRow mRow;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mBuilder = new Notification.Builder(mContext).setSmallIcon(
+ R.drawable.ic_person)
+ .setContentTitle("Title")
+ .setContentText("Text")
+ .setStyle(new Notification.BigTextStyle().bigText("big text"));
+ ExpandableNotificationRow row = new NotificationTestHelper(mContext).createRow(
+ mBuilder.build());
+ mRow = spy(row);
+ mNotificationInflater = new NotificationInflater(mRow);
+ mNotificationInflater.setInflationCallback(new NotificationInflater.InflationCallback() {
+ @Override
+ public void handleInflationException(StatusBarNotification notification,
+ InflationException e) {
+ }
+
+ @Override
+ public void onAsyncInflationFinished(NotificationData.Entry entry) {
+ }
+ });
+ }
+
+ @Test
+ public void testIncreasedHeadsUpBeingUsed() {
+ mNotificationInflater.setUsesIncreasedHeadsUpHeight(true);
+ Notification.Builder builder = spy(mBuilder);
+ mNotificationInflater.inflateNotificationViews(FLAG_REINFLATE_ALL, builder, mContext);
+ verify(builder).createHeadsUpContentView(true);
+ }
+
+ @Test
+ public void testIncreasedHeightBeingUsed() {
+ mNotificationInflater.setUsesIncreasedHeight(true);
+ Notification.Builder builder = spy(mBuilder);
+ mNotificationInflater.inflateNotificationViews(FLAG_REINFLATE_ALL, builder, mContext);
+ verify(builder).createContentView(true);
+ }
+
+ @Test
+ public void testInflationCallsUpdated() throws Exception {
+ runThenWaitForInflation(() -> mNotificationInflater.inflateNotificationViews(),
+ mNotificationInflater);
+ verify(mRow).onNotificationUpdated();
+ }
+
+ @Test
+ public void testInflationCallsOnlyRightMethod() throws Exception {
+ mRow.getPrivateLayout().removeAllViews();
+ mRow.getEntry().cachedBigContentView = null;
+ runThenWaitForInflation(() -> mNotificationInflater.inflateNotificationViews(
+ NotificationInflater.FLAG_REINFLATE_EXPANDED_VIEW), mNotificationInflater);
+ Assert.assertTrue(mRow.getPrivateLayout().getChildCount() == 1);
+ Assert.assertTrue(mRow.getPrivateLayout().getChildAt(0)
+ == mRow.getPrivateLayout().getExpandedChild());
+ verify(mRow).onNotificationUpdated();
+ }
+
+ @Test
+ public void testInflationThrowsErrorDoesntCallUpdated() throws Exception {
+ mRow.getPrivateLayout().removeAllViews();
+ mRow.getStatusBarNotification().getNotification().contentView
+ = new RemoteViews(mContext.getPackageName(), R.layout.status_bar);
+ runThenWaitForInflation(() -> mNotificationInflater.inflateNotificationViews(),
+ true /* expectingException */, mNotificationInflater);
+ Assert.assertTrue(mRow.getPrivateLayout().getChildCount() == 0);
+ verify(mRow, times(0)).onNotificationUpdated();
+ }
+
+ @Test
+ public void testAsyncTaskRemoved() throws Exception {
+ mRow.getEntry().abortInflation();
+ runThenWaitForInflation(() -> mNotificationInflater.inflateNotificationViews(),
+ mNotificationInflater);
+ Assert.assertTrue(mRow.getEntry().getRunningTasks().size() == 0);
+ }
+
+ public static void runThenWaitForInflation(Runnable block,
+ NotificationInflater inflater) throws Exception {
+ runThenWaitForInflation(block, false /* expectingException */, inflater);
+ }
+
+ private static void runThenWaitForInflation(Runnable block, boolean expectingException,
+ NotificationInflater inflater) throws Exception {
+ com.android.systemui.util.Assert.isNotMainThread();
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+ final ExceptionHolder exceptionHolder = new ExceptionHolder();
+ inflater.setInflationCallback(new NotificationInflater.InflationCallback() {
+ @Override
+ public void handleInflationException(StatusBarNotification notification,
+ InflationException e) {
+ if (!expectingException) {
+ exceptionHolder.setException(e);
+ }
+ countDownLatch.countDown();
+ }
+
+ @Override
+ public void onAsyncInflationFinished(NotificationData.Entry entry) {
+ if (expectingException) {
+ exceptionHolder.setException(new RuntimeException(
+ "Inflation finished even though there should be an error"));
+ }
+ countDownLatch.countDown();
+ }
+ });
+ block.run();
+ countDownLatch.await(5, java.util.concurrent.TimeUnit.SECONDS);
+ if (exceptionHolder.mException != null) {
+ throw exceptionHolder.mException;
+ }
+ }
+
+ private static class ExceptionHolder {
+ private Exception mException;
+
+ public void setException(Exception exception) {
+ mException = exception;
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationinflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationinflaterTest.java
deleted file mode 100644
index 0ec9c10..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationinflaterTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.notification;
-
-import static com.android.systemui.statusbar.notification.NotificationInflater.FLAG_REINFLATE_ALL;
-
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-import android.app.Notification;
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import com.android.systemui.R;
-import com.android.systemui.statusbar.ExpandableNotificationRow;
-import com.android.systemui.statusbar.NotificationTestHelper;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class NotificationinflaterTest {
-
- private Context mContext;
- private NotificationInflater mNotificationInflater;
- private Notification.Builder mBuilder;
-
- @Before
- @UiThreadTest
- public void setUp() {
- mContext = InstrumentationRegistry.getTargetContext();
- mBuilder = new Notification.Builder(mContext).setSmallIcon(
- R.drawable.ic_person)
- .setContentTitle("Title")
- .setContentText("Text");
- ExpandableNotificationRow row = new NotificationTestHelper(mContext).createRow(
- mBuilder.build());
- mNotificationInflater = new NotificationInflater(row);
- }
-
- @Test
- public void testIncreasedHeadsUpBeingUsed() {
- mNotificationInflater.setUsesIncreasedHeadsUpHeight(true);
- Notification.Builder builder = spy(mBuilder);
- mNotificationInflater.inflateNotificationViews(FLAG_REINFLATE_ALL, builder, mContext);
- verify(builder).createHeadsUpContentView(true);
- }
-
- @Test
- public void testIncreasedHeightBeingUsed() {
- mNotificationInflater.setUsesIncreasedHeight(true);
- Notification.Builder builder = spy(mBuilder);
- mNotificationInflater.inflateNotificationViews(FLAG_REINFLATE_ALL, builder, mContext);
- verify(builder).createContentView(true);
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationChildrenContainerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationChildrenContainerTest.java
index dbe0de4..f051f30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationChildrenContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationChildrenContainerTest.java
@@ -42,8 +42,7 @@
private NotificationTestHelper mNotificationTestHelper;
@Before
- @UiThreadTest
- public void setUp() {
+ public void setUp() throws Exception {
mContext = InstrumentationRegistry.getTargetContext();
mNotificationTestHelper = new NotificationTestHelper(mContext);
mGroup = mNotificationTestHelper.createGroup();
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index dc082e1..cc6e435 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3636,7 +3636,7 @@
// OS: N
ACTION_GET_CONTACT = 864;
- // This values should never appear in log outputs - it is reserved for
+ // This value should never appear in log outputs - it is reserved for
// internal platform metrics use.
RESERVED_FOR_LOGBUILDER_PID = 865;
@@ -3948,6 +3948,10 @@
// OS: O
NOTIFICATION_CHANNEL_LOCK_SCREEN_VIS = 942;
+ // This value should never appear in log outputs - it is reserved for
+ // internal platform metrics use.
+ RESERVED_FOR_LOGBUILDER_UID = 943;
+
// ---- End O Constants, all O constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index f61edc5..6b84c5f 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -19,14 +19,13 @@
import static android.Manifest.permission.MANAGE_AUTO_FILL;
import static android.content.Context.AUTOFILL_MANAGER_SERVICE;
-import static com.android.server.autofill.Helper.DEBUG;
-import static com.android.server.autofill.Helper.VERBOSE;
+import static com.android.server.autofill.Helper.sDebug;
+import static com.android.server.autofill.Helper.sVerbose;
import static com.android.server.autofill.Helper.bundleToString;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
-import android.app.ActivityManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -39,6 +38,7 @@
import android.graphics.Rect;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -50,13 +50,12 @@
import android.os.UserManagerInternal;
import android.provider.Settings;
import android.service.autofill.FillEventHistory;
-import android.text.TextUtils;
import android.util.LocalLog;
-import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
import android.view.autofill.IAutoFillManager;
import android.view.autofill.IAutoFillManagerClient;
@@ -118,10 +117,6 @@
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
- final String reason = intent.getStringExtra("reason");
- if (VERBOSE) {
- Slog.v(TAG, "close system dialogs: " + reason);
- }
mUi.hideAll();
}
}
@@ -132,6 +127,10 @@
mContext = context;
mUi = new AutoFillUI(mContext);
+ final boolean debug = Build.IS_DEBUGGABLE;
+ Slog.i(TAG, "Setting debug to " + debug);
+ setDebugLocked(debug);
+
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
mContext.registerReceiver(mBroadcastReceiver, filter, null, FgThread.getHandler());
@@ -154,7 +153,7 @@
final boolean disabledBefore = mDisabledUsers.get(userId);
if (disabledBefore == disabledNow) {
// Nothing changed, do nothing.
- if (DEBUG) {
+ if (sDebug) {
Slog.d(TAG, "Restriction not changed for user " + userId + ": "
+ bundleToString(newRestrictions));
return;
@@ -368,6 +367,42 @@
}
}
+ // Called by Shell command.
+ void setLogLevel(int level) {
+ Slog.i(TAG, "setLogLevel(): " + level);
+ boolean debug = false;
+ boolean verbose = false;
+ if (level == AutofillManager.FLAG_ADD_CLIENT_VERBOSE) {
+ debug = verbose = true;
+ } else if (level == AutofillManager.FLAG_ADD_CLIENT_DEBUG) {
+ debug = true;
+ }
+ synchronized (mLock) {
+ setDebugLocked(debug);
+ setVerboseLocked(verbose);
+ }
+ }
+
+ // Called by Shell command.
+ int getLogLevel() {
+ synchronized (mLock) {
+ if (sVerbose) return AutofillManager.FLAG_ADD_CLIENT_VERBOSE;
+ if (sDebug) return AutofillManager.FLAG_ADD_CLIENT_DEBUG;
+ return 0;
+ }
+ }
+
+ private void setDebugLocked(boolean debug) {
+ com.android.server.autofill.Helper.sDebug = debug;
+ android.view.autofill.Helper.sDebug = debug;
+ }
+
+
+ private void setVerboseLocked(boolean verbose) {
+ com.android.server.autofill.Helper.sVerbose = verbose;
+ android.view.autofill.Helper.sVerbose = verbose;
+ }
+
/**
* Removes a cached service for a given user.
*/
@@ -390,7 +425,7 @@
* Updates a cached service for a given user.
*/
private void updateCachedServiceLocked(int userId, boolean disabled) {
- AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+ AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
if (service != null) {
service.updateLocked(disabled);
if (!service.isEnabled()) {
@@ -399,24 +434,21 @@
}
}
- private IBinder getTopActivityForUser() {
- final List<IBinder> topActivities = LocalServices
- .getService(ActivityManagerInternal.class).getTopVisibleActivities();
- if (VERBOSE) {
- Slog.v(TAG, "Top activities (" + topActivities.size() + "): " + topActivities);
- }
- if (topActivities.isEmpty()) {
- Slog.w(TAG, "Could not get top activity");
- return null;
- }
- return topActivities.get(0);
- }
-
final class AutoFillManagerServiceStub extends IAutoFillManager.Stub {
@Override
- public boolean addClient(IAutoFillManagerClient client, int userId) {
+ public int addClient(IAutoFillManagerClient client, int userId) {
synchronized (mLock) {
- return getServiceForUserLocked(userId).addClientLocked(client);
+ int flags = 0;
+ if (getServiceForUserLocked(userId).addClientLocked(client)) {
+ flags |= AutofillManager.FLAG_ADD_CLIENT_ENABLED;
+ }
+ if (sDebug) {
+ flags |= AutofillManager.FLAG_ADD_CLIENT_DEBUG;
+ }
+ if (sVerbose) {
+ flags |= AutofillManager.FLAG_ADD_CLIENT_VERBOSE;
+ }
+ return flags;
}
}
@@ -509,12 +541,12 @@
@Override
public void updateSession(int sessionId, AutofillId id, Rect bounds,
- AutofillValue value, int flags, int userId) {
+ AutofillValue value, int action, int flags, int userId) {
synchronized (mLock) {
final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
if (service != null) {
service.updateSessionLocked(sessionId, getCallingUid(), id, bounds, value,
- flags);
+ action, flags);
}
}
}
@@ -568,24 +600,38 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- synchronized (mLock) {
- pw.print("Disabled users: "); pw.println(mDisabledUsers);
- final int size = mServicesCache.size();
- pw.print("Cached services: ");
- if (size == 0) {
- pw.println("none");
- } else {
- pw.println(size);
- for (int i = 0; i < size; i++) {
- pw.print("\nService at index "); pw.println(i);
- final AutofillManagerServiceImpl impl = mServicesCache.valueAt(i);
- impl.dumpLocked(" ", pw);
+
+ boolean oldDebug = sDebug;
+ boolean oldVerbose = sVerbose;
+ try {
+ synchronized (mLock) {
+ oldDebug = sDebug;
+ oldVerbose = sVerbose;
+ setDebugLocked(true);
+ setVerboseLocked(true);
+ pw.print("Debug mode: "); pw.println(oldDebug);
+ pw.print("Verbose mode: "); pw.println(oldVerbose);
+ pw.print("Disabled users: "); pw.println(mDisabledUsers);
+ final int size = mServicesCache.size();
+ pw.print("Cached services: ");
+ if (size == 0) {
+ pw.println("none");
+ } else {
+ pw.println(size);
+ for (int i = 0; i < size; i++) {
+ pw.print("\nService at index "); pw.println(i);
+ final AutofillManagerServiceImpl impl = mServicesCache.valueAt(i);
+ impl.dumpLocked(" ", pw);
+ }
}
+ mUi.dump(pw);
}
- mUi.dump(pw);
+ pw.println("Requests history:");
+ mRequestsHistory.reverseDump(fd, pw, args);
+ } finally {
+ setDebugLocked(oldDebug);
+ setVerboseLocked(oldVerbose);
}
- pw.println("Requests history:");
- mRequestsHistory.reverseDump(fd, pw, args);
}
@Override
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 44a296e..4507eae 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -16,11 +16,10 @@
package com.android.server.autofill;
-import static android.view.autofill.AutofillManager.FLAG_START_SESSION;
+import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
import static android.view.autofill.AutofillManager.NO_SESSION;
-import static com.android.server.autofill.Helper.DEBUG;
-import static com.android.server.autofill.Helper.VERBOSE;
+import static com.android.server.autofill.Helper.sVerbose;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -48,12 +47,9 @@
import android.service.autofill.IAutoFillService;
import android.text.TextUtils;
import android.util.LocalLog;
-import android.util.Log;
-import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.SparseArray;
import android.view.autofill.AutofillId;
-import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
import android.view.autofill.IAutoFillManagerClient;
@@ -271,14 +267,14 @@
}
final String historyItem =
- "id=" + newSession.getId() + " uid=" + uid + " s=" + mInfo.getServiceInfo().packageName
+ "id=" + newSession.id + " uid=" + uid + " s=" + mInfo.getServiceInfo().packageName
+ " u=" + mUserId + " i=" + autofillId + " b=" + virtualBounds + " hc=" +
hasCallback + " f=" + flags;
mRequestsHistory.log(historyItem);
- newSession.updateLocked(autofillId, virtualBounds, value, FLAG_START_SESSION);
+ newSession.updateLocked(autofillId, virtualBounds, value, ACTION_START_SESSION, flags);
- return newSession.getId();
+ return newSession.id;
}
void finishSessionLocked(int sessionId, int uid) {
@@ -288,14 +284,15 @@
final Session session = mSessions.get(sessionId);
if (session == null || uid != session.uid) {
- Slog.w(TAG, "finishSessionLocked(): no session for " + sessionId + "(" + uid + ")");
+ if (sVerbose) {
+ Slog.v(TAG, "finishSessionLocked(): no session for " + sessionId + "(" + uid + ")");
+ }
return;
}
final boolean finished = session.showSaveLocked();
- if (DEBUG) {
- Log.d(TAG, "finishSessionLocked(): session finished on save? " + finished);
- }
+ if (sVerbose) Slog.v(TAG, "finishSessionLocked(): session finished on save? " + finished);
+
if (finished) {
session.removeSelfLocked();
}
@@ -342,7 +339,7 @@
do {
tries++;
if (tries > MAX_SESSION_ID_CREATE_TRIES) {
- Log.w(TAG, "Cannot create session in " + MAX_SESSION_ID_CREATE_TRIES + " tries");
+ Slog.w(TAG, "Cannot create session in " + MAX_SESSION_ID_CREATE_TRIES + " tries");
return null;
}
@@ -350,9 +347,9 @@
} while (sessionId == NO_SESSION || mSessions.indexOfKey(sessionId) >= 0);
final Session newSession = new Session(this, mUi, mContext, mHandlerCaller, mUserId, mLock,
- sessionId, uid, activityToken, windowToken, appCallbackToken, hasCallback, flags,
+ sessionId, uid, activityToken, windowToken, appCallbackToken, hasCallback,
mInfo.getServiceInfo().getComponentName(), packageName);
- mSessions.put(newSession.getId(), newSession);
+ mSessions.put(newSession.id, newSession);
return newSession;
}
@@ -396,17 +393,17 @@
}
void updateSessionLocked(int sessionId, int uid, AutofillId autofillId, Rect virtualBounds,
- AutofillValue value, int flags) {
+ AutofillValue value, int action, int flags) {
final Session session = mSessions.get(sessionId);
if (session == null || session.uid != uid) {
- if (VERBOSE) {
+ if (sVerbose) {
Slog.v(TAG, "updateSessionLocked(): session gone for " + sessionId + "(" + uid
+ ")");
}
return;
}
- session.updateLocked(autofillId, virtualBounds, value, flags);
+ session.updateLocked(autofillId, virtualBounds, value, action, flags);
}
void removeSessionLocked(int sessionId) {
@@ -426,9 +423,7 @@
}
void destroyLocked() {
- if (VERBOSE) {
- Slog.v(TAG, "destroyLocked()");
- }
+ if (sVerbose) Slog.v(TAG, "destroyLocked()");
final int numSessions = mSessions.size();
for (int i = 0; i < numSessions; i++) {
@@ -519,12 +514,6 @@
pw.println(mContext.getString(R.string.config_defaultAutofillService));
pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled);
- if (VERBOSE && mInfo != null) {
- // ServiceInfo dump is too noisy and redundant (it can be obtained through other dumps)
- pw.print(prefix); pw.println("ServiceInfo:");
- mInfo.getServiceInfo().dump(new PrintWriterPrinter(pw), prefix + prefix);
- }
-
final int size = mSessions.size();
if (size == 0) {
pw.print(prefix); pw.println("No sessions");
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
index 62226e3..1b9c86e 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
@@ -18,10 +18,10 @@
import static com.android.server.autofill.AutofillManagerService.RECEIVER_BUNDLE_EXTRA_SESSIONS;
-import android.app.ActivityManager;
import android.os.Bundle;
import android.os.ShellCommand;
import android.os.UserHandle;
+import android.view.autofill.AutofillManager;
import com.android.internal.os.IResultReceiver;
@@ -51,6 +51,10 @@
return requestDestroy(pw);
case "reset":
return requestReset();
+ case "get":
+ return requestGet(pw);
+ case "set":
+ return requestSet(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -63,6 +67,12 @@
pw.println(" help");
pw.println(" Prints this help text.");
pw.println("");
+ pw.println(" get log_level ");
+ pw.println(" Gets the Autofill log level (off | debug | verbose).");
+ pw.println("");
+ pw.println(" set log_level [off | debug | verbose]");
+ pw.println(" Sets the Autofill log level.");
+ pw.println("");
pw.println(" list sessions [--user USER_ID]");
pw.println(" List all pending sessions.");
pw.println("");
@@ -75,6 +85,48 @@
}
}
+ private int requestGet(PrintWriter pw) {
+ if (!isNextArgLogLevel(pw, "get")) {
+ return -1;
+ }
+ final int logLevel = mService.getLogLevel();
+ switch (logLevel) {
+ case AutofillManager.FLAG_ADD_CLIENT_VERBOSE:
+ pw.println("verbose");
+ return 0;
+ case AutofillManager.FLAG_ADD_CLIENT_DEBUG:
+ pw.println("debug");
+ return 0;
+ case 0:
+ pw.println("off");
+ return 0;
+ default:
+ pw.println("unknow (" + logLevel + ")");
+ return 0;
+ }
+ }
+
+ private int requestSet(PrintWriter pw) {
+ if (!isNextArgLogLevel(pw, "set")) {
+ return -1;
+ }
+ final String logLevel = getNextArg();
+ switch (logLevel.toLowerCase()) {
+ case "verbose":
+ mService.setLogLevel(AutofillManager.FLAG_ADD_CLIENT_VERBOSE);
+ return 0;
+ case "debug":
+ mService.setLogLevel(AutofillManager.FLAG_ADD_CLIENT_DEBUG);
+ return 0;
+ case "off":
+ mService.setLogLevel(0);
+ return 0;
+ default:
+ pw.println("Invalid level: " + logLevel);
+ return -1;
+ }
+ }
+
private int requestDestroy(PrintWriter pw) {
if (!isNextArgSessions(pw)) {
return -1;
@@ -121,6 +173,15 @@
return true;
}
+ private boolean isNextArgLogLevel(PrintWriter pw, String cmd) {
+ final String type = getNextArgRequired();
+ if (!type.equals("log_level")) {
+ pw.println("Error: invalid " + cmd + " type: " + type);
+ return false;
+ }
+ return true;
+ }
+
private int requestSessionCommon(PrintWriter pw, CountDownLatch latch,
Runnable command) {
command.run();
@@ -144,13 +205,6 @@
return 0;
}
- private int getUserIdFromArgsOrCurrentUser() {
- if ("--user".equals(getNextArg())) {
- return UserHandle.parseUserArg(getNextArgRequired());
- }
- return ActivityManager.getCurrentUser();
- }
-
private int getUserIdFromArgsOrAllUsers() {
if ("--user".equals(getNextArg())) {
return UserHandle.parseUserArg(getNextArgRequired());
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 5964172..68ade63 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -17,7 +17,6 @@
package com.android.server.autofill;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.assist.AssistStructure;
import android.app.assist.AssistStructure.ViewNode;
import android.os.Bundle;
@@ -27,14 +26,22 @@
import java.util.Objects;
import java.util.Set;
-final class Helper {
+public final class Helper {
- // TODO(b/36141126): set to false and remove guard from places that should always be on
- static final boolean DEBUG = true;
- static final boolean VERBOSE = false;
+ /**
+ * Defines a logging flag that can be dynamically changed at runtime using
+ * {@code cmd autofill debug [on|off]}.
+ */
+ public static boolean sDebug = false;
+
+ /**
+ * Defines a logging flag that can be dynamically changed at runtime using
+ * {@code cmd autofill verbose [on|off]}.
+ */
+ public static boolean sVerbose = false;
static void append(StringBuilder builder, Bundle bundle) {
- if (bundle == null || !DEBUG) {
+ if (bundle == null || !sVerbose) {
builder.append("null");
return;
}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 2aeb07e..a12ebb2 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -18,7 +18,8 @@
import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
-import static com.android.server.autofill.Helper.DEBUG;
+import static com.android.server.autofill.Helper.sDebug;
+import static com.android.server.autofill.Helper.sVerbose;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -89,7 +90,7 @@
private PendingRequest mPendingRequest;
public interface FillServiceCallbacks {
- void onFillRequestSuccess(@Nullable FillResponse response, int serviceUid,
+ void onFillRequestSuccess(int requestFlags, @Nullable FillResponse response, int serviceUid,
@NonNull String servicePackageName);
void onFillRequestFailure(@Nullable CharSequence message,
@NonNull String servicePackageName);
@@ -219,9 +220,7 @@
mPendingRequest = pendingRequest;
ensureBound();
} else {
- if (DEBUG) {
- Slog.d(LOG_TAG, "[user: " + mUserId + "] handlePendingRequest()");
- }
+ if (sVerbose) Slog.v(LOG_TAG, "[user: " + mUserId + "] handlePendingRequest()");
pendingRequest.run();
if (pendingRequest.isFinal()) {
mCompleted = true;
@@ -237,9 +236,7 @@
if (isBound() || mBinding) {
return;
}
- if (DEBUG) {
- Slog.d(LOG_TAG, "[user: " + mUserId + "] ensureBound()");
- }
+ if (sVerbose) Slog.v(LOG_TAG, "[user: " + mUserId + "] ensureBound()");
mBinding = true;
boolean willBind = mContext.bindServiceAsUser(mIntent, mServiceConnection,
@@ -247,9 +244,7 @@
new UserHandle(mUserId));
if (!willBind) {
- if (DEBUG) {
- Slog.d(LOG_TAG, "[user: " + mUserId + "] could not bind to " + mIntent);
- }
+ if (sDebug) Slog.d(LOG_TAG, "[user: " + mUserId + "] could not bind to " + mIntent);
mBinding = false;
if (!mServiceDied) {
@@ -262,9 +257,7 @@
if (!isBound() && !mBinding) {
return;
}
- if (DEBUG) {
- Slog.d(LOG_TAG, "[user: " + mUserId + "] ensureUnbound()");
- }
+ if (sVerbose) Slog.v(LOG_TAG, "[user: " + mUserId + "] ensureUnbound()");
mBinding = false;
if (isBound()) {
try {
@@ -281,10 +274,10 @@
}
private void dispatchOnFillRequestSuccess(PendingRequest pendingRequest,
- int callingUid, FillResponse response) {
+ int callingUid, int requestFlags, FillResponse response) {
mHandler.getHandler().post(() -> {
if (handleResponseCallbackCommon(pendingRequest)) {
- mCallbacks.onFillRequestSuccess(response, callingUid,
+ mCallbacks.onFillRequestSuccess(requestFlags, response, callingUid,
mComponentName.getPackageName());
}
});
@@ -452,8 +445,8 @@
public void onSuccess(FillResponse response) {
RemoteFillService remoteService = mWeakService.get();
if (remoteService != null) {
- remoteService.dispatchOnFillRequestSuccess(
- PendingFillRequest.this, getCallingUid(), response);
+ remoteService.dispatchOnFillRequestSuccess(PendingFillRequest.this,
+ getCallingUid(), request.getFlags(), response);
}
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 0687f6d..f4fd0be 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -20,13 +20,13 @@
import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
import static android.service.voice.VoiceInteractionSession.KEY_RECEIVER_EXTRAS;
import static android.service.voice.VoiceInteractionSession.KEY_STRUCTURE;
-import static android.view.autofill.AutofillManager.FLAG_START_SESSION;
-import static android.view.autofill.AutofillManager.FLAG_VALUE_CHANGED;
-import static android.view.autofill.AutofillManager.FLAG_VIEW_ENTERED;
-import static android.view.autofill.AutofillManager.FLAG_VIEW_EXITED;
+import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
+import static android.view.autofill.AutofillManager.ACTION_VALUE_CHANGED;
+import static android.view.autofill.AutofillManager.ACTION_VIEW_ENTERED;
+import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
-import static com.android.server.autofill.Helper.DEBUG;
-import static com.android.server.autofill.Helper.VERBOSE;
+import static com.android.server.autofill.Helper.sDebug;
+import static com.android.server.autofill.Helper.sVerbose;
import static com.android.server.autofill.Helper.findViewNodeById;
import android.annotation.NonNull;
@@ -108,7 +108,7 @@
private static AtomicInteger sIdCounter = new AtomicInteger();
/** Id of the session */
- private final int mId;
+ public final int id;
/** uid the session is for */
public final int uid;
@@ -174,23 +174,14 @@
private boolean mDestroyed;
/**
- * Flags used to start the session.
- */
- private final int mFlags;
-
- /**
* Receiver of assist data from the app's {@link Activity}.
*/
private final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
@Override
public void send(int resultCode, Bundle resultData) throws RemoteException {
- if (VERBOSE) {
- Slog.v(TAG, "resultCode on mAssistReceiver: " + resultCode);
- }
-
final AssistStructure structure = resultData.getParcelable(KEY_STRUCTURE);
if (structure == null) {
- Slog.wtf(TAG, "no assist structure for id " + resultCode);
+ Slog.wtf(TAG, "no assist structure");
return;
}
@@ -202,8 +193,8 @@
final int requestId = receiverExtras.getInt(EXTRA_REQUEST_ID);
- if (DEBUG) {
- Slog.d(TAG, "New structure for requestId " + requestId + ": " + structure);
+ if (sVerbose) {
+ Slog.v(TAG, "New structure for requestId " + requestId + ": " + structure);
}
final FillRequest request;
@@ -218,6 +209,9 @@
// Sanitize structure before it's sent to service.
structure.sanitizeForParceling(true);
+ // Flags used to start the session.
+ final int flags = structure.getFlags();
+
if (mContexts == null) {
mContexts = new ArrayList<>(1);
}
@@ -230,7 +224,7 @@
fillStructureWithAllowedValues(mContexts.get(i).getStructure());
}
- request = new FillRequest(requestId, mContexts, mClientState, mFlags);
+ request = new FillRequest(requestId, mContexts, mClientState, flags);
}
mRemoteFillService.onFillRequest(request);
@@ -251,9 +245,7 @@
final ViewNode node = findViewNodeById(structure, viewState.id);
if (node == null) {
- if (DEBUG) {
- Slog.w(TAG, "fillStructureWithAllowedValues(): no node for " + viewState.id);
- }
+ Slog.w(TAG, "fillStructureWithAllowedValues(): no node for " + viewState.id);
continue;
}
@@ -295,15 +287,15 @@
/**
* Reads a new structure and then request a new fill response from the fill service.
*/
- private void requestNewFillResponseLocked() {
+ private void requestNewFillResponseLocked(int flags) {
int requestId;
do {
requestId = sIdCounter.getAndIncrement();
} while (requestId == INVALID_REQUEST_ID);
- if (DEBUG) {
- Slog.d(TAG, "Requesting structure for requestId " + requestId);
+ if (sVerbose) {
+ Slog.v(TAG, "Requesting structure for requestId=" + requestId + ", flags=" + flags);
}
// If the focus changes very quickly before the first request is returned each focus change
@@ -319,7 +311,7 @@
final long identity = Binder.clearCallingIdentity();
try {
if (!ActivityManager.getService().requestAutofillData(mAssistReceiver,
- receiverExtras, mActivityToken)) {
+ receiverExtras, mActivityToken, flags)) {
Slog.w(TAG, "failed to request autofill data for " + mActivityToken);
}
} finally {
@@ -334,8 +326,8 @@
@NonNull Context context, @NonNull HandlerCaller handlerCaller, int userId,
@NonNull Object lock, int sessionId, int uid, @NonNull IBinder activityToken,
@Nullable IBinder windowToken, @NonNull IBinder client, boolean hasCallback,
- int flags, @NonNull ComponentName componentName, @NonNull String packageName) {
- mId = sessionId;
+ @NonNull ComponentName componentName, @NonNull String packageName) {
+ id = sessionId;
this.uid = uid;
mService = service;
mLock = lock;
@@ -346,7 +338,6 @@
mWindowToken = windowToken;
mHasCallback = hasCallback;
mPackageName = packageName;
- mFlags = flags;
mClient = IAutoFillManagerClient.Stub.asInterface(client);
mMetricsLogger.action(MetricsEvent.AUTOFILL_SESSION_STARTED, mPackageName);
@@ -371,7 +362,7 @@
synchronized (mLock) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#switchWindow() rejected - session: "
- + mId + " destroyed");
+ + id + " destroyed");
return;
}
mWindowToken = newWindow;
@@ -388,7 +379,7 @@
synchronized (mLock) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#switchActivity() rejected - session: "
- + mId + " destroyed");
+ + id + " destroyed");
return;
}
mActivityToken = newActivity;
@@ -401,17 +392,17 @@
// FillServiceCallbacks
@Override
- public void onFillRequestSuccess(@Nullable FillResponse response, int serviceUid,
- @NonNull String servicePackageName) {
+ public void onFillRequestSuccess(int requestFlags, @Nullable FillResponse response,
+ int serviceUid, @NonNull String servicePackageName) {
synchronized (mLock) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#onFillRequestSuccess() rejected - session: "
- + mId + " destroyed");
+ + id + " destroyed");
return;
}
}
if (response == null) {
- if ((mFlags & FLAG_MANUAL_REQUEST) != 0) {
+ if ((requestFlags & FLAG_MANUAL_REQUEST) != 0) {
getUiForShowing().showError(R.string.autofill_error_cannot_autofill);
}
// Nothing to be done, but need to notify client.
@@ -452,7 +443,7 @@
synchronized (mLock) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#onFillRequestFailure() rejected - session: "
- + mId + " destroyed");
+ + id + " destroyed");
return;
}
}
@@ -472,7 +463,7 @@
synchronized (mLock) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#onSaveRequestSuccess() rejected - session: "
- + mId + " destroyed");
+ + id + " destroyed");
return;
}
}
@@ -494,7 +485,7 @@
synchronized (mLock) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#onSaveRequestFailure() rejected - session: "
- + mId + " destroyed");
+ + id + " destroyed");
return;
}
}
@@ -541,7 +532,7 @@
synchronized (mLock) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#authenticate() rejected - session: "
- + mId + " destroyed");
+ + id + " destroyed");
return;
}
}
@@ -563,11 +554,10 @@
// AutoFillUiCallback
@Override
public void fill(int requestId, Dataset dataset) {
- mHandlerCaller.getHandler().post(() -> autoFill(requestId, dataset));
synchronized (mLock) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#fill() rejected - session: "
- + mId + " destroyed");
+ + id + " destroyed");
return;
}
}
@@ -580,12 +570,12 @@
synchronized (mLock) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#save() rejected - session: "
- + mId + " destroyed");
+ + id + " destroyed");
return;
}
}
mHandlerCaller.getHandler()
- .obtainMessage(AutofillManagerServiceImpl.MSG_SERVICE_SAVE, mId, 0)
+ .obtainMessage(AutofillManagerServiceImpl.MSG_SERVICE_SAVE, id, 0)
.sendToTarget();
}
@@ -595,7 +585,7 @@
synchronized (mLock) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#cancelSave() rejected - session: "
- + mId + " destroyed");
+ + id + " destroyed");
return;
}
}
@@ -609,19 +599,19 @@
synchronized (mLock) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#requestShowFillUi() rejected - session: "
- + mId + " destroyed");
+ + id + " destroyed");
return;
}
if (id.equals(mCurrentViewId)) {
try {
final ViewState view = mViewStates.get(id);
- mClient.requestShowFillUi(mId, mWindowToken, id, width, height,
+ mClient.requestShowFillUi(this.id, mWindowToken, id, width, height,
view.getVirtualBounds(), presenter);
} catch (RemoteException e) {
Slog.e(TAG, "Error requesting to show fill UI", e);
}
} else {
- if (DEBUG) {
+ if (sDebug) {
Slog.d(TAG, "Do not show full UI on " + id + " as it is not the current view ("
+ mCurrentViewId + ") anymore");
}
@@ -636,7 +626,7 @@
// NOTE: We allow this call in a destroyed state as the UI is
// asked to go away after we get destroyed, so let it do that.
try {
- mClient.requestHideFillUi(mId, mWindowToken, id);
+ mClient.requestHideFillUi(this.id, mWindowToken, id);
} catch (RemoteException e) {
Slog.e(TAG, "Error requesting to hide fill UI", e);
}
@@ -649,7 +639,7 @@
synchronized (mLock) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#startIntentSender() rejected - session: "
- + mId + " destroyed");
+ + id + " destroyed");
return;
}
removeSelfLocked();
@@ -668,7 +658,7 @@
void setAuthenticationResultLocked(Bundle data) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#setAuthenticationResultLocked() rejected - session: "
- + mId + " destroyed");
+ + id + " destroyed");
return;
}
if ((mResponseWaitingAuth == null && mDatasetWaitingAuth == null) || data == null) {
@@ -708,7 +698,7 @@
void setHasCallbackLocked(boolean hasIt) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#setHasCallbackLocked() rejected - session: "
- + mId + " destroyed");
+ + id + " destroyed");
return;
}
mHasCallback = hasIt;
@@ -722,7 +712,7 @@
public boolean showSaveLocked() {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#showSaveLocked() rejected - session: "
- + mId + " destroyed");
+ + id + " destroyed");
return false;
}
if (mContexts == null) {
@@ -732,23 +722,23 @@
if (mResponses == null) {
// Happens when the activity / session was finished before the service replied, or
// when the service cannot autofill it (and returned a null response).
- if (DEBUG) {
- Slog.d(TAG, "showSaveLocked(): no responses on session");
+ if (sVerbose) {
+ Slog.v(TAG, "showSaveLocked(): no responses on session");
}
return true;
}
final int lastResponseIdx = getLastResponseIndex();
if (lastResponseIdx < 0) {
- Slog.d(TAG, "showSaveLocked(): mResponses=" + mResponses
+ Slog.w(TAG, "showSaveLocked(): did not get last response. 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 + ", mContexts=" + mContexts
+ if (sVerbose) {
+ Slog.v(TAG, "showSaveLocked(): mResponses=" + mResponses + ", mContexts=" + mContexts
+ ", mViewStates=" + mViewStates);
}
@@ -783,7 +773,7 @@
final AutofillValue currentValue = viewState.getCurrentValue();
if (currentValue == null || currentValue.isEmpty()) {
- if (DEBUG) {
+ if (sDebug) {
Slog.d(TAG, "showSaveLocked(): empty value for required " + id );
}
allRequiredAreNotEmpty = false;
@@ -792,7 +782,7 @@
final AutofillValue filledValue = viewState.getAutofilledValue();
if (!currentValue.equals(filledValue)) {
- if (DEBUG) {
+ if (sDebug) {
Slog.d(TAG, "showSaveLocked(): found a change on required " + id + ": "
+ filledValue + " => " + currentValue);
}
@@ -815,7 +805,7 @@
final AutofillValue currentValue = viewState.getCurrentValue();
final AutofillValue filledValue = viewState.getAutofilledValue();
if (currentValue != null && !currentValue.equals(filledValue)) {
- if (DEBUG) {
+ if (sDebug) {
Slog.d(TAG, "finishSessionLocked(): found a change on optional "
+ id + ": " + filledValue + " => " + currentValue);
}
@@ -832,7 +822,7 @@
}
}
// Nothing changed...
- if (DEBUG) {
+ if (sDebug) {
Slog.d(TAG, "showSaveLocked(): with no changes, comes no responsibilities."
+ "allRequiredAreNotNull=" + allRequiredAreNotEmpty
+ ", atLeastOneChanged=" + atLeastOneChanged);
@@ -846,29 +836,23 @@
void callSaveLocked() {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#callSaveLocked() rejected - session: "
- + mId + " destroyed");
+ + id + " destroyed");
return;
}
- if (DEBUG) {
- Slog.d(TAG, "callSaveLocked(): mViewStates=" + mViewStates);
- }
+ if (sVerbose) Slog.v(TAG, "callSaveLocked(): mViewStates=" + mViewStates);
- int numContexts = mContexts.size();
+ final int numContexts = mContexts.size();
for (int i = 0; i < numContexts; i++) {
- FillContext context = mContexts.get(i);
+ final FillContext context = mContexts.get(i);
- if (VERBOSE) {
- Slog.v(TAG, "callSaveLocked(): updating " + context);
- }
+ if (sVerbose) Slog.v(TAG, "callSaveLocked(): updating " + context);
for (Entry<AutofillId, ViewState> entry : mViewStates.entrySet()) {
final AutofillValue value = entry.getValue().getCurrentValue();
if (value == null) {
- if (VERBOSE) {
- Slog.v(TAG, "callSaveLocked(): skipping " + entry.getKey());
- }
+ if (sVerbose) Slog.v(TAG, "callSaveLocked(): skipping " + entry.getKey());
continue;
}
final AutofillId id = entry.getKey();
@@ -877,9 +861,7 @@
Slog.w(TAG, "callSaveLocked(): did not find node with id " + id);
continue;
}
- if (VERBOSE) {
- Slog.v(TAG, "callSaveLocked(): updating " + id + " to " + value);
- }
+ if (sVerbose) Slog.v(TAG, "callSaveLocked(): updating " + id + " to " + value);
node.updateAutofillValue(value);
}
@@ -887,7 +869,7 @@
// Sanitize structure before it's sent to service.
context.getStructure().sanitizeForParceling(false);
- if (VERBOSE) {
+ if (sVerbose) {
Slog.v(TAG, "Dumping structure of " + context + " before calling service.save()");
context.getStructure().dump();
}
@@ -933,7 +915,7 @@
final int numDatasets = datasets.size();
for (int dataSetNum = 0; dataSetNum < numDatasets; dataSetNum++) {
- final ArrayList fields = datasets.get(dataSetNum).getFieldIds();
+ final ArrayList<AutofillId> fields = datasets.get(dataSetNum).getFieldIds();
if (fields != null && fields.contains(id)) {
return false;
@@ -945,96 +927,92 @@
return true;
}
- void updateLocked(AutofillId id, Rect virtualBounds, AutofillValue value, int flags) {
+ void updateLocked(AutofillId id, Rect virtualBounds, AutofillValue value, int action,
+ int flags) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#updateLocked() rejected - session: "
- + mId + " destroyed");
+ + id + " destroyed");
return;
}
ViewState viewState = mViewStates.get(id);
if (viewState == null) {
- if ((flags & (FLAG_START_SESSION | FLAG_VALUE_CHANGED | FLAG_VIEW_ENTERED)) != 0) {
- if (DEBUG) {
- Slog.d(TAG, "Creating viewState for " + id + " on " + getFlagAsString(flags));
+ if (action == ACTION_START_SESSION || action == ACTION_VALUE_CHANGED
+ || action == ACTION_VIEW_ENTERED) {
+ if (sVerbose) {
+ Slog.v(TAG,
+ "Creating viewState for " + id + " on " + getActionAsString(action));
}
viewState = new ViewState(this, id, value, this, ViewState.STATE_INITIAL);
mViewStates.put(id, viewState);
} else {
- if (VERBOSE) Slog.v(TAG, "Ignored " + getFlagAsString(flags) + " for " + id);
+ if (sVerbose) Slog.v(TAG, "Ignored " + getActionAsString(action) + " for " + id);
return;
}
}
- if ((flags & FLAG_START_SESSION) != 0) {
- // View is triggering autofill.
- mCurrentViewId = viewState.id;
- viewState.update(value, virtualBounds);
- viewState.setState(ViewState.STATE_STARTED_SESSION);
- requestNewFillResponseLocked();
- return;
- }
-
- if ((flags & FLAG_VALUE_CHANGED) != 0) {
- if (value != null && !value.equals(viewState.getCurrentValue())) {
- // Always update the internal state.
- viewState.setCurrentValue(value);
-
- // Must check if this update was caused by autofilling the view, in which
- // case we just update the value, but not the UI.
- final AutofillValue filledValue = viewState.getAutofilledValue();
- if (value.equals(filledValue)) {
- return;
- }
- // Update the internal state...
- viewState.setState(ViewState.STATE_CHANGED);
-
- //..and the UI
- if (value.isText()) {
- getUiForShowing().filterFillUi(value.getTextValue().toString());
- } else {
- getUiForShowing().filterFillUi(null);
- }
- }
-
- return;
- }
-
- if ((flags & FLAG_VIEW_ENTERED) != 0) {
- if (shouldStartNewPartitionLocked(id)) {
- // TODO(b/37424539): proper implementation
- if (mResponseWaitingAuth != null && ((flags & FLAG_START_SESSION) == 0)) {
- viewState.setState(ViewState.STATE_WAITING_RESPONSE_AUTH);
- } else if ((flags & FLAG_START_SESSION) == 0){
- if (DEBUG) {
- Slog.d(TAG, "Starting partition for view id " + viewState.id);
- }
- viewState.setState(ViewState.STATE_STARTED_PARTITION);
- requestNewFillResponseLocked();
- }
- }
-
- // Remove the UI if the ViewState has changed.
- if (mCurrentViewId != viewState.id) {
- mUi.hideFillUi(mCurrentViewId != null ? mCurrentViewId : null);
+ switch(action) {
+ case ACTION_START_SESSION:
+ // View is triggering autofill.
mCurrentViewId = viewState.id;
- }
+ viewState.update(value, virtualBounds);
+ viewState.setState(ViewState.STATE_STARTED_SESSION);
+ requestNewFillResponseLocked(flags);
+ break;
+ case ACTION_VALUE_CHANGED:
+ if (value != null && !value.equals(viewState.getCurrentValue())) {
+ // Always update the internal state.
+ viewState.setCurrentValue(value);
- // If the ViewState is ready to be displayed, onReady() will be called.
- viewState.update(value, virtualBounds);
+ // Must check if this update was caused by autofilling the view, in which
+ // case we just update the value, but not the UI.
+ final AutofillValue filledValue = viewState.getAutofilledValue();
+ if (value.equals(filledValue)) {
+ return;
+ }
+ // Update the internal state...
+ viewState.setState(ViewState.STATE_CHANGED);
- return;
+ //..and the UI
+ if (value.isText()) {
+ getUiForShowing().filterFillUi(value.getTextValue().toString());
+ } else {
+ getUiForShowing().filterFillUi(null);
+ }
+ }
+ break;
+ case ACTION_VIEW_ENTERED:
+ if (shouldStartNewPartitionLocked(id)) {
+ // TODO(b/37424539): proper implementation
+ if (mResponseWaitingAuth != null) {
+ viewState.setState(ViewState.STATE_WAITING_RESPONSE_AUTH);
+ } else {
+ if (sDebug) {
+ Slog.d(TAG, "Starting partition for view id " + viewState.id);
+ }
+ viewState.setState(ViewState.STATE_STARTED_PARTITION);
+ requestNewFillResponseLocked(flags);
+ }
+ }
+
+ // Remove the UI if the ViewState has changed.
+ if (mCurrentViewId != viewState.id) {
+ mUi.hideFillUi(mCurrentViewId != null ? mCurrentViewId : null);
+ mCurrentViewId = viewState.id;
+ }
+
+ // If the ViewState is ready to be displayed, onReady() will be called.
+ viewState.update(value, virtualBounds);
+ break;
+ case ACTION_VIEW_EXITED:
+ if (mCurrentViewId == viewState.id) {
+ mUi.hideFillUi(viewState.id);
+ mCurrentViewId = null;
+ }
+ break;
+ default:
+ Slog.w(TAG, "updateLocked(): unknown action: " + action);
}
-
- if ((flags & FLAG_VIEW_EXITED) != 0) {
- if (mCurrentViewId == viewState.id) {
- mUi.hideFillUi(viewState.id);
- mCurrentViewId = null;
- }
- return;
- }
-
- Slog.w(TAG, "updateLocked(): unknown flags " + flags + ": " + getFlagAsString(flags));
}
@Override
@@ -1043,7 +1021,7 @@
synchronized (mLock) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#onFillReady() rejected - session: "
- + mId + " destroyed");
+ + id + " destroyed");
return;
}
}
@@ -1056,12 +1034,8 @@
getUiForShowing().showFillUi(filledId, response, filterText, mPackageName);
}
- static String getFlagAsString(int flag) {
- return DebugUtils.flagsToString(AutofillManager.class, "FLAG_", flag);
- }
-
- int getId() {
- return mId;
+ String getActionAsString(int flag) {
+ return DebugUtils.flagsToString(AutofillManager.class, "ACTION_", flag);
}
boolean isDestroyed() {
@@ -1080,7 +1054,7 @@
synchronized (mLock) {
if (!mHasCallback) return;
try {
- mClient.notifyNoFillUi(mId, mWindowToken, mCurrentViewId);
+ mClient.notifyNoFillUi(id, mWindowToken, mCurrentViewId);
} catch (RemoteException e) {
Slog.e(TAG, "Error notifying client no fill UI: windowToken=" + mWindowToken
+ " id=" + mCurrentViewId, e);
@@ -1115,21 +1089,22 @@
}
try {
- mClient.setTrackedViews(mId, trackedViews, saveOnAllViewsInvisible);
+ mClient.setTrackedViews(id, trackedViews, saveOnAllViewsInvisible);
} catch (RemoteException e) {
Slog.w(TAG, "Cannot set tracked ids", e);
}
}
private void processResponseLocked(@NonNull FillResponse response) {
- if (DEBUG) {
- Slog.d(TAG, "processResponseLocked(mCurrentViewId=" + mCurrentViewId + "):" + response);
+ if (sVerbose) {
+ Slog.v(TAG, "processResponseLocked(mCurrentViewId=" + mCurrentViewId + "):" + response);
}
if (mResponses == null) {
mResponses = new SparseArray<>(4);
}
- mResponses.put(response.getRequestId(), response);
+ final int requestId = response.getRequestId();
+ mResponses.put(requestId, response);
mClientState = response.getClientState();
setViewStatesLocked(response, ViewState.STATE_FILLABLE);
@@ -1139,13 +1114,18 @@
return;
}
- if ((mFlags & FLAG_MANUAL_REQUEST) != 0 && response.getDatasets() != null
- && response.getDatasets().size() == 1) {
- Slog.d(TAG, "autofilling manual request directly");
- autoFill(response.getRequestId(), response.getDatasets().get(0));
- return;
- }
+ final ArrayList<Dataset> datasets = response.getDatasets();
+ if (datasets != null && datasets.size() == 1) {
+ // Check if it its a single response for a manual request, in which case it should
+ // be automatically filled
+ final FillContext context = getFillContextByRequestIdLocked(requestId);
+ if (context != null && (context.getStructure().getFlags() & FLAG_MANUAL_REQUEST) != 0) {
+ Slog.d(TAG, "autofilling manual request directly");
+ autoFill(requestId, datasets.get(0));
+ return;
+ }
+ }
// Updates the UI, if necessary.
final ViewState currentView = mViewStates.get(mCurrentViewId);
currentView.maybeCallOnFillReady();
@@ -1200,14 +1180,14 @@
}
}
- private ViewState createOrUpdateViewStateLocked(AutofillId id, int state,AutofillValue value) {
+ private ViewState createOrUpdateViewStateLocked(AutofillId id, int state, AutofillValue value) {
ViewState viewState = mViewStates.get(id);
if (viewState != null) {
viewState.setState(state);
} else {
viewState = new ViewState(this, id, null, this, state);
- if (DEBUG) { // TODO(b/33197203): change to VERBOSE once stable
- Slog.d(TAG, "Adding autofillable view with id " + id + " and state " + state);
+ if (sVerbose) {
+ Slog.v(TAG, "Adding autofillable view with id " + id + " and state " + state);
}
mViewStates.put(id, viewState);
}
@@ -1235,7 +1215,7 @@
synchronized (mLock) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#autoFill() rejected - session: "
- + mId + " destroyed");
+ + id + " destroyed");
return;
}
// Autofill it directly...
@@ -1281,7 +1261,7 @@
private void startAuthentication(IntentSender intent, Intent fillInIntent) {
try {
synchronized (mLock) {
- mClient.authenticate(mId, intent, fillInIntent);
+ mClient.authenticate(id, intent, fillInIntent);
}
} catch (RemoteException e) {
Slog.e(TAG, "Error launching auth intent", e);
@@ -1289,10 +1269,9 @@
}
void dumpLocked(String prefix, PrintWriter pw) {
- pw.print(prefix); pw.print("id: "); pw.println(mId);
+ pw.print(prefix); pw.print("id: "); pw.println(id);
pw.print(prefix); pw.print("uid: "); pw.println(uid);
pw.print(prefix); pw.print("mActivityToken: "); pw.println(mActivityToken);
- pw.print(prefix); pw.print("mFlags: "); pw.println(mFlags);
pw.print(prefix); pw.print("mResponses: "); pw.println(mResponses);
pw.print(prefix); pw.print("mResponseWaitingAuth: "); pw.println(mResponseWaitingAuth);
pw.print(prefix); pw.print("mDatasetWaitingAuth: "); pw.println(mDatasetWaitingAuth);
@@ -1312,7 +1291,7 @@
FillContext context = mContexts.get(i);
pw.print(prefix2); pw.print(context);
- if (VERBOSE) {
+ if (sVerbose) {
pw.println(context.getStructure() + " (look at logcat)");
// TODO: add method on AssistStructure to dump on pw
@@ -1333,14 +1312,12 @@
synchronized (mLock) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#autoFillApp() rejected - session: "
- + mId + " destroyed");
+ + id + " destroyed");
return;
}
try {
- if (DEBUG) {
- Slog.d(TAG, "autoFillApp(): the buck is on the app: " + dataset);
- }
- mClient.autofill(mId, mWindowToken, dataset.getFieldIds(),
+ if (sDebug) Slog.d(TAG, "autoFillApp(): the buck is on the app: " + dataset);
+ mClient.autofill(id, mWindowToken, dataset.getFieldIds(),
dataset.getFieldValues());
setViewStatesLocked(null, dataset, ViewState.STATE_AUTOFILLED);
} catch (RemoteException e) {
@@ -1374,16 +1351,14 @@
}
void removeSelfLocked() {
- if (VERBOSE) {
- Slog.v(TAG, "removeSelfLocked()");
- }
+ if (sVerbose) Slog.v(TAG, "removeSelfLocked()");
if (mDestroyed) {
Slog.w(TAG, "Call to Session#removeSelfLocked() rejected - session: "
- + mId + " destroyed");
+ + id + " destroyed");
return;
}
destroyLocked();
- mService.removeSessionLocked(mId);
+ mService.removeSessionLocked(id);
}
private int getLastResponseIndex() {
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index 3967f59..7ca9435 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -16,7 +16,7 @@
package com.android.server.autofill;
-import static com.android.server.autofill.Helper.DEBUG;
+import static com.android.server.autofill.Helper.sDebug;
import android.annotation.Nullable;
import android.graphics.Rect;
@@ -65,15 +65,15 @@
public static final int STATE_WAITING_RESPONSE_AUTH = 0x80;
public final AutofillId id;
+
private final Listener mListener;
private final Session mSession;
- private FillResponse mResponse;
+ private FillResponse mResponse;
private AutofillValue mInitialValue;
private AutofillValue mCurrentValue;
private AutofillValue mAutofilledValue;
private Rect mVirtualBounds;
-
private int mState;
ViewState(Session session, AutofillId id, AutofillValue value, Listener listener, int state) {
@@ -172,9 +172,7 @@
*/
void maybeCallOnFillReady() {
if ((mState & (STATE_AUTOFILLED | STATE_WAITING_DATASET_AUTH)) != 0) {
- if (DEBUG) {
- Slog.d(TAG, "Ignoring UI for " + id + " on " + getStateAsString());
- }
+ if (sDebug) Slog.d(TAG, "Ignoring UI for " + id + " on " + getStateAsString());
return;
}
// First try the current response associated with this View.
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 0556c67..086742e 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -15,7 +15,7 @@
*/
package com.android.server.autofill.ui;
-import static com.android.server.autofill.ui.Helper.DEBUG;
+import static com.android.server.autofill.Helper.sDebug;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -47,7 +47,7 @@
* managing saving of user edits.
*/
public final class AutoFillUI {
- private static final String TAG = "AutoFillUI";
+ private static final String TAG = "AutofillUI";
private final Handler mHandler = UiThread.getHandler();
private final @NonNull Context mContext;
@@ -139,7 +139,7 @@
*/
public void showFillUi(@NonNull AutofillId focusedId, @NonNull FillResponse response,
@Nullable String filterText, @NonNull String packageName) {
- if (DEBUG) {
+ if (sDebug) {
Slog.d(TAG, "showFillUi(): id=" + focusedId + ", filter=" + filterText);
}
final LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_FILL_UI))
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index bb47e5b..fa95e03 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -15,6 +15,8 @@
*/
package com.android.server.autofill.ui;
+import static com.android.server.autofill.Helper.sDebug;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PendingIntent;
@@ -341,7 +343,7 @@
mWm.updateViewLayout(mContentView, params);
}
} catch (WindowManager.BadTokenException e) {
- Slog.i(TAG, "Filed with with token " + params.token + " gone.");
+ if (sDebug) Slog.d(TAG, "Filed with with token " + params.token + " gone.");
mCallback.onDestroy();
}
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/Helper.java b/services/autofill/java/com/android/server/autofill/ui/Helper.java
deleted file mode 100644
index 996e421..0000000
--- a/services/autofill/java/com/android/server/autofill/ui/Helper.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.autofill.ui;
-
-final class Helper {
-
- static final boolean DEBUG = true; // TODO(b/33197203): set to false when stable
- static final boolean VERBOSE = false;
- private Helper() {
- throw new UnsupportedOperationException("contains static members only");
- }
-}
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index cbaaef7..63420fd 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -16,7 +16,7 @@
package com.android.server.autofill.ui;
-import static com.android.server.autofill.ui.Helper.DEBUG;
+import static com.android.server.autofill.Helper.sDebug;
import android.annotation.NonNull;
import android.app.Dialog;
@@ -42,7 +42,7 @@
*/
final class SaveUi {
- private static final String TAG = "SaveUi";
+ private static final String TAG = "AutofillSaveUi";
public interface OnSaveListener {
void onSave();
@@ -61,7 +61,7 @@
@Override
public void onSave() {
- if (DEBUG) Slog.d(TAG, "onSave(): " + mDone);
+ if (sDebug) Slog.d(TAG, "onSave(): " + mDone);
if (mDone) {
return;
}
@@ -71,7 +71,7 @@
@Override
public void onCancel(IntentSender listener) {
- if (DEBUG) Slog.d(TAG, "onCancel(): " + mDone);
+ if (sDebug) Slog.d(TAG, "onCancel(): " + mDone);
if (mDone) {
return;
}
@@ -81,7 +81,7 @@
@Override
public void onDestroy() {
- if (DEBUG) Slog.d(TAG, "onDestroy(): " + mDone);
+ if (sDebug) Slog.d(TAG, "onDestroy(): " + mDone);
if (mDone) {
return;
}
@@ -154,8 +154,9 @@
subTitleView.setVisibility(View.VISIBLE);
}
- if (DEBUG) {
- Slog.d(TAG, "Title: " + title + " SubTitle: " + subTitle);
+ Slog.i(TAG, "Showing save dialog: " + title);
+ if (sDebug) {
+ Slog.d(TAG, "SubTitle: " + subTitle);
}
final TextView noButton = view.findViewById(R.id.autofill_save_no);
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 6c18b26..18b4571 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -18,6 +18,7 @@
import android.Manifest;
import android.app.ActivityManager;
+import android.app.AppGlobals;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.IBluetooth;
@@ -37,11 +38,11 @@
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.os.Binder;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -50,7 +51,6 @@
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
@@ -61,15 +61,15 @@
import android.util.Slog;
import com.android.internal.util.DumpUtils;
-import com.android.server.pm.PackageManagerService;
+import com.android.server.pm.UserRestrictionsUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
class BluetoothManagerService extends IBluetoothManager.Stub {
@@ -120,7 +120,6 @@
private static final int MESSAGE_ADD_PROXY_DELAYED = 400;
private static final int MESSAGE_BIND_PROFILE_SERVICE = 401;
- private static final int MAX_SAVE_RETRIES = 3;
private static final int MAX_ERROR_RESTART_RETRIES = 6;
// Bluetooth persisted setting is off
@@ -223,22 +222,25 @@
@Override
public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
Bundle prevRestrictions) {
- if (!newRestrictions.containsKey(UserManager.DISALLOW_BLUETOOTH)
- && !prevRestrictions.containsKey(UserManager.DISALLOW_BLUETOOTH)) {
- // The relevant restriction has not changed - do nothing.
- return;
+ if (!UserRestrictionsUtils.restrictionsChanged(prevRestrictions, newRestrictions,
+ UserManager.DISALLOW_BLUETOOTH, UserManager.DISALLOW_BLUETOOTH_SHARING)) {
+ return; // No relevant changes, nothing to do.
}
- final boolean bluetoothDisallowed =
- newRestrictions.getBoolean(UserManager.DISALLOW_BLUETOOTH);
- if ((mEnable || mEnableExternal) && bluetoothDisallowed) {
+
+ final boolean disallowed = newRestrictions.getBoolean(UserManager.DISALLOW_BLUETOOTH);
+
+ // DISALLOW_BLUETOOTH is a global restriction that can only be set by DO or PO on the
+ // system user, so we only look at the system user.
+ if (userId == UserHandle.USER_SYSTEM && disallowed && (mEnable || mEnableExternal)) {
try {
- disable(null, true);
+ disable(null /* packageName */, true /* persist */);
} catch (RemoteException e) {
- Slog.w(TAG, "Exception when disabling Bluetooth from UserRestrictionsListener",
- e);
+ Slog.w(TAG, "Exception when disabling Bluetooth", e);
}
}
- updateOppLauncherComponentState(bluetoothDisallowed);
+ final boolean sharingDisallowed = disallowed
+ || newRestrictions.getBoolean(UserManager.DISALLOW_BLUETOOTH_SHARING);
+ updateOppLauncherComponentState(userId, sharingDisallowed);
}
};
@@ -994,11 +996,6 @@
LocalServices.getService(UserManagerInternal.class);
userManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
final boolean isBluetoothDisallowed = isBluetoothDisallowed();
- PackageManagerService packageManagerService =
- (PackageManagerService) ServiceManager.getService("package");
- if (packageManagerService != null && !packageManagerService.isOnlyCoreApps()) {
- updateOppLauncherComponentState(isBluetoothDisallowed);
- }
if (isBluetoothDisallowed) {
return;
}
@@ -2074,21 +2071,21 @@
/**
* Disables BluetoothOppLauncherActivity component, so the Bluetooth sharing option is not
- * offered to the user if Bluetooth is disallowed. Puts the component to its default state if
- * Bluetooth is not disallowed.
+ * offered to the user if Bluetooth or sharing is disallowed. Puts the component to its default
+ * state if Bluetooth is not disallowed.
*
- * @param bluetoothDisallowed whether the {@link UserManager.DISALLOW_BLUETOOTH} user
- * restriction was set.
+ * @param userId user to disable bluetooth sharing for.
+ * @param bluetoothSharingDisallowed whether bluetooth sharing is disallowed.
*/
- private void updateOppLauncherComponentState(boolean bluetoothDisallowed) {
+ private void updateOppLauncherComponentState(int userId, boolean bluetoothSharingDisallowed) {
final ComponentName oppLauncherComponent = new ComponentName("com.android.bluetooth",
"com.android.bluetooth.opp.BluetoothOppLauncherActivity");
- final int newState = bluetoothDisallowed
+ final int newState = bluetoothSharingDisallowed
? PackageManager.COMPONENT_ENABLED_STATE_DISABLED
: PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
try {
- mContext.getPackageManager()
- .setComponentEnabledSetting(oppLauncherComponent, newState, 0);
+ final IPackageManager imp = AppGlobals.getPackageManager();
+ imp.setComponentEnabledSetting(oppLauncherComponent, newState, 0 /* flags */, userId);
} catch (Exception e) {
// The component was not found, do nothing.
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 018e41b..03da5b2 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -576,6 +576,22 @@
long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
+ if (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)) {
+ int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
+ if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
+ return visibility;
+ } else {
+ return AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
+ }
+ }
+ if (AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName)) {
+ int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
+ if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
+ return visibility;
+ } else {
+ return AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
+ }
+ }
return resolveAccountVisibility(account, packageName, accounts);
} finally {
restoreCallingIdentity(identityToken);
@@ -641,11 +657,6 @@
return AccountManager.VISIBILITY_VISIBLE; // Authenticator can always see the account
}
- if (isSpecialPackageKey(packageName)) {
- Log.d(TAG, "Package name is forbidden: " + packageName);
- return AccountManager.VISIBILITY_NOT_VISIBLE;
- }
-
// Return stored value if it was set.
int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8d1435b..cabaebd4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -12836,7 +12836,7 @@
public Bundle getAssistContextExtras(int requestType) {
PendingAssistExtras pae = enqueueAssistContext(requestType, null, null, null,
null, null, true /* focused */, true /* newSessionId */,
- UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT);
+ UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT, 0);
if (pae == null) {
return null;
}
@@ -12906,25 +12906,21 @@
Bundle receiverExtras, IBinder activityToken, boolean focused, boolean newSessionId) {
return enqueueAssistContext(requestType, null, null, receiver, receiverExtras,
activityToken, focused, newSessionId, UserHandle.getCallingUserId(), null,
- PENDING_ASSIST_EXTRAS_LONG_TIMEOUT) != null;
+ PENDING_ASSIST_EXTRAS_LONG_TIMEOUT, 0) != null;
}
@Override
public boolean requestAutofillData(IResultReceiver receiver, Bundle receiverExtras,
- IBinder activityToken) {
- // NOTE: we could always use ActivityManager.ASSIST_CONTEXT_FULL and let ActivityThread
- // rely on the flags to decide whether the handleRequestAssistContextExtras() is for
- // autofill, but it's safer to explicitly use new AutoFill types, in case the Assist
- // requests use flags in the future as well (since their flags value might collide with the
- // autofill flag values).
+ IBinder activityToken, int flags) {
return enqueueAssistContext(ActivityManager.ASSIST_CONTEXT_AUTOFILL, null, null,
receiver, receiverExtras, activityToken, true, true, UserHandle.getCallingUserId(),
- null, PENDING_AUTOFILL_ASSIST_STRUCTURE_TIMEOUT) != null;
+ null, PENDING_AUTOFILL_ASSIST_STRUCTURE_TIMEOUT, flags) != null;
}
private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint,
IResultReceiver receiver, Bundle receiverExtras, IBinder activityToken,
- boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout) {
+ boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout,
+ int flags) {
enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO,
"enqueueAssistContext()");
@@ -12974,7 +12970,7 @@
}
try {
activity.app.thread.requestAssistContextExtras(activity.appToken, pae, requestType,
- mViSessionId);
+ mViSessionId, flags);
mPendingAssistExtras.add(pae);
mUiHandler.postDelayed(pae, timeout);
} catch (RemoteException e) {
@@ -13086,7 +13082,7 @@
Bundle args) {
return enqueueAssistContext(requestType, intent, hint, null, null, null,
true /* focused */, true /* newSessionId */, userHandle, args,
- PENDING_ASSIST_EXTRAS_TIMEOUT) != null;
+ PENDING_ASSIST_EXTRAS_TIMEOUT, 0) != null;
}
public void registerProcessObserver(IProcessObserver observer) {
@@ -14644,8 +14640,10 @@
}
static int procStateToImportance(int procState, int memAdj,
- ActivityManager.RunningAppProcessInfo currApp) {
- int imp = ActivityManager.RunningAppProcessInfo.procStateToImportance(procState);
+ ActivityManager.RunningAppProcessInfo currApp,
+ int clientTargetSdk) {
+ int imp = ActivityManager.RunningAppProcessInfo.procStateToImportanceForTargetSdk(
+ procState, clientTargetSdk);
if (imp == ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
currApp.lru = memAdj;
} else {
@@ -14655,7 +14653,8 @@
}
private void fillInProcMemInfo(ProcessRecord app,
- ActivityManager.RunningAppProcessInfo outInfo) {
+ ActivityManager.RunningAppProcessInfo outInfo,
+ int clientTargetSdk) {
outInfo.pid = app.pid;
outInfo.uid = app.info.uid;
if (mHeavyWeightProcess == app) {
@@ -14670,7 +14669,7 @@
outInfo.lastTrimLevel = app.trimMemoryLevel;
int adj = app.curAdj;
int procState = app.curProcState;
- outInfo.importance = procStateToImportance(procState, adj, outInfo);
+ outInfo.importance = procStateToImportance(procState, adj, outInfo, clientTargetSdk);
outInfo.importanceReasonCode = app.adjTypeCode;
outInfo.processState = app.curProcState;
}
@@ -14680,6 +14679,7 @@
enforceNotIsolatedCaller("getRunningAppProcesses");
final int callingUid = Binder.getCallingUid();
+ final int clientTargetSdk = mPackageManagerInt.getUidTargetSdkVersion(callingUid);
// Lazy instantiation of list
List<ActivityManager.RunningAppProcessInfo> runList = null;
@@ -14702,7 +14702,7 @@
ActivityManager.RunningAppProcessInfo currApp =
new ActivityManager.RunningAppProcessInfo(app.processName,
app.pid, app.getPackageList());
- fillInProcMemInfo(app, currApp);
+ fillInProcMemInfo(app, currApp, clientTargetSdk);
if (app.adjSource instanceof ProcessRecord) {
currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
currApp.importanceReasonImportance =
@@ -14758,12 +14758,16 @@
@Override
public void getMyMemoryState(ActivityManager.RunningAppProcessInfo outInfo) {
enforceNotIsolatedCaller("getMyMemoryState");
+
+ final int callingUid = Binder.getCallingUid();
+ final int clientTargetSdk = mPackageManagerInt.getUidTargetSdkVersion(callingUid);
+
synchronized (this) {
ProcessRecord proc;
synchronized (mPidsSelfLocked) {
proc = mPidsSelfLocked.get(Binder.getCallingPid());
}
- fillInProcMemInfo(proc, outInfo);
+ fillInProcMemInfo(proc, outInfo, clientTargetSdk);
}
}
@@ -21722,9 +21726,11 @@
}
}
} catch (Exception e) {
- Slog.w(TAG, "Failed setting process group of " + app.pid
- + " to " + app.curSchedGroup);
- e.printStackTrace();
+ if (false) {
+ Slog.w(TAG, "Failed setting process group of " + app.pid
+ + " to " + app.curSchedGroup);
+ Slog.w(TAG, "at location", e);
+ }
} finally {
Binder.restoreCallingIdentity(oldId);
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 728a3b9..82e2a3d 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3301,13 +3301,21 @@
final ActivityRecord next = topRunningActivityLocked();
final String myReason = reason + " adjustFocus";
+
if (next != r) {
if (next != null && StackId.keepFocusInStackIfPossible(mStackId) && isFocusable()) {
// For freeform, docked, and pinned stacks we always keep the focus within the
// stack as long as there is a running activity.
return;
} else {
+ // Task is not guaranteed to be non-null. For example, destroying the
+ // {@link ActivityRecord} will disassociate the task from the activity.
final TaskRecord task = r.getTask();
+
+ if (task == null) {
+ throw new IllegalStateException("activity no longer associated with task:" + r);
+ }
+
final boolean isAssistantOrOverAssistant = task.getStack().isAssistantStack() ||
task.isOverAssistantStack();
if (r.frontOfTask && isATopFinishingTask(task)
@@ -3373,8 +3381,8 @@
if (DEBUG_STATES) Slog.d(TAG_STATES, "no-history finish of " + r);
if (requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
"stop-no-history", false)) {
- // Activity was finished, no need to continue trying to schedule stop.
- adjustFocusedActivityStackLocked(r, "stopActivityFinished");
+ // If {@link requestFinishActivityLocked} returns {@code true},
+ // {@link adjustFocusedActivityStackLocked} would have been already called.
r.resumeKeyDispatchingLocked();
return;
}
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 1f4b21b1..ca842d55 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -245,6 +245,9 @@
ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
TaskRecord inTask) {
int err = ActivityManager.START_SUCCESS;
+ // Pull the optional Ephemeral Installer-only bundle out of the options early.
+ final Bundle verificationBundle
+ = options != null ? options.popAppVerificationBundle() : null;
ProcessRecord callerApp = null;
if (caller != null) {
@@ -466,7 +469,7 @@
// app [on install success].
if (rInfo != null && rInfo.auxiliaryInfo != null) {
intent = createLaunchIntent(rInfo.auxiliaryInfo, ephemeralIntent,
- callingPackage, resolvedType, userId);
+ callingPackage, verificationBundle, resolvedType, userId);
resolvedType = null;
callingUid = realCallingUid;
callingPid = realCallingPid;
@@ -522,14 +525,16 @@
* Creates a launch intent for the given auxiliary resolution data.
*/
private @NonNull Intent createLaunchIntent(@NonNull AuxiliaryResolveInfo auxiliaryResponse,
- Intent originalIntent, String callingPackage, String resolvedType, int userId) {
+ Intent originalIntent, String callingPackage, Bundle verificationBundle,
+ String resolvedType, int userId) {
if (auxiliaryResponse.needsPhaseTwo) {
// request phase two resolution
mService.getPackageManagerInternalLocked().requestInstantAppResolutionPhaseTwo(
- auxiliaryResponse, originalIntent, resolvedType, callingPackage, userId);
+ auxiliaryResponse, originalIntent, resolvedType, callingPackage,
+ verificationBundle, userId);
}
return InstantAppResolver.buildEphemeralInstallerIntent(originalIntent,
- callingPackage, resolvedType, userId, auxiliaryResponse.packageName,
+ callingPackage, verificationBundle, resolvedType, userId, auxiliaryResponse.packageName,
auxiliaryResponse.splitName, auxiliaryResponse.versionCode,
auxiliaryResponse.token, auxiliaryResponse.needsPhaseTwo);
}
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index ba72dcf..d6bfb35 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -751,6 +751,26 @@
mAppsNotReportingCrashes.add(proc.info.packageName);
}
+ static boolean isInterestingForBackgroundTraces(ProcessRecord app) {
+ // The system_server is always considered interesting.
+ if (app.pid == MY_PID) {
+ return true;
+ }
+
+ // A package is considered interesting if any of the following is true :
+ //
+ // - It's displaying an activity.
+ // - It's the SystemUI.
+ // - It has an overlay or a top UI visible.
+ //
+ // NOTE: The check whether a given ProcessRecord belongs to the systemui
+ // process is a bit of a kludge, but the same pattern seems repeated at
+ // several places in the system server.
+ return app.isInterestingToUserLocked() ||
+ (app.info != null && "com.android.systemui".equals(app.info.packageName)) ||
+ (app.hasTopUi || app.hasOverlayUi);
+ }
+
final void appNotResponding(ProcessRecord app, ActivityRecord activity,
ActivityRecord parent, boolean aboveSystem, final String annotation) {
ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
@@ -812,7 +832,7 @@
firstPids.add(app.pid);
// Don't dump other PIDs if it's a background ANR
- isSilentANR = !showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID;
+ isSilentANR = !showBackground && !isInterestingForBackgroundTraces(app);
if (!isSilentANR) {
int parentPid = app.pid;
if (parent != null && parent.app != null && parent.app.pid > 0) {
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index dd16e22..144eb11 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -95,6 +95,7 @@
return;
}
mKeyguardShowing = showing;
+ dismissDockedStackIfNeeded();
if (showing) {
mKeyguardGoingAway = false;
mDismissalRequested = false;
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 3c5c5fd..b025385 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -520,6 +520,14 @@
return true;
}
}
+
+ final int servicesSize = services.size();
+ for (int i = 0; i < servicesSize; i++) {
+ ServiceRecord r = services.valueAt(i);
+ if (r.isForeground) {
+ return true;
+ }
+ }
return false;
}
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 42c405fe..027dc08 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -495,8 +495,9 @@
Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
runningIntent.setData(Uri.fromParts("package",
appInfo.packageName, null));
- PendingIntent pi = PendingIntent.getActivity(ams.mContext, 0,
- runningIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ PendingIntent pi = PendingIntent.getActivityAsUser(ams.mContext, 0,
+ runningIntent, PendingIntent.FLAG_UPDATE_CURRENT, null,
+ UserHandle.of(userId));
notiBuilder.setColor(ams.mContext.getColor(
com.android.internal
.R.color.system_notification_accent_color));
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 742ee35..e2b838f 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -232,6 +232,7 @@
private static final int MSG_UNMUTE_STREAM = 24;
private static final int MSG_DYN_POLICY_MIX_STATE_UPDATE = 25;
private static final int MSG_INDICATE_SYSTEM_READY = 26;
+ private static final int MSG_ACCESSORY_PLUG_MEDIA_UNMUTE = 27;
// start of messages handled under wakelock
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
// and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -3964,6 +3965,33 @@
}
}
+ private static final int DEVICE_MEDIA_UNMUTED_ON_PLUG =
+ AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
+ AudioSystem.DEVICE_OUT_LINE |
+ AudioSystem.DEVICE_OUT_ALL_A2DP |
+ AudioSystem.DEVICE_OUT_ALL_USB |
+ AudioSystem.DEVICE_OUT_HDMI;
+
+ private void onAccessoryPlugMediaUnmute(int newDevice) {
+ if (DEBUG_VOL) {
+ Log.i(TAG, String.format("onAccessoryPlugMediaUnmute newDevice=%d [%s]",
+ newDevice, AudioSystem.getOutputDeviceName(newDevice)));
+ }
+ synchronized (mConnectedDevices) {
+ if ((newDevice & DEVICE_MEDIA_UNMUTED_ON_PLUG) != 0
+ && mStreamStates[AudioSystem.STREAM_MUSIC].mIsMuted
+ && mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(newDevice) != 0
+ && (newDevice & AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC)) != 0)
+ {
+ if (DEBUG_VOL) {
+ Log.i(TAG, String.format(" onAccessoryPlugMediaUnmute unmuting device=%d [%s]",
+ newDevice, AudioSystem.getOutputDeviceName(newDevice)));
+ }
+ mStreamStates[AudioSystem.STREAM_MUSIC].mute(false);
+ }
+ }
+ }
+
///////////////////////////////////////////////////////////////////////////
// Inner classes
///////////////////////////////////////////////////////////////////////////
@@ -4854,6 +4882,10 @@
onIndicateSystemReady();
break;
+ case MSG_ACCESSORY_PLUG_MEDIA_UNMUTE:
+ onAccessoryPlugMediaUnmute(msg.arg1);
+ break;
+
case MSG_PERSIST_MUSIC_ACTIVE_MS:
final int musicActiveMs = msg.arg1;
Settings.Secure.putIntForUser(mContentResolver,
@@ -4942,7 +4974,7 @@
// must be called synchronized on mConnectedDevices
private void makeA2dpDeviceAvailable(String address, String name) {
- // enable A2DP before notifying A2DP connection to avoid unecessary processing in
+ // enable A2DP before notifying A2DP connection to avoid unnecessary processing in
// audio policy manager
VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
@@ -4956,6 +4988,8 @@
makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
new DeviceListSpec(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
address));
+ sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, null, 0);
}
private void onSendBecomingNoisyIntent() {
@@ -5115,7 +5149,7 @@
private void onBluetoothA2dpDeviceConfigChange(BluetoothDevice btDevice)
{
- if (DEBUG_VOL) {
+ if (DEBUG_DEVICES) {
Log.d(TAG, "onBluetoothA2dpDeviceConfigChange btDevice=" + btDevice);
}
if (btDevice == null) {
@@ -5132,8 +5166,13 @@
final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
if (deviceSpec != null) {
// Device is connected
- AudioSystem.handleDeviceConfigChange(device, address,
- btDevice.getName());
+ if (AudioSystem.handleDeviceConfigChange(device, address,
+ btDevice.getName()) != AudioSystem.AUDIO_STATUS_OK) {
+ // force A2DP device disconnection in case of error so that AudioService state is
+ // consistent with audio policy manager state
+ setBluetoothA2dpDeviceConnectionState(
+ btDevice, BluetoothA2dp.STATE_DISCONNECTED, BluetoothProfile.A2DP_SINK);
+ }
}
}
}
@@ -5176,6 +5215,8 @@
return false;
}
mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
+ sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
+ device, 0, null, 0);
return true;
} else if (!connect && isConnected) {
AudioSystem.setDeviceConnectionState(device,
@@ -6182,6 +6223,7 @@
pw.print(" mCameraSoundForced="); pw.println(mCameraSoundForced);
pw.print(" mHasVibrator="); pw.println(mHasVibrator);
pw.print(" mVolumePolicy="); pw.println(mVolumePolicy);
+ pw.print(" mAvrcpAbsVolSupported="); pw.println(mAvrcpAbsVolSupported);
dumpAudioPolicies(pw);
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index ac5fb43..b42242e 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -218,6 +218,10 @@
return (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
}
+ private WifiManager getWifiManager() {
+ return (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+ }
+
private void updateConfiguration() {
mConfig = new TetheringConfiguration(mContext);
}
@@ -396,9 +400,9 @@
private int setWifiTethering(final boolean enable) {
synchronized (mPublicSync) {
mWifiTetherRequested = enable;
- final WifiManager wifiManager =
- (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- if (wifiManager.setWifiApEnabled(null /* use existing wifi config */, enable)) {
+ final WifiManager wifiManager = getWifiManager();
+ if ((enable && wifiManager.startSoftAp(null /* use existing wifi config */)) ||
+ (!enable && wifiManager.stopSoftAp())) {
return ConnectivityManager.TETHER_ERROR_NO_ERROR;
}
return ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
@@ -1420,12 +1424,37 @@
} else {
mForwardedDownstreams.remove(who);
}
+
+ // If this is a Wi-Fi interface, notify WifiManager of the active serving state.
+ if (who.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
+ final WifiManager mgr = getWifiManager();
+ final String iface = who.interfaceName();
+ switch (mode) {
+ case IControlsTethering.STATE_TETHERED:
+ mgr.updateInterfaceIpState(iface, WifiManager.IFACE_IP_MODE_TETHERED);
+ break;
+ case IControlsTethering.STATE_LOCAL_ONLY:
+ mgr.updateInterfaceIpState(iface, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
+ break;
+ default:
+ Log.wtf(TAG, "Unknown active serving mode: " + mode);
+ break;
+ }
+ }
}
private void handleInterfaceServingStateInactive(TetherInterfaceStateMachine who) {
mNotifyList.remove(who);
mIPv6TetheringCoordinator.removeActiveDownstream(who);
mForwardedDownstreams.remove(who);
+
+ // If this is a Wi-Fi interface, tell WifiManager of any errors.
+ if (who.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
+ if (who.lastError() != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ getWifiManager().updateInterfaceIpState(
+ who.interfaceName(), WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR);
+ }
+ }
}
class InitialState extends State {
@@ -1742,7 +1771,7 @@
public void notifyInterfaceStateChange(String iface, TetherInterfaceStateMachine who,
int state, int error) {
synchronized (mPublicSync) {
- TetherState tetherState = mTetherStates.get(iface);
+ final TetherState tetherState = mTetherStates.get(iface);
if (tetherState != null && tetherState.stateMachine.equals(who)) {
tetherState.lastState = state;
tetherState.lastError = error;
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index e21349a..d3cfd87 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -117,9 +117,11 @@
setInitialState(mInitialState);
}
- public int interfaceType() {
- return mInterfaceType;
- }
+ public String interfaceName() { return mIfaceName; }
+
+ public int interfaceType() { return mInterfaceType; }
+
+ public int lastError() { return mLastError; }
// configured when we start tethering and unconfig'd on error or conclusion
private boolean configureIfaceIp(boolean enabled) {
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 313abab..dbccc07 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -353,6 +353,7 @@
&& mCurrentDreamIsTest == isTest
&& mCurrentDreamCanDoze == canDoze
&& mCurrentDreamUserId == userId) {
+ Slog.i(TAG, "Already in target dream.");
return;
}
@@ -388,6 +389,7 @@
mHandler.post(new Runnable() {
@Override
public void run() {
+ Slog.i(TAG, "Performing gentle wake from dream.");
mController.stopDream(immediate);
}
});
diff --git a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
index 848704e..1c31c3e 100644
--- a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
+++ b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
@@ -109,44 +109,49 @@
final String pkgName = getNextArgRequired();
final int jobId = Integer.parseInt(getNextArgRequired());
- int ret = mInternal.executeRunCommand(pkgName, userId, jobId, force);
- switch (ret) {
- case CMD_ERR_NO_PACKAGE:
- pw.print("Package not found: ");
- pw.print(pkgName);
- pw.print(" / user ");
- pw.println(userId);
- break;
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ int ret = mInternal.executeRunCommand(pkgName, userId, jobId, force);
+ switch (ret) {
+ case CMD_ERR_NO_PACKAGE:
+ pw.print("Package not found: ");
+ pw.print(pkgName);
+ pw.print(" / user ");
+ pw.println(userId);
+ break;
- case CMD_ERR_NO_JOB:
- pw.print("Could not find job ");
- pw.print(jobId);
- pw.print(" in package ");
- pw.print(pkgName);
- pw.print(" / user ");
- pw.println(userId);
- break;
+ case CMD_ERR_NO_JOB:
+ pw.print("Could not find job ");
+ pw.print(jobId);
+ pw.print(" in package ");
+ pw.print(pkgName);
+ pw.print(" / user ");
+ pw.println(userId);
+ break;
- case CMD_ERR_CONSTRAINTS:
- pw.print("Job ");
- pw.print(jobId);
- pw.print(" in package ");
- pw.print(pkgName);
- pw.print(" / user ");
- pw.print(userId);
- pw.println(" has functional constraints but --force not specified");
- break;
+ case CMD_ERR_CONSTRAINTS:
+ pw.print("Job ");
+ pw.print(jobId);
+ pw.print(" in package ");
+ pw.print(pkgName);
+ pw.print(" / user ");
+ pw.print(userId);
+ pw.println(" has functional constraints but --force not specified");
+ break;
- default:
- // success!
- pw.print("Running job");
- if (force) {
- pw.print(" [FORCED]");
- }
- pw.println();
- break;
+ default:
+ // success!
+ pw.print("Running job");
+ if (force) {
+ pw.print(" [FORCED]");
+ }
+ pw.println();
+ break;
+ }
+ return ret;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- return ret;
}
private int runMonitorBattery(PrintWriter pw) throws Exception {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 51cc391..b8ca2bb 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -56,6 +56,7 @@
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import android.Manifest;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
@@ -980,6 +981,14 @@
void addNotification(NotificationRecord r) {
mNotificationList.add(r);
mNotificationsByKey.put(r.sbn.getKey(), r);
+ if (r.sbn.isGroup()) {
+ mSummaryByGroupKey.put(r.getGroupKey(), r);
+ }
+ }
+
+ @VisibleForTesting
+ void addEnqueuedNotification(NotificationRecord r) {
+ mEnqueuedNotifications.add(r);
}
@VisibleForTesting
@@ -1016,7 +1025,7 @@
@VisibleForTesting
void init(Looper looper, IPackageManager packageManager, PackageManager packageManagerClient,
LightsManager lightsManager, NotificationListeners notificationListeners,
- ICompanionDeviceManager companionManager) {
+ ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper) {
Resources resources = getContext().getResources();
mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
@@ -1071,21 +1080,7 @@
sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
}
});
- mSnoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
- @Override
- public void repost(int userId, NotificationRecord r) {
- try {
- if (DBG) {
- Slog.d(TAG, "Reposting " + r.getKey());
- }
- enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
- r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
- r.sbn.getNotification(), userId);
- } catch (Exception e) {
- Slog.e(TAG, "Cannot un-snooze notification", e);
- }
- }
- }, mUserProfiles);
+ mSnoozeHelper = snoozeHelper;
mGroupHelper = new GroupHelper(new GroupHelper.Callback() {
@Override
public void addAutoGroup(String key) {
@@ -1204,9 +1199,25 @@
@Override
public void onStart() {
+ SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
+ @Override
+ public void repost(int userId, NotificationRecord r) {
+ try {
+ if (DBG) {
+ Slog.d(TAG, "Reposting " + r.getKey());
+ }
+ enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
+ r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
+ r.sbn.getNotification(), userId);
+ } catch (Exception e) {
+ Slog.e(TAG, "Cannot un-snooze notification", e);
+ }
+ }
+ }, mUserProfiles);
+
init(Looper.myLooper(), AppGlobals.getPackageManager(), getContext().getPackageManager(),
getLocalService(LightsManager.class), new NotificationListeners(),
- null);
+ null, snoozeHelper);
publishBinderService(Context.NOTIFICATION_SERVICE, mService);
publishLocalService(NotificationManagerInternal.class, mInternalService);
}
@@ -3304,7 +3315,7 @@
return false;
}
} else if (isCallerInstantApp(pkg)) {
- // Ephemeral apps have some special contraints for notifications.
+ // Ephemeral apps have some special constraints for notifications.
// They are not allowed to create new notifications however they are allowed to
// update notifications created by the system (e.g. a foreground service
// notification).
@@ -3378,6 +3389,76 @@
return isBlocked;
}
+ protected class SnoozeNotificationRunnable implements Runnable {
+ private final String mKey;
+ private final long mDuration;
+ private final String mSnoozeCriterionId;
+
+ SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
+ mKey = key;
+ mDuration = duration;
+ mSnoozeCriterionId = snoozeCriterionId;
+ }
+
+ @Override
+ public void run() {
+ synchronized (mNotificationLock) {
+ final NotificationRecord r = findNotificationByKeyLocked(mKey);
+ if (r != null) {
+ snoozeLocked(r);
+ }
+ }
+ }
+
+ void snoozeLocked(NotificationRecord r) {
+ if (r.sbn.isGroup()) {
+ final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
+ r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
+ if (r.getNotification().isGroupSummary()) {
+ // snooze summary and all children
+ for (int i = 0; i < groupNotifications.size(); i++) {
+ snoozeNotificationLocked(groupNotifications.get(i));
+ }
+ } else {
+ // if there is a valid summary for this group, and we are snoozing the only
+ // child, also snooze the summary
+ if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
+ if (groupNotifications.size() != 2) {
+ snoozeNotificationLocked(r);
+ } else {
+ // snooze summary and the one child
+ for (int i = 0; i < groupNotifications.size(); i++) {
+ snoozeNotificationLocked(groupNotifications.get(i));
+ }
+ }
+ } else {
+ snoozeNotificationLocked(r);
+ }
+ }
+ } else {
+ // just snooze the one notification
+ snoozeNotificationLocked(r);
+ }
+ }
+
+ void snoozeNotificationLocked(NotificationRecord r) {
+ MetricsLogger.action(r.getLogMaker()
+ .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
+ .setType(MetricsEvent.TYPE_CLOSE)
+ .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
+ mSnoozeCriterionId == null ? 0 : 1));
+ cancelNotificationLocked(r, false, REASON_SNOOZED);
+ updateLightsLocked();
+ if (mSnoozeCriterionId != null) {
+ mNotificationAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
+ mSnoozeHelper.snooze(r);
+ } else {
+ mSnoozeHelper.snooze(r, mDuration);
+ }
+ savePolicyFile();
+ }
+ }
+
protected class EnqueueNotificationRunnable implements Runnable {
private final NotificationRecord r;
private final int userId;
@@ -3412,6 +3493,11 @@
// can to avoid extracting signals.
handleGroupedNotificationLocked(r, old, callingUid, callingPid);
+ // if this is a group child, unsnooze parent summary
+ if (n.isGroup() && notification.isGroupChild()) {
+ mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
+ }
+
// This conditional is a dirty hack to limit the logging done on
// behalf of the download manager without affecting other apps.
if (!pkg.equals("com.android.providers.downloads")
@@ -4394,31 +4480,7 @@
snoozeCriterionId, listenerName));
}
// Needs to post so that it can cancel notifications not yet enqueued.
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- synchronized (mNotificationLock) {
- final NotificationRecord r = findNotificationByKeyLocked(key);
- if (r != null) {
- MetricsLogger.action(r.getLogMaker()
- .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
- .setType(MetricsEvent.TYPE_CLOSE)
- .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
- snoozeCriterionId == null ? 0 : 1));
- cancelNotificationLocked(r, false, REASON_SNOOZED);
- updateLightsLocked();
- if (snoozeCriterionId != null) {
- mNotificationAssistants.notifyAssistantSnoozedLocked(r.sbn,
- snoozeCriterionId);
- mSnoozeHelper.snooze(r);
- } else {
- mSnoozeHelper.snooze(r, duration);
- }
- savePolicyFile();
- }
- }
- }
- });
+ mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
}
void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
@@ -4531,6 +4593,30 @@
}
}
+ @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
+ String groupKey, int userId) {
+ List<NotificationRecord> records = new ArrayList<>();
+ records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
+ records.addAll(
+ findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
+ return records;
+ }
+
+
+ private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
+ ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
+ List<NotificationRecord> records = new ArrayList<>();
+ final int len = list.size();
+ for (int i = 0; i < len; i++) {
+ NotificationRecord r = list.get(i);
+ if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
+ && r.sbn.getPackageName().equals(pkg)) {
+ records.add(r);
+ }
+ }
+ return records;
+ }
+
// Searches both enqueued and posted notifications by key.
// TODO: need to combine a bunch of these getters with slightly different behavior.
// TODO: Should enqueuing just add to mNotificationsByKey instead?
@@ -4545,7 +4631,7 @@
return null;
}
- private NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
+ NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
NotificationRecord r;
if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
return r;
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index 913f636..42b4f57 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -25,6 +25,7 @@
import android.annotation.NonNull;
import android.app.AlarmManager;
+import android.app.Notification;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -61,7 +62,6 @@
private static final String REPOST_ACTION = SnoozeHelper.class.getSimpleName() + ".EVALUATE";
private static final int REQUEST_CODE_REPOST = 1;
private static final String REPOST_SCHEME = "repost";
- private static final String EXTRA_PKG = "pkg";
private static final String EXTRA_KEY = "key";
private static final String EXTRA_USER_ID = "userId";
@@ -98,7 +98,7 @@
protected Collection<NotificationRecord> getSnoozed(int userId, String pkg) {
if (mSnoozedNotifications.containsKey(userId)
&& mSnoozedNotifications.get(userId).containsKey(pkg)) {
- mSnoozedNotifications.get(userId).get(pkg).values();
+ return mSnoozedNotifications.get(userId).get(pkg).values();
}
return Collections.EMPTY_LIST;
}
@@ -106,16 +106,18 @@
protected @NonNull List<NotificationRecord> getSnoozed() {
List<NotificationRecord> snoozedForUser = new ArrayList<>();
int[] userIds = mUserProfiles.getCurrentProfileIds();
- final int N = userIds.length;
- for (int i = 0; i < N; i++) {
- final ArrayMap<String, ArrayMap<String, NotificationRecord>> snoozedPkgs =
- mSnoozedNotifications.get(userIds[i]);
- if (snoozedPkgs != null) {
- final int M = snoozedPkgs.size();
- for (int j = 0; j < M; j++) {
- final ArrayMap<String, NotificationRecord> records = snoozedPkgs.valueAt(j);
- if (records != null) {
- snoozedForUser.addAll(records.values());
+ if (userIds != null) {
+ final int N = userIds.length;
+ for (int i = 0; i < N; i++) {
+ final ArrayMap<String, ArrayMap<String, NotificationRecord>> snoozedPkgs =
+ mSnoozedNotifications.get(userIds[i]);
+ if (snoozedPkgs != null) {
+ final int M = snoozedPkgs.size();
+ for (int j = 0; j < M; j++) {
+ final ArrayMap<String, NotificationRecord> records = snoozedPkgs.valueAt(j);
+ if (records != null) {
+ snoozedForUser.addAll(records.values());
+ }
}
}
}
@@ -281,6 +283,42 @@
}
}
+ protected void repostGroupSummary(String pkg, int userId, String groupKey) {
+ if (mSnoozedNotifications.containsKey(userId)) {
+ ArrayMap<String, ArrayMap<String, NotificationRecord>> keysByPackage
+ = mSnoozedNotifications.get(userId);
+
+ if (keysByPackage != null && keysByPackage.containsKey(pkg)) {
+ ArrayMap<String, NotificationRecord> recordsByKey = keysByPackage.get(pkg);
+
+ if (recordsByKey != null) {
+ String groupSummaryKey = null;
+ int N = recordsByKey.size();
+ for (int i = 0; i < N; i++) {
+ final NotificationRecord potentialGroupSummary = recordsByKey.valueAt(i);
+ if (potentialGroupSummary.sbn.isGroup()
+ && potentialGroupSummary.getNotification().isGroupSummary()
+ && groupKey.equals(potentialGroupSummary.getGroupKey())) {
+ groupSummaryKey = potentialGroupSummary.getKey();
+ break;
+ }
+ }
+
+ if (groupSummaryKey != null) {
+ NotificationRecord record = recordsByKey.remove(groupSummaryKey);
+ mPackages.remove(groupSummaryKey);
+ mUsers.remove(groupSummaryKey);
+
+ MetricsLogger.action(record.getLogMaker()
+ .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED)
+ .setType(MetricsProto.MetricsEvent.TYPE_OPEN));
+ mCallback.repost(userId, record);
+ }
+ }
+ }
+ }
+ }
+
private PendingIntent createPendingIntent(String pkg, String key, int userId) {
return PendingIntent.getBroadcast(mContext,
REQUEST_CODE_REPOST,
diff --git a/services/core/java/com/android/server/pm/InstantAppResolver.java b/services/core/java/com/android/server/pm/InstantAppResolver.java
index b56db04..624d8c9 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolver.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolver.java
@@ -41,6 +41,7 @@
import android.metrics.LogMaker;
import android.os.Binder;
import android.os.Build;
+import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
@@ -147,6 +148,7 @@
final Intent installerIntent = buildEphemeralInstallerIntent(
requestObj.origIntent,
requestObj.callingPackage,
+ requestObj.verificationBundle,
requestObj.resolvedType,
requestObj.userId,
packageName,
@@ -172,6 +174,7 @@
*/
public static Intent buildEphemeralInstallerIntent(@NonNull Intent origIntent,
@NonNull String callingPackage,
+ @Nullable Bundle verificationBundle,
@NonNull String resolvedType,
int userId,
@NonNull String instantAppPackageName,
@@ -234,6 +237,10 @@
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, instantAppPackageName);
intent.putExtra(Intent.EXTRA_SPLIT_NAME, instantAppSplitName);
intent.putExtra(Intent.EXTRA_VERSION_CODE, versionCode);
+ intent.putExtra(Intent.EXTRA_CALLING_PACKAGE, callingPackage);
+ if (verificationBundle != null) {
+ intent.putExtra(Intent.EXTRA_VERIFICATION_BUNDLE, verificationBundle);
+ }
}
return intent;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d1b9cbb..a56590e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -739,12 +739,123 @@
@GuardedBy("mPackages")
final SparseArray<Map<String, Integer>> mChangedPackagesSequenceNumbers = new SparseArray<>();
- final PackageParser.Callback mPackageParserCallback = new PackageParser.Callback() {
- @Override public boolean hasFeature(String feature) {
+ class PackageParserCallback implements PackageParser.Callback {
+ @Override public final boolean hasFeature(String feature) {
return PackageManagerService.this.hasSystemFeature(feature, 0);
}
+
+ final List<PackageParser.Package> getStaticOverlayPackagesLocked(
+ Collection<PackageParser.Package> allPackages, String targetPackageName) {
+ List<PackageParser.Package> overlayPackages = null;
+ for (PackageParser.Package p : allPackages) {
+ if (targetPackageName.equals(p.mOverlayTarget) && p.mIsStaticOverlay) {
+ if (overlayPackages == null) {
+ overlayPackages = new ArrayList<PackageParser.Package>();
+ }
+ overlayPackages.add(p);
+ }
+ }
+ if (overlayPackages != null) {
+ Comparator<PackageParser.Package> cmp = new Comparator<PackageParser.Package>() {
+ public int compare(PackageParser.Package p1, PackageParser.Package p2) {
+ return p1.mOverlayPriority - p2.mOverlayPriority;
+ }
+ };
+ Collections.sort(overlayPackages, cmp);
+ }
+ return overlayPackages;
+ }
+
+ final String[] getStaticOverlayPathsLocked(Collection<PackageParser.Package> allPackages,
+ String targetPackageName, String targetPath) {
+ if ("android".equals(targetPackageName)) {
+ // Static RROs targeting to "android", ie framework-res.apk, are already applied by
+ // native AssetManager.
+ return null;
+ }
+ List<PackageParser.Package> overlayPackages =
+ getStaticOverlayPackagesLocked(allPackages, targetPackageName);
+ if (overlayPackages == null || overlayPackages.isEmpty()) {
+ return null;
+ }
+ List<String> overlayPathList = null;
+ for (PackageParser.Package overlayPackage : overlayPackages) {
+ if (targetPath == null) {
+ if (overlayPathList == null) {
+ overlayPathList = new ArrayList<String>();
+ }
+ overlayPathList.add(overlayPackage.baseCodePath);
+ continue;
+ }
+
+ try {
+ // Creates idmaps for system to parse correctly the Android manifest of the
+ // target package.
+ //
+ // OverlayManagerService will update each of them with a correct gid from its
+ // target package app id.
+ mInstaller.idmap(targetPath, overlayPackage.baseCodePath,
+ UserHandle.getSharedAppGid(
+ UserHandle.getUserGid(UserHandle.USER_SYSTEM)));
+ if (overlayPathList == null) {
+ overlayPathList = new ArrayList<String>();
+ }
+ overlayPathList.add(overlayPackage.baseCodePath);
+ } catch (InstallerException e) {
+ Slog.e(TAG, "Failed to generate idmap for " + targetPath + " and " +
+ overlayPackage.baseCodePath);
+ }
+ }
+ return overlayPathList == null ? null : overlayPathList.toArray(new String[0]);
+ }
+
+ String[] getStaticOverlayPaths(String targetPackageName, String targetPath) {
+ synchronized (mPackages) {
+ return getStaticOverlayPathsLocked(
+ mPackages.values(), targetPackageName, targetPath);
+ }
+ }
+
+ @Override public final String[] getOverlayApks(String targetPackageName) {
+ return getStaticOverlayPaths(targetPackageName, null);
+ }
+
+ @Override public final String[] getOverlayPaths(String targetPackageName,
+ String targetPath) {
+ return getStaticOverlayPaths(targetPackageName, targetPath);
+ }
};
+ class ParallelPackageParserCallback extends PackageParserCallback {
+ List<PackageParser.Package> mOverlayPackages = null;
+
+ void findStaticOverlayPackages() {
+ synchronized (mPackages) {
+ for (PackageParser.Package p : mPackages.values()) {
+ if (p.mIsStaticOverlay) {
+ if (mOverlayPackages == null) {
+ mOverlayPackages = new ArrayList<PackageParser.Package>();
+ }
+ mOverlayPackages.add(p);
+ }
+ }
+ }
+ }
+
+ @Override
+ synchronized String[] getStaticOverlayPaths(String targetPackageName, String targetPath) {
+ // We can trust mOverlayPackages without holding mPackages because package uninstall
+ // can't happen while running parallel parsing.
+ // Moreover holding mPackages on each parsing thread causes dead-lock.
+ return mOverlayPackages == null ? null :
+ getStaticOverlayPathsLocked(mOverlayPackages, targetPackageName, targetPath);
+ }
+ }
+
+ final PackageParser.Callback mPackageParserCallback = new PackageParserCallback();
+ final ParallelPackageParserCallback mParallelPackageParserCallback =
+ new ParallelPackageParserCallback();
+
public static final class SharedLibraryEntry {
public final String path;
public final String apk;
@@ -2453,6 +2564,8 @@
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
+ mParallelPackageParserCallback.findStaticOverlayPackages();
+
// Find base frameworks (resource packages without code).
scanDirTracedLI(frameworkDir, mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
@@ -5820,10 +5933,10 @@
private void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
Intent origIntent, String resolvedType, String callingPackage,
- int userId) {
+ Bundle verificationBundle, int userId) {
final Message msg = mHandler.obtainMessage(INSTANT_APP_RESOLUTION_PHASE_TWO,
new InstantAppRequest(responseObj, origIntent, resolvedType,
- callingPackage, userId));
+ callingPackage, userId, verificationBundle));
mHandler.sendMessage(msg);
}
@@ -6372,7 +6485,7 @@
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
final InstantAppRequest requestObject = new InstantAppRequest(
null /*responseObj*/, intent /*origIntent*/, resolvedType,
- null /*callingPackage*/, userId);
+ null /*callingPackage*/, userId, null /*verificationBundle*/);
final AuxiliaryResolveInfo auxiliaryResponse =
InstantAppResolver.doInstantAppResolutionPhaseOne(
mContext, mInstantAppResolverConnection, requestObject);
@@ -7856,7 +7969,8 @@
+ " flags=0x" + Integer.toHexString(parseFlags));
}
ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
- mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir, mPackageParserCallback);
+ mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
+ mParallelPackageParserCallback);
// Submit files for parsing in parallel
int fileCount = 0;
@@ -20570,6 +20684,7 @@
public static final int DUMP_DEXOPT = 1 << 20;
public static final int DUMP_COMPILER_STATS = 1 << 21;
public static final int DUMP_ENABLED_OVERLAYS = 1 << 22;
+ public static final int DUMP_CHANGES = 1 << 23;
public static final int OPTION_SHOW_FILTERS = 1 << 0;
@@ -20815,6 +20930,8 @@
dumpState.setDump(DumpState.DUMP_COMPILER_STATS);
} else if ("enabled-overlays".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_ENABLED_OVERLAYS);
+ } else if ("changes".equals(cmd)) {
+ dumpState.setDump(DumpState.DUMP_CHANGES);
} else if ("write".equals(cmd)) {
synchronized (mPackages) {
mSettings.writeLPr();
@@ -21145,6 +21262,31 @@
mSettings.dumpSharedUsersLPr(pw, packageName, permissionNames, dumpState, checkin);
}
+ if (dumpState.isDumping(DumpState.DUMP_CHANGES)) {
+ if (dumpState.onTitlePrinted()) pw.println();
+ pw.println("Package Changes:");
+ pw.print(" Sequence number="); pw.println(mChangedPackagesSequenceNumber);
+ final int K = mChangedPackages.size();
+ for (int i = 0; i < K; i++) {
+ final SparseArray<String> changes = mChangedPackages.valueAt(i);
+ pw.print(" User "); pw.print(mChangedPackages.keyAt(i)); pw.println(":");
+ final int N = changes.size();
+ if (N == 0) {
+ pw.print(" "); pw.println("No packages changed");
+ } else {
+ for (int j = 0; j < N; j++) {
+ final String pkgName = changes.valueAt(j);
+ final int sequenceNumber = changes.keyAt(j);
+ pw.print(" ");
+ pw.print("seq=");
+ pw.print(sequenceNumber);
+ pw.print(", package=");
+ pw.println(pkgName);
+ }
+ }
+ }
+ }
+
if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS) && packageName == null) {
mSettings.dumpRestoredPermissionGrantsLPr(pw, dumpState);
}
@@ -23423,9 +23565,11 @@
@Override
public void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
- Intent origIntent, String resolvedType, String callingPackage, int userId) {
+ Intent origIntent, String resolvedType, String callingPackage,
+ Bundle verificationBundle, int userId) {
PackageManagerService.this.requestInstantAppResolutionPhaseTwo(
- responseObj, origIntent, resolvedType, callingPackage, userId);
+ responseObj, origIntent, resolvedType, callingPackage, verificationBundle,
+ userId);
}
@Override
@@ -23570,6 +23714,13 @@
mIsolatedOwners.delete(isolatedUid);
}
}
+
+ @Override
+ public int getUidTargetSdkVersion(int uid) {
+ synchronized (mPackages) {
+ return getUidTargetSdkVersionLockedLPr(uid);
+ }
+ }
}
@Override
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 84381fe..c6667a7 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -74,6 +74,7 @@
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
UserManager.DISALLOW_CONFIG_BLUETOOTH,
UserManager.DISALLOW_BLUETOOTH,
+ UserManager.DISALLOW_BLUETOOTH_SHARING,
UserManager.DISALLOW_USB_FILE_TRANSFER,
UserManager.DISALLOW_CONFIG_CREDENTIALS,
UserManager.DISALLOW_REMOVE_USER,
@@ -155,6 +156,7 @@
*/
private static final Set<String> GLOBAL_RESTRICTIONS = Sets.newArraySet(
UserManager.DISALLOW_ADJUST_VOLUME,
+ UserManager.DISALLOW_BLUETOOTH_SHARING,
UserManager.DISALLOW_RUN_IN_BACKGROUND,
UserManager.DISALLOW_UNMUTE_MICROPHONE,
UserManager.DISALLOW_UNMUTE_DEVICE
@@ -167,6 +169,17 @@
UserManager.DISALLOW_ADD_MANAGED_PROFILE
);
+ /**
+ * User restrictions that default to {@code true} for managed profile owners.
+ *
+ * NB: {@link UserManager#DISALLOW_INSTALL_UNKNOWN_SOURCES} is also set by default but it is
+ * not set to existing profile owners unless they used to have INSTALL_NON_MARKET_APPS disabled
+ * in settings. So it is handled separately.
+ */
+ private static final Set<String> DEFAULT_ENABLED_FOR_MANAGED_PROFILES = Sets.newArraySet(
+ UserManager.DISALLOW_BLUETOOTH_SHARING
+ );
+
/*
* Special user restrictions that are always applied to all users no matter who sets them.
*/
@@ -308,6 +321,13 @@
}
/**
+ * Returns the user restrictions that default to {@code true} for managed profile owners.
+ */
+ public static @NonNull Set<String> getDefaultEnabledForManagedProfiles() {
+ return DEFAULT_ENABLED_FOR_MANAGED_PROFILES;
+ }
+
+ /**
* Takes restrictions that can be set by device owner, and sort them into what should be applied
* globally and what should be applied only on the current user.
*/
@@ -544,8 +564,8 @@
public static void moveRestriction(String restrictionKey, SparseArray<Bundle> srcRestrictions,
SparseArray<Bundle> destRestrictions) {
for (int i = 0; i < srcRestrictions.size(); i++) {
- int key = srcRestrictions.keyAt(i);
- Bundle from = srcRestrictions.valueAt(i);
+ final int key = srcRestrictions.keyAt(i);
+ final Bundle from = srcRestrictions.valueAt(i);
if (contains(from, restrictionKey)) {
from.remove(restrictionKey);
Bundle to = destRestrictions.get(key);
@@ -562,4 +582,24 @@
}
}
}
+
+ /**
+ * Returns whether restrictions differ between two bundles.
+ * @param oldRestrictions old bundle of restrictions.
+ * @param newRestrictions new bundle of restrictions
+ * @param restrictions restrictions of interest, if empty, all restrictions are checked.
+ */
+ public static boolean restrictionsChanged(Bundle oldRestrictions, Bundle newRestrictions,
+ String... restrictions) {
+ if (restrictions.length == 0) {
+ return areEqual(oldRestrictions, newRestrictions);
+ }
+ for (final String restriction : restrictions) {
+ if (oldRestrictions.getBoolean(restriction, false) !=
+ newRestrictions.getBoolean(restriction, false)) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2f26f43..6584672 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1903,7 +1903,7 @@
setDeviceOwnerSystemPropertyLocked();
findOwnerComponentIfNecessaryLocked();
migrateUserRestrictionsIfNecessaryLocked();
- setDefaultEnabledUserRestrictionsIfNecessaryLocked();
+ maybeSetDefaultDeviceOwnerUserRestrictionsLocked();
// TODO PO may not have a class name either due to b/17652534. Address that too.
@@ -1911,36 +1911,80 @@
}
}
- private void setDefaultEnabledUserRestrictionsIfNecessaryLocked() {
+ /** Apply default restrictions that haven't been applied to device owners yet. */
+ private void maybeSetDefaultDeviceOwnerUserRestrictionsLocked() {
final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
- if (deviceOwner != null
- && !UserRestrictionsUtils.getDefaultEnabledForDeviceOwner().equals(
- deviceOwner.defaultEnabledRestrictionsAlreadySet)) {
- Slog.i(LOG_TAG,"New user restrictions need to be set by default for the device owner");
+ if (deviceOwner != null) {
+ maybeSetDefaultRestrictionsForAdminLocked(mOwners.getDeviceOwnerUserId(),
+ deviceOwner, UserRestrictionsUtils.getDefaultEnabledForDeviceOwner());
+ }
+ }
- if (VERBOSE_LOG) {
- Slog.d(LOG_TAG,"Default enabled restrictions for DO: "
- + UserRestrictionsUtils.getDefaultEnabledForDeviceOwner()
- + ". Restrictions already enabled: "
- + deviceOwner.defaultEnabledRestrictionsAlreadySet);
- }
-
- Set<String> restrictionsToSet = new ArraySet<>(
- UserRestrictionsUtils.getDefaultEnabledForDeviceOwner());
- restrictionsToSet.removeAll(deviceOwner.defaultEnabledRestrictionsAlreadySet);
- if (!restrictionsToSet.isEmpty()) {
- for (String restriction : restrictionsToSet) {
- deviceOwner.ensureUserRestrictions().putBoolean(restriction, true);
+ /** Apply default restrictions that haven't been applied to profile owners yet. */
+ private void maybeSetDefaultProfileOwnerUserRestrictions() {
+ synchronized (this) {
+ for (final int userId : mOwners.getProfileOwnerKeys()) {
+ final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId);
+ // The following restrictions used to be applied to managed profiles by different
+ // means (via Settings or by disabling components). Now they are proper user
+ // restrictions so we apply them to managed profile owners. Non-managed secondary
+ // users didn't have those restrictions so we skip them to keep existing behavior.
+ if (profileOwner == null || !mUserManager.isManagedProfile(userId)) {
+ continue;
}
- deviceOwner.defaultEnabledRestrictionsAlreadySet.addAll(restrictionsToSet);
- Slog.i(LOG_TAG,
- "Enabled the following restrictions by default: " + restrictionsToSet);
-
- saveUserRestrictionsLocked(mOwners.getDeviceOwnerUserId());
+ maybeSetDefaultRestrictionsForAdminLocked(userId, profileOwner,
+ UserRestrictionsUtils.getDefaultEnabledForManagedProfiles());
+ ensureUnknownSourcesRestrictionForProfileOwnerLocked(
+ userId, profileOwner, false /* newOwner */);
}
}
}
+ /**
+ * Checks whether {@link UserManager#DISALLOW_INSTALL_UNKNOWN_SOURCES} should be added to the
+ * set of restrictions for this profile owner.
+ */
+ private void ensureUnknownSourcesRestrictionForProfileOwnerLocked(int userId,
+ ActiveAdmin profileOwner, boolean newOwner) {
+ if (newOwner || mInjector.settingsSecureGetIntForUser(
+ Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, 0, userId) != 0) {
+ profileOwner.ensureUserRestrictions().putBoolean(
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true);
+ saveUserRestrictionsLocked(userId);
+ mInjector.settingsSecurePutIntForUser(
+ Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, 0, userId);
+ }
+ }
+
+ /**
+ * Apply default restrictions that haven't been applied to a given admin yet.
+ */
+ private void maybeSetDefaultRestrictionsForAdminLocked(
+ int userId, ActiveAdmin admin, Set<String> defaultRestrictions) {
+ if (defaultRestrictions.equals(admin.defaultEnabledRestrictionsAlreadySet)) {
+ return; // The same set of default restrictions has been already applied.
+ }
+ Slog.i(LOG_TAG, "New user restrictions need to be set by default for user " + userId);
+
+ if (VERBOSE_LOG) {
+ Slog.d(LOG_TAG,"Default enabled restrictions: "
+ + defaultRestrictions
+ + ". Restrictions already enabled: "
+ + admin.defaultEnabledRestrictionsAlreadySet);
+ }
+
+ final Set<String> restrictionsToSet = new ArraySet<>(defaultRestrictions);
+ restrictionsToSet.removeAll(admin.defaultEnabledRestrictionsAlreadySet);
+ if (!restrictionsToSet.isEmpty()) {
+ for (final String restriction : restrictionsToSet) {
+ admin.ensureUserRestrictions().putBoolean(restriction, true);
+ }
+ admin.defaultEnabledRestrictionsAlreadySet.addAll(restrictionsToSet);
+ Slog.i(LOG_TAG, "Enabled the following restrictions by default: " + restrictionsToSet);
+ saveUserRestrictionsLocked(userId);
+ }
+ }
+
private void setDeviceOwnerSystemPropertyLocked() {
final boolean deviceProvisioned =
mInjector.settingsGlobalGetInt(Settings.Global.DEVICE_PROVISIONED, 0) != 0;
@@ -2927,41 +2971,11 @@
}
}
- private void ensureUnknownSourcesRestrictionForProfileOwners() {
- synchronized (this) {
- for (int userId : mOwners.getProfileOwnerKeys()) {
- if (!mUserManager.isManagedProfile(userId) ||
- mInjector.settingsSecureGetIntForUser(
- Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, 0, userId) == 0) {
- continue;
- }
- setUserRestrictionOnBehalfOfProfileOwnerLocked(
- UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, userId);
- mInjector.settingsSecurePutIntForUser(
- Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, 0, userId);
- }
- }
- }
-
- private void setUserRestrictionOnBehalfOfProfileOwnerLocked(String userRestrictionKey,
- int userId) {
- if (UserRestrictionsUtils.isValidRestriction(userRestrictionKey) &&
- UserRestrictionsUtils.canProfileOwnerChange(userRestrictionKey, userId)) {
- ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId);
- if (profileOwner == null) {
- return;
- }
- Bundle restrictions = profileOwner.ensureUserRestrictions();
- restrictions.putBoolean(userRestrictionKey, true);
- saveUserRestrictionsLocked(userId);
- }
- }
-
private void onLockSettingsReady() {
getUserData(UserHandle.USER_SYSTEM);
loadOwners();
cleanUpOldUsers();
- ensureUnknownSourcesRestrictionForProfileOwners();
+ maybeSetDefaultProfileOwnerUserRestrictions();
handleStartUser(UserHandle.USER_SYSTEM);
// Register an observer for watching for user setup complete and settings changes.
@@ -4637,19 +4651,20 @@
final long ident = mInjector.binderClearCallingIdentity();
try {
// Evict key
- if ((flags & DevicePolicyManager.FLAG_EVICT_CE_KEY) != 0) {
- enforceManagedProfile(callingUserId, "set FLAG_EVICT_CE_KEY");
+ if ((flags & DevicePolicyManager.FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY) != 0) {
+ enforceManagedProfile(
+ callingUserId, "set FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY");
if (!isProfileOwner(admin.info.getComponent(), callingUserId)) {
- throw new SecurityException(
- "Only profile owner admins can set FLAG_EVICT_CE_KEY");
+ throw new SecurityException("Only profile owner admins can set "
+ + "FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY");
}
if (parent) {
throw new IllegalArgumentException(
- "Cannot set FLAG_EVICT_CE_KEY for the parent");
+ "Cannot set FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY for the parent");
}
if (!mInjector.storageManagerIsFileBasedEncryptionEnabled()) {
throw new UnsupportedOperationException(
- "FLAG_EVICT_CE_KEY only applies to FBE devices");
+ "FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY only applies to FBE devices");
}
mUserManager.evictCredentialEncryptionKey(callingUserId);
}
@@ -6713,8 +6728,8 @@
synchronized (this) {
enforceCanSetProfileOwnerLocked(who, userHandle, hasIncompatibleAccountsOrNonAdb);
- if (getActiveAdminUncheckedLocked(who, userHandle) == null
- || getUserData(userHandle).mRemovingAdmins.contains(who)) {
+ final ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+ if (admin == null || getUserData(userHandle).mRemovingAdmins.contains(who)) {
throw new IllegalArgumentException("Not active admin: " + who);
}
@@ -6730,10 +6745,10 @@
final long id = mInjector.binderClearCallingIdentity();
try {
if (mUserManager.isManagedProfile(userHandle)) {
- setUserRestrictionOnBehalfOfProfileOwnerLocked(
- UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, userHandle);
- mInjector.settingsSecurePutIntForUser(
- Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, 0, userHandle);
+ maybeSetDefaultRestrictionsForAdminLocked(userHandle, admin,
+ UserRestrictionsUtils.getDefaultEnabledForManagedProfiles());
+ ensureUnknownSourcesRestrictionForProfileOwnerLocked(userHandle, admin,
+ true /* newOwner */);
}
} finally {
mInjector.binderRestoreCallingIdentity(id);
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index d402d10..f41a99f9 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -24,6 +24,7 @@
import static junit.framework.Assert.fail;
import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.any;
@@ -96,6 +97,7 @@
private NotificationManagerService.NotificationListeners mNotificationListeners;
private ManagedServices.ManagedServiceInfo mListener;
@Mock private ICompanionDeviceManager mCompanionMgr;
+ @Mock SnoozeHelper mSnoozeHelper;
// Use a Testable subclass so we can simulate calls from the system without failing.
private static class TestableNotificationManagerService extends NotificationManagerService {
@@ -133,7 +135,8 @@
null, new ComponentName(PKG, "test_class"), uid, true, null, 0);
when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
mNotificationManagerService.init(mTestableLooper.getLooper(), mPackageManager,
- mPackageManagerClient, mockLightsManager, mNotificationListeners, mCompanionMgr);
+ mPackageManagerClient, mockLightsManager, mNotificationListeners, mCompanionMgr,
+ mSnoozeHelper);
// Tests call directly into the Binder.
mBinderService = mNotificationManagerService.getBinderService();
@@ -147,6 +150,18 @@
mTestableLooper.processAllMessages();
}
+ private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id,
+ String groupKey, boolean isSummary) {
+ Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
+ .setContentTitle("foo")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .setGroup(groupKey)
+ .setGroupSummary(isSummary);
+
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id, "tag", uid, 0,
+ nb.build(), new UserHandle(uid), null, 0);
+ return new NotificationRecord(mContext, sbn, channel);
+ }
private NotificationRecord generateNotificationRecord(NotificationChannel channel) {
return generateNotificationRecord(channel, null);
}
@@ -396,6 +411,46 @@
}
@Test
+ public void testFindGroupNotificationsLocked() throws Exception {
+ // make sure the same notification can be found in both lists and returned
+ final NotificationRecord group1 = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group1", true);
+ mNotificationManagerService.addEnqueuedNotification(group1);
+ mNotificationManagerService.addNotification(group1);
+
+ // should not be returned
+ final NotificationRecord group2 = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group2", true);
+ mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
+ group2.sbn.getId(), group2.sbn.getNotification(), group2.sbn.getUserId());
+ waitForIdle();
+
+ // should not be returned
+ final NotificationRecord nonGroup = generateNotificationRecord(
+ mTestNotificationChannel, 3, null, false);
+ mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
+ nonGroup.sbn.getId(), nonGroup.sbn.getNotification(), nonGroup.sbn.getUserId());
+ waitForIdle();
+
+ // same group, child, should be returned
+ final NotificationRecord group1Child = generateNotificationRecord(
+ mTestNotificationChannel, 4, "group1", false);
+ mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null, group1Child.sbn.getId(),
+ group1Child.sbn.getNotification(), group1Child.sbn.getUserId());
+ waitForIdle();
+
+ List<NotificationRecord> inGroup1 =
+ mNotificationManagerService.findGroupNotificationsLocked(PKG, group1.getGroupKey(),
+ group1.sbn.getUserId());
+ assertEquals(3, inGroup1.size());
+ for (NotificationRecord record : inGroup1) {
+ assertTrue(record.getGroupKey().equals(group1.getGroupKey()));
+ assertTrue(record.sbn.getId() == 1 || record.sbn.getId() == 4);
+ }
+ }
+
+
+ @Test
public void testTvExtenderChannelOverride_onTv() throws Exception {
mNotificationManagerService.setIsTelevision(true);
mNotificationManagerService.setRankingHelper(mRankingHelper);
@@ -701,4 +756,134 @@
assertFalse(mNotificationManagerService.hasCompanionDevice(mListener));
}
+ @Test
+ public void testSnoozeRunnable_snoozeNonGrouped() throws Exception {
+ final NotificationRecord nonGrouped = generateNotificationRecord(
+ mTestNotificationChannel, 1, null, false);
+ final NotificationRecord grouped = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group", false);
+ mNotificationManagerService.addNotification(grouped);
+ mNotificationManagerService.addNotification(nonGrouped);
+
+ NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
+ mNotificationManagerService.new SnoozeNotificationRunnable(
+ nonGrouped.getKey(), 100, null);
+ snoozeNotificationRunnable.run();
+
+ // only snooze the one notification
+ verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
+ }
+
+ @Test
+ public void testSnoozeRunnable_snoozeSummary_withChildren() throws Exception {
+ final NotificationRecord parent = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ final NotificationRecord child = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group", false);
+ final NotificationRecord child2 = generateNotificationRecord(
+ mTestNotificationChannel, 3, "group", false);
+ mNotificationManagerService.addNotification(parent);
+ mNotificationManagerService.addNotification(child);
+ mNotificationManagerService.addNotification(child2);
+
+ NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
+ mNotificationManagerService.new SnoozeNotificationRunnable(
+ parent.getKey(), 100, null);
+ snoozeNotificationRunnable.run();
+
+ // snooze parent and children
+ verify(mSnoozeHelper, times(3)).snooze(any(NotificationRecord.class), anyLong());
+ }
+
+ @Test
+ public void testSnoozeRunnable_snoozeGroupChild_fellowChildren() throws Exception {
+ final NotificationRecord parent = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ final NotificationRecord child = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group", false);
+ final NotificationRecord child2 = generateNotificationRecord(
+ mTestNotificationChannel, 3, "group", false);
+ mNotificationManagerService.addNotification(parent);
+ mNotificationManagerService.addNotification(child);
+ mNotificationManagerService.addNotification(child2);
+
+ NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
+ mNotificationManagerService.new SnoozeNotificationRunnable(
+ child2.getKey(), 100, null);
+ snoozeNotificationRunnable.run();
+
+ // only snooze the one child
+ verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
+ }
+
+ @Test
+ public void testSnoozeRunnable_snoozeGroupChild_onlyChildOfSummary() throws Exception {
+ final NotificationRecord parent = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ assertTrue(parent.sbn.getNotification().isGroupSummary());
+ final NotificationRecord child = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group", false);
+ mNotificationManagerService.addNotification(parent);
+ mNotificationManagerService.addNotification(child);
+
+ NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
+ mNotificationManagerService.new SnoozeNotificationRunnable(
+ child.getKey(), 100, null);
+ snoozeNotificationRunnable.run();
+
+ // snooze child and summary
+ verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong());
+ }
+
+ @Test
+ public void testSnoozeRunnable_snoozeGroupChild_noOthersInGroup() throws Exception {
+ final NotificationRecord child = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group", false);
+ mNotificationManagerService.addNotification(child);
+
+ NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
+ mNotificationManagerService.new SnoozeNotificationRunnable(
+ child.getKey(), 100, null);
+ snoozeNotificationRunnable.run();
+
+ // snooze child only
+ verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
+ }
+
+ @Test
+ public void testPostGroupChild_unsnoozeParent() throws Exception {
+ final NotificationRecord child = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group", false);
+
+ mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
+ child.sbn.getId(), child.sbn.getNotification(), child.sbn.getUserId());
+ waitForIdle();
+
+ verify(mSnoozeHelper, times(1)).repostGroupSummary(
+ anyString(), anyInt(), eq(child.getGroupKey()));
+ }
+
+ @Test
+ public void testPostNonGroup_noUnsnoozing() throws Exception {
+ final NotificationRecord record = generateNotificationRecord(
+ mTestNotificationChannel, 2, null, false);
+
+ mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
+ record.sbn.getId(), record.sbn.getNotification(), record.sbn.getUserId());
+ waitForIdle();
+
+ verify(mSnoozeHelper, never()).repostGroupSummary(anyString(), anyInt(), anyString());
+ }
+
+ @Test
+ public void testPostGroupSummary_noUnsnoozing() throws Exception {
+ final NotificationRecord parent = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group", true);
+
+ mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
+ parent.sbn.getId(), parent.sbn.getNotification(), parent.sbn.getUserId());
+ waitForIdle();
+
+ verify(mSnoozeHelper, never()).repostGroupSummary(anyString(), anyInt(), anyString());
+ }
}
diff --git a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
index 9575d32..51ec05c 100644
--- a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
@@ -34,6 +34,7 @@
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Slog;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -232,13 +233,50 @@
assertEquals(4, mSnoozeHelper.getSnoozed().size());
}
+ @Test
+ public void repostGroupSummary_onlyFellowGroupChildren() throws Exception {
+ NotificationRecord r = getNotificationRecord(
+ "pkg", 1, "one", UserHandle.SYSTEM, "group1", false);
+ NotificationRecord r2 = getNotificationRecord(
+ "pkg", 2, "two", UserHandle.SYSTEM, "group1", false);
+ mSnoozeHelper.snooze(r, 1000);
+ mSnoozeHelper.snooze(r2, 1000);
+ mSnoozeHelper.repostGroupSummary("pkg", UserHandle.USER_SYSTEM, "group1");
+
+ verify(mCallback, never()).repost(UserHandle.USER_SYSTEM, r);
+ }
+
+ @Test
+ public void repostGroupSummary_repostsSummary() throws Exception {
+ when(mUserProfiles.getCurrentProfileIds()).thenReturn(
+ new int[] {UserHandle.USER_SYSTEM});
+ NotificationRecord r = getNotificationRecord(
+ "pkg", 1, "one", UserHandle.SYSTEM, "group1", true);
+ NotificationRecord r2 = getNotificationRecord(
+ "pkg", 2, "two", UserHandle.SYSTEM, "group1", false);
+ mSnoozeHelper.snooze(r, 1000);
+ mSnoozeHelper.snooze(r2, 1000);
+ assertEquals(2, mSnoozeHelper.getSnoozed().size());
+ assertEquals(2, mSnoozeHelper.getSnoozed(UserHandle.USER_SYSTEM, "pkg").size());
+
+ mSnoozeHelper.repostGroupSummary("pkg", UserHandle.USER_SYSTEM, r.getGroupKey());
+
+ verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r);
+ verify(mCallback, never()).repost(UserHandle.USER_SYSTEM, r2);
+
+ assertEquals(1, mSnoozeHelper.getSnoozed().size());
+ assertEquals(1, mSnoozeHelper.getSnoozed(UserHandle.USER_SYSTEM, "pkg").size());
+ }
+
private NotificationRecord getNotificationRecord(String pkg, int id, String tag,
- UserHandle user) {
+ UserHandle user, String groupKey, boolean groupSummary) {
Notification n = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("A")
.setGroup("G")
.setSortKey("A")
.setWhen(1205)
+ .setGroup(groupKey)
+ .setGroupSummary(groupSummary)
.build();
final NotificationChannel notificationChannel = new NotificationChannel(
TEST_CHANNEL_ID, "name", NotificationManager.IMPORTANCE_LOW);
@@ -246,4 +284,9 @@
pkg, pkg, id, tag, 0, 0, n, user, null,
System.currentTimeMillis()), notificationChannel);
}
+
+ private NotificationRecord getNotificationRecord(String pkg, int id, String tag,
+ UserHandle user) {
+ return getNotificationRecord(pkg, id, tag, user, null, false);
+ }
}
diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/profile_device_policies.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/profile_device_policies.xml
new file mode 100644
index 0000000..b162785
--- /dev/null
+++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/profile_device_policies.xml
@@ -0,0 +1,8 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policies setup-complete="true" provisioning-state="3">
+<admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin1">
+ <policies flags="991" />
+ <strong-auth-unlock-timeout value="0" />
+ <organization-color value="-16738680" />
+</admin>
+</policies>
diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/profile_owner.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/profile_owner.xml
new file mode 100644
index 0000000..7440424
--- /dev/null
+++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/profile_owner.xml
@@ -0,0 +1,8 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<root>
+ <profile-owner
+ package="com.android.frameworks.servicestests"
+ name="com.android.frameworks.servicestests"
+ component="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin1"
+ userRestrictionsMigrated="true" />
+</root>
diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/system_device_policies.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/system_device_policies.xml
new file mode 100644
index 0000000..5f9a871
--- /dev/null
+++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/system_device_policies.xml
@@ -0,0 +1,3 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policies setup-complete="true" provisioning-state="3">
+</policies>
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java
index cf477f2..f8dfee4 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java
@@ -131,7 +131,7 @@
mFingerprintGestureController.registerFingerprintGestureCallback(
mMockFingerprintGestureCallback, null);
mFingerprintGestureController.onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
- verify(mMockFingerprintGestureCallback, times(1)).onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
+ verify(mMockFingerprintGestureCallback, times(1)).onGestureDetected(FINGERPRINT_GESTURE_SWIPE_DOWN);
reset(mMockFingerprintGestureCallback);
mFingerprintGestureController.unregisterFingerprintGestureCallback(
@@ -150,9 +150,9 @@
mFingerprintGestureController.registerFingerprintGestureCallback(
mMockFingerprintGestureCallback, messageCapturingHandler);
mFingerprintGestureController.onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
- verify(mMockFingerprintGestureCallback, times(0)).onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
+ verify(mMockFingerprintGestureCallback, times(0)).onGestureDetected(FINGERPRINT_GESTURE_SWIPE_DOWN);
messageCapturingHandler.sendLastMessage();
- verify(mMockFingerprintGestureCallback, times(1)).onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
+ verify(mMockFingerprintGestureCallback, times(1)).onGestureDetected(FINGERPRINT_GESTURE_SWIPE_DOWN);
reset(mMockFingerprintGestureCallback);
mFingerprintGestureController.unregisterFingerprintGestureCallback(
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
index 58166b6..c87eaed 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -22,6 +22,7 @@
import static org.junit.Assert.assertTrue;
import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -84,4 +85,16 @@
// Make sure the resumed activity is untouched.
assertEquals(testStack.mResumedActivity, activityRecord);
}
+
+ @Test
+ public void testStopActivityWhenActivityDestroyed() throws Exception {
+ final ActivityManagerService service = createActivityManagerService();
+ final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID);
+ final ActivityRecord activityRecord = createActivity(service, testActivityComponent, task);
+ activityRecord.info.flags |= ActivityInfo.FLAG_NO_HISTORY;
+ final ActivityStack testStack = service.mStackSupervisor.getStack(TEST_STACK_ID);
+ service.mStackSupervisor.setFocusStackUnchecked("testStopActivityWithDestroy", testStack);
+
+ testStack.stopActivityLocked(activityRecord);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 0827084..3fc2c12 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -161,6 +161,11 @@
void moveHomeStackToFront(String reason) {
}
+ @Override
+ boolean moveHomeStackTaskToTop(String reason) {
+ return true;
+ }
+
// Invoked during {@link ActivityStack} creation.
@Override
void updateUIDsPresentOnDisplay() {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
index b440095..be1d07b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
@@ -15,31 +15,28 @@
*/
package com.android.server.devicepolicy;
-import com.android.server.LocalServices;
-import com.android.server.SystemService;
-import com.android.server.devicepolicy.DevicePolicyManagerServiceTestable.OwnersTestable;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
-import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
-import android.util.Pair;
+import android.provider.Settings;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+import com.android.server.devicepolicy.DevicePolicyManagerServiceTestable.OwnersTestable;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.when;
+import java.util.Set;
public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
private DpmMockContext mContext;
@@ -57,7 +54,7 @@
public void testMigration() throws Exception {
final File user10dir = mMockContext.addUser(10, 0);
final File user11dir = mMockContext.addUser(11, UserInfo.FLAG_MANAGED_PROFILE);
- final File user12dir = mMockContext.addUser(12, 0);
+ mMockContext.addUser(12, 0);
setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
setUpPackageManagerForAdmin(admin2, UserHandle.getUid(10, 123));
@@ -109,16 +106,13 @@
final Map<Integer, Bundle> newBaseRestrictions = new HashMap<>();
- doAnswer(new Answer<Void>() {
- @Override
- public Void answer(InvocationOnMock invocation) throws Throwable {
- Integer userId = (Integer) invocation.getArguments()[0];
- Bundle bundle = (Bundle) invocation.getArguments()[1];
+ doAnswer(invocation -> {
+ Integer userId = (Integer) invocation.getArguments()[0];
+ Bundle bundle = (Bundle) invocation.getArguments()[1];
- newBaseRestrictions.put(userId, bundle);
+ newBaseRestrictions.put(userId, bundle);
- return null;
- }
+ return null;
}).when(mContext.userManagerInternal).setBaseUserRestrictionsByDpmsForMigration(
anyInt(), any(Bundle.class));
@@ -225,16 +219,13 @@
final Map<Integer, Bundle> newBaseRestrictions = new HashMap<>();
- doAnswer(new Answer<Void>() {
- @Override
- public Void answer(InvocationOnMock invocation) throws Throwable {
- Integer userId = (Integer) invocation.getArguments()[0];
- Bundle bundle = (Bundle) invocation.getArguments()[1];
+ doAnswer(invocation -> {
+ Integer userId = (Integer) invocation.getArguments()[0];
+ Bundle bundle = (Bundle) invocation.getArguments()[1];
- newBaseRestrictions.put(userId, bundle);
+ newBaseRestrictions.put(userId, bundle);
- return null;
- }
+ return null;
}).when(mContext.userManagerInternal).setBaseUserRestrictionsByDpmsForMigration(
anyInt(), any(Bundle.class));
@@ -278,4 +269,63 @@
),
dpms.getProfileOwnerAdminLocked(UserHandle.USER_SYSTEM).ensureUserRestrictions());
}
+
+ // Test setting default restrictions for managed profile.
+ public void testMigration3_managedProfileOwner() throws Exception {
+ // Create a managed profile user.
+ final File user10dir = mMockContext.addUser(10, UserInfo.FLAG_MANAGED_PROFILE);
+ // Profile owner package for managed profile user.
+ setUpPackageManagerForAdmin(admin1, UserHandle.getUid(10, 123));
+ // Set up fake UserManager to make it look like a managed profile.
+ when(mMockContext.userManager.isManagedProfile(eq(10))).thenReturn(true);
+ // Set up fake Settings to make it look like INSTALL_NON_MARKET_APPS was reversed.
+ when(mMockContext.settings.settingsSecureGetIntForUser(
+ eq(Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED),
+ eq(0), eq(10))).thenReturn(1);
+ // Write policy and owners files.
+ DpmTestUtils.writeToFile(
+ (new File(mContext.systemUserDataDir, "device_policies.xml")).getAbsoluteFile(),
+ DpmTestUtils.readAsset(mRealTestContext,
+ "DevicePolicyManagerServiceMigrationTest3/system_device_policies.xml"));
+ DpmTestUtils.writeToFile(
+ (new File(user10dir, "device_policies.xml")).getAbsoluteFile(),
+ DpmTestUtils.readAsset(mRealTestContext,
+ "DevicePolicyManagerServiceMigrationTest3/profile_device_policies.xml"));
+ DpmTestUtils.writeToFile(
+ (new File(user10dir, "profile_owner.xml")).getAbsoluteFile(),
+ DpmTestUtils.readAsset(mRealTestContext,
+ "DevicePolicyManagerServiceMigrationTest3/profile_owner.xml"));
+
+ final DevicePolicyManagerServiceTestable dpms;
+
+ // Initialize DPM/DPMS and let it migrate the persisted information.
+ // (Need clearCallingIdentity() to pass permission checks.)
+ final long ident = mContext.binder.clearCallingIdentity();
+ try {
+ LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+
+ dpms = new DevicePolicyManagerServiceTestable(mContext, dataDir);
+
+ dpms.systemReady(SystemService.PHASE_LOCK_SETTINGS_READY);
+ dpms.systemReady(SystemService.PHASE_BOOT_COMPLETED);
+ } finally {
+ mContext.binder.restoreCallingIdentity(ident);
+ }
+
+ assertFalse(dpms.mOwners.hasDeviceOwner());
+ assertTrue(dpms.mOwners.hasProfileOwner(10));
+
+ // Check that default restrictions were applied.
+ DpmTestUtils.assertRestrictions(
+ DpmTestUtils.newRestrictions(
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
+ UserManager.DISALLOW_BLUETOOTH_SHARING
+ ),
+ dpms.getProfileOwnerAdminLocked(10).ensureUserRestrictions());
+
+ final Set<String> alreadySet =
+ dpms.getProfileOwnerAdminLocked(10).defaultEnabledRestrictionsAlreadySet;
+ assertEquals(alreadySet.size(), 1);
+ assertTrue(alreadySet.contains(UserManager.DISALLOW_BLUETOOTH_SHARING));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index a6ce1d5..46da3de 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -21,7 +21,6 @@
import android.app.backup.IBackupManager;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManagerInternal;
import android.database.ContentObserver;
@@ -56,17 +55,17 @@
public static class OwnersTestable extends Owners {
public static final String LEGACY_FILE = "legacy.xml";
public static final String DEVICE_OWNER_FILE = "device_owner2.xml";
- public static final String PROFILE_OWNER_FILE_BASE = "profile_owner.xml";
+ public static final String PROFILE_OWNER_FILE = "profile_owner.xml";
private final File mLegacyFile;
private final File mDeviceOwnerFile;
- private final File mProfileOwnerBase;
+ private final File mUsersDataDir;
public OwnersTestable(DpmMockContext context) {
super(context.userManager, context.userManagerInternal, context.packageManagerInternal);
mLegacyFile = new File(context.dataDir, LEGACY_FILE);
mDeviceOwnerFile = new File(context.dataDir, DEVICE_OWNER_FILE);
- mProfileOwnerBase = new File(context.dataDir, PROFILE_OWNER_FILE_BASE);
+ mUsersDataDir = new File(context.dataDir, "users");
}
@Override
@@ -81,7 +80,8 @@
@Override
File getProfileOwnerFileWithTestOverride(int userId) {
- return new File(mDeviceOwnerFile.getAbsoluteFile() + "-" + userId);
+ final File userDir = new File(mUsersDataDir, String.valueOf(userId));
+ return new File(userDir, PROFILE_OWNER_FILE);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 1ea12d8..23fada4 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -468,7 +468,7 @@
when(accountManager.getAccountsAsUser(anyInt())).thenReturn(new Account[0]);
// Create a data directory.
- final File dir = new File(dataDir, "user" + userId);
+ final File dir = new File(dataDir, "users/" + userId);
DpmTestUtils.clearDir(dir);
when(environment.getUserSystemDirectory(eq(userId))).thenReturn(dir);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java
index 315d37c..caa26e1 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java
@@ -35,7 +35,7 @@
p.setDataPosition(0);
ConnectEvent unparceledEvent = p.readParcelable(NetworkEventTest.class.getClassLoader());
p.recycle();
- assertEquals(event.getIpAddress(), unparceledEvent.getIpAddress());
+ assertEquals(event.getInetAddress(), unparceledEvent.getInetAddress());
assertEquals(event.getPort(), unparceledEvent.getPort());
assertEquals(event.getPackageName(), unparceledEvent.getPackageName());
assertEquals(event.getTimestamp(), unparceledEvent.getTimestamp());
@@ -53,9 +53,9 @@
DnsEvent unparceledEvent = p.readParcelable(NetworkEventTest.class.getClassLoader());
p.recycle();
assertEquals(event.getHostname(), unparceledEvent.getHostname());
- assertEquals(event.getIpAddresses()[0], unparceledEvent.getIpAddresses()[0]);
- assertEquals(event.getIpAddresses()[1], unparceledEvent.getIpAddresses()[1]);
- assertEquals(event.getIpAddressesCount(), unparceledEvent.getIpAddressesCount());
+ assertEquals(event.getInetAddresses()[0], unparceledEvent.getInetAddresses()[0]);
+ assertEquals(event.getInetAddresses()[1], unparceledEvent.getInetAddresses()[1]);
+ assertEquals(event.getTotalResolvedAddressCount(), unparceledEvent.getTotalResolvedAddressCount());
assertEquals(event.getPackageName(), unparceledEvent.getPackageName());
assertEquals(event.getTimestamp(), unparceledEvent.getTimestamp());
}
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 2ebf5fc..e13665b 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -157,7 +157,7 @@
@Override
public long getTotalBytes(String volumeUuid, String callingPackage) {
- enforcePermission(Binder.getCallingUid(), callingPackage);
+ // NOTE: No permissions required
if (volumeUuid == StorageManager.UUID_PRIVATE_INTERNAL) {
return FileUtils.roundStorageSize(mStorage.getPrimaryStorageSize());
@@ -173,7 +173,7 @@
@Override
public long getFreeBytes(String volumeUuid, String callingPackage) {
- enforcePermission(Binder.getCallingUid(), callingPackage);
+ // NOTE: No permissions required
long cacheBytes = 0;
final long token = Binder.clearCallingIdentity();
@@ -187,14 +187,14 @@
}
if (volumeUuid == StorageManager.UUID_PRIVATE_INTERNAL) {
- return Environment.getDataDirectory().getUsableSpace() + cacheBytes;
+ return Environment.getDataDirectory().getFreeSpace() + cacheBytes;
} else {
final VolumeInfo vol = mStorage.findVolumeByUuid(volumeUuid);
if (vol == null) {
throw new ParcelableException(
new IOException("Failed to find storage device for UUID " + volumeUuid));
}
- return vol.getPath().getUsableSpace() + cacheBytes;
+ return vol.getPath().getFreeSpace() + cacheBytes;
}
}
@@ -213,7 +213,6 @@
@Override
public StorageStats queryStatsForPackage(String volumeUuid, String packageName, int userId,
String callingPackage) {
- enforcePermission(Binder.getCallingUid(), callingPackage);
if (userId != UserHandle.getCallingUserId()) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
@@ -227,6 +226,12 @@
throw new ParcelableException(e);
}
+ if (Binder.getCallingUid() == appInfo.uid) {
+ // No permissions required when asking about themselves
+ } else {
+ enforcePermission(Binder.getCallingUid(), callingPackage);
+ }
+
if (mPackage.getPackagesForUid(appInfo.uid).length == 1) {
// Only one package inside UID means we can fast-path
return queryStatsForUid(volumeUuid, appInfo.uid, callingPackage);
@@ -257,14 +262,19 @@
@Override
public StorageStats queryStatsForUid(String volumeUuid, int uid, String callingPackage) {
- enforcePermission(Binder.getCallingUid(), callingPackage);
- if (UserHandle.getUserId(uid) != UserHandle.getCallingUserId()) {
+ final int userId = UserHandle.getUserId(uid);
+ final int appId = UserHandle.getAppId(uid);
+
+ if (userId != UserHandle.getCallingUserId()) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
}
- final int userId = UserHandle.getUserId(uid);
- final int appId = UserHandle.getAppId(uid);
+ if (Binder.getCallingUid() == uid) {
+ // No permissions required when asking about themselves
+ } else {
+ enforcePermission(Binder.getCallingUid(), callingPackage);
+ }
final String[] packageNames = mPackage.getPackagesForUid(uid);
final long[] ceDataInodes = new long[packageNames.length];
@@ -304,12 +314,14 @@
@Override
public StorageStats queryStatsForUser(String volumeUuid, int userId, String callingPackage) {
- enforcePermission(Binder.getCallingUid(), callingPackage);
if (userId != UserHandle.getCallingUserId()) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
}
+ // Always require permission to see user-level stats
+ enforcePermission(Binder.getCallingUid(), callingPackage);
+
final int[] appIds = getAppIds(userId);
final PackageStats stats = new PackageStats(TAG);
try {
@@ -329,12 +341,14 @@
@Override
public ExternalStorageStats queryExternalStatsForUser(String volumeUuid, int userId,
String callingPackage) {
- enforcePermission(Binder.getCallingUid(), callingPackage);
if (userId != UserHandle.getCallingUserId()) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
}
+ // Always require permission to see user-level stats
+ enforcePermission(Binder.getCallingUid(), callingPackage);
+
final int[] appIds = getAppIds(userId);
final long[] stats;
try {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 6c4ced4..4ffacfd 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1203,6 +1203,50 @@
}
@Override
+ public void onPackageModified(String pkgName) {
+ // If the package modified is not in the current user, then don't bother making
+ // any changes as we are going to do any initialization needed when we switch users.
+ if (mCurUser != getChangingUserId()) {
+ return;
+ }
+ // Package getting updated will be handled by {@link #onSomePackagesChanged}.
+ if (isPackageAppearing(pkgName) != PACKAGE_UNCHANGED) {
+ return;
+ }
+ final ComponentName curInteractor = getCurInteractor(mCurUser);
+ if (curInteractor == null) {
+ final VoiceInteractionServiceInfo availInteractorInfo
+ = findAvailInteractor(mCurUser, pkgName);
+ if (availInteractorInfo != null) {
+ final ComponentName availInteractor = new ComponentName(
+ availInteractorInfo.getServiceInfo().packageName,
+ availInteractorInfo.getServiceInfo().name);
+ setCurInteractor(availInteractor, mCurUser);
+ if (getCurRecognizer(mCurUser) == null &&
+ availInteractorInfo.getRecognitionService() != null) {
+ setCurRecognizer(new ComponentName(
+ availInteractorInfo.getServiceInfo().packageName,
+ availInteractorInfo.getRecognitionService()), mCurUser);
+ }
+ }
+ } else {
+ if (didSomePackagesChange()) {
+ // Package is changed
+ if (curInteractor != null && pkgName.equals(
+ curInteractor.getPackageName())) {
+ switchImplementationIfNeeded(true);
+ }
+ } else {
+ // Only some components are changed
+ if (curInteractor != null
+ && isComponentModified(curInteractor.getClassName())) {
+ switchImplementationIfNeeded(true);
+ }
+ }
+ }
+ }
+
+ @Override
public void onSomePackagesChanged() {
int userHandle = getChangingUserId();
if (DEBUG) Slog.d(TAG, "onSomePackagesChanged user=" + userHandle);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 0b4a3e8..7174a70 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -993,6 +993,20 @@
"carrier_default_actions_on_dcfailure_string_array";
/**
+ * Defines carrier-specific actions which act upon
+ * com.android.internal.telephony.CARRIER_SIGNAL_RESET, used for customization of the
+ * default carrier app
+ * Format: "CARRIER_ACTION_IDX, ..."
+ * Where {@code CARRIER_ACTION_IDX} is an integer defined in
+ * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils}
+ * Example:
+ * {@link com.android.carrierdefaultapp.CarrierActionUtils
+ * #CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS clear all notifications on reset}
+ * @hide
+ */
+ public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_RESET =
+ "carrier_default_actions_on_reset_string_array";
+ /**
* Defines a list of acceptable redirection url for default carrier app
* @hides
*/
@@ -1594,7 +1608,8 @@
sDefaults.putStringArray(KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
new String[]{
"com.android.carrierdefaultapp/.CarrierDefaultBroadcastReceiver:" +
- "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED"
+ "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED," +
+ "com.android.internal.telephony.CARRIER_SIGNAL_RESET"
});
sDefaults.putStringArray(KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY, null);
@@ -1606,6 +1621,9 @@
//4: CARRIER_ACTION_DISABLE_METERED_APNS
//1: CARRIER_ACTION_SHOW_PORTAL_NOTIFICATION
});
+ sDefaults.putStringArray(KEY_CARRIER_DEFAULT_ACTIONS_ON_RESET, new String[]{
+ "6" //6: CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS
+ });
sDefaults.putStringArray(KEY_CARRIER_DEFAULT_REDIRECTION_URL_STRING_ARRAY, null);
sDefaults.putInt(KEY_MONTHLY_DATA_CYCLE_DAY_INT, DATA_CYCLE_USE_PLATFORM_DEFAULT);
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index f9875c5..ec9ca1d 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -402,7 +402,7 @@
* <ul>
* <li>apnType</li><dd>A string with the apn type.</dd>
* <li>redirectionUrl</li><dd>redirection url string</dd>
- * <li>subId</dt><li>Sub Id which associated the data connection failure.</dd>
+ * <li>subId</li><dd>Sub Id which associated the data connection failure.</dd>
* </ul>
* <p class="note">This is a protected intent that can only be sent by the system.</p>
*/
@@ -415,7 +415,7 @@
* <ul>
* <li>apnType</li><dd>A string with the apn type.</dd>
* <li>errorCode</li><dd>A integer with dataFailCause.</dd>
- * <li>subId</dt><li>Sub Id which associated the data connection failure.</dd>
+ * <li>subId</li><dd>Sub Id which associated the data connection failure.</dd>
* </ul>
* <p class="note">This is a protected intent that can only be sent by the system. </p>
*/
@@ -432,13 +432,25 @@
* IPV4V6)</dd>
* <li>pcoId</li><dd>An integer indicating the pco id for the data.</dd>
* <li>pcoValue</li><dd>A byte array of pco data read from modem.</dd>
- * <li>subId</dt><li>Sub Id which associated the data connection.</dd>
+ * <li>subId</li><dd>Sub Id which associated the data connection.</dd>
* </ul>
* <p class="note">This is a protected intent that can only be sent by the system. </p>
*/
public static final String ACTION_CARRIER_SIGNAL_PCO_VALUE =
"com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE";
+ /**
+ * <p>Broadcast Action: when framework reset all carrier actions on sim load or absent.
+ * intended for carrier apps clean up (clear UI e.g.) and only sent to the specified carrier app
+ * The intent will have the following extra values:</p>
+ * <ul>
+ * <li>subId</li><dd>Sub Id which associated the data connection failure.</dd>
+ * </ul>
+ * <p class="note">This is a protected intent that can only be sent by the system.</p>
+ */
+ public static final String ACTION_CARRIER_SIGNAL_RESET =
+ "com.android.internal.telephony.CARRIER_SIGNAL_RESET";
+
// CARRIER_SIGNAL_ACTION extra keys
public static final String EXTRA_REDIRECTION_URL_KEY = "redirectionUrl";
public static final String EXTRA_ERROR_CODE_KEY = "errorCode";
diff --git a/tests/FeatureSplit/feature1/AndroidManifest.xml b/tests/FeatureSplit/feature1/AndroidManifest.xml
index 42619b6..b87361f 100644
--- a/tests/FeatureSplit/feature1/AndroidManifest.xml
+++ b/tests/FeatureSplit/feature1/AndroidManifest.xml
@@ -16,7 +16,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.test.split.feature"
- featureName="feature1">
+ featureSplit="feature1">
<uses-sdk android:minSdkVersion="21" />
diff --git a/tests/FeatureSplit/feature1/res/layout/included.xml b/tests/FeatureSplit/feature1/res/layout/included.xml
new file mode 100644
index 0000000..c64bdb7
--- /dev/null
+++ b/tests/FeatureSplit/feature1/res/layout/included.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
diff --git a/tests/FeatureSplit/feature1/res/layout/main.xml b/tests/FeatureSplit/feature1/res/layout/main.xml
new file mode 100644
index 0000000..dbea42a
--- /dev/null
+++ b/tests/FeatureSplit/feature1/res/layout/main.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <include layout="@layout/included"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+</FrameLayout>
diff --git a/tests/FeatureSplit/feature1/src/com/android/test/split/feature/one/One.java b/tests/FeatureSplit/feature1/src/com/android/test/split/feature/one/One.java
index def1339..61ac9df 100644
--- a/tests/FeatureSplit/feature1/src/com/android/test/split/feature/one/One.java
+++ b/tests/FeatureSplit/feature1/src/com/android/test/split/feature/one/One.java
@@ -15,17 +15,16 @@
*/
package com.android.test.split.feature.one;
-import com.android.test.split.feature.ActivityMain;
-
+import android.app.Activity;
import android.widget.TextView;
import android.os.Bundle;
-public class One extends ActivityMain {
+public class One extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- ((TextView) findViewById(com.android.test.split.feature.R.id.text))
- .setText(R.string.feature_string);
+ setContentView(R.layout.main);
+ ((TextView) findViewById(R.id.text)).setText(R.string.feature_string);
}
}
diff --git a/tests/FeatureSplit/feature2/AndroidManifest.xml b/tests/FeatureSplit/feature2/AndroidManifest.xml
index b50044a..abd0b5e 100644
--- a/tests/FeatureSplit/feature2/AndroidManifest.xml
+++ b/tests/FeatureSplit/feature2/AndroidManifest.xml
@@ -16,7 +16,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.test.split.feature"
- featureName="feature2">
+ featureSplit="feature2">
<uses-sdk android:minSdkVersion="21" />
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index 47630e2..7a1c239 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -223,8 +223,6 @@
@Test
public void workingLocalOnlyHotspot() throws Exception {
when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
- when(mWifiManager.setWifiApEnabled(any(WifiConfiguration.class), anyBoolean()))
- .thenReturn(true);
// Emulate externally-visible WifiManager effects, causing the
// per-interface state machine to start up, and telling us that
@@ -238,6 +236,9 @@
verify(mNMService, times(1)).setIpForwardingEnabled(true);
verify(mNMService, times(1)).startTethering(any(String[].class));
verifyNoMoreInteractions(mNMService);
+ verify(mWifiManager).updateInterfaceIpState(
+ mTestIfname, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
+ verifyNoMoreInteractions(mWifiManager);
verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY);
// UpstreamNetworkMonitor will be started, and will register two callbacks:
// a "listen all" and a "track default".
@@ -263,6 +264,7 @@
verify(mNMService, times(1)).stopTethering();
verify(mNMService, times(1)).setIpForwardingEnabled(false);
verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mWifiManager);
// Asking for the last error after the per-interface state machine
// has been reaped yields an unknown interface error.
assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
@@ -272,13 +274,12 @@
@Test
public void workingWifiTethering() throws Exception {
when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
- when(mWifiManager.setWifiApEnabled(any(WifiConfiguration.class), anyBoolean()))
- .thenReturn(true);
+ when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
// Emulate pressing the WiFi tethering button.
mTethering.startTethering(ConnectivityManager.TETHERING_WIFI, null, false);
mLooper.dispatchAll();
- verify(mWifiManager, times(1)).setWifiApEnabled(null, true);
+ verify(mWifiManager, times(1)).startSoftAp(null);
verifyNoMoreInteractions(mWifiManager);
verifyNoMoreInteractions(mConnectivityManager);
verifyNoMoreInteractions(mNMService);
@@ -295,6 +296,9 @@
verify(mNMService, times(1)).setIpForwardingEnabled(true);
verify(mNMService, times(1)).startTethering(any(String[].class));
verifyNoMoreInteractions(mNMService);
+ verify(mWifiManager).updateInterfaceIpState(
+ mTestIfname, WifiManager.IFACE_IP_MODE_TETHERED);
+ verifyNoMoreInteractions(mWifiManager);
verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_TETHER);
// UpstreamNetworkMonitor will be started, and will register two callbacks:
// a "listen all" and a "track default".
@@ -322,7 +326,7 @@
// Emulate pressing the WiFi tethering button.
mTethering.stopTethering(ConnectivityManager.TETHERING_WIFI);
mLooper.dispatchAll();
- verify(mWifiManager, times(1)).setWifiApEnabled(null, false);
+ verify(mWifiManager, times(1)).stopSoftAp();
verifyNoMoreInteractions(mWifiManager);
verifyNoMoreInteractions(mConnectivityManager);
verifyNoMoreInteractions(mNMService);
@@ -341,6 +345,7 @@
verify(mNMService, times(1)).stopTethering();
verify(mNMService, times(1)).setIpForwardingEnabled(false);
verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mWifiManager);
// Asking for the last error after the per-interface state machine
// has been reaped yields an unknown interface error.
assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 60b01e3..b872ebb 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -274,7 +274,13 @@
if (!attr.namespace_uri.empty()) {
std::cerr << attr.namespace_uri << ":";
}
- std::cerr << attr.name << "=" << attr.value << "\n";
+ std::cerr << attr.name;
+
+ if (attr.compiled_attribute) {
+ std::cerr << "(" << attr.compiled_attribute.value().id.value_or_default(ResourceId(0x0))
+ << ")";
+ }
+ std::cerr << "=" << attr.value << "\n";
}
const size_t previous_size = prefix_.size();
diff --git a/tools/aapt2/flatten/TableFlattener.cpp b/tools/aapt2/flatten/TableFlattener.cpp
index d44b3e0..f4d0226 100644
--- a/tools/aapt2/flatten/TableFlattener.cpp
+++ b/tools/aapt2/flatten/TableFlattener.cpp
@@ -573,10 +573,17 @@
// Write the ResTable header.
ChunkWriter table_writer(buffer_);
- ResTable_header* table_header =
- table_writer.StartChunk<ResTable_header>(RES_TABLE_TYPE);
+ ResTable_header* table_header = table_writer.StartChunk<ResTable_header>(RES_TABLE_TYPE);
table_header->packageCount = util::HostToDevice32(table->packages.size());
+ // Write a self mapping entry for this package if the ID is non-standard (0x7f).
+ if (context->GetPackageType() == PackageType::kApp) {
+ const uint8_t package_id = context->GetPackageId();
+ if (package_id != kFrameworkPackageId && package_id != kAppPackageId) {
+ table->included_packages_[package_id] = context->GetCompilationPackage();
+ }
+ }
+
// Flatten the values string pool.
StringPool::FlattenUtf8(table_writer.buffer(), table->string_pool);
diff --git a/tools/aapt2/flatten/TableFlattener_test.cpp b/tools/aapt2/flatten/TableFlattener_test.cpp
index 8dff3a2..6d1350d 100644
--- a/tools/aapt2/flatten/TableFlattener_test.cpp
+++ b/tools/aapt2/flatten/TableFlattener_test.cpp
@@ -400,7 +400,7 @@
const DynamicRefTable* dynamic_ref_table = result.getDynamicRefTableForCookie(1);
ASSERT_NE(nullptr, dynamic_ref_table);
- const KeyedVector<String16, uint8_t> entries = dynamic_ref_table->entries();
+ const KeyedVector<String16, uint8_t>& entries = dynamic_ref_table->entries();
ssize_t idx = entries.indexOfKey(android::String16("lib_one"));
ASSERT_GE(idx, 0);
@@ -411,6 +411,26 @@
EXPECT_EQ(0x03u, entries.valueAt(idx));
}
+TEST_F(TableFlattenerTest, PackageWithNonStandardIdHasDynamicRefTable) {
+ std::unique_ptr<IAaptContext> context =
+ test::ContextBuilder().SetCompilationPackage("app").SetPackageId(0x80).Build();
+ std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
+ .SetPackageId("app", 0x80)
+ .AddSimple("app:id/foo", ResourceId(0x80010000))
+ .Build();
+
+ ResTable result;
+ ASSERT_TRUE(Flatten(context.get(), {}, table.get(), &result));
+
+ const DynamicRefTable* dynamic_ref_table = result.getDynamicRefTableForCookie(1);
+ ASSERT_NE(nullptr, dynamic_ref_table);
+
+ const KeyedVector<String16, uint8_t>& entries = dynamic_ref_table->entries();
+ ssize_t idx = entries.indexOfKey(android::String16("app"));
+ ASSERT_GE(idx, 0);
+ EXPECT_EQ(0x80u, entries.valueAt(idx));
+}
+
TEST_F(TableFlattenerTest, LongPackageNameIsTruncated) {
std::string kPackageName(256, 'F');
diff --git a/tools/aapt2/flatten/XmlFlattener_test.cpp b/tools/aapt2/flatten/XmlFlattener_test.cpp
index 494d9d2..f0613e7 100644
--- a/tools/aapt2/flatten/XmlFlattener_test.cpp
+++ b/tools/aapt2/flatten/XmlFlattener_test.cpp
@@ -35,13 +35,16 @@
.SetNameManglerPolicy(NameManglerPolicy{"com.app.test"})
.AddSymbolSource(
test::StaticSymbolSourceBuilder()
- .AddSymbol("android:attr/id", ResourceId(0x010100d0),
- test::AttributeBuilder().Build())
+ .AddPublicSymbol("android:attr/id", ResourceId(0x010100d0),
+ test::AttributeBuilder().Build())
.AddSymbol("com.app.test:id/id", ResourceId(0x7f020000))
.AddPublicSymbol("android:attr/paddingStart", ResourceId(0x010103b3),
test::AttributeBuilder().Build())
.AddPublicSymbol("android:attr/colorAccent", ResourceId(0x01010435),
test::AttributeBuilder().Build())
+ .AddSymbol("com.app.test.feature:id/foo", ResourceId(0x80020000))
+ .AddSymbol("com.app.test.feature:attr/foo", ResourceId(0x80010000),
+ test::AttributeBuilder().Build())
.Build())
.Build();
}
@@ -65,7 +68,7 @@
}
protected:
- std::unique_ptr<IAaptContext> context_;
+ std::unique_ptr<test::Context> context_;
};
TEST_F(XmlFlattenerTest, FlattenXmlWithNoCompiledAttributes) {
@@ -218,14 +221,10 @@
EXPECT_EQ(tree.indexOfStyle(), 1);
}
-/*
- * The device ResXMLParser in libandroidfw differentiates between empty
- * namespace and null
- * namespace.
- */
+// The device ResXMLParser in libandroidfw differentiates between empty namespace and null
+// namespace.
TEST_F(XmlFlattenerTest, NoNamespaceIsNotTheSameAsEmptyNamespace) {
- std::unique_ptr<xml::XmlResource> doc =
- test::BuildXmlDom("<View package=\"android\"/>");
+ std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom("<View package=\"android\"/>");
android::ResXMLTree tree;
ASSERT_TRUE(Flatten(doc.get(), &tree));
@@ -261,4 +260,44 @@
EXPECT_NE(nullptr, tree.getAttributeStringValue(idx, &len));
}
+TEST_F(XmlFlattenerTest, FlattenNonStandardPackageId) {
+ context_->SetCompilationPackage("com.app.test.feature");
+ context_->SetPackageId(0x80);
+ context_->SetNameManglerPolicy({"com.app.test.feature"});
+
+ std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDomForPackageName(context_.get(), R"EOF(
+ <View xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@id/foo"
+ app:foo="@id/foo" />)EOF");
+
+ XmlReferenceLinker linker;
+ ASSERT_TRUE(linker.Consume(context_.get(), doc.get()));
+
+ // The tree needs a custom DynamicRefTable since it is not using a standard app ID (0x7f).
+ android::DynamicRefTable dynamic_ref_table;
+ dynamic_ref_table.addMapping(0x80, 0x80);
+
+ android::ResXMLTree tree(&dynamic_ref_table);
+ ASSERT_TRUE(Flatten(doc.get(), &tree));
+
+ while (tree.next() != android::ResXMLTree::START_TAG) {
+ ASSERT_NE(android::ResXMLTree::BAD_DOCUMENT, tree.getEventType());
+ ASSERT_NE(android::ResXMLTree::END_DOCUMENT, tree.getEventType());
+ }
+
+ ssize_t idx;
+
+ idx = tree.indexOfAttribute(xml::kSchemaAndroid, "id");
+ ASSERT_GE(idx, 0);
+ EXPECT_EQ(idx, tree.indexOfID());
+ EXPECT_EQ(ResourceId(0x010100d0), ResourceId(tree.getAttributeNameResID(idx)));
+
+ idx = tree.indexOfAttribute(xml::kSchemaAuto, "foo");
+ ASSERT_GE(idx, 0);
+ EXPECT_EQ(ResourceId(0x80010000), ResourceId(tree.getAttributeNameResID(idx)));
+ EXPECT_EQ(android::Res_value::TYPE_REFERENCE, tree.getAttributeDataType(idx));
+ EXPECT_EQ(ResourceId(0x80020000), tree.getAttributeData(idx));
+}
+
} // namespace aapt
diff --git a/tools/aapt2/test/Context.h b/tools/aapt2/test/Context.h
index 29d1838..0564db0 100644
--- a/tools/aapt2/test/Context.h
+++ b/tools/aapt2/test/Context.h
@@ -52,15 +52,27 @@
return compilation_package_.value();
}
+ void SetCompilationPackage(const android::StringPiece& package) {
+ compilation_package_ = package.to_string();
+ }
+
uint8_t GetPackageId() override {
CHECK(bool(package_id_)) << "package ID not set";
return package_id_.value();
}
+ void SetPackageId(uint8_t package_id) {
+ package_id_ = package_id;
+ }
+
NameMangler* GetNameMangler() override {
return &name_mangler_;
}
+ void SetNameManglerPolicy(const NameManglerPolicy& policy) {
+ name_mangler_ = NameMangler(policy);
+ }
+
bool IsVerbose() override {
return false;
}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 229aa97..a7b4544 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -81,7 +81,7 @@
boolean disableNetwork(int netId);
- void startScan(in ScanSettings requested, in WorkSource ws);
+ void startScan(in ScanSettings requested, in WorkSource ws, in String packageName);
List<ScanResult> getScanResults(String callingPackage);
@@ -125,6 +125,8 @@
void setWifiApEnabled(in WifiConfiguration wifiConfig, boolean enable);
+ void updateInterfaceIpState(String ifaceName, int mode);
+
boolean startSoftAp(in WifiConfiguration wifiConfig);
boolean stopSoftAp();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index ed54c3b..ab069f2 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -20,7 +20,6 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
-import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.net.ConnectivityManager;
@@ -46,9 +45,9 @@
import com.android.server.net.NetworkPinner;
import java.net.InetAddress;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
-import java.util.Collections;
/**
* This class provides the primary API for managing all aspects of Wi-Fi
@@ -446,6 +445,35 @@
* @hide
*/
public static final int SAP_START_FAILURE_NO_CHANNEL = 1;
+
+ /**
+ * Interface IP mode for configuration error.
+ *
+ * @see updateInterfaceIpState(String, int)
+ *
+ * @hide
+ */
+ public static final int IFACE_IP_MODE_CONFIGURATION_ERROR = 0;
+
+ /**
+ * Interface IP mode for tethering.
+ *
+ * @see updateInterfaceIpState(String, int)
+ *
+ * @hide
+ */
+ public static final int IFACE_IP_MODE_TETHERED = 1;
+
+ /**
+ * Interface IP mode for Local Only Hotspot.
+ *
+ * @see updateInterfaceIpState(String, int)
+ *
+ * @hide
+ */
+ public static final int IFACE_IP_MODE_LOCAL_ONLY = 2;
+
+
/**
* Broadcast intent action indicating that a connection to the supplicant has
* been established (and it is now possible
@@ -1429,19 +1457,15 @@
* @return {@code true} if the operation succeeded, i.e., the scan was initiated
*/
public boolean startScan() {
- try {
- mService.startScan(null, null);
- return true;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return startScan(null);
}
/** @hide */
@SystemApi
public boolean startScan(WorkSource workSource) {
try {
- mService.startScan(null, workSource);
+ String packageName = mContext.getOpPackageName();
+ mService.startScan(null, workSource, packageName);
return true;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1732,6 +1756,26 @@
}
/**
+ * Call allowing ConnectivityService to update WifiService with interface mode changes.
+ *
+ * The possible modes include: {@link IFACE_IP_MODE_TETHERED},
+ * {@link IFACE_IP_MODE_LOCAL_ONLY},
+ * {@link IFACE_IP_MODE_CONFIGURATION_ERROR}
+ *
+ * @param ifaceName String name of the updated interface
+ * @param mode int representing the new mode
+ *
+ * @hide
+ */
+ public void updateInterfaceIpState(String ifaceName, int mode) {
+ try {
+ mService.updateInterfaceIpState(ifaceName, mode);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Start SoftAp mode with the specified configuration.
* Note that starting in access point mode disables station
* mode operation