summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt4
-rw-r--r--api/system-current.txt4
-rw-r--r--api/test-current.txt4
-rw-r--r--core/java/android/bluetooth/BluetoothCodecConfig.java7
-rw-r--r--core/java/android/content/IntentFilter.java3
-rw-r--r--core/java/android/content/pm/PackageParser.java637
-rw-r--r--core/java/android/content/res/TypedArray.java2
-rw-r--r--core/java/android/os/HwBinder.java7
-rw-r--r--core/java/android/os/IHwBinder.java1
-rw-r--r--core/java/android/os/UserManager.java6
-rw-r--r--core/java/android/provider/DocumentsContract.java3
-rw-r--r--core/java/android/provider/DocumentsProvider.java4
-rw-r--r--core/java/android/view/MenuInflater.java10
-rw-r--r--core/java/android/view/MenuItem.java36
-rw-r--r--core/java/android/view/WindowManagerGlobal.java13
-rw-r--r--core/java/android/webkit/WebViewZygote.java117
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java4
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java5
-rw-r--r--core/java/com/android/internal/app/ResolverListController.java6
-rw-r--r--core/java/com/android/internal/os/WebViewZygoteInit.java5
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java6
-rw-r--r--core/java/com/android/internal/view/TooltipPopup.java22
-rw-r--r--core/java/com/android/internal/view/menu/ActionMenuItem.java39
-rw-r--r--core/java/com/android/internal/view/menu/ActionMenuItemView.java21
-rw-r--r--core/java/com/android/internal/view/menu/IconMenuItemView.java17
-rw-r--r--core/java/com/android/internal/view/menu/ListMenuItemView.java4
-rw-r--r--core/java/com/android/internal/view/menu/MenuItemImpl.java39
-rw-r--r--core/java/com/android/internal/widget/FloatingToolbar.java36
-rw-r--r--core/jni/Android.mk1
-rw-r--r--core/jni/android/graphics/BitmapFactory.cpp52
-rw-r--r--core/jni/android_os_HwBinder.cpp34
-rw-r--r--core/res/res/values-mk-rMK/strings.xml4
-rw-r--r--core/res/res/values-pt-rBR/strings.xml2
-rw-r--r--core/res/res/values-pt/strings.xml2
-rw-r--r--core/res/res/values/attrs.xml6
-rw-r--r--core/res/res/values/styles.xml1
-rw-r--r--core/res/res/values/styles_holo.xml2
-rw-r--r--core/res/res/values/styles_material.xml1
-rwxr-xr-xdocs/html/google/play/billing/billing_integrate.jd2
-rw-r--r--packages/SettingsLib/res/layout/drawer_category.xml4
-rw-r--r--packages/SettingsLib/res/layout/drawer_item.xml17
-rw-r--r--packages/SettingsLib/res/layout/drawer_spacer.xml2
-rw-r--r--packages/SettingsLib/res/layout/settings_with_drawer.xml2
-rw-r--r--packages/SettingsLib/res/values-hy-rAM/strings.xml2
-rwxr-xr-xpackages/SettingsLib/res/values/config.xml3
-rw-r--r--packages/SettingsLib/res/values/dimens.xml7
-rw-r--r--packages/SettingsLib/res/values/styles.xml24
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/Utils.java17
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java26
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java58
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java35
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java12
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java33
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java8
-rw-r--r--packages/SystemUI/res/color/data_usage_graph_track.xml18
-rw-r--r--packages/SystemUI/res/color/data_usage_graph_warning.xml18
-rw-r--r--packages/SystemUI/res/drawable-nodpi/tuner.xml3
-rw-r--r--packages/SystemUI/res/layout-sw410dp/status_bar_alarm_group.xml1
-rw-r--r--packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml9
-rw-r--r--packages/SystemUI/res/layout/status_bar_alarm_group.xml1
-rw-r--r--packages/SystemUI/res/values/colors.xml4
-rw-r--r--packages/SystemUI/res/values/styles.xml6
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/PowerUI.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/DataUsageGraph.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java14
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java8
-rw-r--r--services/core/java/com/android/server/audio/PlaybackActivityMonitor.java48
-rw-r--r--services/core/java/com/android/server/pm/UserRestrictionsUtils.java3
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp79
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java424
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&lt;String&gt; skuList = new ArrayList&lt;String&gt; ();
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);
+ }
+ }
+ }
}
+