diff options
74 files changed, 1819 insertions, 276 deletions
diff --git a/api/current.txt b/api/current.txt index b017f9d2f5b9..b58947d36c0b 100644 --- a/api/current.txt +++ b/api/current.txt @@ -42593,6 +42593,7 @@ package android.view { method public abstract android.view.ActionProvider getActionProvider(); method public abstract android.view.View getActionView(); method public abstract char getAlphabeticShortcut(); + method public default java.lang.CharSequence getContentDescription(); method public abstract int getGroupId(); method public abstract android.graphics.drawable.Drawable getIcon(); method public abstract android.content.Intent getIntent(); @@ -42603,6 +42604,7 @@ package android.view { method public abstract android.view.SubMenu getSubMenu(); method public abstract java.lang.CharSequence getTitle(); method public abstract java.lang.CharSequence getTitleCondensed(); + method public default java.lang.CharSequence getTooltip(); method public abstract boolean hasSubMenu(); method public abstract boolean isActionViewExpanded(); method public abstract boolean isCheckable(); @@ -42615,6 +42617,7 @@ package android.view { method public abstract android.view.MenuItem setAlphabeticShortcut(char); method public abstract android.view.MenuItem setCheckable(boolean); method public abstract android.view.MenuItem setChecked(boolean); + method public default android.view.MenuItem setContentDescription(java.lang.CharSequence); method public abstract android.view.MenuItem setEnabled(boolean); method public abstract android.view.MenuItem setIcon(android.graphics.drawable.Drawable); method public abstract android.view.MenuItem setIcon(int); @@ -42628,6 +42631,7 @@ package android.view { method public abstract android.view.MenuItem setTitle(java.lang.CharSequence); method public abstract android.view.MenuItem setTitle(int); method public abstract android.view.MenuItem setTitleCondensed(java.lang.CharSequence); + method public default android.view.MenuItem setTooltip(java.lang.CharSequence); method public abstract android.view.MenuItem setVisible(boolean); field public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2 field public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8 diff --git a/api/system-current.txt b/api/system-current.txt index a5534deebd93..7a0f24c3c9f9 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -45803,6 +45803,7 @@ package android.view { method public abstract android.view.ActionProvider getActionProvider(); method public abstract android.view.View getActionView(); method public abstract char getAlphabeticShortcut(); + method public default java.lang.CharSequence getContentDescription(); method public abstract int getGroupId(); method public abstract android.graphics.drawable.Drawable getIcon(); method public abstract android.content.Intent getIntent(); @@ -45813,6 +45814,7 @@ package android.view { method public abstract android.view.SubMenu getSubMenu(); method public abstract java.lang.CharSequence getTitle(); method public abstract java.lang.CharSequence getTitleCondensed(); + method public default java.lang.CharSequence getTooltip(); method public abstract boolean hasSubMenu(); method public abstract boolean isActionViewExpanded(); method public abstract boolean isCheckable(); @@ -45825,6 +45827,7 @@ package android.view { method public abstract android.view.MenuItem setAlphabeticShortcut(char); method public abstract android.view.MenuItem setCheckable(boolean); method public abstract android.view.MenuItem setChecked(boolean); + method public default android.view.MenuItem setContentDescription(java.lang.CharSequence); method public abstract android.view.MenuItem setEnabled(boolean); method public abstract android.view.MenuItem setIcon(android.graphics.drawable.Drawable); method public abstract android.view.MenuItem setIcon(int); @@ -45838,6 +45841,7 @@ package android.view { method public abstract android.view.MenuItem setTitle(java.lang.CharSequence); method public abstract android.view.MenuItem setTitle(int); method public abstract android.view.MenuItem setTitleCondensed(java.lang.CharSequence); + method public default android.view.MenuItem setTooltip(java.lang.CharSequence); method public abstract android.view.MenuItem setVisible(boolean); field public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2 field public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8 diff --git a/api/test-current.txt b/api/test-current.txt index 5db134a28964..4118053af2f7 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -42880,6 +42880,7 @@ package android.view { method public abstract android.view.ActionProvider getActionProvider(); method public abstract android.view.View getActionView(); method public abstract char getAlphabeticShortcut(); + method public default java.lang.CharSequence getContentDescription(); method public abstract int getGroupId(); method public abstract android.graphics.drawable.Drawable getIcon(); method public abstract android.content.Intent getIntent(); @@ -42890,6 +42891,7 @@ package android.view { method public abstract android.view.SubMenu getSubMenu(); method public abstract java.lang.CharSequence getTitle(); method public abstract java.lang.CharSequence getTitleCondensed(); + method public default java.lang.CharSequence getTooltip(); method public abstract boolean hasSubMenu(); method public abstract boolean isActionViewExpanded(); method public abstract boolean isCheckable(); @@ -42902,6 +42904,7 @@ package android.view { method public abstract android.view.MenuItem setAlphabeticShortcut(char); method public abstract android.view.MenuItem setCheckable(boolean); method public abstract android.view.MenuItem setChecked(boolean); + method public default android.view.MenuItem setContentDescription(java.lang.CharSequence); method public abstract android.view.MenuItem setEnabled(boolean); method public abstract android.view.MenuItem setIcon(android.graphics.drawable.Drawable); method public abstract android.view.MenuItem setIcon(int); @@ -42915,6 +42918,7 @@ package android.view { method public abstract android.view.MenuItem setTitle(java.lang.CharSequence); method public abstract android.view.MenuItem setTitle(int); method public abstract android.view.MenuItem setTitleCondensed(java.lang.CharSequence); + method public default android.view.MenuItem setTooltip(java.lang.CharSequence); method public abstract android.view.MenuItem setVisible(boolean); field public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2 field public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8 diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.java b/core/java/android/bluetooth/BluetoothCodecConfig.java index 5cc127766e83..52cd2de4c2b6 100644 --- a/core/java/android/bluetooth/BluetoothCodecConfig.java +++ b/core/java/android/bluetooth/BluetoothCodecConfig.java @@ -47,7 +47,14 @@ public final class BluetoothCodecConfig implements Parcelable { public static final String EXTRA_PREVIOUS_CODEC_CONFIG = "android.bluetooth.codec.extra.PREVIOUS_CODEC_CONFIG"; + // Add an entry for each source codec here. + // NOTE: The values should be same as those listed in the following file: + // hardware/libhardware/include/hardware/bt_av.h public static final int SOURCE_CODEC_TYPE_SBC = 0; + public static final int SOURCE_CODEC_TYPE_APTX = 1; + public static final int SOURCE_CODEC_TYPE_APTX_HD = 2; + public static final int SOURCE_CODEC_TYPE_LDAC = 3; + public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000; public static final int CODEC_PRIORITY_DEFAULT = 0; diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java index 7036f87b98f9..e6cae6932402 100644 --- a/core/java/android/content/IntentFilter.java +++ b/core/java/android/content/IntentFilter.java @@ -1883,7 +1883,8 @@ public class IntentFilter implements Parcelable { */ } - private IntentFilter(Parcel source) { + /** @hide */ + public IntentFilter(Parcel source) { mActions = new ArrayList<String>(); source.readStringList(mActions); if (source.readInt() != 0) { diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index ce8c4e328cc5..cf4c0fae6f16 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -16,6 +16,8 @@ package android.content.pm; +import android.os.Parcel; +import android.os.Parcelable; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; @@ -65,6 +67,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; +import java.lang.reflect.Constructor; import java.security.GeneralSecurityException; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; @@ -80,6 +83,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import java.util.zip.ZipEntry; @@ -307,14 +311,16 @@ public class PackageParser { } } - static class ParseComponentArgs extends ParsePackageItemArgs { + /** @hide */ + @VisibleForTesting + public static class ParseComponentArgs extends ParsePackageItemArgs { final String[] sepProcesses; final int processRes; final int descriptionRes; final int enabledRes; int flags; - ParseComponentArgs(Package _owner, String[] _outError, + public ParseComponentArgs(Package _owner, String[] _outError, int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes, int _bannerRes, String[] _sepProcesses, int _processRes, @@ -874,12 +880,24 @@ public class PackageParser { @VisibleForTesting protected Package fromCacheEntry(byte[] bytes) throws IOException { - return null; + Parcel p = Parcel.obtain(); + p.unmarshall(bytes, 0, bytes.length); + p.setDataPosition(0); + + PackageParser.Package pkg = new PackageParser.Package(p); + p.recycle(); + + return pkg; } @VisibleForTesting protected byte[] toCacheEntry(Package pkg) throws IOException { - return null; + Parcel p = Parcel.obtain(); + pkg.writeToParcel(p, 0 /* flags */); + byte[] serialized = p.marshall(); + p.recycle(); + + return serialized; } /** @@ -1521,7 +1539,7 @@ public class PackageParser { final Certificate[][] certificates; if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) { // TODO: factor signature related items out of Package object - final Package tempPkg = new Package(null); + final Package tempPkg = new Package((String) null); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); try { collectCertificates(tempPkg, apkFile, flags); @@ -3628,6 +3646,13 @@ public class PackageParser { private static boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo, String[] outError, String tag, TypedArray sa, boolean nameRequired, int nameRes, int labelRes, int iconRes, int roundIconRes, int logoRes, int bannerRes) { + // This case can only happen in unit tests where we sometimes need to create fakes + // of various package parser data structures. + if (sa == null) { + outError[0] = tag + " does not contain any attributes"; + return false; + } + String name = sa.getNonConfigurationString(nameRes, 0); if (name == null) { if (nameRequired) { @@ -5118,7 +5143,7 @@ public class PackageParser { * Representation of a full package parsed from APK files on disk. A package * consists of a single base APK, and zero or more split APKs. */ - public final static class Package { + public final static class Package implements Parcelable { public String packageName; @@ -5159,7 +5184,7 @@ public class PackageParser { public boolean baseHardwareAccelerated; // For now we only support one application per package. - public final ApplicationInfo applicationInfo = new ApplicationInfo(); + public ApplicationInfo applicationInfo = new ApplicationInfo(); public final ArrayList<Permission> permissions = new ArrayList<Permission>(0); public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0); @@ -5583,13 +5608,296 @@ public class PackageParser { + Integer.toHexString(System.identityHashCode(this)) + " " + packageName + "}"; } + + @Override + public int describeContents() { + return 0; + } + + public Package(Parcel dest) { + // We use the boot classloader for all classes that we load. + final ClassLoader boot = Object.class.getClassLoader(); + + packageName = dest.readString(); + splitNames = dest.readStringArray(); + volumeUuid = dest.readString(); + codePath = dest.readString(); + baseCodePath = dest.readString(); + splitCodePaths = dest.readStringArray(); + baseRevisionCode = dest.readInt(); + splitRevisionCodes = dest.createIntArray(); + splitFlags = dest.createIntArray(); + splitPrivateFlags = dest.createIntArray(); + baseHardwareAccelerated = (dest.readInt() == 1); + applicationInfo = dest.readParcelable(boot); + + // We don't serialize the "owner" package and the application info object for each of + // these components, in order to save space and to avoid circular dependencies while + // serialization. We need to fix them all up here. + dest.readParcelableList(permissions, boot); + fixupOwner(permissions); + dest.readParcelableList(permissionGroups, boot); + fixupOwner(permissionGroups); + dest.readParcelableList(activities, boot); + fixupOwner(activities); + dest.readParcelableList(receivers, boot); + fixupOwner(receivers); + dest.readParcelableList(providers, boot); + fixupOwner(providers); + dest.readParcelableList(services, boot); + fixupOwner(services); + dest.readParcelableList(instrumentation, boot); + fixupOwner(instrumentation); + + dest.readStringList(requestedPermissions); + protectedBroadcasts = dest.createStringArrayList(); + parentPackage = dest.readParcelable(boot); + + childPackages = new ArrayList<>(); + dest.readParcelableList(childPackages, boot); + if (childPackages.size() == 0) { + childPackages = null; + } + + libraryNames = dest.createStringArrayList(); + usesLibraries = dest.createStringArrayList(); + usesOptionalLibraries = dest.createStringArrayList(); + usesLibraryFiles = dest.readStringArray(); + + preferredActivityFilters = new ArrayList<>(); + dest.readParcelableList(preferredActivityFilters, boot); + if (preferredActivityFilters.size() == 0) { + preferredActivityFilters = null; + } + + mOriginalPackages = dest.createStringArrayList(); + mRealPackage = dest.readString(); + mAdoptPermissions = dest.createStringArrayList(); + mAppMetaData = dest.readBundle(); + mVersionCode = dest.readInt(); + mVersionName = dest.readString(); + mSharedUserId = dest.readString(); + mSharedUserLabel = dest.readInt(); + + mSignatures = (Signature[]) dest.readParcelableArray(boot, Signature.class); + mCertificates = (Certificate[][]) dest.readSerializable(); + + mPreferredOrder = dest.readInt(); + + // long[] packageUsageTimeMillis is not persisted because it isn't information that + // is parsed from the APK. + + // Object mExtras is not persisted because it is not information that is read from + // the APK, rather, it is supplied by callers. + + + configPreferences = new ArrayList<>(); + dest.readParcelableList(configPreferences, boot); + if (configPreferences.size() == 0) { + configPreferences = null; + } + + reqFeatures = new ArrayList<>(); + dest.readParcelableList(reqFeatures, boot); + if (reqFeatures.size() == 0) { + reqFeatures = null; + } + + featureGroups = new ArrayList<>(); + dest.readParcelableList(featureGroups, boot); + if (featureGroups.size() == 0) { + featureGroups = null; + } + + installLocation = dest.readInt(); + coreApp = (dest.readInt() == 1); + mRequiredForAllUsers = (dest.readInt() == 1); + mRestrictedAccountType = dest.readString(); + mRequiredAccountType = dest.readString(); + mOverlayTarget = dest.readString(); + mOverlayPriority = dest.readInt(); + mTrustedOverlay = (dest.readInt() == 1); + mSigningKeys = (ArraySet<PublicKey>) dest.readArraySet(boot); + mUpgradeKeySets = (ArraySet<String>) dest.readArraySet(boot); + + mKeySetMapping = readKeySetMapping(dest); + + cpuAbiOverride = dest.readString(); + use32bitAbi = (dest.readInt() == 1); + restrictUpdateHash = dest.createByteArray(); + } + + /** + * Sets the package owner and the the {@code applicationInfo} for every component + * owner by this package. + */ + private void fixupOwner(List<? extends Component<?>> list) { + if (list != null) { + for (Component<?> c : list) { + c.owner = this; + if (c instanceof Activity) { + ((Activity) c).info.applicationInfo = this.applicationInfo; + } else if (c instanceof Service) { + ((Service) c).info.applicationInfo = this.applicationInfo; + } else if (c instanceof Provider) { + ((Provider) c).info.applicationInfo = this.applicationInfo; + } + } + } + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(packageName); + dest.writeStringArray(splitNames); + dest.writeString(volumeUuid); + dest.writeString(codePath); + dest.writeString(baseCodePath); + dest.writeStringArray(splitCodePaths); + dest.writeInt(baseRevisionCode); + dest.writeIntArray(splitRevisionCodes); + dest.writeIntArray(splitFlags); + dest.writeIntArray(splitPrivateFlags); + dest.writeInt(baseHardwareAccelerated ? 1 : 0); + dest.writeParcelable(applicationInfo, flags); + + dest.writeParcelableList(permissions, flags); + dest.writeParcelableList(permissionGroups, flags); + dest.writeParcelableList(activities, flags); + dest.writeParcelableList(receivers, flags); + dest.writeParcelableList(providers, flags); + dest.writeParcelableList(services, flags); + dest.writeParcelableList(instrumentation, flags); + + dest.writeStringList(requestedPermissions); + dest.writeStringList(protectedBroadcasts); + dest.writeParcelable(parentPackage, flags); + dest.writeParcelableList(childPackages, flags); + dest.writeStringList(libraryNames); + dest.writeStringList(usesLibraries); + dest.writeStringList(usesOptionalLibraries); + dest.writeStringArray(usesLibraryFiles); + + dest.writeParcelableList(preferredActivityFilters, flags); + + dest.writeStringList(mOriginalPackages); + dest.writeString(mRealPackage); + dest.writeStringList(mAdoptPermissions); + dest.writeBundle(mAppMetaData); + dest.writeInt(mVersionCode); + dest.writeString(mVersionName); + dest.writeString(mSharedUserId); + dest.writeInt(mSharedUserLabel); + + dest.writeParcelableArray(mSignatures, flags); + dest.writeSerializable(mCertificates); + + dest.writeInt(mPreferredOrder); + + // long[] packageUsageTimeMillis is not persisted because it isn't information that + // is parsed from the APK. + + // Object mExtras is not persisted because it is not information that is read from + // the APK, rather, it is supplied by callers. + + dest.writeParcelableList(configPreferences, flags); + dest.writeParcelableList(reqFeatures, flags); + dest.writeParcelableList(featureGroups, flags); + + dest.writeInt(installLocation); + dest.writeInt(coreApp ? 1 : 0); + dest.writeInt(mRequiredForAllUsers ? 1 : 0); + dest.writeString(mRestrictedAccountType); + dest.writeString(mRequiredAccountType); + dest.writeString(mOverlayTarget); + dest.writeInt(mOverlayPriority); + dest.writeInt(mTrustedOverlay ? 1 : 0); + dest.writeArraySet(mSigningKeys); + dest.writeArraySet(mUpgradeKeySets); + writeKeySetMapping(dest, mKeySetMapping); + dest.writeString(cpuAbiOverride); + dest.writeInt(use32bitAbi ? 1 : 0); + dest.writeByteArray(restrictUpdateHash); + } + + + /** + * Writes the keyset mapping to the provided package. {@code null} mappings are permitted. + */ + private static void writeKeySetMapping( + Parcel dest, ArrayMap<String, ArraySet<PublicKey>> keySetMapping) { + if (keySetMapping == null) { + dest.writeInt(-1); + return; + } + + final int N = keySetMapping.size(); + dest.writeInt(N); + + for (int i = 0; i < N; i++) { + dest.writeString(keySetMapping.keyAt(i)); + ArraySet<PublicKey> keys = keySetMapping.valueAt(i); + if (keys == null) { + dest.writeInt(-1); + continue; + } + + final int M = keys.size(); + dest.writeInt(M); + for (int j = 0; j < M; j++) { + dest.writeSerializable(keys.valueAt(j)); + } + } + } + + /** + * Reads a keyset mapping from the given parcel at the given data position. May return + * {@code null} if the serialized mapping was {@code null}. + */ + private static ArrayMap<String, ArraySet<PublicKey>> readKeySetMapping(Parcel in) { + final int N = in.readInt(); + if (N == -1) { + return null; + } + + ArrayMap<String, ArraySet<PublicKey>> keySetMapping = new ArrayMap<>(); + for (int i = 0; i < N; ++i) { + String key = in.readString(); + final int M = in.readInt(); + if (M == -1) { + keySetMapping.put(key, null); + continue; + } + + ArraySet<PublicKey> keys = new ArraySet<>(M); + for (int j = 0; j < M; ++j) { + PublicKey pk = (PublicKey) in.readSerializable(); + keys.add(pk); + } + + keySetMapping.put(key, keys); + } + + return keySetMapping; + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Package>() { + public Package createFromParcel(Parcel in) { + return new Package(in); + } + + public Package[] newArray(int size) { + return new Package[size]; + } + }; } - public static class Component<II extends IntentInfo> { - public final Package owner; + public static abstract class Component<II extends IntentInfo> { public final ArrayList<II> intents; public final String className; + public Bundle metaData; + public Package owner; ComponentName componentName; String componentShortName; @@ -5660,6 +5968,83 @@ public class PackageParser { return componentName; } + protected Component(Parcel in) { + className = in.readString(); + metaData = in.readBundle(); + intents = createIntentsList(in); + + owner = null; + } + + protected void writeToParcel(Parcel dest, int flags) { + dest.writeString(className); + dest.writeBundle(metaData); + + writeIntentsList(intents, dest, flags); + } + + /** + * <p> + * Implementation note: The serialized form for the intent list also contains the name + * of the concrete class that's stored in the list, and assumes that every element of the + * list is of the same type. This is very similar to the original parcelable mechanism. + * We cannot use that directly because IntentInfo extends IntentFilter, which is parcelable + * and is public API. It also declares Parcelable related methods as final which means + * we can't extend them. The approach of using composition instead of inheritance leads to + * a large set of cascading changes in the PackageManagerService, which seem undesirable. + * + * <p> + * <b>WARNING: </b> The list of objects returned by this function might need to be fixed up + * to make sure their owner fields are consistent. See {@code fixupOwner}. + */ + private static void writeIntentsList(ArrayList<? extends IntentInfo> list, Parcel out, + int flags) { + if (list == null) { + out.writeInt(-1); + return; + } + + final int N = list.size(); + out.writeInt(N); + + // Don't bother writing the component name if the list is empty. + if (N > 0) { + IntentInfo info = list.get(0); + out.writeString(info.getClass().getName()); + + for (int i = 0; i < N;i++) { + list.get(i).writeIntentInfoToParcel(out, flags); + } + } + } + + private static <T extends IntentInfo> ArrayList<T> createIntentsList(Parcel in) { + int N = in.readInt(); + if (N == -1) { + return null; + } + + if (N == 0) { + return new ArrayList<>(0); + } + + String componentName = in.readString(); + final ArrayList<T> intentsList; + try { + final Class<T> cls = (Class<T>) Class.forName(componentName); + final Constructor<T> cons = cls.getConstructor(Parcel.class); + + intentsList = new ArrayList<>(N); + for (int i = 0; i < N; ++i) { + intentsList.add(cons.newInstance(in)); + } + } catch (ReflectiveOperationException ree) { + throw new AssertionError("Unable to construct intent list for: " + componentName); + } + + return intentsList; + } + public void appendComponentShortName(StringBuilder sb) { ComponentName.appendShortString(sb, owner.applicationInfo.packageName, className); } @@ -5674,7 +6059,7 @@ public class PackageParser { } } - public final static class Permission extends Component<IntentInfo> { + public final static class Permission extends Component<IntentInfo> implements Parcelable { public final PermissionInfo info; public boolean tree; public PermissionGroup group; @@ -5699,9 +6084,40 @@ public class PackageParser { + Integer.toHexString(System.identityHashCode(this)) + " " + info.name + "}"; } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeParcelable(info, flags); + dest.writeInt(tree ? 1 : 0); + dest.writeParcelable(group, flags); + } + + private Permission(Parcel in) { + super(in); + final ClassLoader boot = Object.class.getClassLoader(); + info = in.readParcelable(boot); + tree = (in.readInt() == 1); + group = in.readParcelable(boot); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Permission>() { + public Permission createFromParcel(Parcel in) { + return new Permission(in); + } + + public Permission[] newArray(int size) { + return new Permission[size]; + } + }; } - public final static class PermissionGroup extends Component<IntentInfo> { + public final static class PermissionGroup extends Component<IntentInfo> implements Parcelable { public final PermissionGroupInfo info; public PermissionGroup(Package _owner) { @@ -5724,6 +6140,32 @@ public class PackageParser { + Integer.toHexString(System.identityHashCode(this)) + " " + info.name + "}"; } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeParcelable(info, flags); + } + + private PermissionGroup(Parcel in) { + super(in); + info = in.readParcelable(Object.class.getClassLoader()); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator<PermissionGroup>() { + public PermissionGroup createFromParcel(Parcel in) { + return new PermissionGroup(in); + } + + public PermissionGroup[] newArray(int size) { + return new PermissionGroup[size]; + } + }; } private static boolean copyNeeded(int flags, Package p, @@ -5876,7 +6318,7 @@ public class PackageParser { return pgi; } - public final static class Activity extends Component<ActivityIntentInfo> { + public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable { public final ActivityInfo info; public Activity(final ParseComponentArgs args, final ActivityInfo _info) { @@ -5899,6 +6341,36 @@ public class PackageParser { sb.append('}'); return sb.toString(); } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES); + } + + private Activity(Parcel in) { + super(in); + info = in.readParcelable(Object.class.getClassLoader()); + + for (ActivityIntentInfo aii : intents) { + aii.activity = this; + } + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Activity>() { + public Activity createFromParcel(Parcel in) { + return new Activity(in); + } + + public Activity[] newArray(int size) { + return new Activity[size]; + } + }; } public static final ActivityInfo generateActivityInfo(Activity a, int flags, @@ -5930,7 +6402,7 @@ public class PackageParser { return ai; } - public final static class Service extends Component<ServiceIntentInfo> { + public final static class Service extends Component<ServiceIntentInfo> implements Parcelable { public final ServiceInfo info; public Service(final ParseComponentArgs args, final ServiceInfo _info) { @@ -5953,6 +6425,36 @@ public class PackageParser { sb.append('}'); return sb.toString(); } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES); + } + + private Service(Parcel in) { + super(in); + info = in.readParcelable(Object.class.getClassLoader()); + + for (ServiceIntentInfo aii : intents) { + aii.service = this; + } + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Service>() { + public Service createFromParcel(Parcel in) { + return new Service(in); + } + + public Service[] newArray(int size) { + return new Service[size]; + } + }; } public static final ServiceInfo generateServiceInfo(Service s, int flags, @@ -5971,7 +6473,7 @@ public class PackageParser { return si; } - public final static class Provider extends Component<ProviderIntentInfo> { + public final static class Provider extends Component<ProviderIntentInfo> implements Parcelable { public final ProviderInfo info; public boolean syncable; @@ -6002,6 +6504,38 @@ public class PackageParser { sb.append('}'); return sb.toString(); } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES); + dest.writeInt((syncable) ? 1 : 0); + } + + private Provider(Parcel in) { + super(in); + info = in.readParcelable(Object.class.getClassLoader()); + syncable = (in.readInt() == 1); + + for (ProviderIntentInfo aii : intents) { + aii.provider = this; + } + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Provider>() { + public Provider createFromParcel(Parcel in) { + return new Provider(in); + } + + public Provider[] newArray(int size) { + return new Provider[size]; + } + }; } public static final ProviderInfo generateProviderInfo(Provider p, int flags, @@ -6025,7 +6559,8 @@ public class PackageParser { return pi; } - public final static class Instrumentation extends Component<IntentInfo> { + public final static class Instrumentation extends Component<IntentInfo> implements + Parcelable { public final InstrumentationInfo info; public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) { @@ -6047,6 +6582,32 @@ public class PackageParser { sb.append('}'); return sb.toString(); } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeParcelable(info, flags); + } + + private Instrumentation(Parcel in) { + super(in); + info = in.readParcelable(Object.class.getClassLoader()); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Instrumentation>() { + public Instrumentation createFromParcel(Parcel in) { + return new Instrumentation(in); + } + + public Instrumentation[] newArray(int size) { + return new Instrumentation[size]; + } + }; } public static final InstrumentationInfo generateInstrumentationInfo( @@ -6060,7 +6621,7 @@ public class PackageParser { return ii; } - public static class IntentInfo extends IntentFilter { + public static abstract class IntentInfo extends IntentFilter { public boolean hasDefault; public int labelRes; public CharSequence nonLocalizedLabel; @@ -6068,10 +6629,36 @@ public class PackageParser { public int logo; public int banner; public int preferred; + + protected IntentInfo() { + } + + protected IntentInfo(Parcel dest) { + super(dest); + hasDefault = (dest.readInt() == 1); + labelRes = dest.readInt(); + nonLocalizedLabel = dest.readCharSequence(); + icon = dest.readInt(); + logo = dest.readInt(); + banner = dest.readInt(); + preferred = dest.readInt(); + } + + + public void writeIntentInfoToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeInt(hasDefault ? 1 : 0); + dest.writeInt(labelRes); + dest.writeCharSequence(nonLocalizedLabel); + dest.writeInt(icon); + dest.writeInt(logo); + dest.writeInt(banner); + dest.writeInt(preferred); + } } public final static class ActivityIntentInfo extends IntentInfo { - public final Activity activity; + public Activity activity; public ActivityIntentInfo(Activity _activity) { activity = _activity; @@ -6086,10 +6673,14 @@ public class PackageParser { sb.append('}'); return sb.toString(); } + + public ActivityIntentInfo(Parcel in) { + super(in); + } } public final static class ServiceIntentInfo extends IntentInfo { - public final Service service; + public Service service; public ServiceIntentInfo(Service _service) { service = _service; @@ -6104,10 +6695,14 @@ public class PackageParser { sb.append('}'); return sb.toString(); } + + public ServiceIntentInfo(Parcel in) { + super(in); + } } public static final class ProviderIntentInfo extends IntentInfo { - public final Provider provider; + public Provider provider; public ProviderIntentInfo(Provider provider) { this.provider = provider; @@ -6122,6 +6717,10 @@ public class PackageParser { sb.append('}'); return sb.toString(); } + + public ProviderIntentInfo(Parcel in) { + super(in); + } } /** diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java index ca95ce19fa9c..391220134ade 100644 --- a/core/java/android/content/res/TypedArray.java +++ b/core/java/android/content/res/TypedArray.java @@ -79,7 +79,7 @@ public class TypedArray { final int dataLen = len * AssetManager.STYLE_NUM_ENTRIES; final int indicesLen = len + 1; final VMRuntime runtime = VMRuntime.getRuntime(); - if (mData == null || mData.length < dataLen) { + if (mDataAddress == 0 || mData.length < dataLen) { mData = (int[]) runtime.newNonMovableArray(int.class, dataLen); mDataAddress = runtime.addressOf(mData); mIndices = (int[]) runtime.newNonMovableArray(int.class, indicesLen); diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java index bcc3468724fd..e02549426cb5 100644 --- a/core/java/android/os/HwBinder.java +++ b/core/java/android/os/HwBinder.java @@ -17,6 +17,7 @@ package android.os; import java.util.ArrayList; +import java.util.NoSuchElementException; import libcore.util.NativeAllocationRegistry; /** @hide */ @@ -44,11 +45,13 @@ public abstract class HwBinder implements IHwBinder { public native final void registerService( ArrayList<String> interfaceChain, - String serviceName); + String serviceName) + throws RemoteException; public static native final IHwBinder getService( String iface, - String serviceName); + String serviceName) + throws RemoteException, NoSuchElementException; // Returns address of the "freeFunction". private static native final long native_init(); diff --git a/core/java/android/os/IHwBinder.java b/core/java/android/os/IHwBinder.java index 2a6567989ced..619f4dc631d5 100644 --- a/core/java/android/os/IHwBinder.java +++ b/core/java/android/os/IHwBinder.java @@ -37,6 +37,5 @@ public interface IHwBinder { } public boolean linkToDeath(DeathRecipient recipient, long cookie); - public boolean unlinkToDeath(DeathRecipient recipient); } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 0a32f0dd3720..802b1804c71d 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -256,7 +256,7 @@ public class UserManager { * Specifies if managed profiles of this user can be removed, other than by its profile owner. * The default value is <code>false</code>. * <p> - * This restriction can only be set by device owners. + * This restriction has no effect on managed profiles. * * <p>Key for user restrictions. * <p>Type: Boolean @@ -353,8 +353,8 @@ public class UserManager { /** * Specifies if a user is disallowed from adding managed profiles. * <p>The default value for an unmanaged user is <code>false</code>. - * For users with a device owner set, the default is <code>true</code> - * <p>This restriction can only be set by device owners. + * For users with a device owner set, the default is <code>true</code>. + * <p>This restriction has no effect on managed profiles. * * <p>Key for user restrictions. * <p>Type: Boolean diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index 5a6940941698..ded715f38426 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -393,6 +393,9 @@ public final class DocumentsContract { * Flag indicating that a document is virtual, and doesn't have byte * representation in the MIME type specified as {@link #COLUMN_MIME_TYPE}. * + * <p><em>Virtual documents must have at least one alternative streamable + * format via {@link DocumentsProvider#openTypedDocument}</em> + * * @see #COLUMN_FLAGS * @see #COLUMN_MIME_TYPE * @see DocumentsProvider#openTypedDocument(String, String, Bundle, diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java index 96c2556428b8..584f5fe494e1 100644 --- a/core/java/android/provider/DocumentsProvider.java +++ b/core/java/android/provider/DocumentsProvider.java @@ -575,6 +575,8 @@ public abstract class DocumentsProvider extends ContentProvider { * <p> * A provider may perform a conversion if the documents's MIME type is not * matching the specified MIME type filter. + * <p> + * Virtual documents must have at least one streamable format. * * @param documentId the document to return. * @param mimeTypeFilter the MIME type filter for the requested format. May @@ -1044,6 +1046,8 @@ public abstract class DocumentsProvider extends ContentProvider { * {@link #queryDocument(String, String[])} as long as it matches the filter and the document * does not have the {@link Document#FLAG_VIRTUAL_DOCUMENT} flag set. * + * <p>Virtual documents must have at least one streamable format. + * * @see #getStreamTypes(Uri, String) * @see #openTypedDocument(String, String, Bundle, CancellationSignal) */ diff --git a/core/java/android/view/MenuInflater.java b/core/java/android/view/MenuInflater.java index 73ea9ee31bce..f3f3d40213ec 100644 --- a/core/java/android/view/MenuInflater.java +++ b/core/java/android/view/MenuInflater.java @@ -334,6 +334,9 @@ public class MenuInflater { private ActionProvider itemActionProvider; + private CharSequence itemContentDescription; + private CharSequence itemTooltip; + private static final int defaultGroupId = NO_ID; private static final int defaultItemId = NO_ID; private static final int defaultItemCategory = 0; @@ -424,6 +427,10 @@ public class MenuInflater { itemActionProvider = null; } + itemContentDescription = + a.getText(com.android.internal.R.styleable.MenuItem_contentDescription); + itemTooltip = a.getText(com.android.internal.R.styleable.MenuItem_tooltip); + a.recycle(); itemAdded = false; @@ -486,6 +493,9 @@ public class MenuInflater { if (itemActionProvider != null) { item.setActionProvider(itemActionProvider); } + + item.setContentDescription(itemContentDescription); + item.setTooltip(itemTooltip); } public MenuItem addItem() { diff --git a/core/java/android/view/MenuItem.java b/core/java/android/view/MenuItem.java index 9e8b97eade6b..5ced76592756 100644 --- a/core/java/android/view/MenuItem.java +++ b/core/java/android/view/MenuItem.java @@ -599,4 +599,40 @@ public interface MenuItem { * @return This menu item instance for call chaining */ public MenuItem setOnActionExpandListener(OnActionExpandListener listener); + + /** + * Change the content description associated with this menu item. + * + * @param contentDescription The new content description. + */ + default MenuItem setContentDescription(CharSequence contentDescription) { + return this; + } + + /** + * Retrieve the content description associated with this menu item. + * + * @return The content description. + */ + default CharSequence getContentDescription() { + return null; + } + + /** + * Change the tooltip text associated with this menu item. + * + * @param tooltip The new tooltip text. + */ + default MenuItem setTooltip(CharSequence tooltip) { + return this; + } + + /** + * Retrieve the tooltip text associated with this menu item. + * + * @return The tooltip text. + */ + default CharSequence getTooltip() { + return null; + } } diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index 83fc3623cf20..fc6448ad7eac 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -249,6 +249,19 @@ public final class WindowManagerGlobal { return views; } + public View getWindowView(IBinder windowToken) { + synchronized (mLock) { + final int numViews = mViews.size(); + for (int i = 0; i < numViews; ++i) { + final View view = mViews.get(i); + if (view.getWindowToken() == windowToken) { + return view; + } + } + } + return null; + } + public View getRootView(String name) { synchronized (mLock) { for (int i = mRoots.size() - 1; i >= 0; --i) { diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java index e0d589a8a8fb..2d6f44352ba7 100644 --- a/core/java/android/webkit/WebViewZygote.java +++ b/core/java/android/webkit/WebViewZygote.java @@ -24,6 +24,8 @@ import android.os.ZygoteProcess; import android.text.TextUtils; import android.util.Log; +import com.android.internal.annotations.GuardedBy; + import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -38,70 +40,104 @@ public class WebViewZygote { private static final String WEBVIEW_ZYGOTE_SERVICE_32 = "webview_zygote32"; private static final String WEBVIEW_ZYGOTE_SERVICE_64 = "webview_zygote64"; + /** + * Lock object that protects all other static members. + */ + private static final Object sLock = new Object(); + + /** + * Instance that maintains the socket connection to the zygote. This is null if the zygote + * is not running or is not connected. + */ + @GuardedBy("sLock") private static ZygoteProcess sZygote; + /** + * Information about the selected WebView package. This is set from #onWebViewProviderChanged(). + */ + @GuardedBy("sLock") private static PackageInfo sPackage; + /** + * Flag for whether multi-process WebView is enabled. If this is false, the zygote + * will not be started. + */ + @GuardedBy("sLock") private static boolean sMultiprocessEnabled = false; public static ZygoteProcess getProcess() { - connectToZygoteIfNeeded(); - return sZygote; + synchronized (sLock) { + connectToZygoteIfNeededLocked(); + return sZygote; + } } public static String getPackageName() { - return sPackage.packageName; + synchronized (sLock) { + return sPackage.packageName; + } } public static boolean isMultiprocessEnabled() { - return sMultiprocessEnabled && sPackage != null; + synchronized (sLock) { + return sMultiprocessEnabled && sPackage != null; + } } public static void setMultiprocessEnabled(boolean enabled) { - sMultiprocessEnabled = enabled; - - // When toggling between multi-process being on/off, start or stop the - // service. If it is enabled and the zygote is not yet started, bring up the service. - // Otherwise, bring down the service. The name may be null if the package - // information has not yet been resolved. - final String serviceName = getServiceName(); - if (serviceName == null) return; - - if (enabled && sZygote == null) { - SystemService.start(serviceName); - } else { - SystemService.stop(serviceName); - sZygote = null; + synchronized (sLock) { + sMultiprocessEnabled = enabled; + + // When toggling between multi-process being on/off, start or stop the + // service. If it is enabled and the zygote is not yet started, bring up the service. + // Otherwise, bring down the service. The name may be null if the package + // information has not yet been resolved. + final String serviceName = getServiceNameLocked(); + if (serviceName == null) return; + + if (enabled && sZygote == null) { + SystemService.start(serviceName); + } else { + SystemService.stop(serviceName); + sZygote = null; + } } } public static void onWebViewProviderChanged(PackageInfo packageInfo) { - sPackage = packageInfo; - - // If multi-process is not enabled, then do not start the zygote service. - if (!sMultiprocessEnabled) { - return; - } + String serviceName; + synchronized (sLock) { + sPackage = packageInfo; - final String serviceName = getServiceName(); + // If multi-process is not enabled, then do not start the zygote service. + if (!sMultiprocessEnabled) { + return; + } - if (SystemService.isStopped(serviceName)) { - SystemService.start(serviceName); - } else if (sZygote != null) { - SystemService.restart(serviceName); - } + serviceName = getServiceNameLocked(); + sZygote = null; - try { - SystemService.waitForState(serviceName, SystemService.State.RUNNING, 5000); - } catch (TimeoutException e) { - Log.e(LOGTAG, "Timed out waiting for " + serviceName); - return; + // The service may enter the RUNNING state before it opens the socket, + // so connectToZygoteIfNeededLocked() may still fail. + if (SystemService.isStopped(serviceName)) { + SystemService.start(serviceName); + } else { + SystemService.restart(serviceName); + } + + try { + SystemService.waitForState(serviceName, SystemService.State.RUNNING, 5000); + } catch (TimeoutException e) { + Log.e(LOGTAG, "Timed out waiting for " + serviceName); + return; + } + + connectToZygoteIfNeededLocked(); } - - connectToZygoteIfNeeded(); } - private static String getServiceName() { + @GuardedBy("sLock") + private static String getServiceNameLocked() { if (sPackage == null) return null; @@ -113,7 +149,8 @@ public class WebViewZygote { return WEBVIEW_ZYGOTE_SERVICE_32; } - private static void connectToZygoteIfNeeded() { + @GuardedBy("sLock") + private static void connectToZygoteIfNeededLocked() { if (sZygote != null) return; @@ -122,7 +159,7 @@ public class WebViewZygote { return; } - final String serviceName = getServiceName(); + final String serviceName = getServiceNameLocked(); if (!SystemService.isRunning(serviceName)) { Log.e(LOGTAG, serviceName + " is not running"); return; diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 16a12518574d..6c4faa4dec06 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -589,7 +589,9 @@ public class ChooserActivity extends ResolverActivity { if (ri != null && ri.activityInfo != null) { usageStatsManager.reportChooserSelection(ri.activityInfo.packageName, getUserId(), annotation, null, info.getResolvedIntent().getAction()); - mResolverComparator.updateModel(info.getResolvedComponentName()); + if (mAdapter != null) { + mAdapter.updateModel(info.getResolvedComponentName()); + } if (DEBUG) { Log.d(TAG, "ResolveInfo Package is" + ri.activityInfo.packageName); } diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index f2bd701920e8..23c1969cf8c3 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -107,7 +107,6 @@ public class ResolverActivity extends Activity { private PickTargetOptionRequest mPickOptionRequest; private String mReferrerPackage; - protected ResolverComparator mResolverComparator; protected ResolverDrawerLayout mResolverDrawerLayout; protected String mContentType; protected PackageManager mPm; @@ -1290,6 +1289,10 @@ public class ResolverActivity extends Activity { return mResolverListController.getScore(target); } + public void updateModel(ComponentName componentName) { + mResolverListController.updateModel(componentName); + } + /** * Rebuild the list of resolvers. In some cases some parts will need some asynchronous work * to complete. diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java index b91ecb625bcf..d864a310e91b 100644 --- a/core/java/com/android/internal/app/ResolverListController.java +++ b/core/java/com/android/internal/app/ResolverListController.java @@ -218,4 +218,10 @@ public class ResolverListController { } return mResolverComparator.getScore(target.getResolvedComponentName()); } + + public void updateModel(ComponentName componentName) { + if (mResolverComparator != null) { + mResolverComparator.updateModel(componentName); + } + } } diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java index a8a55499f5f3..12d699d2ae15 100644 --- a/core/java/com/android/internal/os/WebViewZygoteInit.java +++ b/core/java/com/android/internal/os/WebViewZygoteInit.java @@ -54,6 +54,11 @@ class WebViewZygoteInit { } @Override + protected void maybePreload() { + // Do nothing, we don't need to call ZygoteInit.maybePreload() for the WebView zygote. + } + + @Override protected boolean handlePreloadPackage(String packagePath, String libsPath) { // Ask ApplicationLoaders to create and cache a classloader for the WebView APK so that // our children will reuse the same classloader instead of creating their own. diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index e9e642a58a33..345350cc45fb 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -171,7 +171,7 @@ class ZygoteConnection { return handleAbiListQuery(); } - ZygoteInit.maybePreload(); + maybePreload(); if (parsedArgs.preloadPackage != null) { return handlePreloadPackage(parsedArgs.preloadPackage, @@ -279,6 +279,10 @@ class ZygoteConnection { } } + protected void maybePreload() { + ZygoteInit.maybePreload(); + } + protected boolean handlePreloadPackage(String packagePath, String libsPath) { throw new RuntimeException("Zyogte does not support package preloading"); } diff --git a/core/java/com/android/internal/view/TooltipPopup.java b/core/java/com/android/internal/view/TooltipPopup.java index c5f6356e92b1..ebbbdbb0d6a6 100644 --- a/core/java/com/android/internal/view/TooltipPopup.java +++ b/core/java/com/android/internal/view/TooltipPopup.java @@ -19,13 +19,17 @@ package com.android.internal.view; import android.content.Context; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.util.Slog; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; +import android.view.WindowManagerGlobal; import android.widget.TextView; public class TooltipPopup { + private static final String TAG = "TooltipPopup"; + private final Context mContext; private final View mContentView; @@ -34,6 +38,7 @@ public class TooltipPopup { private final WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams(); private final Rect mTmpDisplayFrame = new Rect(); private final int[] mTmpAnchorPos = new int[2]; + private final int[] mTmpAppPos = new int[2]; public TooltipPopup(Context context) { mContext = context; @@ -124,8 +129,21 @@ public class TooltipPopup { fromTouch ? com.android.internal.R.dimen.tooltip_y_offset_touch : com.android.internal.R.dimen.tooltip_y_offset_non_touch); - anchorView.getWindowVisibleDisplayFrame(mTmpDisplayFrame); - anchorView.getLocationInWindow(mTmpAnchorPos); + // Find the main app window. The popup window will be positioned relative to it. + final View appView = WindowManagerGlobal.getInstance().getWindowView( + anchorView.getApplicationWindowToken()); + if (appView == null) { + Slog.e(TAG, "Cannot find app view"); + return; + } + appView.getWindowVisibleDisplayFrame(mTmpDisplayFrame); + appView.getLocationOnScreen(mTmpAppPos); + + anchorView.getLocationOnScreen(mTmpAnchorPos); + mTmpAnchorPos[0] -= mTmpAppPos[0]; + mTmpAnchorPos[1] -= mTmpAppPos[1]; + // mTmpAnchorPos is now relative to the main app window. + outParams.x = mTmpAnchorPos[0] + offsetX - mTmpDisplayFrame.width() / 2; final int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); diff --git a/core/java/com/android/internal/view/menu/ActionMenuItem.java b/core/java/com/android/internal/view/menu/ActionMenuItem.java index ed676bb703e9..c8697ddba029 100644 --- a/core/java/com/android/internal/view/menu/ActionMenuItem.java +++ b/core/java/com/android/internal/view/menu/ActionMenuItem.java @@ -39,23 +39,26 @@ public class ActionMenuItem implements MenuItem { private Intent mIntent; private char mShortcutNumericChar; private char mShortcutAlphabeticChar; - + private Drawable mIconDrawable; private int mIconResId = NO_ICON; - + private Context mContext; - + private MenuItem.OnMenuItemClickListener mClickListener; - + + private CharSequence mContentDescription; + private CharSequence mTooltip; + private static final int NO_ICON = 0; - + private int mFlags = ENABLED; private static final int CHECKABLE = 0x00000001; private static final int CHECKED = 0x00000002; private static final int EXCLUSIVE = 0x00000004; private static final int HIDDEN = 0x00000008; private static final int ENABLED = 0x00000010; - + public ActionMenuItem(Context context, int group, int id, int categoryOrder, int ordering, CharSequence title) { mContext = context; @@ -65,7 +68,7 @@ public class ActionMenuItem implements MenuItem { mOrdering = ordering; mTitle = title; } - + public char getAlphabeticShortcut() { return mShortcutAlphabeticChar; } @@ -274,4 +277,26 @@ public class ActionMenuItem implements MenuItem { // No need to save the listener; ActionMenuItem does not support collapsing items. return this; } + + @Override + public MenuItem setContentDescription(CharSequence contentDescription) { + mContentDescription = contentDescription; + return this; + } + + @Override + public CharSequence getContentDescription() { + return mContentDescription; + } + + @Override + public MenuItem setTooltip(CharSequence tooltip) { + mTooltip = tooltip; + return this; + } + + @Override + public CharSequence getTooltip() { + return mTooltip; + } } diff --git a/core/java/com/android/internal/view/menu/ActionMenuItemView.java b/core/java/com/android/internal/view/menu/ActionMenuItemView.java index af4f77786a5d..4ee59931d831 100644 --- a/core/java/com/android/internal/view/menu/ActionMenuItemView.java +++ b/core/java/com/android/internal/view/menu/ActionMenuItemView.java @@ -119,7 +119,7 @@ public class ActionMenuItemView extends TextView mItemData = itemData; setIcon(itemData.getIcon()); - setTitle(itemData.getTitleForItemView(this)); // Title only takes effect if there is no icon + setTitle(itemData.getTitleForItemView(this)); // Title is only displayed if there is no icon setId(itemData.getItemId()); setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE); @@ -184,8 +184,22 @@ public class ActionMenuItemView extends TextView setText(visible ? mTitle : null); - // Show the tooltip for items that do not already show text. - setTooltip(visible ? null : mTitle); + final CharSequence contentDescription = mItemData.getContentDescription(); + if (TextUtils.isEmpty(contentDescription)) { + // Use the uncondensed title for content description, but only if the title is not + // shown already. + setContentDescription(visible ? null : mItemData.getTitle()); + } else { + setContentDescription(contentDescription); + } + + final CharSequence tooltip = mItemData.getTooltip(); + if (TextUtils.isEmpty(tooltip)) { + // Use the uncondensed title for tooltip, but only if the title is not shown already. + setTooltip(visible ? null : mItemData.getTitle()); + } else { + setTooltip(tooltip); + } } public void setIcon(Drawable icon) { @@ -221,7 +235,6 @@ public class ActionMenuItemView extends TextView public void setTitle(CharSequence title) { mTitle = title; - setContentDescription(mTitle); updateTextButtonVisibility(); } diff --git a/core/java/com/android/internal/view/menu/IconMenuItemView.java b/core/java/com/android/internal/view/menu/IconMenuItemView.java index 0e0c9b0cf244..f9ebdbc4f0bb 100644 --- a/core/java/com/android/internal/view/menu/IconMenuItemView.java +++ b/core/java/com/android/internal/view/menu/IconMenuItemView.java @@ -22,6 +22,7 @@ import android.content.Context; import android.content.res.TypedArray; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.text.TextUtils; import android.util.AttributeSet; import android.view.Gravity; import android.view.SoundEffectConstants; @@ -31,7 +32,7 @@ import android.widget.TextView; import android.text.Layout; /** - * The item view for each item in the {@link IconMenuView}. + * The item view for each item in the {@link IconMenuView}. */ public final class IconMenuItemView extends TextView implements MenuView.ItemView { @@ -104,13 +105,23 @@ public final class IconMenuItemView extends TextView implements MenuView.ItemVie setTitle(title); setIcon(icon); + + if (mItemData != null) { + final CharSequence contentDescription = mItemData.getContentDescription(); + if (TextUtils.isEmpty(contentDescription)) { + setContentDescription(title); + } else { + setContentDescription(contentDescription); + } + setTooltip(mItemData.getTooltip()); + } } - + public void initialize(MenuItemImpl itemData, int menuType) { mItemData = itemData; initialize(itemData.getTitleForItemView(this), itemData.getIcon()); - + setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE); setEnabled(itemData.isEnabled()); } diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java index 25263932bb75..7c9f70902d05 100644 --- a/core/java/com/android/internal/view/menu/ListMenuItemView.java +++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java @@ -107,13 +107,15 @@ public class ListMenuItemView extends LinearLayout implements MenuView.ItemView mMenuType = menuType; setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE); - + setTitle(itemData.getTitleForItemView(this)); setCheckable(itemData.isCheckable()); setShortcut(itemData.shouldShowShortcut(), itemData.getShortcut()); setIcon(itemData.getIcon()); setEnabled(itemData.isEnabled()); setSubMenuArrowVisible(itemData.hasSubMenu()); + setContentDescription(itemData.getContentDescription()); + setTooltip(itemData.getTooltip()); } public void setForceShowIcon(boolean forceShow) { diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java index 624c9e24e945..cad027616582 100644 --- a/core/java/com/android/internal/view/menu/MenuItemImpl.java +++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java @@ -90,16 +90,19 @@ public final class MenuItemImpl implements MenuItem { /** * Current use case is for context menu: Extra information linked to the * View that added this item to the context menu. - */ + */ private ContextMenuInfo mMenuInfo; - + + private CharSequence mContentDescription; + private CharSequence mTooltip; + private static String sLanguage; private static String sPrependShortcutLabel; private static String sEnterShortcutLabel; private static String sDeleteShortcutLabel; private static String sSpaceShortcutLabel; - - + + /** * Instantiates this menu item. * @@ -670,4 +673,32 @@ public final class MenuItemImpl implements MenuItem { public boolean isActionViewExpanded() { return mIsActionViewExpanded; } + + @Override + public MenuItem setContentDescription(CharSequence contentDescription) { + mContentDescription = contentDescription; + + mMenu.onItemsChanged(false); + + return this; + } + + @Override + public CharSequence getContentDescription() { + return mContentDescription; + } + + @Override + public MenuItem setTooltip(CharSequence tooltip) { + mTooltip = tooltip; + + mMenu.onItemsChanged(false); + + return this; + } + + @Override + public CharSequence getTooltip() { + return mTooltip; + } } diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java index 66042086e925..04e09a85d1bf 100644 --- a/core/java/com/android/internal/widget/FloatingToolbar.java +++ b/core/java/com/android/internal/widget/FloatingToolbar.java @@ -1585,7 +1585,13 @@ public final class FloatingToolbar { } if (menuItem != null) { menuButton.setText(menuItem.getTitle()); - menuButton.setContentDescription(menuItem.getTitle()); + final CharSequence contentDescription = menuItem.getContentDescription(); + if (TextUtils.isEmpty(contentDescription)) { + menuButton.setContentDescription(menuItem.getTitle()); + } else { + menuButton.setContentDescription(contentDescription); + } + menuButton.setTooltip(menuItem.getTooltip()); menuButton.setMinimumWidth(minimumWidth); } return menuButton; @@ -1629,19 +1635,31 @@ public final class FloatingToolbar { * Creates and returns a menu button for the specified menu item. */ private static View createMenuItemButton(Context context, MenuItem menuItem) { + final View menuItemButton; if (isIconOnlyMenuItem(menuItem)) { - View imageMenuItemButton = LayoutInflater.from(context) + menuItemButton = LayoutInflater.from(context) .inflate(R.layout.floating_popup_menu_image_button, null); - ((ImageButton) imageMenuItemButton + ((ImageButton) menuItemButton .findViewById(R.id.floating_toolbar_menu_item_image_button)) .setImageDrawable(menuItem.getIcon()); - return imageMenuItemButton; + final CharSequence tooltip = menuItem.getTooltip(); + if (TextUtils.isEmpty(tooltip)) { + menuItemButton.setTooltip(menuItem.getTitle()); + } else { + menuItemButton.setTooltip(tooltip); + } + } else { + menuItemButton = LayoutInflater.from(context) + .inflate(R.layout.floating_popup_menu_button, null); + ((Button) menuItemButton).setText(menuItem.getTitle()); + menuItemButton.setTooltip(menuItem.getTooltip()); + } + final CharSequence contentDescription = menuItem.getContentDescription(); + if (TextUtils.isEmpty(contentDescription)) { + menuItemButton.setContentDescription(menuItem.getTitle()); + } else { + menuItemButton.setContentDescription(contentDescription); } - - Button menuItemButton = (Button) LayoutInflater.from(context) - .inflate(R.layout.floating_popup_menu_button, null); - menuItemButton.setText(menuItem.getTitle()); - menuItemButton.setContentDescription(menuItem.getTitle()); return menuItemButton; } diff --git a/core/jni/Android.mk b/core/jni/Android.mk index a13ebaf55cf4..252f168040df 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -215,6 +215,7 @@ LOCAL_C_INCLUDES += \ external/skia/src/effects \ external/skia/src/image \ external/skia/src/images \ + external/skia/src/utils \ external/sqlite/dist \ external/sqlite/android \ external/tremor/Tremor \ diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index 1165a45c1535..19d4848e1656 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -8,6 +8,7 @@ #include "SkBRDAllocator.h" #include "SkFrontBufferedStream.h" #include "SkMath.h" +#include "SkOpts.h" #include "SkPixelRef.h" #include "SkStream.h" #include "SkUtils.h" @@ -224,6 +225,45 @@ static bool needsFineScale(const SkISize fullSize, const SkISize decodedSize, needsFineScale(fullSize.height(), decodedSize.height(), sampleSize); } +static inline SkAlphaType computeDecodeAlphaType(SkColorType colorType, SkAlphaType alphaType) { +#ifndef ANDROID_ENABLE_LINEAR_BLENDING + // Skia premultiplies linearly. Until the framework enables linear blending, + // it expects a legacy premultiply. + if (kPremul_SkAlphaType == alphaType && kRGBA_F16_SkColorType != colorType) { + return kUnpremul_SkAlphaType; + } +#endif + + return alphaType; +} + +static inline void premultiplyIfNecessary(SkBitmap* bitmap, SkPMColor* colorPtr, int* colorCount, + SkAlphaType alphaType, bool requireUnpremultiplied) { +#ifndef ANDROID_ENABLE_LINEAR_BLENDING + if (kUnpremul_SkAlphaType != alphaType || requireUnpremultiplied) { + return; + } + + switch (bitmap->colorType()) { + case kN32_SkColorType: + for (int y = 0; y < bitmap->height(); y++) { + SkOpts::RGBA_to_rgbA(bitmap->getAddr32(0, y), bitmap->getAddr32(0, y), + bitmap->width()); + } + + return; + case kIndex_8_SkColorType: + SkOpts::RGBA_to_rgbA(colorPtr, colorPtr, *colorCount); + return; + default: + // kRGBA_F16 will be premultiplied by the codec if necessary. + // kGray_8 (alias kAlpha_8) and k565 are opaque. + LOG_ALWAYS_FATAL("Should be unreachable - no need for legacy premultiply."); + return; + } +#endif +} + static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding, jobject options) { // This function takes ownership of the input stream. Since the SkAndroidCodec // will take ownership of the stream, we don't necessarily need to take ownership @@ -391,13 +431,17 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding colorCount = &maxColors; } - // Set the alpha type for the decode. SkAlphaType alphaType = codec->computeOutputAlphaType(requireUnpremultiplied); + SkAlphaType decodeAlphaType = computeDecodeAlphaType(decodeColorType, alphaType); const SkImageInfo decodeInfo = SkImageInfo::Make(size.width(), size.height(), - decodeColorType, alphaType, GraphicsJNI::colorSpaceForType(decodeColorType)); + decodeColorType, decodeAlphaType, codec->computeOutputColorSpace(decodeColorType)); + + // When supported by the colorType, we will decode to sRGB (or linear sRGB). However, + // we only want to mark the bitmap as sRGB when linear blending is enabled. + SkImageInfo bitmapInfo = decodeInfo.makeAlphaType(alphaType) + .makeColorSpace(GraphicsJNI::colorSpaceForType(decodeColorType)); - SkImageInfo bitmapInfo = decodeInfo; if (decodeColorType == kGray_8_SkColorType) { // The legacy implementation of BitmapFactory used kAlpha8 for // grayscale images (before kGray8 existed). While the codec @@ -433,6 +477,8 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding default: return nullObjectReturn("codec->getAndroidPixels() failed."); } + premultiplyIfNecessary(&decodingBitmap, colorPtr, colorCount, decodeAlphaType, + requireUnpremultiplied); jbyteArray ninePatchChunk = NULL; if (peeker.mPatch != NULL) { diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp index c456d622ab5a..20bb885eb578 100644 --- a/core/jni/android_os_HwBinder.cpp +++ b/core/jni/android_os_HwBinder.cpp @@ -39,6 +39,8 @@ using android::AndroidRuntime; using android::hardware::hidl_vec; using android::hardware::hidl_string; +template<typename T> +using Return = android::hardware::Return<T>; #define PACKAGE_PATH "android/os" #define CLASS_NAME "HwBinder" @@ -257,8 +259,6 @@ static void JHwBinder_native_registerService( hidl_vec<hidl_string> interfaceChain; interfaceChain.setToExternal(strings, numInterfaces, true /* shouldOwn */); - using android::hidl::manager::V1_0::IServiceManager; - sp<hardware::IBinder> binder = JHwBinder::GetNativeContext(env, thiz); /* TODO(b/33440494) this is not right */ @@ -268,24 +268,23 @@ static void JHwBinder_native_registerService( if (manager == nullptr) { LOG(ERROR) << "Could not get hwservicemanager."; - signalExceptionForError(env, UNKNOWN_ERROR); + signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */); return; } - bool ok = manager->add( - interfaceChain, - serviceName, - base); + Return<bool> ret = manager->add(interfaceChain, serviceName, base); env->ReleaseStringUTFChars(serviceNameObj, serviceName); serviceName = NULL; + bool ok = ret.isOk() && ret; + if (ok) { LOG(INFO) << "Starting thread pool."; ::android::hardware::ProcessState::self()->startThreadPool(); } - signalExceptionForError(env, (ok ? OK : UNKNOWN_ERROR)); + signalExceptionForError(env, (ok ? OK : UNKNOWN_ERROR), true /* canThrowRemoteException */); } static jobject JHwBinder_native_getService( @@ -321,19 +320,18 @@ static jobject JHwBinder_native_getService( if (manager == nullptr) { LOG(ERROR) << "Could not get hwservicemanager."; - signalExceptionForError(env, UNKNOWN_ERROR); + signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */); return NULL; } - sp<hardware::IBinder> service; - manager->get( - ifaceName, - serviceName, - [&service](sp<hidl::base::V1_0::IBase> out) { - service = hardware::toBinder< - hidl::base::V1_0::IBase, hidl::base::V1_0::BpBase - >(out); - }); + Return<sp<hidl::base::V1_0::IBase>> ret = manager->get(ifaceName, serviceName); + + if (!ret.isOk()) { + signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */); + } + + sp<hardware::IBinder> service = hardware::toBinder< + hidl::base::V1_0::IBase, hidl::base::V1_0::BpBase>(ret); env->ReleaseStringUTFChars(ifaceNameObj, ifaceName); ifaceName = NULL; diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml index 53b7ab72481b..abd1bfdb5944 100644 --- a/core/res/res/values-mk-rMK/strings.xml +++ b/core/res/res/values-mk-rMK/strings.xml @@ -201,9 +201,9 @@ <string name="reboot_to_update_title" msgid="6212636802536823850">"Системско ажурирање на Android"</string> <string name="reboot_to_update_prepare" msgid="6305853831955310890">"Се подготвува ажурирањето…"</string> <string name="reboot_to_update_package" msgid="3871302324500927291">"Пакетот за ажурирање се обработува..."</string> - <string name="reboot_to_update_reboot" msgid="6428441000951565185">"Се престартува…"</string> + <string name="reboot_to_update_reboot" msgid="6428441000951565185">"Се рестартира…"</string> <string name="reboot_to_reset_title" msgid="4142355915340627490">"Ресетирање фабрички податоци"</string> - <string name="reboot_to_reset_message" msgid="2432077491101416345">"Се престартува…"</string> + <string name="reboot_to_reset_message" msgid="2432077491101416345">"Се рестартира…"</string> <string name="shutdown_progress" msgid="2281079257329981203">"Се исклучува..."</string> <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Вашиот таблет ќе се исклучи."</string> <string name="shutdown_confirm" product="tv" msgid="476672373995075359">"Вашиот телевизор ќе се исклучи."</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 71b974725e80..51519a71bab8 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -1267,7 +1267,7 @@ <string name="progress_erasing" product="default" msgid="6596988875507043042">"Apagando cartão SD..."</string> <string name="share" msgid="1778686618230011964">"Compartilhar"</string> <string name="find" msgid="4808270900322985960">"Localizar"</string> - <string name="websearch" msgid="4337157977400211589">"Pesquisa na web do Google"</string> + <string name="websearch" msgid="4337157977400211589">"Pesquisa Google na Web"</string> <string name="find_next" msgid="5742124618942193978">"Localizar próximo"</string> <string name="find_previous" msgid="2196723669388360506">"Localizar anterior"</string> <string name="gpsNotifTicker" msgid="5622683912616496172">"Solicitação de local de <xliff:g id="NAME">%s</xliff:g>"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 71b974725e80..51519a71bab8 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -1267,7 +1267,7 @@ <string name="progress_erasing" product="default" msgid="6596988875507043042">"Apagando cartão SD..."</string> <string name="share" msgid="1778686618230011964">"Compartilhar"</string> <string name="find" msgid="4808270900322985960">"Localizar"</string> - <string name="websearch" msgid="4337157977400211589">"Pesquisa na web do Google"</string> + <string name="websearch" msgid="4337157977400211589">"Pesquisa Google na Web"</string> <string name="find_next" msgid="5742124618942193978">"Localizar próximo"</string> <string name="find_previous" msgid="2196723669388360506">"Localizar anterior"</string> <string name="gpsNotifTicker" msgid="5622683912616496172">"Solicitação de local de <xliff:g id="NAME">%s</xliff:g>"</string> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 05658b018861..37b3ffc48016 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -7009,6 +7009,12 @@ for more info. --> <attr name="actionProviderClass" format="string" /> + <!-- The content description associated with the item. --> + <attr name="contentDescription" format="string" /> + + <!-- The tooltip text associated with the item. --> + <attr name="tooltip" format="string" /> + </declare-styleable> <!-- Attrbitutes for a ActvityChooserView. --> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index 0f756b94a321..ce7ab1626aa0 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -1290,6 +1290,7 @@ please see styles_device_defaults.xml. <style name="Widget.ActionButton.Overflow"> <item name="src">@drawable/ic_menu_more</item> <item name="contentDescription">@string/action_menu_overflow_description</item> + <item name="tooltip">@string/action_menu_overflow_description</item> </style> <style name="Widget.ActionButton.CloseMode"> diff --git a/core/res/res/values/styles_holo.xml b/core/res/res/values/styles_holo.xml index 8ca12ae66986..12b8164ad001 100644 --- a/core/res/res/values/styles_holo.xml +++ b/core/res/res/values/styles_holo.xml @@ -660,6 +660,7 @@ please see styles_device_defaults.xml. <item name="src">@drawable/ic_menu_moreoverflow_holo_dark</item> <item name="background">?attr/actionBarItemBackground</item> <item name="contentDescription">@string/action_menu_overflow_description</item> + <item name="tooltip">@string/action_menu_overflow_description</item> </style> <style name="Widget.Holo.ActionButton.TextButton" parent="Widget.Holo.ButtonBar.Button" /> @@ -994,6 +995,7 @@ please see styles_device_defaults.xml. <style name="Widget.Holo.Light.ActionButton.Overflow"> <item name="src">@drawable/ic_menu_moreoverflow_holo_light</item> <item name="contentDescription">@string/action_menu_overflow_description</item> + <item name="tooltip">@string/action_menu_overflow_description</item> </style> <style name="Widget.Holo.Light.ActionBar.TabView" parent="Widget.Holo.ActionBar.TabView" /> diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml index a1e12d281c95..709200eabff2 100644 --- a/core/res/res/values/styles_material.xml +++ b/core/res/res/values/styles_material.xml @@ -944,6 +944,7 @@ please see styles_device_defaults.xml. <item name="src">@drawable/ic_menu_moreoverflow_material</item> <item name="background">?attr/actionBarItemBackground</item> <item name="contentDescription">@string/action_menu_overflow_description</item> + <item name="tooltip">@string/action_menu_overflow_description</item> <item name="minWidth">@dimen/action_button_min_width_overflow_material</item> <item name="minHeight">@dimen/action_button_min_height_material</item> <item name="paddingStart">@dimen/action_bar_overflow_padding_start_material</item> diff --git a/docs/html/google/play/billing/billing_integrate.jd b/docs/html/google/play/billing/billing_integrate.jd index 506a44006bdb..d2839bd8f0c3 100755 --- a/docs/html/google/play/billing/billing_integrate.jd +++ b/docs/html/google/play/billing/billing_integrate.jd @@ -310,7 +310,7 @@ ArrayList<String> skuList = new ArrayList<String> (); skuList.add("premiumUpgrade"); skuList.add("gas"); Bundle querySkus = new Bundle(); -querySkus.putStringArrayList(“ITEM_ID_LIST”, skuList); +querySkus.putStringArrayList("ITEM_ID_LIST", skuList); </pre> <p> diff --git a/packages/SettingsLib/res/layout/drawer_category.xml b/packages/SettingsLib/res/layout/drawer_category.xml index 582821bdf6bb..72cfddb1a431 100644 --- a/packages/SettingsLib/res/layout/drawer_category.xml +++ b/packages/SettingsLib/res/layout/drawer_category.xml @@ -26,13 +26,13 @@ android:background="?android:attr/listDivider" /> <TextView + style="@style/TextAppearanceSmall" android:id="@android:id/title" android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="48dp" android:paddingTop="16dp" android:paddingBottom="16dp" - android:paddingStart="16dp" - android:textAppearance="?android:attr/textAppearanceSmall" /> + android:paddingStart="16dp" /> </LinearLayout> diff --git a/packages/SettingsLib/res/layout/drawer_item.xml b/packages/SettingsLib/res/layout/drawer_item.xml index e1f1ae5ef706..d492ddfee0fe 100644 --- a/packages/SettingsLib/res/layout/drawer_item.xml +++ b/packages/SettingsLib/res/layout/drawer_item.xml @@ -23,19 +23,22 @@ <ImageView android:id="@android:id/icon" - android:layout_width="72dp" - android:layout_height="24dp" + android:layout_width="@dimen/drawer_icon_size" + android:layout_height="@dimen/drawer_icon_size" + android:layout_marginStart="@dimen/drawer_icon_margin" + android:layout_marginEnd="@dimen/drawer_icon_margin" + android:layout_marginTop="@dimen/drawer_item_top_bottom_margin" + android:layout_marginBottom="@dimen/drawer_item_top_bottom_margin" + android:scaleType="fitCenter" android:layout_gravity="center_vertical" - android:tint="?android:attr/colorAccent" - android:paddingStart="16dp" - android:paddingEnd="32dp" /> + android:tint="?android:attr/colorAccent"/> <TextView + android:textAppearance="@style/TextAppearanceMedium" android:id="@android:id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" - android:textColor="?android:attr/colorControlNormal" - android:textAppearance="?android:attr/textAppearanceMedium" /> + android:textColor="?android:attr/colorControlNormal" /> </LinearLayout> diff --git a/packages/SettingsLib/res/layout/drawer_spacer.xml b/packages/SettingsLib/res/layout/drawer_spacer.xml index ee1835d7c231..98120cf904d0 100644 --- a/packages/SettingsLib/res/layout/drawer_spacer.xml +++ b/packages/SettingsLib/res/layout/drawer_spacer.xml @@ -17,4 +17,4 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/spacer" android:layout_width="match_parent" - android:layout_height="32dp" /> + android:layout_height="@dimen/drawer_spacer_height" /> diff --git a/packages/SettingsLib/res/layout/settings_with_drawer.xml b/packages/SettingsLib/res/layout/settings_with_drawer.xml index abe310a6e38a..af96d8b25e64 100644 --- a/packages/SettingsLib/res/layout/settings_with_drawer.xml +++ b/packages/SettingsLib/res/layout/settings_with_drawer.xml @@ -53,7 +53,7 @@ </LinearLayout> <!-- The navigation drawer --> <ListView android:id="@+id/left_drawer" - android:layout_width="300dp" + android:layout_width="@dimen/drawer_width" android:layout_height="match_parent" android:layout_gravity="start" android:choiceMode="singleChoice" diff --git a/packages/SettingsLib/res/values-hy-rAM/strings.xml b/packages/SettingsLib/res/values-hy-rAM/strings.xml index 817bb60c22bb..bcd56d5a82c9 100644 --- a/packages/SettingsLib/res/values-hy-rAM/strings.xml +++ b/packages/SettingsLib/res/values-hy-rAM/strings.xml @@ -170,7 +170,7 @@ <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Միշտ թույլատրել Wi‑Fi ռոումինգի որոնումը"</string> <string name="mobile_data_always_on" msgid="7745605759775320362">"Բջջային տվյալները՝ միշտ ակտիվացրած"</string> <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Անջատել ձայնի բացարձակ ուժգնությունը"</string> - <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Ցույց տալ անլար էկրանի վկայագրման ընտրանքները"</string> + <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Ցույց տալ անլար էկրանի հավաստագրման ընտրանքները"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Բարձրացնել մակարդակը, Wi‑Fi ընտրիչում ամեն մի SSID-ի համար ցույց տալ RSSI"</string> <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Եթե այս գործառույթը միացված է, Wi‑Fi-ի թույլ ազդանշանի դեպքում Wi‑Fi ինտերնետից անցումը բջջային ինտերնետին ավելի կտրուկ կլինի"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Թույլատրել/արգելել Wi‑Fi ռոումինգի որոնումը՝ կախված միջերեսում տվյալների երթևեկի ծավալից"</string> diff --git a/packages/SettingsLib/res/values/config.xml b/packages/SettingsLib/res/values/config.xml index 64f21b50c0bc..ee69b56ef472 100755 --- a/packages/SettingsLib/res/values/config.xml +++ b/packages/SettingsLib/res/values/config.xml @@ -26,6 +26,9 @@ <!-- Whether to send a custom package name with the PSD.--> <bool name="config_sendPackageName">false</bool> + <!-- Whether to enable the left nav drawer in all Settings UI.--> + <bool name="config_enable_nav_drawer">false</bool> + <!-- Name for the set of keys associating package names --> <string name="config_helpPackageNameKey" translatable="false"></string> diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml index c3b3cfc47bfd..2e8b30fb5abf 100644 --- a/packages/SettingsLib/res/values/dimens.xml +++ b/packages/SettingsLib/res/values/dimens.xml @@ -51,5 +51,10 @@ <dimen name="usage_graph_dot_size">.75dp</dimen> <dimen name="usage_graph_dot_interval">7dp</dimen> - + <dimen name="drawer_icon_size">24dp</dimen> + <dimen name="normal_icon_size">24dp</dimen> + <dimen name="drawer_icon_margin">24dp</dimen> + <dimen name="drawer_width">300dp</dimen> + <dimen name="drawer_item_top_bottom_margin">4dp</dimen> + <dimen name="drawer_spacer_height">32dp</dimen> </resources> diff --git a/packages/SettingsLib/res/values/styles.xml b/packages/SettingsLib/res/values/styles.xml new file mode 100644 index 000000000000..3f312f4efda3 --- /dev/null +++ b/packages/SettingsLib/res/values/styles.xml @@ -0,0 +1,24 @@ +<!-- + ~ Copyright (C) 2016 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<resources> + <style name="TextAppearanceSmall"> + <item name="android:textAppearance">?android:attr/textAppearanceSmall</item> + </style> + <style name="TextAppearanceMedium"> + <item name="android:textAppearance">?android:attr/textAppearanceMedium</item> + </style> +</resources> diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java index e0490792001e..6179244a27f6 100644 --- a/packages/SettingsLib/src/com/android/settingslib/Utils.java +++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java @@ -8,6 +8,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.UserInfo; import android.content.pm.Signature; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; @@ -165,6 +166,22 @@ public class Utils { return colorAccent; } + @ColorInt + public static int getColorError(Context context) { + TypedArray ta = context.obtainStyledAttributes(new int[]{android.R.attr.textColorError}); + @ColorInt int colorError = ta.getColor(0, 0); + ta.recycle(); + return colorError; + } + + @ColorInt + public static int getDefaultColor(Context context, int resId) { + final ColorStateList list = + context.getResources().getColorStateList(resId, context.getTheme()); + + return list.getDefaultColor(); + } + /** * Determine whether a package is a "system package", in which case certain things (like * disabling notifications or disabling the package altogether) should be disallowed. diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java index 6ccba92e2e5f..fa5ba73b318f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java @@ -72,21 +72,30 @@ public class CategoryManager { } public synchronized DashboardCategory getTilesByCategory(Context context, String categoryKey) { - tryInitCategories(context); + return getTilesByCategory(context, categoryKey, TileUtils.SETTING_PKG); + } + + public synchronized DashboardCategory getTilesByCategory(Context context, String categoryKey, + String settingPkg) { + tryInitCategories(context, settingPkg); return mCategoryByKeyMap.get(categoryKey); } public synchronized List<DashboardCategory> getCategories(Context context) { - tryInitCategories(context); + return getCategories(context, TileUtils.SETTING_PKG); + } + + public synchronized List<DashboardCategory> getCategories(Context context, String settingPkg) { + tryInitCategories(context, settingPkg); return mCategories; } - public synchronized void reloadAllCategories(Context context) { + public synchronized void reloadAllCategories(Context context, String settingPkg) { final boolean forceClearCache = mInterestingConfigChanges.applyNewConfig( context.getResources()); mCategories = null; - tryInitCategories(context, forceClearCache); + tryInitCategories(context, forceClearCache, settingPkg); } public synchronized void updateCategoryFromBlacklist(Set<ComponentName> tileBlacklist) { @@ -104,20 +113,21 @@ public class CategoryManager { } } - private synchronized void tryInitCategories(Context context) { + private synchronized void tryInitCategories(Context context, String settingPkg) { // Keep cached tiles by default. The cache is only invalidated when InterestingConfigChange // happens. - tryInitCategories(context, false /* forceClearCache */); + tryInitCategories(context, false /* forceClearCache */, settingPkg); } - private synchronized void tryInitCategories(Context context, boolean forceClearCache) { + private synchronized void tryInitCategories(Context context, boolean forceClearCache, + String settingPkg) { if (mCategories == null) { if (forceClearCache) { mTileByComponentCache.clear(); } mCategoryByKeyMap.clear(); mCategories = TileUtils.getCategories(context, mTileByComponentCache, - false /* categoryDefinedInManifest */, mExtraAction); + false /* categoryDefinedInManifest */, mExtraAction, settingPkg); for (DashboardCategory category : mCategories) { mCategoryByKeyMap.put(category.key, category); } diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java index 86514dc5a5cf..89ed110d3246 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java @@ -28,7 +28,6 @@ import android.content.pm.PackageManager; import android.content.res.TypedArray; import android.os.AsyncTask; import android.os.Bundle; -import android.os.UserManager; import android.provider.Settings; import android.support.v4.widget.DrawerLayout; import android.util.ArraySet; @@ -72,7 +71,6 @@ public class SettingsDrawerActivity extends Activity { private FrameLayout mContentHeaderContainer; private DrawerLayout mDrawerLayout; private boolean mShowingMenu; - private UserManager mUserManager; // Remove below after new IA @Deprecated @@ -108,6 +106,9 @@ public class SettingsDrawerActivity extends Activity { mDrawerLayout = null; return; } + if (!isNavDrawerEnabled()) { + setIsDrawerPresent(false); + } if (!isDashboardFeatureEnabled()) { getDashboardCategories(); } @@ -122,7 +123,6 @@ public class SettingsDrawerActivity extends Activity { } }); - mUserManager = UserManager.get(this); if (DEBUG_TIMING) Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime) + " ms"); } @@ -138,6 +138,15 @@ public class SettingsDrawerActivity extends Activity { } @Override + public boolean onNavigateUp() { + if (!isNavDrawerEnabled()) { + finish(); + return true; + } + return super.onNavigateUp(); + } + + @Override protected void onResume() { super.onResume(); @@ -184,8 +193,9 @@ public class SettingsDrawerActivity extends Activity { } if (isDashboardFeatureEnabled()) { final DashboardCategory homepageCategories = CategoryManager.get(this) - .getTilesByCategory(this, CategoryKey.CATEGORY_HOMEPAGE); - return homepageCategories.containsComponent(componentName); + .getTilesByCategory(this, CategoryKey.CATEGORY_HOMEPAGE, getSettingPkg()); + return homepageCategories == + null ? false : homepageCategories.containsComponent(componentName); } else { // Look for a tile that has the same component as incoming intent final List<DashboardCategory> categories = getDashboardCategories(); @@ -201,6 +211,14 @@ public class SettingsDrawerActivity extends Activity { } } + /** + * Gets the name of the intent action of the default setting app. Used to launch setting app + * when Settings Home is clicked. + */ + public String getSettingAction() { + return Settings.ACTION_SETTINGS; + } + public void addCategoryListener(CategoryListener listener) { mCategoryListeners.add(listener); } @@ -265,7 +283,7 @@ public class SettingsDrawerActivity extends Activity { } // TODO: Do this in the background with some loading. if (isDashboardFeatureEnabled()) { - mDrawerAdapter.updateHomepageCategories(); + mDrawerAdapter.updateHomepageCategories(getSettingPkg()); } else { mDrawerAdapter.updateCategories(); } @@ -277,10 +295,13 @@ public class SettingsDrawerActivity extends Activity { } public void showMenuIcon() { - mShowingMenu = true; - getActionBar().setHomeAsUpIndicator(R.drawable.ic_menu); - getActionBar().setHomeActionContentDescription(R.string.content_description_menu_button); getActionBar().setDisplayHomeAsUpEnabled(true); + if (isNavDrawerEnabled()) { + mShowingMenu = true; + getActionBar().setHomeAsUpIndicator(R.drawable.ic_menu); + getActionBar().setHomeActionContentDescription( + R.string.content_description_menu_button); + } } public List<DashboardCategory> getDashboardCategories() { @@ -305,8 +326,9 @@ public class SettingsDrawerActivity extends Activity { public boolean openTile(Tile tile) { closeDrawer(); if (tile == null) { - startActivity(new Intent(Settings.ACTION_SETTINGS).addFlags( - Intent.FLAG_ACTIVITY_CLEAR_TASK)); + Intent intent = new Intent(getSettingAction()).addFlags( + Intent.FLAG_ACTIVITY_CLEAR_TASK); + startActivity(intent); return true; } try { @@ -364,6 +386,10 @@ public class SettingsDrawerActivity extends Activity { } } + public String getSettingPkg() { + return TileUtils.SETTING_PKG; + } + public interface CategoryListener { void onCategoriesChanged(); } @@ -414,7 +440,7 @@ public class SettingsDrawerActivity extends Activity { @Override protected Void doInBackground(Void... params) { - mCategoryManager.reloadAllCategories(SettingsDrawerActivity.this); + mCategoryManager.reloadAllCategories(SettingsDrawerActivity.this, getSettingPkg()); return null; } @@ -425,10 +451,18 @@ public class SettingsDrawerActivity extends Activity { } } + /** + * @return {@code true} if IA (Information Architecture) is enabled. + */ protected boolean isDashboardFeatureEnabled() { return false; } + boolean isNavDrawerEnabled() { + return !isDashboardFeatureEnabled() + || getResources().getBoolean(R.bool.config_enable_nav_drawer); + } + private class PackageReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java index 602d135dd6c9..75942f93b67b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java @@ -68,9 +68,9 @@ public class SettingsDrawerAdapter extends BaseAdapter { notifyDataSetChanged(); } - public void updateHomepageCategories() { + public void updateHomepageCategories(String settingPkg) { final DashboardCategory category = CategoryManager.get(mActivity) - .getTilesByCategory(mActivity, CategoryKey.CATEGORY_HOMEPAGE); + .getTilesByCategory(mActivity, CategoryKey.CATEGORY_HOMEPAGE, settingPkg); mItems.clear(); // Spacer. mItems.add(null); diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java index a0109e29831a..0cc5ab1900ba 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java @@ -147,7 +147,7 @@ public class TileUtils { public static final String META_DATA_PREFERENCE_SUMMARY_URI = "com.android.settings.summary_uri"; - private static final String SETTING_PKG = "com.android.settings"; + public static final String SETTING_PKG = "com.android.settings"; /** * Build a list of DashboardCategory. Each category must be defined in manifest. @@ -167,39 +167,43 @@ public class TileUtils { */ public static List<DashboardCategory> getCategories(Context context, Map<Pair<String, String>, Tile> cache, boolean categoryDefinedInManifest) { - return getCategories(context, cache, categoryDefinedInManifest, null); + return getCategories(context, cache, categoryDefinedInManifest, null, SETTING_PKG); } /** * Build a list of DashboardCategory. * @param categoryDefinedInManifest If true, an dummy activity must exists in manifest to * represent this category (eg: .Settings$DeviceSettings) - * @param extraAction additional intent filter action to be used to build the dashboard + * @param extraAction additional intent filter action to be usetileutild to build the dashboard * categories */ public static List<DashboardCategory> getCategories(Context context, Map<Pair<String, String>, Tile> cache, boolean categoryDefinedInManifest, - String extraAction) { + String extraAction, String settingPkg) { final long startTime = System.currentTimeMillis(); boolean setup = Global.getInt(context.getContentResolver(), Global.DEVICE_PROVISIONED, 0) != 0; ArrayList<Tile> tiles = new ArrayList<>(); - UserManager userManager = UserManager.get(context); + UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); for (UserHandle user : userManager.getUserProfiles()) { // TODO: Needs much optimization, too many PM queries going on here. if (user.getIdentifier() == ActivityManager.getCurrentUser()) { // Only add Settings for this user. - getTilesForAction(context, user, SETTINGS_ACTION, cache, null, tiles, true); + getTilesForAction(context, user, SETTINGS_ACTION, cache, null, tiles, true, + settingPkg); getTilesForAction(context, user, OPERATOR_SETTINGS, cache, - OPERATOR_DEFAULT_CATEGORY, tiles, false, true); + OPERATOR_DEFAULT_CATEGORY, tiles, false, true, settingPkg); getTilesForAction(context, user, MANUFACTURER_SETTINGS, cache, - MANUFACTURER_DEFAULT_CATEGORY, tiles, false, true); + MANUFACTURER_DEFAULT_CATEGORY, tiles, false, true, settingPkg); } if (setup) { - getTilesForAction(context, user, EXTRA_SETTINGS_ACTION, cache, null, tiles, false); - getTilesForAction(context, user, IA_SETTINGS_ACTION, cache, null, tiles, false); + getTilesForAction(context, user, EXTRA_SETTINGS_ACTION, cache, null, tiles, false, + settingPkg); + getTilesForAction(context, user, IA_SETTINGS_ACTION, cache, null, tiles, false, + settingPkg); if (extraAction != null) { - getTilesForAction(context, user, extraAction, cache, null, tiles, false); + getTilesForAction(context, user, extraAction, cache, null, tiles, false, + settingPkg); } } } @@ -263,18 +267,19 @@ public class TileUtils { private static void getTilesForAction(Context context, UserHandle user, String action, Map<Pair<String, String>, Tile> addedCache, - String defaultCategory, ArrayList<Tile> outTiles, boolean requireSettings) { + String defaultCategory, ArrayList<Tile> outTiles, boolean requireSettings, + String settingPkg) { getTilesForAction(context, user, action, addedCache, defaultCategory, outTiles, - requireSettings, requireSettings); + requireSettings, requireSettings, settingPkg); } private static void getTilesForAction(Context context, UserHandle user, String action, Map<Pair<String, String>, Tile> addedCache, String defaultCategory, ArrayList<Tile> outTiles, boolean requireSettings, - boolean usePriority) { + boolean usePriority, String settingPkg) { Intent intent = new Intent(action); if (requireSettings) { - intent.setPackage(SETTING_PKG); + intent.setPackage(settingPkg); } getTilesForIntent(context, user, intent, addedCache, defaultCategory, outTiles, usePriority, true); diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java index 1e87ea0f18ef..2fd5ec08656b 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java @@ -52,34 +52,34 @@ public class SettingsDrawerActivityTest { } @Test - public void startActivityWithNoExtra_showNoHamburgerMenu() { + public void startActivityWithNoExtra_showNoNavUp() { Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); instrumentation.startActivitySync(new Intent(instrumentation.getTargetContext(), TestActivity.class)); - onView(withContentDescription(R.string.content_description_menu_button)) + onView(withContentDescription(com.android.internal.R.string.action_bar_up_description)) .check(doesNotExist()); } @Test - public void startActivityWithExtraToHideMenu_showNoHamburgerMenu() { + public void startActivityWithExtraToHideMenu_showNavUp() { Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); Intent intent = new Intent(instrumentation.getTargetContext(), TestActivity.class) .putExtra(TestActivity.EXTRA_SHOW_MENU, false); instrumentation.startActivitySync(intent); - onView(withContentDescription(R.string.content_description_menu_button)) + onView(withContentDescription(com.android.internal.R.string.action_bar_up_description)) .check(doesNotExist()); } @Test - public void startActivityWithExtraToShowMenu_showHamburgerMenu() { + public void startActivityWithExtraToShowMenu_showNavUp() { Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); Intent intent = new Intent(instrumentation.getTargetContext(), TestActivity.class) .putExtra(TestActivity.EXTRA_SHOW_MENU, true); instrumentation.startActivitySync(intent); - onView(withContentDescription(R.string.content_description_menu_button)) + onView(withContentDescription(com.android.internal.R.string.action_bar_up_description)) .check(matches(isDisplayed())); } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java index eb99cac94e40..d8082c41b5ff 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java @@ -16,6 +16,8 @@ package com.android.settingslib.drawer; +import android.app.ActivityManager; +import static org.mockito.Mockito.verify; import android.content.IContentProvider; import android.content.ContentResolver; import android.content.Context; @@ -36,6 +38,7 @@ import android.util.ArrayMap; import android.util.Pair; import com.android.settingslib.TestConfig; +import static org.mockito.Mockito.atLeastOnce; import org.junit.Before; import org.junit.Test; @@ -43,6 +46,7 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.shadows.ShadowApplication; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @@ -59,6 +63,8 @@ import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +import org.mockito.ArgumentCaptor; + @RunWith(RobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) @@ -97,7 +103,7 @@ public class TileUtilsTest { List<Tile> outTiles = new ArrayList<>(); List<ResolveInfo> info = new ArrayList<>(); info.add(newInfo(true, testCategory)); - + Map<Pair<String, String>, Tile> cache = new ArrayMap<>(); when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt())) .thenReturn(info); @@ -169,12 +175,33 @@ public class TileUtilsTest { }), anyInt(), anyInt())).thenReturn(info); List<DashboardCategory> categoryList = TileUtils.getCategories( - mContext, cache, false /* categoryDefinedInManifest */, testAction); - + mContext, cache, false /* categoryDefinedInManifest */, testAction, + TileUtils.SETTING_PKG); assertThat(categoryList.get(0).tiles.get(0).category).isEqualTo(testCategory); } @Test + public void getCategories_withPackageName() throws Exception { + ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); + Map<Pair<String, String>, Tile> cache = new ArrayMap<>(); + Global.putInt(mContext.getContentResolver(), Global.DEVICE_PROVISIONED, 1); + when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); + List<UserHandle> userHandleList = new ArrayList<>(); + + userHandleList.add(new UserHandle(ActivityManager.getCurrentUser())); + when(mUserManager.getUserProfiles()).thenReturn(userHandleList); + + TileUtils.getCategories( + mContext, cache, false /* categoryDefinedInManifest */, null /* action */, + TileUtils.SETTING_PKG); + verify(mPackageManager, atLeastOnce()).queryIntentActivitiesAsUser( + intentCaptor.capture(), anyInt(), anyInt()); + + assertThat(intentCaptor.getAllValues().get(0).getPackage()) + .isEqualTo(TileUtils.SETTING_PKG); + } + + @Test public void getTilesForIntent_shouldNotProcessInvalidUriContentSystemApp() throws RemoteException { Intent intent = new Intent(); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java index 6b01d6687c65..fecc938ad3be 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java @@ -355,9 +355,11 @@ final public class SettingsService extends Binder { final String callPutCommand; if ("system".equals(table)) { callPutCommand = Settings.CALL_METHOD_PUT_SYSTEM; - makeDefault = false; - getOutPrintWriter().println("Ignored makeDefault - " - + "doesn't apply to system settings"); + if (makeDefault) { + getOutPrintWriter().print("Ignored makeDefault - " + + "doesn't apply to system settings"); + makeDefault = false; + } } else if ("secure".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_SECURE; else if ("global".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_GLOBAL; else { diff --git a/packages/SystemUI/res/color/data_usage_graph_track.xml b/packages/SystemUI/res/color/data_usage_graph_track.xml new file mode 100644 index 000000000000..55c4d2f23937 --- /dev/null +++ b/packages/SystemUI/res/color/data_usage_graph_track.xml @@ -0,0 +1,18 @@ +<?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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:alpha="0.2" android:color="?android:attr/colorForeground" /> +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/data_usage_graph_warning.xml b/packages/SystemUI/res/color/data_usage_graph_warning.xml new file mode 100644 index 000000000000..15944c3a2a07 --- /dev/null +++ b/packages/SystemUI/res/color/data_usage_graph_warning.xml @@ -0,0 +1,18 @@ +<?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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="?android:attr/colorForeground" /> +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable-nodpi/tuner.xml b/packages/SystemUI/res/drawable-nodpi/tuner.xml index 0596aa4ed14f..c0e51a411b00 100644 --- a/packages/SystemUI/res/drawable-nodpi/tuner.xml +++ b/packages/SystemUI/res/drawable-nodpi/tuner.xml @@ -17,7 +17,8 @@ android:width="24.0dp" android:height="24.0dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:viewportHeight="24.0" + android:tint="?android:attr/colorControlNormal"> <path android:fillColor="#FFFFFFFF" android:pathData="M22.7,19.0l-9.1,-9.1c0.9,-2.0 0.4,-5.0 -1.5,-6.9 -2.0,-2.0 -5.0,-2.4 -7.4,-1.3L9.0,6.0 6.0,9.0 1.6,4.7C0.4,7.0 0.9,10.1 2.9,12.1c1.9,1.9 4.6,2.4 6.9,1.5l9.1,9.1c0.4,0.4 1.0,0.4 1.4,0.0l2.3,-2.3c0.5,-0.4 0.5,-1.0 0.1,-1.4z"/> diff --git a/packages/SystemUI/res/layout-sw410dp/status_bar_alarm_group.xml b/packages/SystemUI/res/layout-sw410dp/status_bar_alarm_group.xml index efdfae75c1ff..e85b76d3103f 100644 --- a/packages/SystemUI/res/layout-sw410dp/status_bar_alarm_group.xml +++ b/packages/SystemUI/res/layout-sw410dp/status_bar_alarm_group.xml @@ -67,7 +67,6 @@ android:paddingTop="3dp" android:drawablePadding="8dp" android:drawableStart="@drawable/ic_access_alarms_small" - android:textColor="?android:attr/textColorSecondary" android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date" android:gravity="top" android:background="?android:attr/selectableItemBackground" diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml index 6673d6e8255f..53acb9f14ad9 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml @@ -72,19 +72,20 @@ android:clipChildren="false" android:clipToPadding="false"> - <com.android.systemui.statusbar.phone.SettingsButton android:id="@+id/settings_button" + <com.android.systemui.statusbar.phone.SettingsButton + android:id="@+id/settings_button" style="@android:style/Widget.Material.Button.Borderless" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/ripple_drawable" android:src="@drawable/ic_settings_20dp" android:contentDescription="@string/accessibility_quick_settings_settings" /> - <com.android.systemui.statusbar.AlphaOptimizedImageView android:id="@+id/tuner_icon" + <com.android.systemui.statusbar.AlphaOptimizedImageView + android:id="@+id/tuner_icon" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingStart="36dp" - android:tint="#4DFFFFFF" - android:tintMode="src_in" + android:alpha="0.3" android:visibility="invisible" android:src="@drawable/tuner" /> diff --git a/packages/SystemUI/res/layout/status_bar_alarm_group.xml b/packages/SystemUI/res/layout/status_bar_alarm_group.xml index 03585b854898..a02e9af674fa 100644 --- a/packages/SystemUI/res/layout/status_bar_alarm_group.xml +++ b/packages/SystemUI/res/layout/status_bar_alarm_group.xml @@ -65,7 +65,6 @@ android:paddingTop="3dp" android:drawablePadding="8dp" android:drawableStart="@drawable/ic_access_alarms_small" - android:textColor="?android:attr/textColorSecondary" android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date" android:gravity="top" android:background="?android:attr/selectableItemBackground" diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index ba8c64410443..b18b6acb6a35 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -31,15 +31,11 @@ <color name="batterymeter_bolt_color">#FFFFFFFF</color> <color name="qs_batterymeter_frame_color">#FF404040</color> <color name="system_warning_color">@*android:color/system_error</color> - <color name="qs_text">#FFFFFFFF</color> <color name="qs_tile_divider">#29ffffff</color><!-- 16% white --> <color name="qs_subhead">#99FFFFFF</color><!-- 60% white --> <color name="qs_detail_button">@*android:color/quaternary_device_default_settings</color> <color name="qs_detail_button_white">#B3FFFFFF</color><!-- 70% white --> <color name="qs_detail_transition">#66FFFFFF</color> - <color name="data_usage_secondary">#99FFFFFF</color><!-- 60% white --> - <color name="data_usage_graph_track">#33FFFFFF</color><!-- 20% white --> - <color name="data_usage_graph_warning">#FFFFFFFF</color> <color name="status_bar_clock_color">#FFFFFFFF</color> <color name="qs_user_detail_icon_muted">#FFFFFFFF</color> <!-- not so muted after all --> <color name="qs_tile_disabled_color">#9E9E9E</color> <!-- 38% black --> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 614472a7fd01..a9c858c0e721 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -117,13 +117,13 @@ <style name="TextAppearance.StatusBar.Expanded.Date"> <item name="android:textSize">@dimen/qs_date_collapsed_size</item> <item name="android:textStyle">normal</item> - <item name="android:textColor">#b2ffffff</item> + <item name="android:textColor">?android:attr/textColorSecondary</item> </style> <style name="TextAppearance.StatusBar.Expanded.AboveDateTime"> <item name="android:textSize">@dimen/qs_emergency_calls_only_text_size</item> <item name="android:textStyle">normal</item> - <item name="android:textColor">#66ffffff</item> + <item name="android:textColor">?android:attr/textColorSecondary</item> </style> <style name="TextAppearance.StatusBar.Expanded.EmergencyCallsOnly" @@ -207,7 +207,7 @@ </style> <style name="TextAppearance.QS.DataUsage.Secondary"> - <item name="android:textColor">@color/data_usage_secondary</item> + <item name="android:textColor">?android:attr/textColorSecondary</item> </style> <style name="TextAppearance.QS.TileLabel"> diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java index a7cbb3d94557..d4bb994010a3 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java @@ -147,8 +147,6 @@ public class PowerUI extends SystemUI { filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_USER_SWITCHED); - filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING); - filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); mContext.registerReceiver(this, filter, null, mHandler); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/DataUsageGraph.java b/packages/SystemUI/src/com/android/systemui/qs/DataUsageGraph.java index 5f23a40ab3b8..047e0d17ad18 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/DataUsageGraph.java +++ b/packages/SystemUI/src/com/android/systemui/qs/DataUsageGraph.java @@ -45,10 +45,10 @@ public class DataUsageGraph extends View { public DataUsageGraph(Context context, AttributeSet attrs) { super(context, attrs); final Resources res = context.getResources(); - mTrackColor = context.getColor(R.color.data_usage_graph_track); + mTrackColor = Utils.getDefaultColor(context, R.color.data_usage_graph_track); + mWarningColor = Utils.getDefaultColor(context, R.color.data_usage_graph_warning); mUsageColor = Utils.getColorAccent(context); - mOverlimitColor = context.getColor(R.color.system_warning_color); - mWarningColor = context.getColor(R.color.data_usage_graph_warning); + mOverlimitColor = Utils.getColorError(context); mMarkerWidth = res.getDimensionPixelSize(R.dimen.data_usage_graph_marker_width); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 760bf54a540c..1f2007af4870 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -2192,6 +2192,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal mFocusedTask.dump("", writer); } + int numTaskViews = mTaskViews.size(); + for (int i = 0; i < numTaskViews; i++) { + mTaskViews.get(i).dump(innerPrefix, writer); + } + mLayoutAlgorithm.dump(innerPrefix, writer); mStackScroller.dump(innerPrefix, writer); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index 2f4ad6a4d7ce..36d5f838a070 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -58,6 +58,7 @@ import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; +import java.io.PrintWriter; import java.util.ArrayList; /** @@ -715,4 +716,14 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks setClipViewInStack(true); }); } + + public void dump(String prefix, PrintWriter writer) { + String innerPrefix = prefix + " "; + + writer.print(prefix); writer.print("TaskView"); + writer.print(" mTask="); writer.print(mTask.key.id); + writer.println(); + + mThumbnailView.dump(innerPrefix, writer); + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java index d109807c3ca4..58b929ac690a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java @@ -35,8 +35,11 @@ import android.view.View; import android.view.ViewDebug; import com.android.systemui.R; +import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.Task; +import java.io.PrintWriter; + /** * The task thumbnail view. It implements an image view that allows for animating the dim and @@ -343,4 +346,15 @@ public class TaskViewThumbnail extends View { mTask = null; setThumbnail(null, null); } + + public void dump(String prefix, PrintWriter writer) { + String innerPrefix = prefix + " "; + + writer.print(prefix); writer.print("TaskViewThumbnail"); + writer.print(" mTaskViewRect="); writer.print(Utilities.dumpRect(mTaskViewRect)); + writer.print(" mThumbnailRect="); writer.print(Utilities.dumpRect(mThumbnailRect)); + writer.print(" mThumbnailScale="); writer.print(mThumbnailScale); + writer.print(" mDimAlpha="); writer.print(mDimAlpha); + writer.println(); + } } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index a50f722b41d8..2d42c338db37 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -6491,7 +6491,7 @@ public class AudioService extends IAudioService.Stub } //====================== - // Audio policy callbacks from players for playback configuration updates + // Audio playback notification //====================== private final PlaybackActivityMonitor mPlaybackMonitor = new PlaybackActivityMonitor(); @@ -6518,15 +6518,15 @@ public class AudioService extends IAudioService.Stub } public void playerAttributes(int piid, AudioAttributes attr) { - mPlaybackMonitor.playerAttributes(piid, attr); + mPlaybackMonitor.playerAttributes(piid, attr, Binder.getCallingUid()); } public void playerEvent(int piid, int event) { - mPlaybackMonitor.playerEvent(piid, event); + mPlaybackMonitor.playerEvent(piid, event, Binder.getCallingUid()); } public void releasePlayer(int piid) { - mPlaybackMonitor.releasePlayer(piid); + mPlaybackMonitor.releasePlayer(piid, Binder.getCallingUid()); } //====================== diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java index dfa856da0d17..d6b4bee102aa 100644 --- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java +++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java @@ -78,15 +78,15 @@ public final class PlaybackActivityMonitor { return newPiid; } - public void playerAttributes(int piid, @NonNull AudioAttributes attr) { + public void playerAttributes(int piid, @NonNull AudioAttributes attr, int binderUid) { final boolean change; synchronized(mPlayerLock) { final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid)); - if (apc == null) { - Log.e(TAG, "Unknown player " + piid + " for audio attributes change"); - change = false; - } else { + if (checkConfigurationCaller(piid, apc, binderUid)) { change = apc.handleAudioAttributesEvent(attr); + } else { + Log.e(TAG, "Error updating audio attributes"); + change = false; } } if (change) { @@ -94,17 +94,17 @@ public final class PlaybackActivityMonitor { } } - public void playerEvent(int piid, int event) { + public void playerEvent(int piid, int event, int binderUid) { if (DEBUG) { Log.v(TAG, String.format("playerEvent(piid=%d, event=%d)", piid, event)); } final boolean change; synchronized(mPlayerLock) { final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid)); - if (apc == null) { - Log.e(TAG, "Unknown player " + piid + " for event " + event); - change = false; - } else { + if (checkConfigurationCaller(piid, apc, binderUid)) { //TODO add generation counter to only update to the latest state change = apc.handleStateEvent(event); + } else { + Log.e(TAG, "Error handling event " + event); + change = false; } } if (change) { @@ -112,13 +112,14 @@ public final class PlaybackActivityMonitor { } } - public void releasePlayer(int piid) { + public void releasePlayer(int piid, int binderUid) { if (DEBUG) { Log.v(TAG, "releasePlayer() for piid=" + piid); } synchronized(mPlayerLock) { - if (!mPlayers.containsKey(new Integer(piid))) { - Log.e(TAG, "Unknown player " + piid + " for release"); - } else { + final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid)); + if (checkConfigurationCaller(piid, apc, binderUid)) { mPlayers.remove(new Integer(piid)); + } else { + Log.e(TAG, "Error releasing player " + piid); } } } @@ -133,6 +134,25 @@ public final class PlaybackActivityMonitor { } } + /** + * Check that piid and uid are valid for the given configuration. + * @param piid the piid of the player. + * @param apc the configuration found for this piid. + * @param binderUid actual uid of client trying to signal a player state/event/attributes. + * @return true if the call is valid and the change should proceed, false otherwise. + */ + private static boolean checkConfigurationCaller(int piid, + final AudioPlaybackConfiguration apc, int binderUid) { + if (apc == null) { + Log.e(TAG, "Invalid operation: unknown player " + piid); + return false; + } else if ((binderUid != 0) && (apc.getClientUid() != binderUid)) { + Log.e(TAG, "Forbidden operation from uid " + binderUid + " for player " + piid); + return false; + } + return true; + } + private void dispatchPlaybackChange() { synchronized (mClients) { // typical use case, nobody is listening, don't do any work diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java index e91cce11f7df..f5b866981993 100644 --- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java +++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java @@ -126,8 +126,6 @@ public class UserRestrictionsUtils { UserManager.DISALLOW_NETWORK_RESET, UserManager.DISALLOW_FACTORY_RESET, UserManager.DISALLOW_ADD_USER, - UserManager.DISALLOW_ADD_MANAGED_PROFILE, - UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, @@ -261,6 +259,7 @@ public class UserRestrictionsUtils { /** * Returns the user restrictions that default to {@code true} for device owners. + * These user restrictions are local, though. ie only for the device owner's user id. */ public static @NonNull Set<String> getDefaultEnabledForDeviceOwner() { return DEFAULT_ENABLED_FOR_DEVICE_OWNERS; diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index 93c7cd5b9abb..09886db17af6 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -888,75 +888,68 @@ static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, // TODO(b/31632518) gnssHal = IGnss::getService("gnss"); if (gnssHal != nullptr) { - auto result = gnssHal->getExtensionXtra([](const sp<IGnssXtra>& xtraIface) { - gnssXtraIface = xtraIface; - }); - - if (!result.isOk()) { + auto gnssXtra = gnssHal->getExtensionXtra(); + if (!gnssXtra.isOk()) { ALOGD("Unable to get a handle to Xtra"); + } else { + gnssXtraIface = gnssXtra; } - result = gnssHal->getExtensionAGnssRil([](const sp<IAGnssRil>& rilIface) { - agnssRilIface = rilIface; - }); - - if (!result.isOk()) { + auto gnssRil = gnssHal->getExtensionAGnssRil(); + if (!gnssRil.isOk()) { ALOGD("Unable to get a handle to AGnssRil"); + } else { + agnssRilIface = gnssRil; } - result = gnssHal->getExtensionAGnss([](const sp<IAGnss>& assistedGnssIface) { - agnssIface = assistedGnssIface; - }); - - if (!result.isOk()) { + auto gnssAgnss = gnssHal->getExtensionAGnss(); + if (!gnssAgnss.isOk()) { ALOGD("Unable to get a handle to AGnss"); + } else { + agnssIface = gnssAgnss; } - result = gnssHal->getExtensionGnssNavigationMessage( - [](const sp<IGnssNavigationMessage>& navigationMessageIface) { - gnssNavigationMessageIface = navigationMessageIface; - }); - - if (!result.isOk()) { + auto gnssNavigationMessage = gnssHal->getExtensionGnssNavigationMessage(); + if (!gnssNavigationMessage.isOk()) { ALOGD("Unable to get a handle to GnssNavigationMessage"); + } else { + gnssNavigationMessageIface = gnssNavigationMessage; } - result = gnssHal->getExtensionGnssMeasurement([]( - const sp<IGnssMeasurement>& measurementIface) { - gnssMeasurementIface = measurementIface; - }); - if (!result.isOk()) { + auto gnssMeasurement = gnssHal->getExtensionGnssMeasurement(); + if (!gnssMeasurement.isOk()) { ALOGD("Unable to get a handle to GnssMeasurement"); + } else { + gnssMeasurementIface = gnssMeasurement; } - result = gnssHal->getExtensionGnssDebug([](const sp<IGnssDebug>& debugIface) { - gnssDebugIface = debugIface; - }); - if (!result.isOk()) { + auto gnssDebug = gnssHal->getExtensionGnssDebug(); + if (!gnssDebug.isOk()) { ALOGD("Unable to get a handle to GnssDebug"); + } else { + gnssDebugIface = gnssDebug; } - result = gnssHal->getExtensionGnssNi([](const sp<IGnssNi>& niIface) { - gnssNiIface = niIface; - }); - if (!result.isOk()) { + auto gnssNi = gnssHal->getExtensionGnssNi(); + if (!gnssNi.isOk()) { ALOGD("Unable to get a handle to GnssNi"); + } else { + gnssNiIface = gnssNi; } - result = gnssHal->getExtensionGnssConfiguration([](const sp<IGnssConfiguration>& configIface) { - gnssConfigurationIface = configIface; - }); - if (!result.isOk()) { + auto gnssConfiguration = gnssHal->getExtensionGnssConfiguration(); + if (!gnssConfiguration.isOk()) { ALOGD("Unable to get a handle to GnssConfiguration"); + } else { + gnssConfigurationIface = gnssConfiguration; } - result = gnssHal->getExtensionGnssGeofencing([](const sp<IGnssGeofencing>& geofenceIface) { - gnssGeofencingIface = geofenceIface; - }); - if (!result.isOk()) { + auto gnssGeofencing = gnssHal->getExtensionGnssGeofencing(); + if (!gnssGeofencing.isOk()) { ALOGD("Unable to get a handle to GnssGeofencing"); + } else { + gnssGeofencingIface = gnssGeofencing; } - } else { ALOGE("Unable to get GPS service\n"); } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 469dea5a7259..d39245992d49 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -1208,8 +1208,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { ); verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions( eq(UserHandle.USER_SYSTEM), - MockUtils.checkUserRestrictions(), - MockUtils.checkUserRestrictions(defaultRestrictions) + MockUtils.checkUserRestrictions(defaultRestrictions), + MockUtils.checkUserRestrictions() ); reset(mContext.userManagerInternal); @@ -1479,8 +1479,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { ); verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions( eq(UserHandle.USER_SYSTEM), - MockUtils.checkUserRestrictions(), - MockUtils.checkUserRestrictions(defaultRestrictions) + MockUtils.checkUserRestrictions(defaultRestrictions), + MockUtils.checkUserRestrictions() ); reset(mContext.userManagerInternal); @@ -1521,8 +1521,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { ); verify(mContext.userManagerInternal, atLeast(1)).setDevicePolicyUserRestrictions( eq(UserHandle.USER_SYSTEM), - MockUtils.checkUserRestrictions(), - MockUtils.checkUserRestrictions(newDefaultEnabledRestriction) + MockUtils.checkUserRestrictions(newDefaultEnabledRestriction), + MockUtils.checkUserRestrictions() ); reset(mContext.userManagerInternal); diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java index 84bb4e889793..e30bd5d96672 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java @@ -15,14 +15,37 @@ */ package com.android.server.pm; +import android.annotation.TestApi; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.ConfigurationInfo; +import android.content.pm.FeatureGroupInfo; +import android.content.pm.FeatureInfo; +import android.content.pm.InstrumentationInfo; import android.content.pm.PackageParser; +import android.content.pm.ProviderInfo; +import android.content.pm.ServiceInfo; +import android.content.pm.Signature; +import android.os.Bundle; +import android.os.Parcel; import android.support.test.runner.AndroidJUnit4; import android.test.suitebuilder.annotation.MediumTest; import java.io.File; +import java.lang.reflect.Array; +import java.lang.reflect.Field; import java.nio.charset.StandardCharsets; +import java.security.cert.Certificate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import static org.junit.Assert.*; + +import android.util.ArrayMap; +import android.util.ArraySet; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -87,6 +110,36 @@ public class PackageParserTest { assertEquals("android", pkg.packageName); } + @Test + public void test_serializePackage() throws Exception { + PackageParser pp = new PackageParser(); + pp.setCacheDir(mTmpDir); + + PackageParser.Package pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, + true /* useCaches */); + + Parcel p = Parcel.obtain(); + pkg.writeToParcel(p, 0 /* flags */); + + p.setDataPosition(0); + PackageParser.Package deserialized = new PackageParser.Package(p); + + assertPackagesEqual(pkg, deserialized); + } + + @Test + public void test_roundTripKnownFields() throws Exception { + PackageParser.Package pkg = new PackageParser.Package("foo"); + setKnownFields(pkg); + + Parcel p = Parcel.obtain(); + pkg.writeToParcel(p, 0 /* flags */); + + p.setDataPosition(0); + PackageParser.Package deserialized = new PackageParser.Package(p); + assertAllFieldsExist(deserialized); + } + /** * A trivial subclass of package parser that only caches the package name, and throws away * all other information. @@ -102,4 +155,375 @@ public class PackageParserTest { return new Package(new String(cacheEntry, StandardCharsets.UTF_8)); } } + + // NOTE: The equality assertions below are based on code autogenerated by IntelliJ. + + public static void assertPackagesEqual(PackageParser.Package a, PackageParser.Package b) { + assertEquals(a.baseRevisionCode, b.baseRevisionCode); + assertEquals(a.baseHardwareAccelerated, b.baseHardwareAccelerated); + assertEquals(a.mVersionCode, b.mVersionCode); + assertEquals(a.mSharedUserLabel, b.mSharedUserLabel); + assertEquals(a.mPreferredOrder, b.mPreferredOrder); + assertEquals(a.installLocation, b.installLocation); + assertEquals(a.coreApp, b.coreApp); + assertEquals(a.mRequiredForAllUsers, b.mRequiredForAllUsers); + assertEquals(a.mOverlayPriority, b.mOverlayPriority); + assertEquals(a.mTrustedOverlay, b.mTrustedOverlay); + assertEquals(a.use32bitAbi, b.use32bitAbi); + assertEquals(a.packageName, b.packageName); + assertTrue(Arrays.equals(a.splitNames, b.splitNames)); + assertEquals(a.volumeUuid, b.volumeUuid); + assertEquals(a.codePath, b.codePath); + assertEquals(a.baseCodePath, b.baseCodePath); + assertTrue(Arrays.equals(a.splitCodePaths, b.splitCodePaths)); + assertTrue(Arrays.equals(a.splitRevisionCodes, b.splitRevisionCodes)); + assertTrue(Arrays.equals(a.splitFlags, b.splitFlags)); + assertTrue(Arrays.equals(a.splitPrivateFlags, b.splitPrivateFlags)); + assertApplicationInfoEqual(a.applicationInfo, b.applicationInfo); + + assertEquals(a.permissions.size(), b.permissions.size()); + for (int i = 0; i < a.permissions.size(); ++i) { + assertPermissionsEqual(a.permissions.get(i), b.permissions.get(i)); + assertSame(a.permissions.get(i).owner, a); + assertSame(b.permissions.get(i).owner, b); + } + + assertEquals(a.permissionGroups.size(), b.permissionGroups.size()); + for (int i = 0; i < a.permissionGroups.size(); ++i) { + assertPermissionGroupsEqual(a.permissionGroups.get(i), b.permissionGroups.get(i)); + } + + assertEquals(a.activities.size(), b.activities.size()); + for (int i = 0; i < a.activities.size(); ++i) { + assertActivitiesEqual(a.activities.get(i), b.activities.get(i)); + } + + assertEquals(a.receivers.size(), b.receivers.size()); + for (int i = 0; i < a.receivers.size(); ++i) { + assertActivitiesEqual(a.receivers.get(i), b.receivers.get(i)); + } + + assertEquals(a.providers.size(), b.providers.size()); + for (int i = 0; i < a.providers.size(); ++i) { + assertProvidersEqual(a.providers.get(i), b.providers.get(i)); + } + + assertEquals(a.services.size(), b.services.size()); + for (int i = 0; i < a.services.size(); ++i) { + assertServicesEqual(a.services.get(i), b.services.get(i)); + } + + assertEquals(a.instrumentation.size(), b.instrumentation.size()); + for (int i = 0; i < a.instrumentation.size(); ++i) { + assertInstrumentationEqual(a.instrumentation.get(i), b.instrumentation.get(i)); + } + + assertEquals(a.requestedPermissions, b.requestedPermissions); + assertEquals(a.protectedBroadcasts, b.protectedBroadcasts); + assertEquals(a.parentPackage, b.parentPackage); + assertEquals(a.childPackages, b.childPackages); + assertEquals(a.libraryNames, b.libraryNames); + assertEquals(a.usesLibraries, b.usesLibraries); + assertEquals(a.usesOptionalLibraries, b.usesOptionalLibraries); + assertTrue(Arrays.equals(a.usesLibraryFiles, b.usesLibraryFiles)); + assertEquals(a.mOriginalPackages, b.mOriginalPackages); + assertEquals(a.mRealPackage, b.mRealPackage); + assertEquals(a.mAdoptPermissions, b.mAdoptPermissions); + assertBundleApproximateEquals(a.mAppMetaData, b.mAppMetaData); + assertEquals(a.mVersionName, b.mVersionName); + assertEquals(a.mSharedUserId, b.mSharedUserId); + assertTrue(Arrays.equals(a.mSignatures, b.mSignatures)); + assertTrue(Arrays.equals(a.mCertificates, b.mCertificates)); + assertTrue(Arrays.equals(a.mLastPackageUsageTimeInMills, b.mLastPackageUsageTimeInMills)); + assertEquals(a.mExtras, b.mExtras); + assertEquals(a.mRestrictedAccountType, b.mRestrictedAccountType); + assertEquals(a.mRequiredAccountType, b.mRequiredAccountType); + assertEquals(a.mOverlayTarget, b.mOverlayTarget); + assertEquals(a.mSigningKeys, b.mSigningKeys); + assertEquals(a.mUpgradeKeySets, b.mUpgradeKeySets); + assertEquals(a.mKeySetMapping, b.mKeySetMapping); + assertEquals(a.cpuAbiOverride, b.cpuAbiOverride); + assertTrue(Arrays.equals(a.restrictUpdateHash, b.restrictUpdateHash)); + } + + private static void assertBundleApproximateEquals(Bundle a, Bundle b) { + if (a == b) { + return; + } + + // Force the bundles to be unparceled. + a.getBoolean("foo"); + b.getBoolean("foo"); + + assertEquals(a.toString(), b.toString()); + } + + private static void assertComponentsEqual(PackageParser.Component<?> a, + PackageParser.Component<?> b) { + assertEquals(a.className, b.className); + assertBundleApproximateEquals(a.metaData, b.metaData); + assertEquals(a.getComponentName(), b.getComponentName()); + + if (a.intents != null && b.intents != null) { + assertEquals(a.intents.size(), b.intents.size()); + } else if (a.intents == null || b.intents == null) { + return; + } + + for (int i = 0; i < a.intents.size(); ++i) { + PackageParser.IntentInfo aIntent = a.intents.get(i); + PackageParser.IntentInfo bIntent = b.intents.get(i); + + assertEquals(aIntent.hasDefault, bIntent.hasDefault); + assertEquals(aIntent.labelRes, bIntent.labelRes); + assertEquals(aIntent.nonLocalizedLabel, bIntent.nonLocalizedLabel); + assertEquals(aIntent.icon, bIntent.icon); + assertEquals(aIntent.logo, bIntent.logo); + assertEquals(aIntent.banner, bIntent.banner); + assertEquals(aIntent.preferred, bIntent.preferred); + } + } + + private static void assertPermissionsEqual(PackageParser.Permission a, + PackageParser.Permission b) { + assertComponentsEqual(a, b); + assertEquals(a.tree, b.tree); + + // Verify basic flags in PermissionInfo to make sure they're consistent. We don't perform + // a full structural equality here because the code that serializes them isn't parser + // specific and is tested elsewhere. + assertEquals(a.info.protectionLevel, b.info.protectionLevel); + assertEquals(a.info.group, b.info.group); + assertEquals(a.info.flags, b.info.flags); + + if (a.group != null && b.group != null) { + assertPermissionGroupsEqual(a.group, b.group); + } else if (a.group != null || b.group != null) { + throw new AssertionError(); + } + } + + private static void assertInstrumentationEqual(PackageParser.Instrumentation a, + PackageParser.Instrumentation b) { + assertComponentsEqual(a, b); + + // Sanity check for InstrumentationInfo. + assertEquals(a.info.targetPackage, b.info.targetPackage); + assertEquals(a.info.sourceDir, b.info.sourceDir); + assertEquals(a.info.publicSourceDir, b.info.publicSourceDir); + } + + private static void assertServicesEqual(PackageParser.Service a, PackageParser.Service b) { + assertComponentsEqual(a, b); + + // Sanity check for ServiceInfo. + assertApplicationInfoEqual(a.info.applicationInfo, b.info.applicationInfo); + assertEquals(a.info.name, b.info.name); + } + + private static void assertProvidersEqual(PackageParser.Provider a, PackageParser.Provider b) { + assertComponentsEqual(a, b); + + // Sanity check for ProviderInfo + assertApplicationInfoEqual(a.info.applicationInfo, b.info.applicationInfo); + assertEquals(a.info.name, b.info.name); + } + + private static void assertActivitiesEqual(PackageParser.Activity a, PackageParser.Activity b) { + assertComponentsEqual(a, b); + + // Sanity check for ActivityInfo. + assertApplicationInfoEqual(a.info.applicationInfo, b.info.applicationInfo); + assertEquals(a.info.name, b.info.name); + } + + private static void assertPermissionGroupsEqual(PackageParser.PermissionGroup a, + PackageParser.PermissionGroup b) { + assertComponentsEqual(a, b); + + // Sanity check for PermissionGroupInfo. + assertEquals(a.info.name, b.info.name); + assertEquals(a.info.descriptionRes, b.info.descriptionRes); + } + + private static void assertApplicationInfoEqual(ApplicationInfo a, ApplicationInfo that) { + assertEquals(a.descriptionRes, that.descriptionRes); + assertEquals(a.theme, that.theme); + assertEquals(a.fullBackupContent, that.fullBackupContent); + assertEquals(a.uiOptions, that.uiOptions); + assertEquals(a.flags, that.flags); + assertEquals(a.privateFlags, that.privateFlags); + assertEquals(a.requiresSmallestWidthDp, that.requiresSmallestWidthDp); + assertEquals(a.compatibleWidthLimitDp, that.compatibleWidthLimitDp); + assertEquals(a.largestWidthLimitDp, that.largestWidthLimitDp); + assertEquals(a.nativeLibraryRootRequiresIsa, that.nativeLibraryRootRequiresIsa); + assertEquals(a.uid, that.uid); + assertEquals(a.minSdkVersion, that.minSdkVersion); + assertEquals(a.targetSdkVersion, that.targetSdkVersion); + assertEquals(a.versionCode, that.versionCode); + assertEquals(a.enabled, that.enabled); + assertEquals(a.enabledSetting, that.enabledSetting); + assertEquals(a.installLocation, that.installLocation); + assertEquals(a.networkSecurityConfigRes, that.networkSecurityConfigRes); + assertEquals(a.taskAffinity, that.taskAffinity); + assertEquals(a.permission, that.permission); + assertEquals(a.processName, that.processName); + assertEquals(a.className, that.className); + assertEquals(a.manageSpaceActivityName, that.manageSpaceActivityName); + assertEquals(a.backupAgentName, that.backupAgentName); + assertEquals(a.volumeUuid, that.volumeUuid); + assertEquals(a.scanSourceDir, that.scanSourceDir); + assertEquals(a.scanPublicSourceDir, that.scanPublicSourceDir); + assertEquals(a.sourceDir, that.sourceDir); + assertEquals(a.publicSourceDir, that.publicSourceDir); + assertTrue(Arrays.equals(a.splitSourceDirs, that.splitSourceDirs)); + assertTrue(Arrays.equals(a.splitPublicSourceDirs, that.splitPublicSourceDirs)); + assertTrue(Arrays.equals(a.resourceDirs, that.resourceDirs)); + assertEquals(a.seinfo, that.seinfo); + assertTrue(Arrays.equals(a.sharedLibraryFiles, that.sharedLibraryFiles)); + assertEquals(a.dataDir, that.dataDir); + assertEquals(a.deviceProtectedDataDir, that.deviceProtectedDataDir); + assertEquals(a.deviceEncryptedDataDir, that.deviceEncryptedDataDir); + assertEquals(a.credentialProtectedDataDir, that.credentialProtectedDataDir); + assertEquals(a.credentialEncryptedDataDir, that.credentialEncryptedDataDir); + assertEquals(a.nativeLibraryDir, that.nativeLibraryDir); + assertEquals(a.secondaryNativeLibraryDir, that.secondaryNativeLibraryDir); + assertEquals(a.nativeLibraryRootDir, that.nativeLibraryRootDir); + assertEquals(a.primaryCpuAbi, that.primaryCpuAbi); + assertEquals(a.secondaryCpuAbi, that.secondaryCpuAbi); + } + + public static void setKnownFields(PackageParser.Package pkg) { + pkg.baseRevisionCode = 100; + pkg.baseHardwareAccelerated = true; + pkg.mVersionCode = 100; + pkg.mSharedUserLabel = 100; + pkg.mPreferredOrder = 100; + pkg.installLocation = 100; + pkg.coreApp = true; + pkg.mRequiredForAllUsers = true; + pkg.mOverlayPriority = 100; + pkg.mTrustedOverlay = true; + pkg.use32bitAbi = true; + pkg.packageName = "foo"; + pkg.splitNames = new String[] { "foo" }; + pkg.volumeUuid = "foo"; + pkg.codePath = "foo"; + pkg.baseCodePath = "foo"; + pkg.splitCodePaths = new String[] { "foo" }; + pkg.splitRevisionCodes = new int[] { 100 }; + pkg.splitFlags = new int[] { 100 }; + pkg.splitPrivateFlags = new int[] { 100 }; + pkg.applicationInfo = new ApplicationInfo(); + + pkg.permissions.add(new PackageParser.Permission(pkg)); + pkg.permissionGroups.add(new PackageParser.PermissionGroup(pkg)); + + final PackageParser.ParseComponentArgs dummy = new PackageParser.ParseComponentArgs( + pkg, new String[1], 0, 0, 0, 0, 0, 0, null, 0, 0, 0); + + pkg.activities.add(new PackageParser.Activity(dummy, new ActivityInfo())); + pkg.receivers.add(new PackageParser.Activity(dummy, new ActivityInfo())); + pkg.providers.add(new PackageParser.Provider(dummy, new ProviderInfo())); + pkg.services.add(new PackageParser.Service(dummy, new ServiceInfo())); + pkg.instrumentation.add(new PackageParser.Instrumentation(dummy, new InstrumentationInfo())); + pkg.requestedPermissions.add("foo"); + + pkg.protectedBroadcasts = new ArrayList<>(); + pkg.protectedBroadcasts.add("foo"); + + pkg.parentPackage = new PackageParser.Package("foo"); + + pkg.childPackages = new ArrayList<>(); + pkg.childPackages.add(new PackageParser.Package("bar")); + + pkg.libraryNames = new ArrayList<>(); + pkg.libraryNames.add("foo"); + + pkg.usesLibraries = new ArrayList<>(); + pkg.usesLibraries.add("foo"); + + pkg.usesOptionalLibraries = new ArrayList<>(); + pkg.usesOptionalLibraries.add("foo"); + + pkg.usesLibraryFiles = new String[] { "foo "}; + + pkg.mOriginalPackages = new ArrayList<>(); + pkg.mOriginalPackages.add("foo"); + + pkg.mRealPackage = "foo"; + + pkg.mAdoptPermissions = new ArrayList<>(); + pkg.mAdoptPermissions.add("foo"); + + pkg.mAppMetaData = new Bundle(); + pkg.mVersionName = "foo"; + pkg.mSharedUserId = "foo"; + pkg.mSignatures = new Signature[] { new Signature(new byte[16]) }; + pkg.mCertificates = new Certificate[][] { new Certificate[] { null }}; + pkg.mExtras = new Bundle(); + pkg.mRestrictedAccountType = "foo"; + pkg.mRequiredAccountType = "foo"; + pkg.mOverlayTarget = "foo"; + pkg.mSigningKeys = new ArraySet<>(); + pkg.mUpgradeKeySets = new ArraySet<>(); + pkg.mKeySetMapping = new ArrayMap<>(); + pkg.cpuAbiOverride = "foo"; + pkg.restrictUpdateHash = new byte[16]; + + pkg.preferredActivityFilters = new ArrayList<>(); + pkg.preferredActivityFilters.add(new PackageParser.ActivityIntentInfo( + new PackageParser.Activity(dummy, new ActivityInfo()))); + + pkg.configPreferences = new ArrayList<>(); + pkg.configPreferences.add(new ConfigurationInfo()); + + pkg.reqFeatures = new ArrayList<>(); + pkg.reqFeatures.add(new FeatureInfo()); + + pkg.featureGroups = new ArrayList<>(); + pkg.featureGroups.add(new FeatureGroupInfo()); + } + + private static void assertAllFieldsExist(PackageParser.Package pkg) throws Exception { + Field[] fields = PackageParser.Package.class.getDeclaredFields(); + + Set<String> nonSerializedFields = new HashSet<>(); + nonSerializedFields.add("mExtras"); + nonSerializedFields.add("packageUsageTimeMillis"); + + for (Field f : fields) { + final Class<?> fieldType = f.getType(); + + if (nonSerializedFields.contains(f.getName())) { + continue; + } + + if (List.class.isAssignableFrom(fieldType)) { + // Sanity check for list fields: Assume they're non-null and contain precisely + // one element. + List<?> list = (List<?>) f.get(pkg); + assertNotNull(list); + assertEquals(1, list.size()); + } else if (fieldType.getComponentType() != null) { + // Sanity check for array fields: Assume they're non-null and contain precisely + // one element. + Object array = f.get(pkg); + assertNotNull(Array.get(array, 0)); + } else if (fieldType == String.class) { + // String fields: Check that they're set to "foo". + String value = (String) f.get(pkg); + assertEquals("foo", value); + } else if (fieldType == int.class) { + // int fields: Check that they're set to 100. + int value = (int) f.get(pkg); + assertEquals(100, value); + } else { + // All other fields: Check that they're set. + Object o = f.get(pkg); + assertNotNull("Field was null: " + f.getName(), o); + } + } + } } + |