Merge "Remove activity from task if not set properly."
diff --git a/api/current.txt b/api/current.txt
index 1d02ded..db13a0b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1005,7 +1005,7 @@
field public static final int preferenceStyle = 16842894; // 0x101008e
field public static final int presentationTheme = 16843712; // 0x10103c0
field public static final int previewImage = 16843482; // 0x10102da
- field public static final int primaryContentAlpha = 16843367; // 0x1010267
+ field public static final int primaryContentAlpha = 16844117; // 0x1010555
field public static final int priority = 16842780; // 0x101001c
field public static final int privateImeOptions = 16843299; // 0x1010223
field public static final int process = 16842769; // 0x1010011
@@ -1061,7 +1061,9 @@
field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
field public static final int required = 16843406; // 0x101028e
field public static final int requiredAccountType = 16843734; // 0x10103d6
+ field public static final int requiredFeature = 16844119; // 0x1010557
field public static final int requiredForAllUsers = 16843728; // 0x10103d0
+ field public static final int requiredNotFeature = 16844120; // 0x1010558
field public static final int requiresFadingEdge = 16843685; // 0x10103a5
field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
field public static final int resizeClip = 16843983; // 0x10104cf
@@ -1130,7 +1132,7 @@
field public static final int searchSuggestSelection = 16843224; // 0x10101d8
field public static final int searchSuggestThreshold = 16843373; // 0x101026d
field public static final int searchViewStyle = 16843904; // 0x1010480
- field public static final int secondaryContentAlpha = 16843688; // 0x10103a8
+ field public static final int secondaryContentAlpha = 16844118; // 0x1010556
field public static final int secondaryProgress = 16843064; // 0x1010138
field public static final int secondaryProgressTint = 16843879; // 0x1010467
field public static final int secondaryProgressTintMode = 16843880; // 0x1010468
@@ -5482,6 +5484,7 @@
public final class NotificationChannel implements android.os.Parcelable {
ctor public NotificationChannel(java.lang.String, java.lang.CharSequence, int);
+ ctor public NotificationChannel(java.lang.String, int, int);
ctor protected NotificationChannel(android.os.Parcel);
method public boolean canBypassDnd();
method public boolean canShowBadge();
@@ -5495,6 +5498,7 @@
method public int getLightColor();
method public int getLockscreenVisibility();
method public java.lang.CharSequence getName();
+ method public int getNameResId();
method public android.net.Uri getSound();
method public long[] getVibrationPattern();
method public void setBypassDnd(boolean);
@@ -13831,12 +13835,12 @@
}
public final class Icon implements android.os.Parcelable {
+ method public static android.graphics.drawable.Icon createWithAdaptiveBitmap(android.graphics.Bitmap);
method public static android.graphics.drawable.Icon createWithBitmap(android.graphics.Bitmap);
method public static android.graphics.drawable.Icon createWithContentUri(java.lang.String);
method public static android.graphics.drawable.Icon createWithContentUri(android.net.Uri);
method public static android.graphics.drawable.Icon createWithData(byte[], int, int);
method public static android.graphics.drawable.Icon createWithFilePath(java.lang.String);
- method public static android.graphics.drawable.Icon createWithMaskableBitmap(android.graphics.Bitmap);
method public static android.graphics.drawable.Icon createWithResource(android.content.Context, int);
method public static android.graphics.drawable.Icon createWithResource(java.lang.String, int);
method public int describeContents();
diff --git a/api/system-current.txt b/api/system-current.txt
index 21b0bec..9536d13 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1117,7 +1117,7 @@
field public static final int preferenceStyle = 16842894; // 0x101008e
field public static final int presentationTheme = 16843712; // 0x10103c0
field public static final int previewImage = 16843482; // 0x10102da
- field public static final int primaryContentAlpha = 16843367; // 0x1010267
+ field public static final int primaryContentAlpha = 16844117; // 0x1010555
field public static final int priority = 16842780; // 0x101001c
field public static final int privateImeOptions = 16843299; // 0x1010223
field public static final int process = 16842769; // 0x1010011
@@ -1173,7 +1173,9 @@
field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
field public static final int required = 16843406; // 0x101028e
field public static final int requiredAccountType = 16843734; // 0x10103d6
+ field public static final int requiredFeature = 16844119; // 0x1010557
field public static final int requiredForAllUsers = 16843728; // 0x10103d0
+ field public static final int requiredNotFeature = 16844120; // 0x1010558
field public static final int requiresFadingEdge = 16843685; // 0x10103a5
field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
field public static final int resizeClip = 16843983; // 0x10104cf
@@ -1246,7 +1248,7 @@
field public static final int searchSuggestSelection = 16843224; // 0x10101d8
field public static final int searchSuggestThreshold = 16843373; // 0x101026d
field public static final int searchViewStyle = 16843904; // 0x1010480
- field public static final int secondaryContentAlpha = 16843688; // 0x10103a8
+ field public static final int secondaryContentAlpha = 16844118; // 0x1010556
field public static final int secondaryProgress = 16843064; // 0x1010138
field public static final int secondaryProgressTint = 16843879; // 0x1010467
field public static final int secondaryProgressTintMode = 16843880; // 0x1010468
@@ -5658,6 +5660,7 @@
public final class NotificationChannel implements android.os.Parcelable {
ctor public NotificationChannel(java.lang.String, java.lang.CharSequence, int);
+ ctor public NotificationChannel(java.lang.String, int, int);
ctor protected NotificationChannel(android.os.Parcel);
method public boolean canBypassDnd();
method public boolean canShowBadge();
@@ -5671,6 +5674,7 @@
method public int getLightColor();
method public int getLockscreenVisibility();
method public java.lang.CharSequence getName();
+ method public int getNameResId();
method public android.net.Uri getSound();
method public int getUserLockedFields();
method public long[] getVibrationPattern();
@@ -14466,12 +14470,12 @@
}
public final class Icon implements android.os.Parcelable {
+ method public static android.graphics.drawable.Icon createWithAdaptiveBitmap(android.graphics.Bitmap);
method public static android.graphics.drawable.Icon createWithBitmap(android.graphics.Bitmap);
method public static android.graphics.drawable.Icon createWithContentUri(java.lang.String);
method public static android.graphics.drawable.Icon createWithContentUri(android.net.Uri);
method public static android.graphics.drawable.Icon createWithData(byte[], int, int);
method public static android.graphics.drawable.Icon createWithFilePath(java.lang.String);
- method public static android.graphics.drawable.Icon createWithMaskableBitmap(android.graphics.Bitmap);
method public static android.graphics.drawable.Icon createWithResource(android.content.Context, int);
method public static android.graphics.drawable.Icon createWithResource(java.lang.String, int);
method public int describeContents();
diff --git a/api/test-current.txt b/api/test-current.txt
index 94605de..5776bc3 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1005,7 +1005,7 @@
field public static final int preferenceStyle = 16842894; // 0x101008e
field public static final int presentationTheme = 16843712; // 0x10103c0
field public static final int previewImage = 16843482; // 0x10102da
- field public static final int primaryContentAlpha = 16843367; // 0x1010267
+ field public static final int primaryContentAlpha = 16844117; // 0x1010555
field public static final int priority = 16842780; // 0x101001c
field public static final int privateImeOptions = 16843299; // 0x1010223
field public static final int process = 16842769; // 0x1010011
@@ -1061,7 +1061,9 @@
field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
field public static final int required = 16843406; // 0x101028e
field public static final int requiredAccountType = 16843734; // 0x10103d6
+ field public static final int requiredFeature = 16844119; // 0x1010557
field public static final int requiredForAllUsers = 16843728; // 0x10103d0
+ field public static final int requiredNotFeature = 16844120; // 0x1010558
field public static final int requiresFadingEdge = 16843685; // 0x10103a5
field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
field public static final int resizeClip = 16843983; // 0x10104cf
@@ -1130,7 +1132,7 @@
field public static final int searchSuggestSelection = 16843224; // 0x10101d8
field public static final int searchSuggestThreshold = 16843373; // 0x101026d
field public static final int searchViewStyle = 16843904; // 0x1010480
- field public static final int secondaryContentAlpha = 16843688; // 0x10103a8
+ field public static final int secondaryContentAlpha = 16844118; // 0x1010556
field public static final int secondaryProgress = 16843064; // 0x1010138
field public static final int secondaryProgressTint = 16843879; // 0x1010467
field public static final int secondaryProgressTintMode = 16843880; // 0x1010468
@@ -5492,6 +5494,7 @@
public final class NotificationChannel implements android.os.Parcelable {
ctor public NotificationChannel(java.lang.String, java.lang.CharSequence, int);
+ ctor public NotificationChannel(java.lang.String, int, int);
ctor protected NotificationChannel(android.os.Parcel);
method public boolean canBypassDnd();
method public boolean canShowBadge();
@@ -5505,6 +5508,7 @@
method public int getLightColor();
method public int getLockscreenVisibility();
method public java.lang.CharSequence getName();
+ method public int getNameResId();
method public android.net.Uri getSound();
method public long[] getVibrationPattern();
method public void setBypassDnd(boolean);
@@ -13869,12 +13873,12 @@
}
public final class Icon implements android.os.Parcelable {
+ method public static android.graphics.drawable.Icon createWithAdaptiveBitmap(android.graphics.Bitmap);
method public static android.graphics.drawable.Icon createWithBitmap(android.graphics.Bitmap);
method public static android.graphics.drawable.Icon createWithContentUri(java.lang.String);
method public static android.graphics.drawable.Icon createWithContentUri(android.net.Uri);
method public static android.graphics.drawable.Icon createWithData(byte[], int, int);
method public static android.graphics.drawable.Icon createWithFilePath(java.lang.String);
- method public static android.graphics.drawable.Icon createWithMaskableBitmap(android.graphics.Bitmap);
method public static android.graphics.drawable.Icon createWithResource(android.content.Context, int);
method public static android.graphics.drawable.Icon createWithResource(java.lang.String, int);
method public int describeContents();
diff --git a/core/java/android/app/FragmentTransition.java b/core/java/android/app/FragmentTransition.java
index f62ab8d..780a922 100644
--- a/core/java/android/app/FragmentTransition.java
+++ b/core/java/android/app/FragmentTransition.java
@@ -780,8 +780,10 @@
names = inTransaction.mSharedElementTargetNames;
}
- inSharedElements.retainAll(names);
- if (sharedElementCallback != null) {
+ if (names != null) {
+ inSharedElements.retainAll(names);
+ }
+ if (names != null && sharedElementCallback != null) {
sharedElementCallback.onMapSharedElements(names, inSharedElements);
for (int i = names.size() - 1; i >= 0; i--) {
String name = names.get(i);
@@ -830,8 +832,9 @@
FragmentContainerTransition fragments,
Transition enterTransition, boolean inIsPop) {
BackStackRecord inTransaction = fragments.lastInTransaction;
- if (enterTransition != null && inTransaction.mSharedElementSourceNames != null &&
- !inTransaction.mSharedElementSourceNames.isEmpty()) {
+ if (enterTransition != null && inSharedElements != null
+ && inTransaction.mSharedElementSourceNames != null
+ && !inTransaction.mSharedElementSourceNames.isEmpty()) {
final String targetName = inIsPop
? inTransaction.mSharedElementSourceNames.get(0)
: inTransaction.mSharedElementTargetNames.get(0);
@@ -1096,7 +1099,9 @@
if (transition != null) {
viewList = new ArrayList<>();
View root = fragment.getView();
- root.captureTransitioningViews(viewList);
+ if (root != null) {
+ root.captureTransitioningViews(viewList);
+ }
if (sharedElements != null) {
viewList.removeAll(sharedElements);
}
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 1a51608..85e6b85 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -20,8 +20,10 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringRes;
import android.annotation.SystemApi;
-import android.graphics.Color;
import android.media.AudioAttributes;
import android.net.Uri;
import android.os.Parcel;
@@ -45,6 +47,7 @@
private static final String TAG_CHANNEL = "channel";
private static final String ATT_NAME = "name";
+ private static final String ATT_NAME_RES_ID = "name_res_id";
private static final String ATT_ID = "id";
private static final String ATT_DELETED = "deleted";
private static final String ATT_PRIORITY = "priority";
@@ -138,6 +141,7 @@
private final String mId;
private CharSequence mName;
+ private int mNameResId = 0;
private int mImportance = DEFAULT_IMPORTANCE;
private boolean mBypassDnd;
private int mLockscreenVisibility = DEFAULT_VISIBILITY;
@@ -156,7 +160,9 @@
* Creates a notification channel.
*
* @param id The id of the channel. Must be unique per package.
- * @param name The user visible name of the channel.
+ * @param name The user visible name of the channel. Unchangeable once created; use this
+ * constructor if the channel represents a user-defined category that does not
+ * need to be translated.
* @param importance The importance of the channel. This controls how interruptive notifications
* posted to this channel are. See e.g.
* {@link NotificationManager#IMPORTANCE_DEFAULT}.
@@ -167,6 +173,21 @@
this.mImportance = importance;
}
+ /**
+ * Creates a notification channel.
+ *
+ * @param id The id of the channel. Must be unique per package.
+ * @param nameResId The resource id of the string containing the channel name.
+ * @param importance The importance of the channel. This controls how interruptive notifications
+ * posted to this channel are. See e.g.
+ * {@link NotificationManager#IMPORTANCE_DEFAULT}.
+ */
+ public NotificationChannel(String id, @StringRes int nameResId, int importance) {
+ this.mId = id;
+ this.mNameResId = nameResId;
+ this.mImportance = importance;
+ }
+
protected NotificationChannel(Parcel in) {
if (in.readByte() != 0) {
mId = in.readString();
@@ -174,6 +195,7 @@
mId = null;
}
mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ mNameResId = in.readInt();
mImportance = in.readInt();
mBypassDnd = in.readByte() != 0;
mLockscreenVisibility = in.readInt();
@@ -206,6 +228,7 @@
dest.writeByte((byte) 0);
}
TextUtils.writeToParcel(mName, dest, flags);
+ dest.writeInt(mNameResId);
dest.writeInt(mImportance);
dest.writeByte(mBypassDnd ? (byte) 1 : (byte) 0);
dest.writeInt(mLockscreenVisibility);
@@ -382,11 +405,18 @@
/**
* Returns the user visible name of this channel.
*/
- public CharSequence getName() {
+ public @Nullable CharSequence getName() {
return mName;
}
/**
+ * Returns the resource id of the user visible name of this channel.
+ */
+ public int getNameResId() {
+ return mNameResId;
+ }
+
+ /**
* Returns the user specified importance {e.g. @link NotificationManager#IMPORTANCE_LOW} for
* notifications posted to this channel.
*/
@@ -516,7 +546,10 @@
public void writeXml(XmlSerializer out) throws IOException {
out.startTag(null, TAG_CHANNEL);
out.attribute(null, ATT_ID, getId());
- out.attribute(null, ATT_NAME, getName().toString());
+ if (getName() != null) {
+ out.attribute(null, ATT_NAME, getName().toString());
+ }
+ out.attribute(null, ATT_NAME_RES_ID, Integer.toString(getNameResId()));
if (getImportance() != DEFAULT_IMPORTANCE) {
out.attribute(
null, ATT_IMPORTANCE, Integer.toString(getImportance()));
@@ -574,6 +607,7 @@
JSONObject record = new JSONObject();
record.put(ATT_ID, getId());
record.put(ATT_NAME, getName());
+ record.put(ATT_NAME_RES_ID, getNameResId());
if (getImportance() != DEFAULT_IMPORTANCE) {
record.put(ATT_IMPORTANCE,
NotificationListenerService.Ranking.importanceToString(getImportance()));
@@ -691,6 +725,7 @@
NotificationChannel that = (NotificationChannel) o;
+ if (getNameResId() != that.getNameResId()) return false;
if (getImportance() != that.getImportance()) return false;
if (mBypassDnd != that.mBypassDnd) return false;
if (getLockscreenVisibility() != that.getLockscreenVisibility()) return false;
@@ -720,6 +755,7 @@
public int hashCode() {
int result = getId() != null ? getId().hashCode() : 0;
result = 31 * result + (getName() != null ? getName().hashCode() : 0);
+ result = 31 * result + getNameResId();
result = 31 * result + getImportance();
result = 31 * result + (mBypassDnd ? 1 : 0);
result = 31 * result + getLockscreenVisibility();
@@ -741,6 +777,7 @@
return "NotificationChannel{" +
"mId='" + mId + '\'' +
", mName=" + mName +
+ ", mNameResId=" + mNameResId +
", mImportance=" + mImportance +
", mBypassDnd=" + mBypassDnd +
", mLockscreenVisibility=" + mLockscreenVisibility +
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 776492a..c3fd089 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -829,7 +829,7 @@
final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
if (bmp != null) {
BitmapDrawable dr = new BitmapDrawable(mContext.getResources(), bmp);
- if (shortcut.hasMaskableBitmap()) {
+ if (shortcut.hasAdaptiveBitmap()) {
return new AdaptiveIconDrawable(null, dr);
} else {
return dr;
@@ -854,7 +854,7 @@
icon.getResId(), shortcut.getUserHandle(), density);
}
case Icon.TYPE_BITMAP:
- case Icon.TYPE_BITMAP_MASKABLE: {
+ case Icon.TYPE_ADAPTIVE_BITMAP: {
return icon.loadDrawable(mContext);
}
default:
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 9fda3cd..73dc996 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -5000,6 +5000,7 @@
*/
public PackageInfo getPackageArchiveInfo(String archiveFilePath, @PackageInfoFlags int flags) {
final PackageParser parser = new PackageParser();
+ parser.setCallback(new PackageParser.CallbackImpl(this));
final File apkFile = new File(archiveFilePath);
try {
if ((flags & (MATCH_DIRECT_BOOT_UNAWARE | MATCH_DIRECT_BOOT_AWARE)) != 0) {
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index f801e45..60cc6b0 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -285,6 +285,7 @@
private String[] mSeparateProcesses;
private boolean mOnlyCoreApps;
private DisplayMetrics mMetrics;
+ private Callback mCallback;
private File mCacheDir;
private static final int SDK_VERSION = Build.VERSION.SDK_INT;
@@ -506,6 +507,37 @@
mCacheDir = cacheDir;
}
+ /**
+ * Callback interface for retrieving information that may be needed while parsing
+ * a package.
+ */
+ public interface Callback {
+ boolean hasFeature(String feature);
+ }
+
+ /**
+ * Standard implementation of {@link Callback} on top of the public {@link PackageManager}
+ * class.
+ */
+ public static final class CallbackImpl implements Callback {
+ private final PackageManager mPm;
+
+ public CallbackImpl(PackageManager pm) {
+ mPm = pm;
+ }
+
+ @Override public boolean hasFeature(String feature) {
+ return mPm.hasSystemFeature(feature);
+ }
+ }
+
+ /**
+ * Set the {@link Callback} that can be used while parsing.
+ */
+ public void setCallback(Callback cb) {
+ mCallback = cb;
+ }
+
public static final boolean isApkFile(File file) {
return isApkPath(file.getName());
}
@@ -2079,15 +2111,15 @@
return null;
}
} else if (tagName.equals(TAG_PERMISSION_GROUP)) {
- if (parsePermissionGroup(pkg, flags, res, parser, outError) == null) {
+ if (!parsePermissionGroup(pkg, flags, res, parser, outError)) {
return null;
}
} else if (tagName.equals(TAG_PERMISSION)) {
- if (parsePermission(pkg, res, parser, outError) == null) {
+ if (!parsePermission(pkg, res, parser, outError)) {
return null;
}
} else if (tagName.equals(TAG_PERMISSION_TREE)) {
- if (parsePermissionTree(pkg, res, parser, outError) == null) {
+ if (!parsePermissionTree(pkg, res, parser, outError)) {
return null;
}
} else if (tagName.equals(TAG_USES_PERMISSION)) {
@@ -2708,22 +2740,44 @@
}
}
+ final String requiredFeature = sa.getNonConfigurationString(
+ com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredFeature, 0);
+
+ final String requiredNotfeature = sa.getNonConfigurationString(
+ com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredNotFeature, 0);
+
sa.recycle();
- if ((maxSdkVersion == 0) || (maxSdkVersion >= Build.VERSION.RESOURCES_SDK_INT)) {
- if (name != null) {
- int index = pkg.requestedPermissions.indexOf(name);
- if (index == -1) {
- pkg.requestedPermissions.add(name.intern());
- } else {
- Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
- + name + " in package: " + pkg.packageName + " at: "
- + parser.getPositionDescription());
- }
- }
+ XmlUtils.skipCurrentTag(parser);
+
+ if (name == null) {
+ return true;
}
- XmlUtils.skipCurrentTag(parser);
+ if ((maxSdkVersion != 0) && (maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT)) {
+ return true;
+ }
+
+ // Only allow requesting this permission if the platform supports the given feature.
+ if (requiredFeature != null && mCallback != null && !mCallback.hasFeature(requiredFeature)) {
+ return true;
+ }
+
+ // Only allow requesting this permission if the platform doesn't support the given feature.
+ if (requiredNotfeature != null && mCallback != null
+ && mCallback.hasFeature(requiredNotfeature)) {
+ return true;
+ }
+
+ int index = pkg.requestedPermissions.indexOf(name);
+ if (index == -1) {
+ pkg.requestedPermissions.add(name.intern());
+ } else {
+ Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
+ + name + " in package: " + pkg.packageName + " at: "
+ + parser.getPositionDescription());
+ }
+
return true;
}
@@ -2951,7 +3005,7 @@
return true;
}
- private PermissionGroup parsePermissionGroup(Package owner, int flags, Resources res,
+ private boolean parsePermissionGroup(Package owner, int flags, Resources res,
XmlResourceParser parser, String[] outError)
throws XmlPullParserException, IOException {
PermissionGroup perm = new PermissionGroup(owner);
@@ -2968,7 +3022,7 @@
com.android.internal.R.styleable.AndroidManifestPermissionGroup_banner)) {
sa.recycle();
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
perm.info.descriptionRes = sa.getResourceId(
@@ -2987,22 +3041,22 @@
if (!parseAllMetaData(res, parser, "<permission-group>", perm,
outError)) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
owner.permissionGroups.add(perm);
- return perm;
+ return true;
}
- private Permission parsePermission(Package owner, Resources res,
+ private boolean parsePermission(Package owner, Resources res,
XmlResourceParser parser, String[] outError)
throws XmlPullParserException, IOException {
- Permission perm = new Permission(owner);
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifestPermission);
+ Permission perm = new Permission(owner);
if (!parsePackageItemInfo(owner, perm.info, outError,
"<permission>", sa, true /*nameRequired*/,
com.android.internal.R.styleable.AndroidManifestPermission_name,
@@ -3013,7 +3067,7 @@
com.android.internal.R.styleable.AndroidManifestPermission_banner)) {
sa.recycle();
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
// Note: don't allow this value to be a reference to a resource
@@ -3040,7 +3094,7 @@
if (perm.info.protectionLevel == -1) {
outError[0] = "<permission> does not specify protectionLevel";
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
perm.info.protectionLevel = PermissionInfo.fixProtectionLevel(perm.info.protectionLevel);
@@ -3052,21 +3106,21 @@
outError[0] = "<permission> protectionLevel specifies a non-ephemeral flag but is "
+ "not based on signature type";
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
}
if (!parseAllMetaData(res, parser, "<permission>", perm, outError)) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
owner.permissions.add(perm);
- return perm;
+ return true;
}
- private Permission parsePermissionTree(Package owner, Resources res,
+ private boolean parsePermissionTree(Package owner, Resources res,
XmlResourceParser parser, String[] outError)
throws XmlPullParserException, IOException {
Permission perm = new Permission(owner);
@@ -3084,7 +3138,7 @@
com.android.internal.R.styleable.AndroidManifestPermissionTree_banner)) {
sa.recycle();
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
sa.recycle();
@@ -3097,7 +3151,7 @@
outError[0] = "<permission-tree> name has less than three segments: "
+ perm.info.name;
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
perm.info.descriptionRes = 0;
@@ -3107,12 +3161,12 @@
if (!parseAllMetaData(res, parser, "<permission-tree>", perm,
outError)) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
owner.permissions.add(perm);
- return perm;
+ return true;
}
private Instrumentation parseInstrumentation(Package owner, Resources res,
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index d3d3c66..5201694 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -96,7 +96,7 @@
public static final int FLAG_IMMUTABLE = 1 << 8;
/** @hide */
- public static final int FLAG_MASKABLE_BITMAP = 1 << 9;
+ public static final int FLAG_ADAPTIVE_BITMAP = 1 << 9;
/** @hide */
public static final int FLAG_CHOOSER = 1 << 10;
@@ -118,7 +118,7 @@
FLAG_DISABLED,
FLAG_STRINGS_RESOLVED,
FLAG_IMMUTABLE,
- FLAG_MASKABLE_BITMAP,
+ FLAG_ADAPTIVE_BITMAP,
FLAG_CHOOSER,
})
@Retention(RetentionPolicy.SOURCE)
@@ -784,7 +784,7 @@
switch (icon.getType()) {
case Icon.TYPE_RESOURCE:
case Icon.TYPE_BITMAP:
- case Icon.TYPE_BITMAP_MASKABLE:
+ case Icon.TYPE_ADAPTIVE_BITMAP:
break; // OK
default:
throw getInvalidIconException();
@@ -917,7 +917,7 @@
* and will be ignored.
*
* <p>Only icons created with {@link Icon#createWithBitmap(Bitmap)},
- * {@link Icon#createWithMaskableBitmap(Bitmap)}
+ * {@link Icon#createWithAdaptiveBitmap(Bitmap)}
* and {@link Icon#createWithResource} are supported.
* Other types, such as URI-based icons, are not supported.
*
@@ -1615,12 +1615,13 @@
}
/**
- * Return whether a shortcut's icon is maskable.
+ * Return whether a shortcut's icon is adaptive bitmap following design guideline
+ * defined in {@link AdaptiveIconDrawable}.
*
* @hide internal/unit tests only
*/
- public boolean hasMaskableBitmap() {
- return hasFlags(FLAG_MASKABLE_BITMAP);
+ public boolean hasAdaptiveBitmap() {
+ return hasFlags(FLAG_ADAPTIVE_BITMAP);
}
/**
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index b9e4bad..caea202 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -506,7 +506,7 @@
}
/**
- * Detect unbuffered input/output operations.
+ * Disable detection of unbuffered input/output operations.
*/
public Builder permitUnbufferedIo() {
return disable(DETECT_UNBUFFERED_IO);
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 089eaec..62c5dca 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -410,11 +410,13 @@
/**
* Sets a {@link PreferenceDataStore} to be used by this Preference instead of using
* {@link android.content.SharedPreferences}.
- * <p>
- * The data store will remain assigned even if the Preference is moved between multiple
- * instances of {@link PreferenceFragment}.
+ *
+ * <p>The data store will remain assigned even if the Preference is moved around the preference
+ * hierarchy. It will also override a data store propagated from the {@link PreferenceManager}
+ * that owns this Preference.
*
* @param dataStore The {@link PreferenceDataStore} to be used by this Preference.
+ * @see PreferenceManager#setPreferenceDataStore(PreferenceDataStore)
*/
public void setPreferenceDataStore(PreferenceDataStore dataStore) {
mPreferenceDataStore = dataStore;
@@ -424,6 +426,12 @@
* Returns {@link PreferenceDataStore} used by this Preference. Returns {@code null} if
* {@link android.content.SharedPreferences} is used instead.
*
+ * <p>By default preferences always use {@link android.content.SharedPreferences}. To make this
+ * preference to use the {@link PreferenceDataStore} you need to assign your implementation
+ * to the Preference itself via {@link #setPreferenceDataStore(PreferenceDataStore)} or to its
+ * {@link PreferenceManager} via
+ * {@link PreferenceManager#setPreferenceDataStore(PreferenceDataStore)}.
+ *
* @return The {@link PreferenceDataStore} used by this Preference or {@code null} if none.
*/
@Nullable
@@ -1457,12 +1465,12 @@
}
/**
- * Implement this to set the initial value of the Preference.
+ * Implement this to set the initial value of the Preference.
* <p>
- * If <var>restorePersistedValue</var> is true, you should restore the
- * Preference value from the {@link android.content.SharedPreferences}. If
- * <var>restorePersistedValue</var> is false, you should set the Preference
- * value to defaultValue that is given (and possibly store to SharedPreferences
+ * If <var>restorePersistedValue</var> is true, you should restore the
+ * Preference value from the {@link android.content.SharedPreferences}. If
+ * <var>restorePersistedValue</var> is false, you should set the Preference
+ * value to defaultValue that is given (and possibly store to SharedPreferences
* if {@link #shouldPersist()} is true).
* <p>
* This may not always be called. One example is if it should not persist
diff --git a/core/java/android/preference/PreferenceDataStore.java b/core/java/android/preference/PreferenceDataStore.java
index e1a08ac..8caa404 100644
--- a/core/java/android/preference/PreferenceDataStore.java
+++ b/core/java/android/preference/PreferenceDataStore.java
@@ -21,16 +21,32 @@
import java.util.Set;
/**
- * A data store interface to be implemented and provided to the Preferences framework.
+ * A data store interface to be implemented and provided to the Preferences framework. This can be
+ * used to replace the default {@link android.content.SharedPreferences}, if needed.
*
- * Use this to replace the default {@link android.content.SharedPreferences}. By default, all "put"
- * methods throw {@link UnsupportedOperationException}.
+ * <p>In most cases you want to use {@link android.content.SharedPreferences} as it is automatically
+ * backed up and migrated to new devices. However, providing custom data store to preferences can be
+ * useful if your app stores its preferences in a local db, cloud or they are device specific like
+ * "Developer settings". It might be also useful when you want to use the preferences UI but
+ * the data are not supposed to be stored at all because they are valid per session only.
+ *
+ * <p>Once a put method is called it is full responsibility of the data store implementation to
+ * safely store the given values. Time expensive operations need to be done in the background to
+ * prevent from blocking the UI. You also need to have a plan on how to serialize the data in case
+ * the activity holding this object gets destroyed.
+ *
+ * <p>By default, all "put" methods throw {@link UnsupportedOperationException}.
+ *
+ * @see Preference#setPreferenceDataStore(PreferenceDataStore)
+ * @see PreferenceManager#setPreferenceDataStore(PreferenceDataStore)
*/
public interface PreferenceDataStore {
/**
* Set a String value to the data store.
*
+ * <p>Once the value is set the data store is responsible for holding it.
+ *
* @param key The name of the preference to modify.
* @param value The new value for the preference.
* @see #getString(String, String)
@@ -42,6 +58,8 @@
/**
* Set a set of String value to the data store.
*
+ * <p>Once the value is set the data store is responsible for holding it.
+ *
* @param key The name of the preference to modify.
* @param values The set of new values for the preference.
* @see #getStringSet(String, Set)
@@ -53,6 +71,8 @@
/**
* Set an int value to the data store.
*
+ * <p>Once the value is set the data store is responsible for holding it.
+ *
* @param key The name of the preference to modify.
* @param value The new value for the preference.
* @see #getInt(String, int)
@@ -64,6 +84,8 @@
/**
* Set a long value to the data store.
*
+ * <p>Once the value is set the data store is responsible for holding it.
+ *
* @param key The name of the preference to modify.
* @param value The new value for the preference.
* @see #getLong(String, long)
@@ -75,6 +97,8 @@
/**
* Set a float value to the data store.
*
+ * <p>Once the value is set the data store is responsible for holding it.
+ *
* @param key The name of the preference to modify.
* @param value The new value for the preference.
* @see #getFloat(String, float)
@@ -86,6 +110,8 @@
/**
* Set a boolean value to the data store.
*
+ * <p>Once the value is set the data store is responsible for holding it.
+ *
* @param key The name of the preference to modify.
* @param value The new value for the preference.
* @see #getBoolean(String, boolean)
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index 756c3f4..2570374 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -208,10 +208,13 @@
/**
* Sets a {@link PreferenceDataStore} to be used by all Preferences associated with this manager
- * that don't have a custom {@link PreferenceDataStore} assigned. Also if the data store is set,
- * the Preferences will no longer use {@link android.content.SharedPreferences}.
+ * that don't have a custom {@link PreferenceDataStore} assigned via
+ * {@link Preference#setPreferenceDataStore(PreferenceDataStore)}. Also if the data store is
+ * set, the child preferences won't use {@link android.content.SharedPreferences} as long as
+ * they are assigned to this manager.
*
* @param dataStore The {@link PreferenceDataStore} to be used by this manager.
+ * @see Preference#setPreferenceDataStore(PreferenceDataStore)
*/
public void setPreferenceDataStore(PreferenceDataStore dataStore) {
mPreferenceDataStore = dataStore;
@@ -219,9 +222,10 @@
/**
* Returns the {@link PreferenceDataStore} associated with this manager or {@code null} if
- * {@link android.content.SharedPreferences} are used instead.
+ * the default {@link android.content.SharedPreferences} are used instead.
*
* @return The {@link PreferenceDataStore} associated with this manager or {@code null} if none.
+ * @see #setPreferenceDataStore(PreferenceDataStore)
*/
@Nullable
public PreferenceDataStore getPreferenceDataStore() {
@@ -358,8 +362,11 @@
* Sets the name of the SharedPreferences file that preferences managed by this
* will use.
*
+ * <p>If custom {@link PreferenceDataStore} is set, this won't override its usage.
+ *
* @param sharedPreferencesName The name of the SharedPreferences file.
* @see Context#getSharedPreferences(String, int)
+ * @see #setPreferenceDataStore(PreferenceDataStore)
*/
public void setSharedPreferencesName(String sharedPreferencesName) {
mSharedPreferencesName = sharedPreferencesName;
diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java
index c840f26..ec3aac2 100644
--- a/core/java/com/android/internal/notification/SystemNotificationChannels.java
+++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java
@@ -48,12 +48,12 @@
List<NotificationChannel> channelsList = new ArrayList<NotificationChannel>();
channelsList.add(new NotificationChannel(
VIRTUAL_KEYBOARD,
- context.getString(R.string.notification_channel_virtual_keyboard),
+ R.string.notification_channel_virtual_keyboard,
NotificationManager.IMPORTANCE_LOW));
final NotificationChannel physicalKeyboardChannel = new NotificationChannel(
PHYSICAL_KEYBOARD,
- context.getString(R.string.notification_channel_physical_keyboard),
+ R.string.notification_channel_physical_keyboard,
NotificationManager.IMPORTANCE_DEFAULT);
physicalKeyboardChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
Notification.AUDIO_ATTRIBUTES_DEFAULT);
@@ -61,32 +61,32 @@
channelsList.add(new NotificationChannel(
SECURITY,
- context.getString(R.string.notification_channel_security),
+ R.string.notification_channel_security,
NotificationManager.IMPORTANCE_LOW));
channelsList.add(new NotificationChannel(
CAR_MODE,
- context.getString(R.string.notification_channel_car_mode),
+ R.string.notification_channel_car_mode,
NotificationManager.IMPORTANCE_LOW));
channelsList.add(new NotificationChannel(
DEVELOPER,
- context.getString(R.string.notification_channel_developer),
+ R.string.notification_channel_developer,
NotificationManager.IMPORTANCE_LOW));
channelsList.add(new NotificationChannel(
UPDATES,
- context.getString(R.string.notification_channel_updates),
+ R.string.notification_channel_updates,
NotificationManager.IMPORTANCE_LOW));
channelsList.add(new NotificationChannel(
NETWORK_STATUS,
- context.getString(R.string.notification_channel_network_status),
+ R.string.notification_channel_network_status,
NotificationManager.IMPORTANCE_LOW));
final NotificationChannel networkAlertsChannel = new NotificationChannel(
NETWORK_ALERTS,
- context.getString(R.string.notification_channel_network_alerts),
+ R.string.notification_channel_network_alerts,
NotificationManager.IMPORTANCE_HIGH);
networkAlertsChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
Notification.AUDIO_ATTRIBUTES_DEFAULT);
@@ -94,17 +94,17 @@
channelsList.add(new NotificationChannel(
VPN,
- context.getString(R.string.notification_channel_vpn),
+ R.string.notification_channel_vpn,
NotificationManager.IMPORTANCE_LOW));
channelsList.add(new NotificationChannel(
DEVICE_ADMIN,
- context.getString(R.string.notification_channel_device_admin),
+ R.string.notification_channel_device_admin,
NotificationManager.IMPORTANCE_LOW));
final NotificationChannel alertsChannel = new NotificationChannel(
ALERTS,
- context.getString(R.string.notification_channel_alerts),
+ R.string.notification_channel_alerts,
NotificationManager.IMPORTANCE_DEFAULT);
alertsChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
Notification.AUDIO_ATTRIBUTES_DEFAULT);
@@ -112,12 +112,12 @@
channelsList.add(new NotificationChannel(
RETAIL_MODE,
- context.getString(R.string.notification_channel_retail_mode),
+ R.string.notification_channel_retail_mode,
NotificationManager.IMPORTANCE_LOW));
channelsList.add(new NotificationChannel(
USB,
- context.getString(R.string.notification_channel_usb),
+ R.string.notification_channel_usb,
NotificationManager.IMPORTANCE_MIN));
nm.createNotificationChannels(channelsList);
@@ -128,7 +128,7 @@
final NotificationManager nm = context.getSystemService(NotificationManager.class);
nm.createNotificationChannelsForPackage(pkg, Arrays.asList(new NotificationChannel(
ACCOUNT,
- context.getString(R.string.notification_channel_account),
+ R.string.notification_channel_account,
NotificationManager.IMPORTANCE_LOW)));
}
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 76f4a76..deacc24b 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1534,6 +1534,14 @@
of Android higher than the number given here, the permission will not
be requested. -->
<attr name="maxSdkVersion" format="integer" />
+ <!-- Optional: the system must support this feature for the permission to be
+ requested. If it doesn't support the feature, it will be as if the manifest didn't
+ request it at all. -->
+ <attr name="requiredFeature" format="string" />
+ <!-- Optional: the system must NOT support this feature for the permission to be
+ requested. If it does support the feature, it will be as if the manifest didn't
+ request it at all. -->
+ <attr name="requiredNotFeature" format="string" />
</declare-styleable>
<!-- The <code>uses-configuration</code> tag specifies
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 01737e7..15764a9 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2797,6 +2797,10 @@
<public name="fontProviderAuthority" />
<public name="fontProviderQuery" />
<public name="autoFillMode" />
+ <public name="primaryContentAlpha" />
+ <public name="secondaryContentAlpha" />
+ <public name="requiredFeature" />
+ <public name="requiredNotFeature" />
</public-group>
<public-group type="style" first-id="0x010302e0">
@@ -2806,9 +2810,6 @@
<public name="textAssist" />
</public-group>
- <public type="attr" name="primaryContentAlpha" />
- <public type="attr" name="secondaryContentAlpha" />
-
<!-- ===============================================================
DO NOT ADD UN-GROUPED ITEMS HERE
diff --git a/core/tests/coretests/src/android/graphics/drawable/IconTest.java b/core/tests/coretests/src/android/graphics/drawable/IconTest.java
index cf132890..b50955b 100644
--- a/core/tests/coretests/src/android/graphics/drawable/IconTest.java
+++ b/core/tests/coretests/src/android/graphics/drawable/IconTest.java
@@ -108,13 +108,13 @@
}
@SmallTest
- public void testWithMaskableBitmap() throws Exception {
+ public void testWithAdaptiveBitmap() throws Exception {
final Bitmap bm1 = Bitmap.createBitmap(150, 150, Bitmap.Config.ARGB_8888);
final Canvas can1 = new Canvas(bm1);
can1.drawColor(0xFFFF0000);
- final Icon im1 = Icon.createWithMaskableBitmap(bm1);
+ final Icon im1 = Icon.createWithAdaptiveBitmap(bm1);
final AdaptiveIconDrawable draw1 = (AdaptiveIconDrawable) im1.loadDrawable(mContext);
@@ -132,12 +132,12 @@
L("writing temp bitmaps to %s...", dir);
bm1.compress(Bitmap.CompressFormat.PNG, 100,
- new FileOutputStream(new File(dir, "maskable-bitmap1-original.png")));
+ new FileOutputStream(new File(dir, "adaptive-bitmap1-original.png")));
test1.compress(Bitmap.CompressFormat.PNG, 100,
- new FileOutputStream(new File(dir, "maskable-bitmap1-test.png")));
+ new FileOutputStream(new File(dir, "adaptive-bitmap1-test.png")));
if (!equalBitmaps(bm1, test1, draw1.getSafeZone())) {
findBitmapDifferences(bm1, test1);
- fail("maskable bitmap1 differs, check " + dir);
+ fail("adaptive bitmap1 differs, check " + dir);
}
}
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index ff1312a..8ce7ed0 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -68,7 +68,7 @@
/** @hide */
public static final int TYPE_URI = 4;
/** @hide */
- public static final int TYPE_BITMAP_MASKABLE = 5;
+ public static final int TYPE_ADAPTIVE_BITMAP = 5;
private static final int VERSION_STREAM_SERIALIZER = 1;
@@ -103,7 +103,7 @@
* {@link #TYPE_RESOURCE},
* {@link #TYPE_DATA}, or
* {@link #TYPE_URI}.
- * {@link #TYPE_BITMAP_MASKABLE}
+ * {@link #TYPE_ADAPTIVE_BITMAP}
* @hide
*/
public int getType() {
@@ -115,7 +115,7 @@
* @hide
*/
public Bitmap getBitmap() {
- if (mType != TYPE_BITMAP && mType != TYPE_BITMAP_MASKABLE) {
+ if (mType != TYPE_BITMAP && mType != TYPE_ADAPTIVE_BITMAP) {
throw new IllegalStateException("called getBitmap() on " + this);
}
return (Bitmap) mObj1;
@@ -221,7 +221,7 @@
private static final String typeToString(int x) {
switch (x) {
case TYPE_BITMAP: return "BITMAP";
- case TYPE_BITMAP_MASKABLE: return "BITMAP_MASKABLE";
+ case TYPE_ADAPTIVE_BITMAP: return "BITMAP_MASKABLE";
case TYPE_DATA: return "DATA";
case TYPE_RESOURCE: return "RESOURCE";
case TYPE_URI: return "URI";
@@ -289,7 +289,7 @@
switch (mType) {
case TYPE_BITMAP:
return new BitmapDrawable(context.getResources(), getBitmap());
- case TYPE_BITMAP_MASKABLE:
+ case TYPE_ADAPTIVE_BITMAP:
return new AdaptiveIconDrawable(null,
new BitmapDrawable(context.getResources(), getBitmap()));
case TYPE_RESOURCE:
@@ -395,7 +395,7 @@
* @hide
*/
public void convertToAshmem() {
- if ((mType == TYPE_BITMAP || mType == TYPE_BITMAP_MASKABLE) &&
+ if ((mType == TYPE_BITMAP || mType == TYPE_ADAPTIVE_BITMAP) &&
getBitmap().isMutable() &&
getBitmap().getAllocationByteCount() >= MIN_ASHMEM_ICON_SIZE) {
setBitmap(getBitmap().createAshmemBitmap());
@@ -416,7 +416,7 @@
switch (mType) {
case TYPE_BITMAP:
- case TYPE_BITMAP_MASKABLE:
+ case TYPE_ADAPTIVE_BITMAP:
getBitmap().compress(Bitmap.CompressFormat.PNG, 100, dataStream);
break;
case TYPE_DATA:
@@ -452,8 +452,8 @@
switch (type) {
case TYPE_BITMAP:
return createWithBitmap(BitmapFactory.decodeStream(inputStream));
- case TYPE_BITMAP_MASKABLE:
- return createWithMaskableBitmap(BitmapFactory.decodeStream(inputStream));
+ case TYPE_ADAPTIVE_BITMAP:
+ return createWithAdaptiveBitmap(BitmapFactory.decodeStream(inputStream));
case TYPE_DATA:
final int length = inputStream.readInt();
final byte[] data = new byte[length];
@@ -488,7 +488,7 @@
}
switch (mType) {
case TYPE_BITMAP:
- case TYPE_BITMAP_MASKABLE:
+ case TYPE_ADAPTIVE_BITMAP:
return getBitmap() == otherIcon.getBitmap();
case TYPE_DATA:
return getDataLength() == otherIcon.getDataLength()
@@ -566,11 +566,11 @@
* by {@link AdaptiveIconDrawable}.
* @param bits A valid {@link android.graphics.Bitmap} object
*/
- public static Icon createWithMaskableBitmap(Bitmap bits) {
+ public static Icon createWithAdaptiveBitmap(Bitmap bits) {
if (bits == null) {
throw new IllegalArgumentException("Bitmap must not be null.");
}
- final Icon rep = new Icon(TYPE_BITMAP_MASKABLE);
+ final Icon rep = new Icon(TYPE_ADAPTIVE_BITMAP);
rep.setBitmap(bits);
return rep;
}
@@ -679,7 +679,7 @@
final StringBuilder sb = new StringBuilder("Icon(typ=").append(typeToString(mType));
switch (mType) {
case TYPE_BITMAP:
- case TYPE_BITMAP_MASKABLE:
+ case TYPE_ADAPTIVE_BITMAP:
sb.append(" size=")
.append(getBitmap().getWidth())
.append("x")
@@ -718,7 +718,7 @@
* Parcelable interface
*/
public int describeContents() {
- return (mType == TYPE_BITMAP || mType == TYPE_BITMAP_MASKABLE || mType == TYPE_DATA)
+ return (mType == TYPE_BITMAP || mType == TYPE_ADAPTIVE_BITMAP || mType == TYPE_DATA)
? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0;
}
@@ -728,7 +728,7 @@
this(in.readInt());
switch (mType) {
case TYPE_BITMAP:
- case TYPE_BITMAP_MASKABLE:
+ case TYPE_ADAPTIVE_BITMAP:
final Bitmap bits = Bitmap.CREATOR.createFromParcel(in);
mObj1 = bits;
break;
@@ -767,7 +767,7 @@
dest.writeInt(mType);
switch (mType) {
case TYPE_BITMAP:
- case TYPE_BITMAP_MASKABLE:
+ case TYPE_ADAPTIVE_BITMAP:
final Bitmap bits = getBitmap();
getBitmap().writeToParcel(dest, flags);
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index 9703235..807d902 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -72,11 +72,6 @@
private StatusBarNotification mStatusBarNotification;
private NotificationChannel mNotificationChannel;
- private ImageView mAutoButton;
- private TextView mImportanceSummary;
- private TextView mImportanceTitle;
- private boolean mAuto;
-
private TextView mNumChannelsView;
private View mChannelDisabledView;
private Switch mChannelEnabledSwitch;
@@ -105,8 +100,10 @@
int appUid = -1;
String appName = pkg;
Drawable pkgicon = null;
+ CharSequence channelNameText = "";
+ ApplicationInfo info = null;
try {
- final ApplicationInfo info = pm.getApplicationInfo(pkg,
+ info = pm.getApplicationInfo(pkg,
PackageManager.MATCH_UNINSTALLED_PACKAGES
| PackageManager.MATCH_DISABLED_COMPONENTS
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
@@ -115,6 +112,7 @@
appUid = info.uid;
appName = String.valueOf(pm.getApplicationLabel(info));
pkgicon = pm.getApplicationIcon(info);
+
}
} catch (PackageManager.NameNotFoundException e) {
// app is gone, just show package name and generic icon
@@ -135,11 +133,15 @@
R.plurals.notification_num_channels_desc, numChannels), numChannels));
// If this is the placeholder channel, don't use our channel-specific text.
- CharSequence channelNameText;
if (channel.getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
channelNameText = mContext.getString(R.string.notification_header_default_channel);
} else {
- channelNameText = channel.getName();
+ if (info != null && channel.getNameResId() != 0) {
+ channelNameText = pm.getText(pkg, channel.getNameResId(), info);
+ }
+ if (channel.getName() != null) {
+ channelNameText = channel.getName();
+ }
}
((TextView) findViewById(R.id.pkgname)).setText(appName);
((TextView) findViewById(R.id.channel_name)).setText(channelNameText);
@@ -171,8 +173,8 @@
boolean nonBlockable = false;
try {
- final PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
- nonBlockable = Utils.isSystemPackage(getResources(), pm, info);
+ final PackageInfo pkgInfo = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
+ nonBlockable = Utils.isSystemPackage(getResources(), pm, pkgInfo);
} catch (PackageManager.NameNotFoundException e) {
// unlikely.
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
index 15ad0ce..5911766 100644
--- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
+++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
@@ -36,19 +36,19 @@
nm.createNotificationChannels(Arrays.asList(
new NotificationChannel(
ALERTS,
- context.getString(R.string.notification_channel_alerts),
+ R.string.notification_channel_alerts,
NotificationManager.IMPORTANCE_HIGH),
new NotificationChannel(
SCREENSHOTS,
- context.getString(R.string.notification_channel_screenshot),
+ R.string.notification_channel_screenshot,
NotificationManager.IMPORTANCE_LOW),
new NotificationChannel(
GENERAL,
- context.getString(R.string.notification_channel_general),
+ R.string.notification_channel_general,
NotificationManager.IMPORTANCE_MIN),
new NotificationChannel(
STORAGE,
- context.getString(R.string.notification_channel_storage),
+ R.string.notification_channel_storage,
NotificationManager.IMPORTANCE_LOW)
));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index 0491fc4..9a3fabb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -19,6 +19,8 @@
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
@@ -98,6 +100,9 @@
mNotificationChannel = new NotificationChannel(
TEST_CHANNEL, TEST_CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);
when(mMockStatusBarNotification.getPackageName()).thenReturn(TEST_PACKAGE_NAME);
+ when(mMockPackageManager.getText(eq(TEST_PACKAGE_NAME),
+ eq(R.string.notification_menu_accessibility), anyObject())).thenReturn(
+ getContext().getString(R.string.notification_menu_accessibility));
when(mMockINotificationManager.getNumNotificationChannelsForPackage(
eq(TEST_PACKAGE_NAME), anyInt(), anyBoolean())).thenReturn(1);
@@ -178,6 +183,19 @@
@Test
@UiThreadTest
+ public void testBindNotification_SetsTextChannelName_resId() throws Exception {
+ NotificationChannel notificationChannelResId = new NotificationChannel(
+ TEST_CHANNEL, R.string.notification_menu_accessibility,
+ NotificationManager.IMPORTANCE_LOW);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mMockStatusBarNotification, notificationChannelResId, null, null, null);
+ final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
+ assertEquals(getContext().getString(R.string.notification_menu_accessibility),
+ textView.getText());
+ }
+
+ @Test
+ @UiThreadTest
public void testBindNotification_SetsOnClickListenerForSettings() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index ba20999..e47f750 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -12,6 +12,7 @@
import com.android.settingslib.net.DataUsageController;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -106,6 +107,7 @@
TelephonyIcons.QS_DATA_4G);
}
+ @Ignore("Flaky")
@Test
public void testDataDisabledIcon() {
setupNetworkController();
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 867af9a..e72f7ff 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -66,6 +66,7 @@
private static final String ATT_VERSION = "version";
private static final String ATT_NAME = "name";
+ private static final String ATT_NAME_RES_ID = "name_res_id";
private static final String ATT_UID = "uid";
private static final String ATT_ID = "id";
private static final String ATT_PRIORITY = "priority";
@@ -201,12 +202,19 @@
if (TAG_CHANNEL.equals(tagName)) {
String id = parser.getAttributeValue(null, ATT_ID);
CharSequence channelName = parser.getAttributeValue(null, ATT_NAME);
+ int channelNameRes = safeInt(parser, ATT_NAME_RES_ID, -1);
int channelImportance =
safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
if (!TextUtils.isEmpty(id)) {
- final NotificationChannel channel = new NotificationChannel(id,
- channelName, channelImportance);
+ NotificationChannel channel;
+ if (channelName != null) {
+ channel = new NotificationChannel(id, channelName,
+ channelImportance);
+ } else {
+ channel = new NotificationChannel(id, channelNameRes,
+ channelImportance);
+ }
channel.populateFromXml(parser);
r.channels.put(id, channel);
}
@@ -286,7 +294,7 @@
NotificationChannel channel;
channel = new NotificationChannel(
NotificationChannel.DEFAULT_CHANNEL_ID,
- mContext.getString(R.string.default_notification_channel_label),
+ R.string.default_notification_channel_label,
r.importance);
channel.setBypassDnd(r.priority == Notification.PRIORITY_MAX);
channel.setLockscreenVisibility(r.visibility);
@@ -480,7 +488,8 @@
Preconditions.checkNotNull(pkg);
Preconditions.checkNotNull(channel);
Preconditions.checkNotNull(channel.getId());
- Preconditions.checkNotNull(channel.getName());
+ Preconditions.checkArgument(!TextUtils.isEmpty(channel.getName())
+ || channel.getNameResId() != 0);
Record r = getOrCreateRecord(pkg, uid);
if (r == null) {
throw new IllegalArgumentException("Invalid package");
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8380983..9ce8cd7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -746,6 +746,12 @@
@GuardedBy("mPackages")
final SparseArray<Map<String, Integer>> mChangedPackagesSequenceNumbers = new SparseArray<>();
+ final PackageParser.Callback mPackageParserCallback = new PackageParser.Callback() {
+ @Override public boolean hasFeature(String feature) {
+ return PackageManagerService.this.hasSystemFeature(feature, 0);
+ }
+ };
+
public static final class SharedLibraryEntry {
public final String path;
public final String apk;
@@ -7584,7 +7590,7 @@
+ " flags=0x" + Integer.toHexString(parseFlags));
}
ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
- mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir);
+ mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir, mPackageParserCallback);
// Submit files for parsing in parallel
int fileCount = 0;
@@ -7753,6 +7759,7 @@
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
+ pp.setCallback(mPackageParserCallback);
if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
@@ -9616,7 +9623,7 @@
/**
* Asserts the parsed package is valid according to the given policy. If the
- * package is invalid, for whatever reason, throws {@link PackgeManagerException}.
+ * package is invalid, for whatever reason, throws {@link PackageManagerException}.
* <p>
* Implementation detail: This method must NOT have any side effects. It would
* ideally be static, but, it requires locks to read system state.
@@ -12814,7 +12821,7 @@
* By having a field variable, we're able to track filter ordering as soon as
* a non-zero order is defined. Otherwise, multiple loops across the result set
* would be needed to apply ordering. If the intent resolver becomes re-entrant,
- * this needs to be contained entirely within {@link #filterResults()}.
+ * this needs to be contained entirely within {@link #filterResults}.
*/
final ArrayMap<String, Pair<Integer, EphemeralResolveInfo>> mOrderResult = new ArrayMap<>();
@@ -16636,6 +16643,7 @@
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setDisplayMetrics(mMetrics);
+ pp.setCallback(mPackageParserCallback);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
final PackageParser.Package pkg;
diff --git a/services/core/java/com/android/server/pm/ParallelPackageParser.java b/services/core/java/com/android/server/pm/ParallelPackageParser.java
index 6033855..4ff3e12 100644
--- a/services/core/java/com/android/server/pm/ParallelPackageParser.java
+++ b/services/core/java/com/android/server/pm/ParallelPackageParser.java
@@ -46,6 +46,7 @@
private final boolean mOnlyCore;
private final DisplayMetrics mMetrics;
private final File mCacheDir;
+ private final PackageParser.Callback mPackageParserCallback;
private volatile String mInterruptedInThread;
private final BlockingQueue<ParseResult> mQueue = new ArrayBlockingQueue<>(QUEUE_CAPACITY);
@@ -54,11 +55,12 @@
"package-parsing-thread", Process.THREAD_PRIORITY_FOREGROUND);
ParallelPackageParser(String[] separateProcesses, boolean onlyCoreApps,
- DisplayMetrics metrics, File cacheDir) {
+ DisplayMetrics metrics, File cacheDir, PackageParser.Callback callback) {
mSeparateProcesses = separateProcesses;
mOnlyCore = onlyCoreApps;
mMetrics = metrics;
mCacheDir = cacheDir;
+ mPackageParserCallback = callback;
}
static class ParseResult {
@@ -110,6 +112,7 @@
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
pp.setCacheDir(mCacheDir);
+ pp.setCallback(mPackageParserCallback);
pr.scanFile = scanFile;
pr.pkg = parsePackage(pp, scanFile, parseFlags);
} catch (Throwable e) {
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index ac98ab9..7885748 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -1635,10 +1635,10 @@
Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
+ " still has an icon");
}
- if (si.hasMaskableBitmap() && !si.hasIconFile()) {
+ if (si.hasAdaptiveBitmap() && !si.hasIconFile()) {
failed = true;
Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
- + " has maskable bitmap but was not saved to a file.");
+ + " has adaptive bitmap but was not saved to a file.");
}
if (si.hasIconFile() && si.hasIconResource()) {
failed = true;
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 74eb340..43288cd 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -46,7 +46,6 @@
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo;
-import android.content.pm.ShortcutManager;
import android.content.pm.ShortcutServiceInternal;
import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener;
import android.content.pm.UserInfo;
@@ -1219,7 +1218,7 @@
shortcut.setIconResourceId(0);
shortcut.setIconResName(null);
shortcut.clearFlags(ShortcutInfo.FLAG_HAS_ICON_FILE |
- ShortcutInfo.FLAG_MASKABLE_BITMAP | ShortcutInfo.FLAG_HAS_ICON_RES);
+ ShortcutInfo.FLAG_ADAPTIVE_BITMAP | ShortcutInfo.FLAG_HAS_ICON_RES);
}
public void cleanupBitmapsForPackage(@UserIdInt int userId, String packageName) {
@@ -1355,7 +1354,7 @@
return;
}
case Icon.TYPE_BITMAP:
- case Icon.TYPE_BITMAP_MASKABLE: {
+ case Icon.TYPE_ADAPTIVE_BITMAP: {
bitmap = icon.getBitmap(); // Don't recycle in this case.
break;
}
@@ -1386,8 +1385,8 @@
shortcut.setBitmapPath(out.getFile().getAbsolutePath());
shortcut.addFlags(ShortcutInfo.FLAG_HAS_ICON_FILE);
- if (icon.getType() == Icon.TYPE_BITMAP_MASKABLE) {
- shortcut.addFlags(ShortcutInfo.FLAG_MASKABLE_BITMAP);
+ if (icon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) {
+ shortcut.addFlags(ShortcutInfo.FLAG_ADAPTIVE_BITMAP);
}
} finally {
IoUtils.closeQuietly(out);
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 6212626..ffb0a9e 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -196,6 +196,7 @@
private void compareChannels(NotificationChannel expected, NotificationChannel actual) {
assertEquals(expected.getId(), actual.getId());
assertEquals(expected.getName(), actual.getName());
+ assertEquals(expected.getNameResId(), actual.getNameResId());
assertEquals(expected.shouldVibrate(), actual.shouldVibrate());
assertEquals(expected.shouldShowLights(), actual.shouldShowLights());
assertEquals(expected.getImportance(), actual.getImportance());
@@ -260,11 +261,13 @@
@Test
public void testChannelXml() throws Exception {
+ int nameResId = 924896;
+
NotificationChannelGroup ncg = new NotificationChannelGroup("1", "2");
NotificationChannel channel1 =
new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
NotificationChannel channel2 =
- new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
+ new NotificationChannel("id2", nameResId, IMPORTANCE_LOW);
channel2.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
channel2.enableLights(true);
channel2.setBypassDnd(true);
diff --git a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
index 6c6eb7e..d665094 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
@@ -69,7 +69,7 @@
class TestParallelPackageParser extends ParallelPackageParser {
TestParallelPackageParser() {
- super(null, false, null, null);
+ super(null, false, null, null, null);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 94ff07f..4b3c2f8 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -247,7 +247,7 @@
final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.icon1);
final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource(
getTestContext().getResources(), R.drawable.icon2));
- final Icon icon3 = Icon.createWithMaskableBitmap(BitmapFactory.decodeResource(
+ final Icon icon3 = Icon.createWithAdaptiveBitmap(BitmapFactory.decodeResource(
getTestContext().getResources(), R.drawable.icon2));
final ShortcutInfo si1 = makeShortcut(
@@ -567,7 +567,7 @@
final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
getTestContext().getResources(), R.drawable.black_32x32));
- final Icon bmp64x64_maskable = Icon.createWithMaskableBitmap(BitmapFactory.decodeResource(
+ final Icon bmp64x64_maskable = Icon.createWithAdaptiveBitmap(BitmapFactory.decodeResource(
getTestContext().getResources(), R.drawable.black_64x64));
final Icon bmp512x512 = Icon.createWithBitmap(BitmapFactory.decodeResource(
getTestContext().getResources(), R.drawable.black_512x512));
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index c54fa02..900da09 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -46,7 +46,6 @@
import android.test.suitebuilder.annotation.SmallTest;
import com.android.frameworks.servicestests.R;
-import com.android.server.pm.ShortcutService.ConfigConstants;
import com.android.server.pm.ShortcutUser.PackageWithUser;
import java.io.File;
@@ -993,7 +992,7 @@
setCaller(CALLING_PACKAGE_1, USER_10);
- final Icon bmp32x32 = Icon.createWithMaskableBitmap(BitmapFactory.decodeResource(
+ final Icon bmp32x32 = Icon.createWithAdaptiveBitmap(BitmapFactory.decodeResource(
getTestContext().getResources(), R.drawable.black_32x32));
PersistableBundle pb = new PersistableBundle();
@@ -1047,7 +1046,7 @@
assertEquals(1, si.getExtras().getInt("k"));
assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_FILE
- | ShortcutInfo.FLAG_STRINGS_RESOLVED | ShortcutInfo.FLAG_MASKABLE_BITMAP,
+ | ShortcutInfo.FLAG_STRINGS_RESOLVED | ShortcutInfo.FLAG_ADAPTIVE_BITMAP,
si.getFlags());
assertNotNull(si.getBitmapPath()); // Something should be set.
assertEquals(0, si.getIconResourceId());
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 0e031e7..15648bd 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -309,6 +309,8 @@
CATEGORY_ATTR = 0x010103e8,
BANNER_ATTR = 0x10103f2,
ISGAME_ATTR = 0x10103f4,
+ REQUIRED_FEATURE_ATTR = 0x1010557,
+ REQUIRED_NOT_FEATURE_ATTR = 0x1010558,
};
String8 getComponentName(String8 &pkgName, String8 &componentName) {
@@ -366,11 +368,19 @@
printf("\n");
}
-static void printUsesPermission(const String8& name, bool optional=false, int maxSdkVersion=-1) {
+static void printUsesPermission(const String8& name, bool optional=false, int maxSdkVersion=-1,
+ const String8& requiredFeature = String8::empty(),
+ const String8& requiredNotFeature = String8::empty()) {
printf("uses-permission: name='%s'", ResTable::normalizeForOutput(name.string()).string());
if (maxSdkVersion != -1) {
printf(" maxSdkVersion='%d'", maxSdkVersion);
}
+ if (requiredFeature.length() > 0) {
+ printf(" requiredFeature='%s'", requiredFeature.string());
+ }
+ if (requiredNotFeature.length() > 0) {
+ printf(" requiredNotFeature='%s'", requiredNotFeature.string());
+ }
printf("\n");
if (optional) {
@@ -1545,6 +1555,10 @@
const int32_t maxSdkVersion =
AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, -1);
+ const String8 requiredFeature = AaptXml::getAttribute(tree,
+ REQUIRED_FEATURE_ATTR, &error);
+ const String8 requiredNotFeature = AaptXml::getAttribute(tree,
+ REQUIRED_NOT_FEATURE_ATTR, &error);
if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
hasWriteExternalStoragePermission = true;
@@ -1565,7 +1579,7 @@
printUsesPermission(name,
AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
- maxSdkVersion);
+ maxSdkVersion, requiredFeature, requiredNotFeature);
} else if (tag == "uses-permission-sdk-23" || tag == "uses-permission-sdk-m") {
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
diff --git a/tools/layoutlib/bridge/src/android/view/RectShadowPainter.java b/tools/layoutlib/bridge/src/android/view/RectShadowPainter.java
index fad35d2..8130bc2 100644
--- a/tools/layoutlib/bridge/src/android/view/RectShadowPainter.java
+++ b/tools/layoutlib/bridge/src/android/view/RectShadowPainter.java
@@ -52,6 +52,8 @@
throw new IllegalArgumentException("Outline is not a rect shadow");
}
+ // TODO replacing the algorithm here to create better shadow
+
float shadowSize = elevationToShadow(elevation);
int saved = modifyCanvas(canvas, shadowSize);
if (saved == -1) {
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/shadows_test.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/shadows_test.png
new file mode 100644
index 0000000..4f3ed60
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/shadows_test.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/shadows_test.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/shadows_test.xml
new file mode 100644
index 0000000..59dbbec
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/shadows_test.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1">
+
+ <Button
+ android:layout_marginLeft="40dp"
+ android:layout_width="48dp"
+ android:layout_height="40dp"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:elevation="48dp"
+ android:stateListAnimator="@null"/>
+
+ <Button
+ android:layout_marginRight="40dp"
+ android:layout_width="48dp"
+ android:layout_height="40dp"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:elevation="48dp"
+ android:stateListAnimator="@null"/>
+
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1">
+
+ <Button
+ android:layout_marginLeft="40dp"
+ android:layout_width="48dp"
+ android:layout_height="40dp"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:elevation="0dp"
+ android:stateListAnimator="@null"/>
+
+ <Button
+ android:layout_marginRight="40dp"
+ android:layout_width="48dp"
+ android:layout_height="40dp"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:elevation="100dp"
+ android:stateListAnimator="@null"/>
+
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1">
+
+ <Button
+ android:layout_marginLeft="40dp"
+ android:layout_width="48dp"
+ android:layout_height="40dp"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:elevation="12dp"
+ android:stateListAnimator="@null"/>
+
+ <Button
+ android:layout_marginRight="40dp"
+ android:layout_width="48dp"
+ android:layout_height="40dp"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:elevation="36dp"
+ android:stateListAnimator="@null"/>
+
+ </RelativeLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
index 9e60f0f..7199781 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
@@ -424,4 +424,9 @@
assertNotEquals(0, outValue.data);
assertTrue(sRenderMessages.isEmpty());
}
+
+ @Test
+ public void testRectangleShadow() throws Exception {
+ renderAndVerify("shadows_test.xml", "shadows_test.png");
+ }
}