summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt11
-rw-r--r--api/system-current.txt14
-rw-r--r--api/test-current.txt11
-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.java644
-rw-r--r--core/java/android/os/BatteryStats.java25
-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/FocusFinder.java74
-rw-r--r--core/java/android/view/View.java65
-rw-r--r--core/java/android/view/ViewGroup.java29
-rw-r--r--core/java/android/view/ViewParent.java5
-rw-r--r--core/java/android/view/ViewRootImpl.java41
-rw-r--r--core/java/android/webkit/WebViewZygote.java117
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java43
-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/jni/Android.mk1
-rw-r--r--core/jni/android/graphics/BitmapFactory.cpp52
-rw-r--r--core/jni/android_os_HwBinder.cpp12
-rw-r--r--core/res/AndroidManifest.xml11
-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/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java66
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java1
-rw-r--r--core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java28
-rw-r--r--media/java/android/media/IAudioService.aidl2
-rw-r--r--packages/SettingsLib/res/values-hy-rAM/strings.xml2
-rwxr-xr-xpackages/SettingsLib/res/values/config.xml3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/Utils.java17
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java29
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java12
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java8
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java52
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java17
-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/drawable/ic_device_thermostat_24.xml25
-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/config.xml2
-rw-r--r--packages/SystemUI/res/values/ids.xml2
-rw-r--r--packages/SystemUI/res/values/strings.xml8
-rw-r--r--packages/SystemUI/res/values/styles.xml6
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java76
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/PowerUI.java64
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/DataUsageGraph.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java50
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java14
-rw-r--r--services/Android.mk5
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java5
-rw-r--r--services/core/java/com/android/server/HardwarePropertiesManagerService.java15
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java8
-rw-r--r--services/core/java/com/android/server/pm/UserRestrictionsUtils.java3
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java55
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java2
-rw-r--r--services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp26
-rw-r--r--services/core/jni/com_android_server_hdmi_HdmiCecController.cpp26
-rw-r--r--services/core/jni/com_android_server_lights_LightsService.cpp3
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp133
-rw-r--r--services/coverage/Android.mk12
-rw-r--r--services/coverage/java/com/android/server/coverage/CoverageService.java145
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java38
-rw-r--r--services/java/com/android/server/SystemServer.java7
-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
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java44
75 files changed, 2352 insertions, 391 deletions
diff --git a/api/current.txt b/api/current.txt
index a84bfb5f7893..b017f9d2f5b9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -41819,7 +41819,7 @@ package android.view {
method public android.view.View findNearestTouchable(android.view.ViewGroup, int, int, int, int[]);
method public final android.view.View findNextFocus(android.view.ViewGroup, android.view.View, int);
method public android.view.View findNextFocusFromRect(android.view.ViewGroup, android.graphics.Rect, int);
- method public android.view.View findNextKeyboardNavigationCluster(android.view.ViewGroup, android.view.View, int);
+ method public android.view.View findNextKeyboardNavigationCluster(int, android.view.View, android.view.View, int);
method public static android.view.FocusFinder getInstance();
}
@@ -43112,7 +43112,7 @@ package android.view {
method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
method public void addFocusables(java.util.ArrayList<android.view.View>, int);
method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
- method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
+ method public void addKeyboardNavigationClusters(int, java.util.Collection<android.view.View>, int);
method public void addOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
method public void addOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
method public void addTouchables(java.util.ArrayList<android.view.View>);
@@ -43400,7 +43400,7 @@ package android.view {
method public boolean isVerticalFadingEdgeEnabled();
method public boolean isVerticalScrollBarEnabled();
method public void jumpDrawablesToCurrentState();
- method public android.view.View keyboardNavigationClusterSearch(int);
+ method public android.view.View keyboardNavigationClusterSearch(int, android.view.View, int);
method public void layout(int, int, int, int);
method public final void measure(int, int);
method protected static int[] mergeDrawableStates(int[], int[]);
@@ -43682,6 +43682,8 @@ package android.view {
field public static final int FOCUS_BACKWARD = 1; // 0x1
field public static final int FOCUS_DOWN = 130; // 0x82
field public static final int FOCUS_FORWARD = 2; // 0x2
+ field public static final int FOCUS_GROUP_CLUSTER = 1; // 0x1
+ field public static final int FOCUS_GROUP_SECTION = 2; // 0x2
field public static final int FOCUS_LEFT = 17; // 0x11
field public static final int FOCUS_RIGHT = 66; // 0x42
field public static final int FOCUS_UP = 33; // 0x21
@@ -44049,7 +44051,6 @@ package android.view {
method protected deprecated boolean isChildrenDrawnWithCacheEnabled();
method public boolean isMotionEventSplittingEnabled();
method public boolean isTransitionGroup();
- method public android.view.View keyboardNavigationClusterSearch(android.view.View, int);
method public final void layout(int, int, int, int);
method protected void measureChild(android.view.View, int, int);
method protected void measureChildWithMargins(android.view.View, int, int, int, int);
@@ -44212,7 +44213,7 @@ package android.view {
method public abstract boolean isLayoutRequested();
method public abstract boolean isTextAlignmentResolved();
method public abstract boolean isTextDirectionResolved();
- method public abstract android.view.View keyboardNavigationClusterSearch(android.view.View, int);
+ method public abstract android.view.View keyboardNavigationClusterSearch(int, android.view.View, int);
method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
method public abstract boolean onNestedPreFling(android.view.View, float, float);
diff --git a/api/system-current.txt b/api/system-current.txt
index aeb17fbfe530..a5534deebd93 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -66,7 +66,7 @@ package android {
field public static final java.lang.String BLUETOOTH_PRIVILEGED = "android.permission.BLUETOOTH_PRIVILEGED";
field public static final java.lang.String BODY_SENSORS = "android.permission.BODY_SENSORS";
field public static final java.lang.String BRICK = "android.permission.BRICK";
- field public static final java.lang.String BROADCAST_NETWORK_PRIVILEGED = "android.permission.BROADCAST_NETWORK_PRIVILEGED";
+ field public static final deprecated java.lang.String BROADCAST_NETWORK_PRIVILEGED = "android.permission.BROADCAST_NETWORK_PRIVILEGED";
field public static final java.lang.String BROADCAST_PACKAGE_REMOVED = "android.permission.BROADCAST_PACKAGE_REMOVED";
field public static final java.lang.String BROADCAST_SMS = "android.permission.BROADCAST_SMS";
field public static final java.lang.String BROADCAST_STICKY = "android.permission.BROADCAST_STICKY";
@@ -201,6 +201,7 @@ package android {
field public static final java.lang.String REORDER_TASKS = "android.permission.REORDER_TASKS";
field public static final java.lang.String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
+ field public static final java.lang.String REQUEST_NETWORK_SCORES = "android.permission.REQUEST_NETWORK_SCORES";
field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
field public static final java.lang.String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT";
field public static final java.lang.String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS";
@@ -45028,7 +45029,7 @@ package android.view {
method public android.view.View findNearestTouchable(android.view.ViewGroup, int, int, int, int[]);
method public final android.view.View findNextFocus(android.view.ViewGroup, android.view.View, int);
method public android.view.View findNextFocusFromRect(android.view.ViewGroup, android.graphics.Rect, int);
- method public android.view.View findNextKeyboardNavigationCluster(android.view.ViewGroup, android.view.View, int);
+ method public android.view.View findNextKeyboardNavigationCluster(int, android.view.View, android.view.View, int);
method public static android.view.FocusFinder getInstance();
}
@@ -46321,7 +46322,7 @@ package android.view {
method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
method public void addFocusables(java.util.ArrayList<android.view.View>, int);
method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
- method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
+ method public void addKeyboardNavigationClusters(int, java.util.Collection<android.view.View>, int);
method public void addOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
method public void addOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
method public void addTouchables(java.util.ArrayList<android.view.View>);
@@ -46609,7 +46610,7 @@ package android.view {
method public boolean isVerticalFadingEdgeEnabled();
method public boolean isVerticalScrollBarEnabled();
method public void jumpDrawablesToCurrentState();
- method public android.view.View keyboardNavigationClusterSearch(int);
+ method public android.view.View keyboardNavigationClusterSearch(int, android.view.View, int);
method public void layout(int, int, int, int);
method public final void measure(int, int);
method protected static int[] mergeDrawableStates(int[], int[]);
@@ -46891,6 +46892,8 @@ package android.view {
field public static final int FOCUS_BACKWARD = 1; // 0x1
field public static final int FOCUS_DOWN = 130; // 0x82
field public static final int FOCUS_FORWARD = 2; // 0x2
+ field public static final int FOCUS_GROUP_CLUSTER = 1; // 0x1
+ field public static final int FOCUS_GROUP_SECTION = 2; // 0x2
field public static final int FOCUS_LEFT = 17; // 0x11
field public static final int FOCUS_RIGHT = 66; // 0x42
field public static final int FOCUS_UP = 33; // 0x21
@@ -47258,7 +47261,6 @@ package android.view {
method protected deprecated boolean isChildrenDrawnWithCacheEnabled();
method public boolean isMotionEventSplittingEnabled();
method public boolean isTransitionGroup();
- method public android.view.View keyboardNavigationClusterSearch(android.view.View, int);
method public final void layout(int, int, int, int);
method protected void measureChild(android.view.View, int, int);
method protected void measureChildWithMargins(android.view.View, int, int, int, int);
@@ -47421,7 +47423,7 @@ package android.view {
method public abstract boolean isLayoutRequested();
method public abstract boolean isTextAlignmentResolved();
method public abstract boolean isTextDirectionResolved();
- method public abstract android.view.View keyboardNavigationClusterSearch(android.view.View, int);
+ method public abstract android.view.View keyboardNavigationClusterSearch(int, android.view.View, int);
method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
method public abstract boolean onNestedPreFling(android.view.View, float, float);
diff --git a/api/test-current.txt b/api/test-current.txt
index ff70fee1d6e8..5db134a28964 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -42106,7 +42106,7 @@ package android.view {
method public android.view.View findNearestTouchable(android.view.ViewGroup, int, int, int, int[]);
method public final android.view.View findNextFocus(android.view.ViewGroup, android.view.View, int);
method public android.view.View findNextFocusFromRect(android.view.ViewGroup, android.graphics.Rect, int);
- method public android.view.View findNextKeyboardNavigationCluster(android.view.ViewGroup, android.view.View, int);
+ method public android.view.View findNextKeyboardNavigationCluster(int, android.view.View, android.view.View, int);
method public static android.view.FocusFinder getInstance();
}
@@ -43401,7 +43401,7 @@ package android.view {
method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
method public void addFocusables(java.util.ArrayList<android.view.View>, int);
method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
- method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
+ method public void addKeyboardNavigationClusters(int, java.util.Collection<android.view.View>, int);
method public void addOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
method public void addOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
method public void addTouchables(java.util.ArrayList<android.view.View>);
@@ -43690,7 +43690,7 @@ package android.view {
method public boolean isVerticalFadingEdgeEnabled();
method public boolean isVerticalScrollBarEnabled();
method public void jumpDrawablesToCurrentState();
- method public android.view.View keyboardNavigationClusterSearch(int);
+ method public android.view.View keyboardNavigationClusterSearch(int, android.view.View, int);
method public void layout(int, int, int, int);
method public final void measure(int, int);
method protected static int[] mergeDrawableStates(int[], int[]);
@@ -43972,6 +43972,8 @@ package android.view {
field public static final int FOCUS_BACKWARD = 1; // 0x1
field public static final int FOCUS_DOWN = 130; // 0x82
field public static final int FOCUS_FORWARD = 2; // 0x2
+ field public static final int FOCUS_GROUP_CLUSTER = 1; // 0x1
+ field public static final int FOCUS_GROUP_SECTION = 2; // 0x2
field public static final int FOCUS_LEFT = 17; // 0x11
field public static final int FOCUS_RIGHT = 66; // 0x42
field public static final int FOCUS_UP = 33; // 0x21
@@ -44343,7 +44345,6 @@ package android.view {
method protected deprecated boolean isChildrenDrawnWithCacheEnabled();
method public boolean isMotionEventSplittingEnabled();
method public boolean isTransitionGroup();
- method public android.view.View keyboardNavigationClusterSearch(android.view.View, int);
method public final void layout(int, int, int, int);
method protected void measureChild(android.view.View, int, int);
method protected void measureChildWithMargins(android.view.View, int, int, int, int);
@@ -44506,7 +44507,7 @@ package android.view {
method public abstract boolean isLayoutRequested();
method public abstract boolean isTextAlignmentResolved();
method public abstract boolean isTextDirectionResolved();
- method public abstract android.view.View keyboardNavigationClusterSearch(android.view.View, int);
+ method public abstract android.view.View keyboardNavigationClusterSearch(int, android.view.View, int);
method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
method public abstract boolean onNestedPreFling(android.view.View, float, float);
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 2236291fd248..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;
}
/**
@@ -1344,6 +1362,11 @@ public class PackageParser {
verified = true;
} catch (ApkSignatureSchemeV2Verifier.SignatureNotFoundException e) {
// No APK Signature Scheme v2 signature found
+ if ((parseFlags & PARSE_IS_EPHEMERAL) != 0) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "No APK Signature Scheme v2 signature in ephemeral package " + apkPath,
+ e);
+ }
} catch (Exception e) {
// APK Signature Scheme v2 signature was found but did not verify
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
@@ -1516,10 +1539,10 @@ 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, 0 /*parseFlags*/);
+ collectCertificates(tempPkg, apkFile, flags);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -3623,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) {
@@ -5113,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;
@@ -5154,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);
@@ -5578,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;
@@ -5655,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);
}
@@ -5669,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;
@@ -5694,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) {
@@ -5719,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,
@@ -5871,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) {
@@ -5894,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,
@@ -5925,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) {
@@ -5948,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,
@@ -5966,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;
@@ -5997,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,
@@ -6020,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) {
@@ -6042,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(
@@ -6055,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;
@@ -6063,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;
@@ -6081,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;
@@ -6099,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;
@@ -6117,6 +6717,10 @@ public class PackageParser {
sb.append('}');
return sb.toString();
}
+
+ public ProviderIntentInfo(Parcel in) {
+ super(in);
+ }
}
/**
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index e5aeb4b2139d..8d73544602ba 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -39,6 +39,7 @@ import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.TimeUtils;
import android.view.Display;
+
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
@@ -181,6 +182,8 @@ public abstract class BatteryStats implements Parcelable {
*
* New in version 19:
* - Wakelock data (wl) gets current and max times.
+ * New in version 20:
+ * - Sensor gets a background counter.
*/
static final String CHECKIN_VERSION = "20";
@@ -600,10 +603,13 @@ public abstract class BatteryStats implements Parcelable {
*/
// Magic sensor number for the GPS.
public static final int GPS = -10000;
-
+
public abstract int getHandle();
-
+
public abstract Timer getSensorTime();
+
+ /** Returns a counter for usage count when in the background. */
+ public abstract Counter getSensorBgCount();
}
public class Pid {
@@ -3318,13 +3324,16 @@ public abstract class BatteryStats implements Parcelable {
final Uid.Sensor se = sensors.valueAt(ise);
final int sensorNumber = sensors.keyAt(ise);
final Timer timer = se.getSensorTime();
+ final Counter bgCounter = se.getSensorBgCount();
if (timer != null) {
// Convert from microseconds to milliseconds with rounding
final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500)
/ 1000;
final int count = timer.getCountLocked(which);
+ final int bgCount = bgCounter != null ? bgCounter.getCountLocked(which) : 0;
if (totalTime != 0) {
- dumpLine(pw, uid, category, SENSOR_DATA, sensorNumber, totalTime, count);
+ dumpLine(pw, uid, category, SENSOR_DATA, sensorNumber, totalTime, count,
+ bgCount);
}
}
}
@@ -4493,17 +4502,25 @@ public abstract class BatteryStats implements Parcelable {
sb.append(": ");
final Timer timer = se.getSensorTime();
+ final Counter bgCounter = se.getSensorBgCount();
if (timer != null) {
// Convert from microseconds to milliseconds with rounding
final long totalTime = (timer.getTotalTimeLocked(
rawRealtime, which) + 500) / 1000;
final int count = timer.getCountLocked(which);
+ final int bgCount = bgCounter != null ? bgCounter.getCountLocked(which) : 0;
//timer.logState();
if (totalTime != 0) {
formatTimeMs(sb, totalTime);
sb.append("realtime (");
sb.append(count);
- sb.append(" times)");
+ sb.append(" times");
+ if (bgCount > 0) {
+ sb.append(", ");
+ sb.append(bgCount);
+ sb.append(" bg");
+ }
+ sb.append(")");
} else {
sb.append("(not used)");
}
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/FocusFinder.java b/core/java/android/view/FocusFinder.java
index 3f3d5190fac7..1a4f0d1ae803 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -16,12 +16,16 @@
package android.view;
+import static android.view.View.FOCUS_GROUP_CLUSTER;
+import static android.view.View.FOCUS_GROUP_SECTION;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Rect;
import android.util.ArrayMap;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.view.View.FocusGroupType;
import java.util.ArrayList;
import java.util.Collections;
@@ -107,21 +111,26 @@ public class FocusFinder {
/**
* Find the root of the next keyboard navigation cluster after the current one.
- * @param root Thew view tree to look inside. Cannot be null
+ * @param focusGroupType Type of the focus group
+ * @param root The view tree to look inside. Cannot be null
* @param currentCluster The starting point of the search. Null means the default cluster
* @param direction Direction to look
* @return The next cluster, or null if none exists
*/
public View findNextKeyboardNavigationCluster(
- @NonNull ViewGroup root, @Nullable View currentCluster, int direction) {
+ @FocusGroupType int focusGroupType,
+ @NonNull View root,
+ @Nullable View currentCluster,
+ int direction) {
View next = null;
final ArrayList<View> clusters = mTempList;
try {
clusters.clear();
- root.addKeyboardNavigationClusters(clusters, direction);
+ root.addKeyboardNavigationClusters(focusGroupType, clusters, direction);
if (!clusters.isEmpty()) {
- next = findNextKeyboardNavigationCluster(root, currentCluster, clusters, direction);
+ next = findNextKeyboardNavigationCluster(
+ focusGroupType, root, currentCluster, clusters, direction);
}
} finally {
clusters.clear();
@@ -197,19 +206,25 @@ public class FocusFinder {
}
}
- private View findNextKeyboardNavigationCluster(ViewGroup root, View currentCluster,
- List<View> clusters, int direction) {
+ private View findNextKeyboardNavigationCluster(
+ @FocusGroupType int focusGroupType,
+ View root,
+ View currentCluster,
+ List<View> clusters,
+ int direction) {
final int count = clusters.size();
switch (direction) {
case View.FOCUS_FORWARD:
case View.FOCUS_DOWN:
case View.FOCUS_RIGHT:
- return getNextKeyboardNavigationCluster(root, currentCluster, clusters, count);
+ return getNextKeyboardNavigationCluster(
+ focusGroupType, root, currentCluster, clusters, count);
case View.FOCUS_BACKWARD:
case View.FOCUS_UP:
case View.FOCUS_LEFT:
- return getPreviousKeyboardNavigationCluster(root, currentCluster, clusters, count);
+ return getPreviousKeyboardNavigationCluster(
+ focusGroupType, root, currentCluster, clusters, count);
default:
throw new IllegalArgumentException("Unknown direction: " + direction);
}
@@ -315,8 +330,12 @@ public class FocusFinder {
return null;
}
- private static View getNextKeyboardNavigationCluster(ViewGroup root, View currentCluster,
- List<View> clusters, int count) {
+ private static View getNextKeyboardNavigationCluster(
+ @FocusGroupType int focusGroupType,
+ View root,
+ View currentCluster,
+ List<View> clusters,
+ int count) {
if (currentCluster == null) {
// The current cluster is the default one.
// The next cluster after the default one is the first one.
@@ -330,12 +349,25 @@ public class FocusFinder {
return clusters.get(position + 1);
}
- // The current cluster is the last one. The next one is the default one, i.e. the root.
- return root;
+ switch (focusGroupType) {
+ case FOCUS_GROUP_CLUSTER:
+ // The current cluster is the last one. The next one is the default one, i.e. the
+ // root.
+ return root;
+ case FOCUS_GROUP_SECTION:
+ // There is no "default section", hence returning the first one.
+ return clusters.get(0);
+ default:
+ throw new IllegalArgumentException("Unknown focus group type: " + focusGroupType);
+ }
}
- private static View getPreviousKeyboardNavigationCluster(ViewGroup root, View currentCluster,
- List<View> clusters, int count) {
+ private static View getPreviousKeyboardNavigationCluster(
+ @FocusGroupType int focusGroupType,
+ View root,
+ View currentCluster,
+ List<View> clusters,
+ int count) {
if (currentCluster == null) {
// The current cluster is the default one.
// The previous cluster before the default one is the last one.
@@ -349,9 +381,17 @@ public class FocusFinder {
return clusters.get(position - 1);
}
- // The current cluster is the first one. The previous one is the default one, i.e. the
- // root.
- return root;
+ switch (focusGroupType) {
+ case FOCUS_GROUP_CLUSTER:
+ // The current cluster is the first one. The previous one is the default one, i.e.
+ // the root.
+ return root;
+ case FOCUS_GROUP_SECTION:
+ // There is no "default section", hence returning the last one.
+ return clusters.get(count - 1);
+ default:
+ throw new IllegalArgumentException("Unknown focus group type: " + focusGroupType);
+ }
}
/**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f51e02932147..aa941b8fcfb4 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1248,6 +1248,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
@Retention(RetentionPolicy.SOURCE)
public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward
+ /** @hide */
+ @IntDef({
+ FOCUS_GROUP_CLUSTER,
+ FOCUS_GROUP_SECTION
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface FocusGroupType {}
+
/**
* Use with {@link #focusSearch(int)}. Move focus to the previous selectable
* item.
@@ -1281,6 +1289,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
public static final int FOCUS_DOWN = 0x00000082;
/**
+ * Use with {@link #keyboardNavigationClusterSearch(int, View, int)}. Search for a keyboard
+ * navigation cluster.
+ */
+ public static final int FOCUS_GROUP_CLUSTER = 1;
+
+ /**
+ * Use with {@link #keyboardNavigationClusterSearch(int, View, int)}. Search for a keyboard
+ * navigation section.
+ */
+ public static final int FOCUS_GROUP_SECTION = 2;
+
+ /**
* Bits of {@link #getMeasuredWidthAndState()} and
* {@link #getMeasuredWidthAndState()} that provide the actual measured size.
*/
@@ -9096,22 +9116,47 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
+ final boolean isFocusGroupOfType(@FocusGroupType int focusGroupType) {
+ switch (focusGroupType) {
+ case FOCUS_GROUP_CLUSTER:
+ return isKeyboardNavigationCluster();
+ case FOCUS_GROUP_SECTION:
+ return isKeyboardNavigationSection();
+ default:
+ throw new IllegalArgumentException("Unknown focus group type: " + focusGroupType);
+ }
+ }
+
/**
* Find the nearest keyboard navigation cluster in the specified direction.
* This does not actually give focus to that cluster.
*
+ * @param focusGroupType Type of the focus group
+ * @param currentCluster The starting point of the search. Null means the current cluster is not
+ * found yet
* @param direction Direction to look
*
* @return The nearest keyboard navigation cluster in the specified direction, or null if none
* can be found
*/
- public View keyboardNavigationClusterSearch(int direction) {
- if (mParent != null) {
- final View currentCluster = isKeyboardNavigationCluster() ? this : null;
- return mParent.keyboardNavigationClusterSearch(currentCluster, direction);
- } else {
- return null;
+ public View keyboardNavigationClusterSearch(
+ @FocusGroupType int focusGroupType, View currentCluster, int direction) {
+ if (isFocusGroupOfType(focusGroupType)) {
+ currentCluster = this;
+ }
+ if (isRootNamespace()
+ || focusGroupType == FOCUS_GROUP_SECTION && isKeyboardNavigationCluster()) {
+ // Root namespace means we should consider ourselves the top of the
+ // tree for cluster searching; otherwise we could be focus searching
+ // into other tabs. see LocalActivityManager and TabHost for more info.
+ // In addition, a cluster node works as a root for section searches.
+ return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
+ focusGroupType, this, currentCluster, direction);
+ } else if (mParent != null) {
+ return mParent.keyboardNavigationClusterSearch(
+ focusGroupType, currentCluster, direction);
}
+ return null;
}
/**
@@ -9240,11 +9285,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* Adds any keyboard navigation cluster roots that are descendants of this view (possibly
* including this view if it is a cluster root itself) to views.
*
+ * @param focusGroupType Type of the focus group
* @param views Cluster roots found so far
* @param direction Direction to look
*/
- public void addKeyboardNavigationClusters(@NonNull Collection<View> views, int direction) {
- if (!isKeyboardNavigationCluster()) {
+ public void addKeyboardNavigationClusters(
+ @FocusGroupType int focusGroupType,
+ @NonNull Collection<View> views,
+ int direction) {
+ if (!(isFocusGroupOfType(focusGroupType))) {
return;
}
views.add(this);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 7c133ac5b7a9..7835899d1419 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -902,23 +902,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
@Override
- public View keyboardNavigationClusterSearch(View currentCluster, int direction) {
- if (isKeyboardNavigationCluster()) {
- currentCluster = this;
- }
- if (isRootNamespace()) {
- // root namespace means we should consider ourselves the top of the
- // tree for cluster searching; otherwise we could be focus searching
- // into other tabs. see LocalActivityManager and TabHost for more info
- return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
- this, currentCluster, direction);
- } else if (mParent != null) {
- return mParent.keyboardNavigationClusterSearch(currentCluster, direction);
- }
- return null;
- }
-
- @Override
public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
return false;
}
@@ -1164,10 +1147,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
@Override
- public void addKeyboardNavigationClusters(Collection<View> views, int direction) {
+ public void addKeyboardNavigationClusters(
+ @FocusGroupType int focusGroupType, Collection<View> views, int direction) {
final int focusableCount = views.size();
- super.addKeyboardNavigationClusters(views, direction);
+ super.addKeyboardNavigationClusters(focusGroupType, views, direction);
if (focusableCount != views.size()) {
// No need to look for clusters inside a cluster.
@@ -1183,8 +1167,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
for (int i = 0; i < count; i++) {
final View child = children[i];
+ if (focusGroupType == FOCUS_GROUP_SECTION && child.isKeyboardNavigationCluster()) {
+ // When the current cluster is the default cluster, and we are searching for
+ // sections, ignore sections inside non-default clusters.
+ continue;
+ }
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
- child.addKeyboardNavigationClusters(views, direction);
+ child.addKeyboardNavigationClusters(focusGroupType, views, direction);
}
}
}
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 79b05cdb6e50..c5414e925e0e 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -18,6 +18,7 @@ package android.view;
import android.graphics.Rect;
import android.os.Bundle;
+import android.view.View.FocusGroupType;
import android.view.accessibility.AccessibilityEvent;
/**
@@ -150,6 +151,7 @@ public interface ViewParent {
* Find the nearest keyboard navigation cluster in the specified direction.
* This does not actually give focus to that cluster.
*
+ * @param focusGroupType Type of the focus group
* @param currentCluster The starting point of the search. Null means the current cluster is not
* found yet
* @param direction Direction to look
@@ -157,7 +159,8 @@ public interface ViewParent {
* @return The nearest keyboard navigation cluster in the specified direction, or null if none
* can be found
*/
- View keyboardNavigationClusterSearch(View currentCluster, int direction);
+ View keyboardNavigationClusterSearch(
+ @FocusGroupType int focusGroupType, View currentCluster, int direction);
/**
* Change the z order of the child so it's on top of all other children.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4f2020311ff4..75ebbb70dfd2 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -16,6 +16,8 @@
package android.view;
+import static android.view.View.FOCUS_GROUP_CLUSTER;
+import static android.view.View.FOCUS_GROUP_SECTION;
import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
@@ -71,6 +73,7 @@ import android.util.TimeUtils;
import android.util.TypedValue;
import android.view.Surface.OutOfResourcesException;
import android.view.View.AttachInfo;
+import android.view.View.FocusGroupType;
import android.view.View.MeasureSpec;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -4392,11 +4395,12 @@ public final class ViewRootImpl implements ViewParent,
return false;
}
- private boolean performClusterNavigation(int direction) {
+ private boolean performClusterNavigation(
+ @FocusGroupType int focusGroupType, int direction) {
final View focused = mView.findFocus();
final View cluster = focused != null
- ? focused.keyboardNavigationClusterSearch(direction)
- : keyboardNavigationClusterSearch(null, direction);
+ ? focused.keyboardNavigationClusterSearch(focusGroupType, null, direction)
+ : keyboardNavigationClusterSearch(focusGroupType, null, direction);
if (cluster != null && cluster.restoreLastFocus()) {
return true;
@@ -4418,15 +4422,32 @@ public final class ViewRootImpl implements ViewParent,
}
int clusterNavigationDirection = 0;
+ @FocusGroupType int focusGroupType = 0;
if (event.getAction() == KeyEvent.ACTION_DOWN && event.isCtrlPressed()) {
final int character =
event.getUnicodeChar(event.getMetaState() & ~KeyEvent.META_CTRL_MASK);
if (character == '+') {
+ focusGroupType = FOCUS_GROUP_CLUSTER;
clusterNavigationDirection = View.FOCUS_FORWARD;
}
if (character == '_') {
+ focusGroupType = FOCUS_GROUP_CLUSTER;
+ clusterNavigationDirection = View.FOCUS_BACKWARD;
+ }
+ }
+
+ if (event.getAction() == KeyEvent.ACTION_DOWN && event.isAltPressed()) {
+ final int character =
+ event.getUnicodeChar(event.getMetaState() & ~KeyEvent.META_ALT_MASK);
+ if (character == '+') {
+ focusGroupType = FOCUS_GROUP_SECTION;
+ clusterNavigationDirection = View.FOCUS_FORWARD;
+ }
+
+ if (character == '_') {
+ focusGroupType = FOCUS_GROUP_SECTION;
clusterNavigationDirection = View.FOCUS_BACKWARD;
}
}
@@ -4456,7 +4477,7 @@ public final class ViewRootImpl implements ViewParent,
// Handle automatic focus changes.
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (clusterNavigationDirection != 0) {
- if (performClusterNavigation(clusterNavigationDirection)) {
+ if (performClusterNavigation(focusGroupType, clusterNavigationDirection)) {
return FINISH_HANDLED;
}
} else {
@@ -4552,8 +4573,8 @@ public final class ViewRootImpl implements ViewParent,
if (mPointerIconType != pointerType) {
mPointerIconType = pointerType;
+ mCustomPointerIcon = null;
if (mPointerIconType != PointerIcon.TYPE_CUSTOM) {
- mCustomPointerIcon = null;
InputManager.getInstance().setPointerIconType(pointerType);
return true;
}
@@ -5887,13 +5908,11 @@ public final class ViewRootImpl implements ViewParent,
* {@inheritDoc}
*/
@Override
- public View keyboardNavigationClusterSearch(View currentCluster, int direction) {
+ public View keyboardNavigationClusterSearch(
+ @FocusGroupType int focusGroupType, View currentCluster, int direction) {
checkThread();
- if (!(mView instanceof ViewGroup)) {
- return null;
- }
- return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
- (ViewGroup) mView, currentCluster, direction);
+ return FocusFinder.getInstance().findNextKeyboardNavigationCluster(focusGroupType,
+ mView, currentCluster, direction);
}
public void debug() {
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/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 6a5bbccb48f0..5d49d12554e3 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -6912,6 +6912,8 @@ public class BatteryStatsImpl extends BatteryStats {
final int mHandle;
StopwatchTimer mTimer;
+ Counter mBgCounter;
+
public Sensor(BatteryStatsImpl bsi, Uid uid, int handle) {
mBsi = bsi;
mUid = uid;
@@ -6931,7 +6933,17 @@ public class BatteryStatsImpl extends BatteryStats {
return new StopwatchTimer(mBsi.mClocks, mUid, 0, pool, timeBase, in);
}
+ private Counter readCounterFromParcel(TimeBase timeBase, Parcel in) {
+ if (in.readInt() == 0) {
+ return null;
+ }
+ return new Counter(timeBase, in);
+ }
+
boolean reset() {
+ if (mBgCounter != null) {
+ mBgCounter.reset(true);
+ }
if (mTimer.reset(true)) {
mTimer = null;
return true;
@@ -6941,10 +6953,12 @@ public class BatteryStatsImpl extends BatteryStats {
void readFromParcelLocked(TimeBase timeBase, Parcel in) {
mTimer = readTimerFromParcel(timeBase, in);
+ mBgCounter = readCounterFromParcel(timeBase, in);
}
void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) {
Timer.writeTimerToParcel(out, mTimer, elapsedRealtimeUs);
+ Counter.writeCounterToParcel(out, mBgCounter);
}
@Override
@@ -6953,6 +6967,11 @@ public class BatteryStatsImpl extends BatteryStats {
}
@Override
+ public Counter getSensorBgCount() {
+ return mBgCounter;
+ }
+
+ @Override
public int getHandle() {
return mHandle;
}
@@ -7795,6 +7814,22 @@ public class BatteryStatsImpl extends BatteryStats {
return t;
}
+ public Counter getSensorBgCounterLocked(int sensor, boolean create) {
+ Sensor se = mSensorStats.get(sensor);
+ if (se == null) {
+ if (!create) {
+ return null;
+ }
+ se = new Sensor(mBsi, this, sensor);
+ mSensorStats.put(sensor, se);
+ }
+ Counter c = se.mBgCounter;
+ if (c != null) return c;
+ c = new Counter(mBsi.mOnBatteryTimeBase);
+ se.mBgCounter = c;
+ return c;
+ }
+
public void noteStartSyncLocked(String name, long elapsedRealtimeMs) {
StopwatchTimer t = mSyncStats.startObject(name);
if (t != null) {
@@ -7871,6 +7906,10 @@ public class BatteryStatsImpl extends BatteryStats {
if (t != null) {
t.startRunningLocked(elapsedRealtimeMs);
}
+ Counter c = getSensorBgCounterLocked(sensor, true);
+ if (c != null && mProcessState >= PROCESS_STATE_BACKGROUND) {
+ c.stepAtomic();
+ }
}
public void noteStopSensor(int sensor, long elapsedRealtimeMs) {
@@ -7886,6 +7925,10 @@ public class BatteryStatsImpl extends BatteryStats {
if (t != null) {
t.startRunningLocked(elapsedRealtimeMs);
}
+ Counter c = getSensorBgCounterLocked(Sensor.GPS, true);
+ if (c != null && mProcessState >= PROCESS_STATE_BACKGROUND) {
+ c.stepAtomic();
+ }
}
public void noteStopGps(long elapsedRealtimeMs) {
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/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..81199fa41e1b 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -325,15 +325,9 @@ static jobject JHwBinder_native_getService(
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);
- });
+ sp<hidl::base::V1_0::IBase> base = manager->get(ifaceName, serviceName);
+ sp<hardware::IBinder> service = hardware::toBinder<
+ hidl::base::V1_0::IBase, hidl::base::V1_0::BpBase>(base);
env->ReleaseStringUTFChars(ifaceNameObj, ifaceName);
ifaceName = NULL;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4c9fb0455196..4b4fd846df08 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1255,6 +1255,12 @@
<permission android:name="android.permission.SCORE_NETWORKS"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows applications to request network
+ recommendations and scores from the NetworkScoreService.
+ <p>Not for use by third-party applications. @hide -->
+ <permission android:name="android.permission.REQUEST_NETWORK_SCORES"
+ android:protectionLevel="signature|privileged" />
+
<!-- ======================================= -->
<!-- Permissions for short range, peripheral networks -->
<!-- ======================================= -->
@@ -2674,7 +2680,10 @@
android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to broadcast privileged networking requests.
- <p>Not for use by third-party applications. @hide -->
+ <p>Not for use by third-party applications.
+ @hide
+ @deprecated Use {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} instead
+ -->
<permission android:name="android.permission.BROADCAST_NETWORK_PRIVILEGED"
android:protectionLevel="signature|privileged" />
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/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
new file mode 100644
index 000000000000..0bdf7caa8903
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+package com.android.internal.os;
+
+import android.app.ActivityManager;
+import android.os.BatteryStats;
+import android.os.Debug;
+import android.support.test.filters.SmallTest;
+import android.util.Log;
+
+import junit.framework.TestCase;
+
+/**
+ * Test BatteryStatsImpl Sensor Timers.
+ */
+public class BatteryStatsSensorTest extends TestCase {
+
+ private static final int UID = 10500;
+ private static final int SENSOR_ID = -10000;
+
+ @SmallTest
+ public void testSensorStartStop() throws Exception {
+ final MockClocks clocks = new MockClocks();
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+ bi.mForceOnBattery = true;
+ clocks.realtime = 100;
+ clocks.uptime = 100;
+ bi.getOnBatteryTimeBase().setRunning(true, 100, 100);
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+ bi.noteStartSensorLocked(UID, SENSOR_ID);
+ clocks.realtime = 200;
+ clocks.uptime = 200;
+ bi.noteStopSensorLocked(UID, SENSOR_ID);
+
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_RECEIVER);
+ bi.noteStartSensorLocked(UID, SENSOR_ID);
+ clocks.realtime = 400;
+ clocks.uptime = 400;
+ bi.noteStopSensorLocked(UID, SENSOR_ID);
+
+ BatteryStats.Timer sensorTimer = bi.getUidStats().get(UID).getSensorStats()
+ .get(SENSOR_ID).getSensorTime();
+ BatteryStats.Counter sensorBgCounter = bi.getUidStats().get(UID).getSensorStats()
+ .get(SENSOR_ID).getSensorBgCount();
+
+ assertEquals(2, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+ assertEquals(300000,
+ sensorTimer.getTotalTimeLocked(clocks.realtime, BatteryStats.STATS_SINCE_CHARGED));
+
+ assertEquals(1, sensorBgCounter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index 9518219f8c6f..c7cd0ee710e1 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -11,6 +11,7 @@ import org.junit.runners.Suite;
BatteryStatsTimeBaseTest.class,
BatteryStatsTimerTest.class,
BatteryStatsUidTest.class,
+ BatteryStatsSensorTest.class,
})
public class BatteryStatsTests {
}
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index 392448976229..10541060398a 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -16,36 +16,28 @@
package com.android.internal.os;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-
-import android.os.BatteryStats;
-import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-
-import junit.framework.Assert;
-import junit.framework.TestCase;
-
-import com.android.internal.os.BatteryStatsImpl;
-
-import org.mockito.Mockito;
-
/**
* Mocks a BatteryStatsImpl object.
*/
public class MockBatteryStatsImpl extends BatteryStatsImpl {
public BatteryStatsImpl.Clocks clocks;
+ public boolean mForceOnBattery;
- MockBatteryStatsImpl() {
- super(new MockClocks());
+ MockBatteryStatsImpl(Clocks clocks) {
+ super(clocks);
this.clocks = mClocks;
}
+ MockBatteryStatsImpl() {
+ this(new MockClocks());
+ }
+
public TimeBase getOnBatteryTimeBase() {
return mOnBatteryTimeBase;
}
+ public boolean isOnBattery() {
+ return mForceOnBattery ? true : super.isOnBattery();
+ }
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 393ef0dfe44b..432e77ccd720 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -46,7 +46,7 @@ interface IAudioService {
// frameworks/native/include/audiomanager/IAudioManager.h must be updated to match the order
// in this file.
//
- // When a method's argument list is changed, BnAudioManager's corresponding serialization code
+ // When a method's argument list is changed, BpAudioManager's corresponding serialization code
// (if any) in frameworks/native/services/audiomanager/IAudioManager.cpp must be updated.
oneway void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
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/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/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index 86514dc5a5cf..5041e0dccc26 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();
@@ -277,10 +286,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() {
@@ -429,6 +441,11 @@ public class SettingsDrawerActivity extends Activity {
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/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/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/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
index 62d3ce43474f..eab47223bee1 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -14,18 +14,27 @@
package com.android.systemui.plugins;
+import android.app.Notification;
+import android.app.Notification.Action;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.UserHandle;
import android.util.Log;
import android.view.LayoutInflater;
@@ -260,10 +269,9 @@ public class PluginInstanceManager<T extends Plugin> {
String pkg = component.getPackageName();
String cls = component.getClassName();
try {
- PackageManager pm = mPm;
- ApplicationInfo info = pm.getApplicationInfo(pkg, 0);
+ ApplicationInfo info = mPm.getApplicationInfo(pkg, 0);
// TODO: This probably isn't needed given that we don't have IGNORE_SECURITY on
- if (pm.checkPermission(PLUGIN_PERMISSION, pkg)
+ if (mPm.checkPermission(PLUGIN_PERMISSION, pkg)
!= PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "Plugin doesn't have permission: " + pkg);
return null;
@@ -275,6 +283,44 @@ public class PluginInstanceManager<T extends Plugin> {
Class<?> pluginClass = Class.forName(cls, true, classLoader);
T plugin = (T) pluginClass.newInstance();
if (plugin.getVersion() != mVersion) {
+ final int id = mContext.getResources().getIdentifier("notification_plugin",
+ "id", mContext.getPackageName());
+ final int icon = mContext.getResources().getIdentifier("tuner", "drawable",
+ mContext.getPackageName());
+ final int color = Resources.getSystem().getIdentifier(
+ "system_notification_accent_color", "color", "android");
+ final Notification.Builder nb = new Notification.Builder(mContext)
+ .setStyle(new Notification.BigTextStyle())
+ .setSmallIcon(icon)
+ .setWhen(0)
+ .setShowWhen(false)
+ .setPriority(Notification.PRIORITY_MAX)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setColor(mContext.getColor(color));
+ String label = cls;
+ try {
+ label = mPm.getServiceInfo(component, 0).loadLabel(mPm).toString();
+ } catch (NameNotFoundException e) {
+ }
+ if (plugin.getVersion() < mVersion) {
+ // Localization not required as this will never ever appear in a user build.
+ nb.setContentTitle("Plugin \"" + label + "\" is too old")
+ .setContentText("Contact plugin developer to get an updated"
+ + " version.\nPlugin version: " + plugin.getVersion()
+ + "\nSystem version: " + mVersion);
+ } else {
+ // Localization not required as this will never ever appear in a user build.
+ nb.setContentTitle("Plugin \"" + label + "\" is too new")
+ .setContentText("Check to see if an OTA is available.\n"
+ + "Plugin version: " + plugin.getVersion()
+ + "\nSystem version: " + mVersion);
+ }
+ Intent i = new Intent(PluginManager.DISABLE_PLUGIN).setData(
+ Uri.parse("package://" + component.flattenToString()));
+ PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i, 0);
+ nb.addAction(new Action.Builder(null, "Disable plugin", pi).build());
+ mContext.getSystemService(NotificationManager.class)
+ .notifyAsUser(cls, id, nb.build(), UserHandle.ALL);
// TODO: Warn user.
Log.w(TAG, "Plugin has invalid interface version " + plugin.getVersion()
+ ", expected " + mVersion);
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
index 60cf3122966a..c3de09250da4 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
@@ -14,11 +14,14 @@
package com.android.systemui.plugins;
+import android.app.NotificationManager;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Build;
@@ -42,6 +45,8 @@ public class PluginManager extends BroadcastReceiver {
public static final String PLUGIN_CHANGED = "com.android.systemui.action.PLUGIN_CHANGED";
+ static final String DISABLE_PLUGIN = "com.android.systemui.action.DISABLE_PLUGIN";
+
private static PluginManager sInstance;
private final HandlerThread mBackgroundThread;
@@ -112,6 +117,7 @@ public class PluginManager extends BroadcastReceiver {
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(PLUGIN_CHANGED);
+ filter.addAction(DISABLE_PLUGIN);
filter.addDataScheme("package");
mContext.registerReceiver(this, filter);
filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
@@ -128,6 +134,17 @@ public class PluginManager extends BroadcastReceiver {
for (PluginInstanceManager manager : mPluginMap.values()) {
manager.loadAll();
}
+ } else if (DISABLE_PLUGIN.equals(intent.getAction())) {
+ Uri uri = intent.getData();
+ ComponentName component = ComponentName.unflattenFromString(
+ uri.toString().substring(10));
+ mContext.getPackageManager().setComponentEnabledSetting(component,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP);
+ int id = mContext.getResources().getIdentifier("notification_plugin", "id",
+ mContext.getPackageName());
+ mContext.getSystemService(NotificationManager.class).cancel(component.getClassName(),
+ id);
} else {
Uri data = intent.getData();
String pkg = data.getEncodedSchemeSpecificPart();
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/drawable/ic_device_thermostat_24.xml b/packages/SystemUI/res/drawable/ic_device_thermostat_24.xml
new file mode 100644
index 000000000000..1972f6e4427c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_device_thermostat_24.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M15,13L15,5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v8c-1.21,0.91 -2,2.37 -2,4 0,2.76 2.24,5 5,5s5,-2.24 5,-5c0,-1.63 -0.79,-3.09 -2,-4zM11,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1h-1v1h1v2h-1v1h1v2h-2L11,5z"/>
+</vector>
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/config.xml b/packages/SystemUI/res/values/config.xml
index 0f5d37ea3691..c025f932adf8 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -290,4 +290,6 @@
<bool name="quick_settings_show_full_alarm">false</bool>
+ <bool name="config_showTemperatureWarning">false</bool>
+
</resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 2a895f98eefd..56cd8c7c97a3 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -53,6 +53,8 @@
<item type="id" name="notification_screenshot"/>
<item type="id" name="notification_hidden"/>
<item type="id" name="notification_volumeui"/>
+ <item type="id" name="notification_temperature"/>
+ <item type="id" name="notification_plugin"/>
<item type="id" name="transformation_start_x_tag"/>
<item type="id" name="transformation_start_y_tag"/>
<item type="id" name="transformation_start_scale_x_tag"/>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 194653ba15ce..d7033b26f563 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1766,4 +1766,12 @@
<!-- Tuner string -->
<string name="default_theme" translatable="false">Default</string>
+ <!-- Title for notification (and dialog) that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=30] -->
+ <string name="high_temp_title">Phone is getting warm</string>
+ <!-- Message body for notification that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=70] -->
+ <string name="high_temp_notif_message">Some features limited while phone cools down</string>
+ <!-- Text body for dialog alerting user that their phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=300] -->
+ <string name="high_temp_dialog_message">Your phone will automatically try to cool down. You can still use your phone, but it may run slower.\n\nOnce your phone has cooled down, it will run normally.</string>
+
+
</resources>
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/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 8a500c3219f0..848fe9d5a9df 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -50,7 +50,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
private static final String TAG = PowerUI.TAG + ".Notification";
private static final boolean DEBUG = PowerUI.DEBUG;
- private static final String TAG_NOTIFICATION = "low_battery";
+ private static final String TAG_NOTIFICATION_BATTERY = "low_battery";
+ private static final String TAG_NOTIFICATION_TEMPERATURE = "high_temp";
private static final int SHOWING_NOTHING = 0;
private static final int SHOWING_WARNING = 1;
@@ -65,6 +66,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
private static final String ACTION_SHOW_BATTERY_SETTINGS = "PNW.batterySettings";
private static final String ACTION_START_SAVER = "PNW.startSaver";
private static final String ACTION_DISMISSED_WARNING = "PNW.dismissedWarning";
+ private static final String ACTION_CLICKED_TEMP_WARNING = "PNW.clickedTempWarning";
+ private static final String ACTION_DISMISSED_TEMP_WARNING = "PNW.dismissedTempWarning";
private static final AudioAttributes AUDIO_ATTRIBUTES = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
@@ -89,6 +92,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
private boolean mPlaySound;
private boolean mInvalidCharger;
private SystemUIDialog mSaverConfirmation;
+ private boolean mTempWarning;
+ private SystemUIDialog mHighTempDialog;
public PowerNotificationWarnings(Context context, NotificationManager notificationManager,
PhoneStatusBar phoneStatusBar) {
@@ -105,6 +110,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
pw.print("mInvalidCharger="); pw.println(mInvalidCharger);
pw.print("mShowing="); pw.println(SHOWING_STRINGS[mShowing]);
pw.print("mSaverConfirmation="); pw.println(mSaverConfirmation != null ? "not null" : null);
+ pw.print("mTempWarning="); pw.println(mTempWarning);
+ pw.print("mHighTempDialog="); pw.println(mHighTempDialog != null ? "not null" : null);
}
@Override
@@ -129,7 +136,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
showWarningNotification();
mShowing = SHOWING_WARNING;
} else {
- mNoMan.cancelAsUser(TAG_NOTIFICATION, R.id.notification_power, UserHandle.ALL);
+ mNoMan.cancelAsUser(TAG_NOTIFICATION_BATTERY, R.id.notification_power, UserHandle.ALL);
mShowing = SHOWING_NOTHING;
}
}
@@ -148,7 +155,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
com.android.internal.R.color.system_notification_accent_color));
SystemUI.overrideNotificationAppName(mContext, nb);
final Notification n = nb.build();
- mNoMan.notifyAsUser(TAG_NOTIFICATION, R.id.notification_power, n, UserHandle.ALL);
+ mNoMan.notifyAsUser(TAG_NOTIFICATION_BATTERY, R.id.notification_power, n, UserHandle.ALL);
}
private void showWarningNotification() {
@@ -178,12 +185,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
mPlaySound = false;
}
SystemUI.overrideNotificationAppName(mContext, nb);
- mNoMan.notifyAsUser(TAG_NOTIFICATION, R.id.notification_power, nb.build(), UserHandle.ALL);
- }
-
- private PendingIntent pendingActivity(Intent intent) {
- return PendingIntent.getActivityAsUser(mContext,
- 0, intent, 0, null, UserHandle.CURRENT);
+ mNoMan.notifyAsUser(
+ TAG_NOTIFICATION_BATTERY, R.id.notification_power, nb.build(), UserHandle.ALL);
}
private PendingIntent pendingBroadcast(String action) {
@@ -205,6 +208,54 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
}
@Override
+ public void dismissTemperatureWarning() {
+ if (!mTempWarning) {
+ return;
+ }
+ mTempWarning = false;
+ mNoMan.cancelAsUser(
+ TAG_NOTIFICATION_TEMPERATURE, R.id.notification_temperature, UserHandle.ALL);
+ }
+
+ @Override
+ public void showTemperatureWarning() {
+ if (mTempWarning) {
+ return;
+ }
+ mTempWarning = true;
+ final Notification.Builder nb = new Notification.Builder(mContext)
+ .setSmallIcon(R.drawable.ic_device_thermostat_24)
+ .setWhen(0)
+ .setShowWhen(false)
+ .setContentTitle(mContext.getString(R.string.high_temp_title))
+ .setContentText(mContext.getString(R.string.high_temp_notif_message))
+ .setPriority(Notification.PRIORITY_HIGH)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setContentIntent(pendingBroadcast(ACTION_CLICKED_TEMP_WARNING))
+ .setDeleteIntent(pendingBroadcast(ACTION_DISMISSED_TEMP_WARNING))
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.battery_saver_mode_color));
+ SystemUI.overrideNotificationAppName(mContext, nb);
+ final Notification n = nb.build();
+ mNoMan.notifyAsUser(
+ TAG_NOTIFICATION_TEMPERATURE, R.id.notification_temperature, n, UserHandle.ALL);
+
+ }
+
+ private void showTemperatureDialog() {
+ if (mHighTempDialog != null) return;
+ final SystemUIDialog d = new SystemUIDialog(mContext);
+ d.setIconAttribute(android.R.attr.alertDialogIcon);
+ d.setTitle(R.string.high_temp_title);
+ d.setMessage(R.string.high_temp_dialog_message);
+ d.setPositiveButton(com.android.internal.R.string.ok, null);
+ d.setShowForAllUsers(true);
+ d.setOnDismissListener(dialog -> mHighTempDialog = null);
+ d.show();
+ mHighTempDialog = d;
+ }
+
+ @Override
public void updateLowBatteryWarning() {
updateNotification();
}
@@ -317,6 +368,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
filter.addAction(ACTION_SHOW_BATTERY_SETTINGS);
filter.addAction(ACTION_START_SAVER);
filter.addAction(ACTION_DISMISSED_WARNING);
+ filter.addAction(ACTION_CLICKED_TEMP_WARNING);
+ filter.addAction(ACTION_DISMISSED_TEMP_WARNING);
mContext.registerReceiverAsUser(this, UserHandle.ALL, filter,
android.Manifest.permission.STATUS_BAR_SERVICE, mHandler);
}
@@ -333,6 +386,11 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
showStartSaverConfirmation();
} else if (action.equals(ACTION_DISMISSED_WARNING)) {
dismissLowBatteryWarning();
+ } else if (ACTION_CLICKED_TEMP_WARNING.equals(action)) {
+ dismissTemperatureWarning();
+ showTemperatureDialog();
+ } else if (ACTION_DISMISSED_TEMP_WARNING.equals(action)) {
+ dismissTemperatureWarning();
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index b651f2d99523..d4bb994010a3 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -25,12 +25,15 @@ import android.content.IntentFilter;
import android.database.ContentObserver;
import android.os.BatteryManager;
import android.os.Handler;
+import android.os.HardwarePropertiesManager;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
+import android.text.format.DateUtils;
import android.util.Log;
import android.util.Slog;
+import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import java.io.FileDescriptor;
@@ -40,11 +43,13 @@ import java.util.Arrays;
public class PowerUI extends SystemUI {
static final String TAG = "PowerUI";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final long TEMPERATURE_INTERVAL = 30 * DateUtils.SECOND_IN_MILLIS;
private final Handler mHandler = new Handler();
private final Receiver mReceiver = new Receiver();
private PowerManager mPowerManager;
+ private HardwarePropertiesManager mHardwarePropertiesManager;
private WarningsUI mWarnings;
private int mBatteryLevel = 100;
private int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
@@ -56,8 +61,12 @@ public class PowerUI extends SystemUI {
private long mScreenOffTime = -1;
+ private float mThrottlingTemp;
+
public void start() {
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ mHardwarePropertiesManager = (HardwarePropertiesManager)
+ mContext.getSystemService(Context.HARDWARE_PROPERTIES_SERVICE);
mScreenOffTime = mPowerManager.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
mWarnings = new PowerNotificationWarnings(
mContext,
@@ -76,6 +85,8 @@ public class PowerUI extends SystemUI {
false, obs, UserHandle.USER_ALL);
updateBatteryWarningLevels();
mReceiver.init();
+
+ initTemperatureWarning();
}
void updateBatteryWarningLevels() {
@@ -136,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);
}
@@ -211,6 +220,53 @@ public class PowerUI extends SystemUI {
}
};
+ private void initTemperatureWarning() {
+ if (!mContext.getResources().getBoolean(R.bool.config_showTemperatureWarning)) {
+ return;
+ }
+
+ // Get the throttling temperature. No need to check if we're not throttling.
+ float[] throttlingTemps = mHardwarePropertiesManager.getDeviceTemperatures(
+ HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
+ HardwarePropertiesManager.TEMPERATURE_THROTTLING);
+ if (throttlingTemps == null
+ || throttlingTemps.length == 0
+ || throttlingTemps[0] == HardwarePropertiesManager.UNDEFINED_TEMPERATURE) {
+ return;
+ }
+ mThrottlingTemp = throttlingTemps[0];
+
+ // We have passed all of the checks, start checking the temp
+ updateTemperatureWarning();
+ }
+
+ private void updateTemperatureWarning() {
+ PhoneStatusBar phoneStatusBar = getComponent(PhoneStatusBar.class);
+ if (phoneStatusBar != null && phoneStatusBar.isDeviceInVrMode()) {
+ // ensure the warning isn't showing, since VR shows its own warning
+ mWarnings.dismissTemperatureWarning();
+ } else {
+ float[] temps = mHardwarePropertiesManager.getDeviceTemperatures(
+ HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
+ HardwarePropertiesManager.TEMPERATURE_CURRENT);
+ boolean shouldShowTempWarning = false;
+ for (float temp : temps) {
+ if (temp >= mThrottlingTemp) {
+ shouldShowTempWarning = true;
+ break;
+ }
+ }
+ if (shouldShowTempWarning) {
+ mWarnings.showTemperatureWarning();
+ } else {
+ mWarnings.dismissTemperatureWarning();
+ }
+ }
+
+ // TODO: skip this when in VR mode since we already get a callback
+ mHandler.postDelayed(this::updateTemperatureWarning, TEMPERATURE_INTERVAL);
+ }
+
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.print("mLowBatteryAlertCloseLevel=");
pw.println(mLowBatteryAlertCloseLevel);
@@ -237,6 +293,8 @@ public class PowerUI extends SystemUI {
Settings.Global.LOW_BATTERY_SOUND_TIMEOUT, 0));
pw.print("bucket: ");
pw.println(Integer.toString(findBatteryLevelBucket(mBatteryLevel)));
+ pw.print("mThrottlingTemp=");
+ pw.println(Float.toString(mThrottlingTemp));
mWarnings.dump(pw);
}
@@ -248,6 +306,8 @@ public class PowerUI extends SystemUI {
void showInvalidChargerWarning();
void updateLowBatteryWarning();
boolean isInvalidChargerWarningShowing();
+ void dismissTemperatureWarning();
+ void showTemperatureWarning();
void dump(PrintWriter pw);
void userSwitched();
}
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/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
index 9050b83f4ce0..66e617bd8f75 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
@@ -17,11 +17,15 @@ package com.android.systemui.plugins;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Activity;
+import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -34,6 +38,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.HandlerThread;
+import android.os.UserHandle;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
@@ -72,7 +77,7 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
mMockPm = mock(PackageManager.class);
mMockListener = mock(PluginListener.class);
mMockManager = mock(PluginManager.class);
- when(mMockManager.getClassLoader(Mockito.any(), Mockito.any()))
+ when(mMockManager.getClassLoader(any(), any()))
.thenReturn(getClass().getClassLoader());
mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
mMockListener, true, mHandlerThread.getLooper(), 1, mMockManager, true);
@@ -87,8 +92,8 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
}
@Test
- public void testNoPlugins() {
- when(mMockPm.queryIntentServices(Mockito.any(), Mockito.anyInt())).thenReturn(
+ public void testNoPlugins() throws Exception {
+ when(mMockPm.queryIntentServices(any(), anyInt())).thenReturn(
Collections.emptyList());
mPluginInstanceManager.loadAll();
@@ -100,7 +105,7 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
}
@Test
- public void testPluginCreate() {
+ public void testPluginCreate() throws Exception {
createPlugin();
// Verify startup lifecycle
@@ -110,7 +115,7 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
}
@Test
- public void testPluginDestroy() {
+ public void testPluginDestroy() throws Exception {
createPlugin(); // Get into valid created state.
mPluginInstanceManager.destroy();
@@ -124,7 +129,9 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
}
@Test
- public void testIncorrectVersion() {
+ public void testIncorrectVersion() throws Exception {
+ NotificationManager nm = mock(NotificationManager.class);
+ mContext.addMockSystemService(Context.NOTIFICATION_SERVICE, nm);
setupFakePmQuery();
when(sMockPlugin.getVersion()).thenReturn(2);
@@ -136,10 +143,12 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
// Plugin shouldn't be connected because it is the wrong version.
verify(mMockListener, Mockito.never()).onPluginConnected(
ArgumentCaptor.forClass(Plugin.class).capture());
+ verify(nm).notifyAsUser(eq(TestPlugin.class.getName()), eq(R.id.notification_plugin), any(),
+ eq(UserHandle.ALL));
}
@Test
- public void testReloadOnChange() {
+ public void testReloadOnChange() throws Exception {
createPlugin(); // Get into valid created state.
mPluginInstanceManager.onPackageChange("com.android.systemui");
@@ -159,7 +168,7 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
}
@Test
- public void testNonDebuggable() {
+ public void testNonDebuggable() throws Exception {
// Create a version that thinks the build is not debuggable.
mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
mMockListener, true, mHandlerThread.getLooper(), 1, mMockManager, false);
@@ -176,7 +185,7 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
}
@Test
- public void testCheckAndDisable() {
+ public void testCheckAndDisable() throws Exception {
createPlugin(); // Get into valid created state.
// Start with an unrelated class.
@@ -197,7 +206,7 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
}
@Test
- public void testDisableAll() {
+ public void testDisableAll() throws Exception {
createPlugin(); // Get into valid created state.
mPluginInstanceManager.disableAll();
@@ -208,29 +217,26 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
ArgumentCaptor.forClass(int.class).capture());
}
- private void setupFakePmQuery() {
+ private void setupFakePmQuery() throws Exception {
List<ResolveInfo> list = new ArrayList<>();
ResolveInfo info = new ResolveInfo();
- info.serviceInfo = new ServiceInfo();
+ info.serviceInfo = mock(ServiceInfo.class);
info.serviceInfo.packageName = "com.android.systemui";
info.serviceInfo.name = TestPlugin.class.getName();
+ when(info.serviceInfo.loadLabel(any())).thenReturn("Test Plugin");
list.add(info);
- when(mMockPm.queryIntentServices(Mockito.any(), Mockito.anyInt())).thenReturn(list);
+ when(mMockPm.queryIntentServices(any(), Mockito.anyInt())).thenReturn(list);
+ when(mMockPm.getServiceInfo(any(), anyInt())).thenReturn(info.serviceInfo);
when(mMockPm.checkPermission(Mockito.anyString(), Mockito.anyString())).thenReturn(
PackageManager.PERMISSION_GRANTED);
- try {
- ApplicationInfo appInfo = getContext().getApplicationInfo();
- when(mMockPm.getApplicationInfo(Mockito.anyString(), Mockito.anyInt())).thenReturn(
- appInfo);
- } catch (NameNotFoundException e) {
- // Shouldn't be possible, but if it is, we want to fail.
- throw new RuntimeException(e);
- }
+ ApplicationInfo appInfo = getContext().getApplicationInfo();
+ when(mMockPm.getApplicationInfo(Mockito.anyString(), Mockito.anyInt())).thenReturn(
+ appInfo);
}
- private void createPlugin() {
+ private void createPlugin() throws Exception {
setupFakePmQuery();
mPluginInstanceManager.loadAll();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
index 4b1827d51a34..63b1817a1f78 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
@@ -13,10 +13,17 @@
*/
package com.android.systemui.plugins;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.NotificationManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.Uri;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
@@ -113,6 +120,24 @@ public class PluginManagerTest extends SysuiTestCase {
ArgumentCaptor.forClass(Throwable.class).capture());
}
+ @Test
+ public void testDisableIntent() {
+ NotificationManager nm = mock(NotificationManager.class);
+ PackageManager pm = mock(PackageManager.class);
+ mContext.addMockSystemService(Context.NOTIFICATION_SERVICE, nm);
+ mContext.setMockPackageManager(pm);
+
+ ComponentName testComponent = new ComponentName(getContext().getPackageName(),
+ PluginManagerTest.class.getName());
+ Intent intent = new Intent(PluginManager.DISABLE_PLUGIN);
+ intent.setData(Uri.parse("package://" + testComponent.flattenToString()));
+ mPluginManager.onReceive(mContext, intent);
+ verify(nm).cancel(eq(testComponent.getClassName()), eq(R.id.notification_plugin));
+ verify(pm).setComponentEnabledSetting(eq(testComponent),
+ eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED),
+ eq(PackageManager.DONT_KILL_APP));
+ }
+
private void resetExceptionHandler() {
mPluginExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
// Set back the real exception handler so the test can crash if it wants to.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
index 5c87fb01e23c..7070961e39b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
@@ -117,4 +117,18 @@ public class PowerNotificationWarningsTest extends SysuiTestCase {
.notifyAsUser(anyString(), anyInt(), captor.capture(), any());
assertNotEqual(null, captor.getValue().sound);
}
+
+ @Test
+ public void testShowTemperatureWarning_NotifyAsUser() {
+ mPowerNotificationWarnings.showTemperatureWarning();
+ verify(mMockNotificationManager, times(1))
+ .notifyAsUser(anyString(), anyInt(), any(), any());
+ }
+
+ @Test
+ public void testDismissTemperatureWarning_CancelAsUser() {
+ mPowerNotificationWarnings.showTemperatureWarning();
+ mPowerNotificationWarnings.dismissTemperatureWarning();
+ verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(), anyInt(), any());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java
index a95280641aa1..710f88af46bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java
@@ -23,6 +23,7 @@ import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.Handler;
import android.os.IBinder;
@@ -42,6 +43,7 @@ public class TestableContext extends ContextWrapper {
private ArrayMap<ComponentName, IBinder> mMockServices;
private ArrayMap<ServiceConnection, ComponentName> mActiveServices;
+ private PackageManager mMockPackageManager;
private Tracker mReceiver;
private Tracker mService;
private Tracker mComponent;
@@ -59,6 +61,18 @@ public class TestableContext extends ContextWrapper {
mComponent = test.getTracker("component");
}
+ public void setMockPackageManager(PackageManager mock) {
+ mMockPackageManager = mock;
+ }
+
+ @Override
+ public PackageManager getPackageManager() {
+ if (mMockPackageManager != null) {
+ return mMockPackageManager;
+ }
+ return super.getPackageManager();
+ }
+
@Override
public Resources getResources() {
return super.getResources();
diff --git a/services/Android.mk b/services/Android.mk
index 291198303548..0d57efe27833 100644
--- a/services/Android.mk
+++ b/services/Android.mk
@@ -24,6 +24,7 @@ services := \
appwidget \
autofill \
backup \
+ coverage\
devicepolicy \
midi \
net \
@@ -37,6 +38,10 @@ services := \
# The convention is to name each service module 'services.$(module_name)'
LOCAL_STATIC_JAVA_LIBRARIES := $(addprefix services.,$(services))
+ifeq ($(EMMA_INSTRUMENT_FRAMEWORK),true)
+LOCAL_EMMA_INSTRUMENT := true
+endif
+
include $(BUILD_JAVA_LIBRARY)
# native library
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 3419963aaebf..e7f1d16fcc61 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -2045,6 +2045,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
writer.flush();
+ if (args.length == 0) {
+ // Add arg to produce output
+ args = new String[1];
+ args[0] = "--print";
+ }
}
if (mBluetoothBinder == null) {
diff --git a/services/core/java/com/android/server/HardwarePropertiesManagerService.java b/services/core/java/com/android/server/HardwarePropertiesManagerService.java
index 23cf64a031af..36a16cd0a18b 100644
--- a/services/core/java/com/android/server/HardwarePropertiesManagerService.java
+++ b/services/core/java/com/android/server/HardwarePropertiesManagerService.java
@@ -16,6 +16,8 @@
package com.android.server;
+import android.Manifest;
+import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -80,8 +82,9 @@ public class HardwarePropertiesManagerService extends IHardwarePropertiesManager
*
* @param callingPackage The calling package name.
*
- * @throws SecurityException if something other than the profile or device owner, or the
- * current VR service tries to retrieve information provided by this service.
+ * @throws SecurityException if something other than the profile or device owner, the
+ * current VR service, or a caller holding the {@link Manifest.permission#DEVICE_POWER}
+ * permission tries to retrieve information provided by this service.
*/
private void enforceHardwarePropertiesRetrievalAllowed(String callingPackage)
throws SecurityException {
@@ -100,9 +103,11 @@ public class HardwarePropertiesManagerService extends IHardwarePropertiesManager
final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
if (!dpm.isDeviceOwnerApp(callingPackage) && !dpm.isProfileOwnerApp(callingPackage)
- && !vrService.isCurrentVrListener(callingPackage, userId)) {
- throw new SecurityException("The caller is not a device or profile owner or bound "
- + "VrListenerService.");
+ && !vrService.isCurrentVrListener(callingPackage, userId)
+ && mContext.checkCallingOrSelfPermission(Manifest.permission.DEVICE_POWER)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("The caller is not a device or profile owner, bound "
+ + "VrListenerService, or holding the DEVICE_POWER permission.");
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 235325b8b259..028c57117824 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2177,6 +2177,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer
// display because it no longer contains any tasks.
mAllowDockedStackResize = false;
}
+ final ActivityStack fullscreenStack = getStack(FULLSCREEN_WORKSPACE_STACK_ID);
+ final boolean isFullscreenStackVisible = fullscreenStack != null &&
+ fullscreenStack.getStackVisibilityLocked(null) == STACK_VISIBLE;
final ArrayList<TaskRecord> tasks = stack.getAllTasks();
final int size = tasks.size();
if (onTop) {
@@ -2186,9 +2189,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer
// Update the return-to to reflect where the pinned stack task was moved
// from so that we retain the stack that was previously visible if the
// pinned stack is recreated. See moveActivityToPinnedStackLocked().
- final int focusedStackId = getFocusedStack().getStackId();
- task.setTaskToReturnTo(focusedStackId == HOME_STACK_ID || !onTop
- ? HOME_ACTIVITY_TYPE : APPLICATION_ACTIVITY_TYPE);
+ task.setTaskToReturnTo(isFullscreenStackVisible && onTop ?
+ APPLICATION_ACTIVITY_TYPE : HOME_ACTIVITY_TYPE);
}
moveTaskToStackLocked(tasks.get(i).taskId,
FULLSCREEN_WORKSPACE_STACK_ID, onTop, onTop /*forceFocus*/,
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/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index ff841b147d9c..d86c4dab54fb 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2498,19 +2498,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
private void addChild(TaskStack stack, boolean toTop) {
- int addIndex = toTop ? mChildren.size() : 0;
-
- if (toTop
- && mService.isStackVisibleLocked(PINNED_STACK_ID)
- && stack.mStackId != PINNED_STACK_ID) {
- // The pinned stack is always the top most stack (always-on-top) when it is visible.
- // So, stack is moved just below the pinned stack.
- addIndex--;
- TaskStack topStack = mChildren.get(addIndex);
- if (topStack.mStackId != PINNED_STACK_ID) {
- throw new IllegalStateException("Pinned stack isn't top stack??? " + mChildren);
- }
- }
+ final int addIndex = findPositionForStack(toTop ? mChildren.size() : 0, stack,
+ true /* adding */);
addChild(stack, addIndex);
setLayoutNeeded();
}
@@ -2528,7 +2517,45 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
return;
}
- super.positionChildAt(position, child, includingParents);
+ final int targetPosition = findPositionForStack(position, child, false /* adding */);
+ super.positionChildAt(targetPosition, child, includingParents);
+
+ setLayoutNeeded();
+ }
+
+ /**
+ * When stack is added or repositioned, find a proper position for it.
+ * This will make sure that pinned stack always stays on top.
+ * @param requestedPosition Position requested by caller.
+ * @param stack Stack to be added or positioned.
+ * @param adding Flag indicates whether we're adding a new stack or positioning an existing.
+ * @return The proper position for the stack.
+ */
+ private int findPositionForStack(int requestedPosition, TaskStack stack, boolean adding) {
+ final int topChildPosition = mChildren.size() - 1;
+ boolean toTop = requestedPosition == POSITION_TOP;
+ toTop |= adding ? requestedPosition >= topChildPosition + 1
+ : requestedPosition >= topChildPosition;
+ int targetPosition = requestedPosition;
+
+ if (toTop
+ && mService.isStackVisibleLocked(PINNED_STACK_ID)
+ && stack.mStackId != PINNED_STACK_ID) {
+ // The pinned stack is always the top most stack (always-on-top) when it is visible.
+ TaskStack topStack = mChildren.get(topChildPosition);
+ if (topStack.mStackId != PINNED_STACK_ID) {
+ throw new IllegalStateException("Pinned stack isn't top stack??? " + mChildren);
+ }
+
+ // So, stack is moved just below the pinned stack.
+ // When we're adding a new stack the target is the current pinned stack position.
+ // When we're positioning an existing stack the target is the position below pinned
+ // stack, because WindowContainer#positionAt() first removes element and then adds it
+ // to specified place.
+ targetPosition = adding ? topChildPosition : topChildPosition - 1;
+ }
+
+ return targetPosition;
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 984cf55de0e7..c9bf4fa55efd 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -434,7 +434,7 @@ class WindowContainer<E extends WindowContainer> implements Comparable<WindowCon
// TODO: Will this be more correct if it checks the visibility of its parents?
// It depends...For example, Tasks and Stacks are only visible if there children are visible
// but, WindowState are not visible if there parent are not visible. Maybe have the
- // container specify which direction to treverse for for visibility?
+ // container specify which direction to traverse for visibility?
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer wc = mChildren.get(i);
if (wc.isVisible()) {
diff --git a/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
index c42141ada543..17a6c297bd8f 100644
--- a/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
+++ b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
@@ -37,6 +37,8 @@ using hardware::thermal::V1_0::IThermal;
using hardware::thermal::V1_0::Temperature;
using hardware::thermal::V1_0::ThermalStatus;
using hardware::thermal::V1_0::ThermalStatusCode;
+template<typename T>
+using Return = hardware::Return<T>;
// ---------------------------------------------------------------------------
@@ -76,7 +78,7 @@ static jfloatArray nativeGetFanSpeeds(JNIEnv *env, jclass /* clazz */) {
}
hidl_vec<CoolingDevice> list;
- Status status = gThermalModule->getCoolingDevices(
+ Return<void> ret = gThermalModule->getCoolingDevices(
[&list](ThermalStatus status, hidl_vec<CoolingDevice> devices) {
if (status.code == ThermalStatusCode::SUCCESS) {
list = std::move(devices);
@@ -84,10 +86,10 @@ static jfloatArray nativeGetFanSpeeds(JNIEnv *env, jclass /* clazz */) {
ALOGE("Couldn't get fan speeds because of HAL error: %s",
status.debugMessage.c_str());
}
- }).getStatus();
+ });
- if (!status.isOk()) {
- ALOGE("getCoolingDevices failed status: %d", status.exceptionCode());
+ if (!ret.isOk()) {
+ ALOGE("getCoolingDevices failed status: %s", ret.description().c_str());
}
float values[list.size()];
@@ -106,7 +108,7 @@ static jfloatArray nativeGetDeviceTemperatures(JNIEnv *env, jclass /* clazz */,
return env->NewFloatArray(0);
}
hidl_vec<Temperature> list;
- Status status = gThermalModule->getTemperatures(
+ Return<void> ret = gThermalModule->getTemperatures(
[&list](ThermalStatus status, hidl_vec<Temperature> temperatures) {
if (status.code == ThermalStatusCode::SUCCESS) {
list = std::move(temperatures);
@@ -114,10 +116,10 @@ static jfloatArray nativeGetDeviceTemperatures(JNIEnv *env, jclass /* clazz */,
ALOGE("Couldn't get temperatures because of HAL error: %s",
status.debugMessage.c_str());
}
- }).getStatus();
+ });
- if (!status.isOk()) {
- ALOGE("getDeviceTemperatures failed status: %d", status.exceptionCode());
+ if (!ret.isOk()) {
+ ALOGE("getDeviceTemperatures failed status: %s", ret.description().c_str());
}
jfloat values[list.size()];
@@ -151,7 +153,7 @@ static jobjectArray nativeGetCpuUsages(JNIEnv *env, jclass /* clazz */) {
return env->NewObjectArray(0, gCpuUsageInfoClassInfo.clazz, nullptr);
}
hidl_vec<CpuUsage> list;
- Status status = gThermalModule->getCpuUsages(
+ Return<void> ret = gThermalModule->getCpuUsages(
[&list](ThermalStatus status, hidl_vec<CpuUsage> cpuUsages) {
if (status.code == ThermalStatusCode::SUCCESS) {
list = std::move(cpuUsages);
@@ -159,10 +161,10 @@ static jobjectArray nativeGetCpuUsages(JNIEnv *env, jclass /* clazz */) {
ALOGE("Couldn't get CPU usages because of HAL error: %s",
status.debugMessage.c_str());
}
- }).getStatus();
+ });
- if (!status.isOk()) {
- ALOGE("getCpuUsages failed status: %d", status.exceptionCode());
+ if (!ret.isOk()) {
+ ALOGE("getCpuUsages failed status: %s", ret.description().c_str());
}
jobjectArray cpuUsages = env->NewObjectArray(list.size(), gCpuUsageInfoClassInfo.clazz,
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
index 0c5729e9b32c..7790d15719e9 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
@@ -185,14 +185,14 @@ HdmiCecController::HdmiCecController(sp<IHdmiCec> hdmiCec,
mLooper(looper) {
mHdmiCecCallback = new HdmiCecCallback(this);
Return<void> ret = mHdmiCec->setCallback(mHdmiCecCallback);
- if (!ret.getStatus().isOk()) {
+ if (!ret.isOk()) {
ALOGE("Failed to set a cec callback.");
}
}
HdmiCecController::~HdmiCecController() {
Return<void> ret = mHdmiCec->setCallback(nullptr);
- if (!ret.getStatus().isOk()) {
+ if (!ret.isOk()) {
ALOGE("Failed to set a cec callback.");
}
}
@@ -200,7 +200,7 @@ HdmiCecController::~HdmiCecController() {
int HdmiCecController::sendMessage(const CecMessage& message) {
// TODO: propagate send_message's return value.
Return<SendMessageResult> ret = mHdmiCec->sendMessage(message);
- if (!ret.getStatus().isOk()) {
+ if (!ret.isOk()) {
ALOGE("Failed to send CEC message.");
return static_cast<int>(SendMessageResult::FAIL);
}
@@ -209,7 +209,7 @@ int HdmiCecController::sendMessage(const CecMessage& message) {
int HdmiCecController::addLogicalAddress(CecLogicalAddress address) {
Return<Result> ret = mHdmiCec->addLogicalAddress(address);
- if (!ret.getStatus().isOk()) {
+ if (!ret.isOk()) {
ALOGE("Failed to add a logical address.");
return static_cast<int>(Result::FAILURE_UNKNOWN);
}
@@ -218,7 +218,7 @@ int HdmiCecController::addLogicalAddress(CecLogicalAddress address) {
void HdmiCecController::clearLogicaladdress() {
Return<void> ret = mHdmiCec->clearLogicalAddress();
- if (!ret.getStatus().isOk()) {
+ if (!ret.isOk()) {
ALOGE("Failed to clear logical address.");
}
}
@@ -230,7 +230,7 @@ int HdmiCecController::getPhysicalAddress() {
result = res;
addr = paddr;
});
- if (!ret.getStatus().isOk()) {
+ if (!ret.isOk()) {
ALOGE("Failed to get physical address.");
return INVALID_PHYSICAL_ADDRESS;
}
@@ -239,7 +239,7 @@ int HdmiCecController::getPhysicalAddress() {
int HdmiCecController::getVersion() {
Return<int32_t> ret = mHdmiCec->getCecVersion();
- if (!ret.getStatus().isOk()) {
+ if (!ret.isOk()) {
ALOGE("Failed to get cec version.");
}
return ret;
@@ -247,7 +247,7 @@ int HdmiCecController::getVersion() {
uint32_t HdmiCecController::getVendorId() {
Return<uint32_t> ret = mHdmiCec->getVendorId();
- if (!ret.getStatus().isOk()) {
+ if (!ret.isOk()) {
ALOGE("Failed to get vendor id.");
}
return ret;
@@ -267,7 +267,7 @@ jobjectArray HdmiCecController::getPortInfos() {
Return<void> ret = mHdmiCec->getPortInfo([&ports](hidl_vec<HdmiPortInfo> list) {
ports = list;
});
- if (!ret.getStatus().isOk()) {
+ if (!ret.isOk()) {
ALOGE("Failed to get port information.");
return NULL;
}
@@ -287,14 +287,14 @@ jobjectArray HdmiCecController::getPortInfos() {
void HdmiCecController::setOption(OptionKey key, bool enabled) {
Return<void> ret = mHdmiCec->setOption(key, enabled);
- if (!ret.getStatus().isOk()) {
+ if (!ret.isOk()) {
ALOGE("Failed to set option.");
}
}
void HdmiCecController::setLanguage(hidl_string language) {
Return<void> ret = mHdmiCec->setLanguage(language);
- if (!ret.getStatus().isOk()) {
+ if (!ret.isOk()) {
ALOGE("Failed to set language.");
}
}
@@ -302,7 +302,7 @@ void HdmiCecController::setLanguage(hidl_string language) {
// Enable audio return channel.
void HdmiCecController::enableAudioReturnChannel(int port, bool enabled) {
Return<void> ret = mHdmiCec->enableAudioReturnChannel(port, enabled);
- if (!ret.getStatus().isOk()) {
+ if (!ret.isOk()) {
ALOGE("Failed to enable/disable ARC.");
}
}
@@ -310,7 +310,7 @@ void HdmiCecController::enableAudioReturnChannel(int port, bool enabled) {
// Whether to hdmi device is connected to the given port.
bool HdmiCecController::isConnected(int port) {
Return<bool> ret = mHdmiCec->isConnected(port);
- if (!ret.getStatus().isOk()) {
+ if (!ret.isOk()) {
ALOGE("Failed to get connection info.");
}
return ret;
diff --git a/services/core/jni/com_android_server_lights_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp
index a3ab8f67d2fa..cf7f1cbfd0be 100644
--- a/services/core/jni/com_android_server_lights_LightsService.cpp
+++ b/services/core/jni/com_android_server_lights_LightsService.cpp
@@ -117,8 +117,7 @@ static void setLight_native(
ALOGD_IF_SLOW(50, "Excessive delay setting light");
Return<Status> ret = gLight->setLight(type, state);
- // TODO(b/31348667): this is transport specific status
- if (!ret.getStatus().isOk()) {
+ if (!ret.isOk()) {
ALOGE("Failed to issue set light command.");
return;
}
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index b7032dbb0ab0..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.getStatus().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.getStatus().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.getStatus().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.getStatus().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.getStatus().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.getStatus().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.getStatus().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.getStatus().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.getStatus().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");
}
@@ -994,7 +987,7 @@ static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject
}
auto result = gnssHal->setCallback(gnssCbIface);
- if ((!result) || (!result.getStatus().isOk())) {
+ if ((!result) || (!result.isOk())) {
ALOGE("SetCallback for Gnss Interface fails\n");
return JNI_FALSE;
}
@@ -1004,7 +997,7 @@ static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject
ALOGE("Unable to initialize GNSS Xtra interface\n");
} else {
result = gnssXtraIface->setCallback(gnssXtraCbIface);
- if ((!result) || (!result.getStatus().isOk())) {
+ if ((!result) || (!result.isOk())) {
gnssXtraIface = nullptr;
ALOGE("SetCallback for Gnss Xtra Interface fails\n");
}
@@ -1049,7 +1042,7 @@ static jboolean android_location_GnssLocationProvider_set_position_mode(JNIEnv*
min_interval,
preferred_accuracy,
preferred_time);
- if (!result.getStatus().isOk()) {
+ if (!result.isOk()) {
ALOGE("%s: GNSS setPositionMode failed\n", __func__);
return JNI_FALSE;
} else {
@@ -1063,7 +1056,7 @@ static jboolean android_location_GnssLocationProvider_set_position_mode(JNIEnv*
static jboolean android_location_GnssLocationProvider_start(JNIEnv* /* env */, jobject /* obj */) {
if (gnssHal != nullptr) {
auto result = gnssHal->start();
- if (!result.getStatus().isOk()) {
+ if (!result.isOk()) {
return JNI_FALSE;
} else {
return result;
@@ -1076,7 +1069,7 @@ static jboolean android_location_GnssLocationProvider_start(JNIEnv* /* env */, j
static jboolean android_location_GnssLocationProvider_stop(JNIEnv* /* env */, jobject /* obj */) {
if (gnssHal != nullptr) {
auto result = gnssHal->stop();
- if (!result.getStatus().isOk()) {
+ if (!result.isOk()) {
return JNI_FALSE;
} else {
return result;
@@ -1090,7 +1083,7 @@ static void android_location_GnssLocationProvider_delete_aiding_data(JNIEnv* /*
jint flags) {
if (gnssHal != nullptr) {
auto result = gnssHal->deleteAidingData(static_cast<IGnss::GnssAidingData>(flags));
- if (!result.getStatus().isOk()) {
+ if (!result.isOk()) {
ALOGE("Error in deleting aiding data");
}
}
@@ -1191,7 +1184,7 @@ static void android_location_GnssLocationProvider_inject_time(JNIEnv* /* env */,
jlong time, jlong timeReference, jint uncertainty) {
if (gnssHal != nullptr) {
auto result = gnssHal->injectTime(time, timeReference, uncertainty);
- if (!result || !result.getStatus().isOk()) {
+ if (!result || !result.isOk()) {
ALOGE("%s: Gnss injectTime() failed", __func__);
}
}
@@ -1201,7 +1194,7 @@ static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env
jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy) {
if (gnssHal != nullptr) {
auto result = gnssHal->injectLocation(latitude, longitude, accuracy);
- if (!result || !result.getStatus().isOk()) {
+ if (!result || !result.isOk()) {
ALOGE("%s: Gnss injectLocation() failed", __func__);
}
}
@@ -1238,7 +1231,7 @@ static void android_location_GnssLocationProvider_agps_data_conn_open(
const char *apnStr = env->GetStringUTFChars(apn, NULL);
auto result = agnssIface->dataConnOpen(apnStr, static_cast<IAGnss::ApnIpType>(apnIpType));
- if ((!result) || (!result.getStatus().isOk())) {
+ if ((!result) || (!result.isOk())) {
ALOGE("%s: Failed to set APN and its IP type", __func__);
}
env->ReleaseStringUTFChars(apn, apnStr);
@@ -1252,7 +1245,7 @@ static void android_location_GnssLocationProvider_agps_data_conn_closed(JNIEnv*
}
auto result = agnssIface->dataConnClosed();
- if ((!result) || (!result.getStatus().isOk())) {
+ if ((!result) || (!result.isOk())) {
ALOGE("%s: Failed to close AGnss data connection", __func__);
}
}
@@ -1265,7 +1258,7 @@ static void android_location_GnssLocationProvider_agps_data_conn_failed(JNIEnv*
}
auto result = agnssIface->dataConnFailed();
- if ((!result) || (!result.getStatus().isOk())) {
+ if ((!result) || (!result.isOk())) {
ALOGE("%s: Failed to notify unavailability of AGnss data connection", __func__);
}
}
@@ -1281,7 +1274,7 @@ static void android_location_GnssLocationProvider_set_agps_server(JNIEnv* env, j
auto result = agnssIface->setServer(static_cast<IAGnssCallback::AGnssType>(type),
c_hostname,
port);
- if ((!result) || (!result.getStatus().isOk())) {
+ if ((!result) || (!result.isOk())) {
ALOGE("%s: Failed to set AGnss host name and port", __func__);
}
@@ -1354,13 +1347,13 @@ static void android_location_GnssLocationProvider_update_network_state(JNIEnv* e
auto result = agnssRilIface->updateNetworkState(connected,
static_cast<IAGnssRil::NetworkType>(type),
roaming);
- if ((!result) || (!result.getStatus().isOk())) {
+ if ((!result) || (!result.isOk())) {
ALOGE("updateNetworkState failed");
}
const char *c_apn = env->GetStringUTFChars(apn, NULL);
result = agnssRilIface->updateNetworkAvailability(available, c_apn);
- if ((!result) || (!result.getStatus().isOk())) {
+ if ((!result) || (!result.isOk())) {
ALOGE("updateNetworkAvailability failed");
}
@@ -1384,7 +1377,7 @@ static jboolean android_location_GnssLocationProvider_add_geofence(JNIEnv* /* en
geofenceId, latitude, longitude, radius,
static_cast<IGnssGeofenceCallback::GeofenceTransition>(last_transition),
monitor_transition, notification_responsiveness, unknown_timer);
- return boolToJbool(result.getStatus().isOk());
+ return boolToJbool(result.isOk());
} else {
ALOGE("Geofence Interface not available");
}
@@ -1395,7 +1388,7 @@ static jboolean android_location_GnssLocationProvider_remove_geofence(JNIEnv* /*
jobject /* obj */, jint geofenceId) {
if (gnssGeofencingIface != nullptr) {
auto result = gnssGeofencingIface->removeGeofence(geofenceId);
- return boolToJbool(result.getStatus().isOk());
+ return boolToJbool(result.isOk());
} else {
ALOGE("Geofence interface not available");
}
@@ -1406,7 +1399,7 @@ static jboolean android_location_GnssLocationProvider_pause_geofence(JNIEnv* /*
jobject /* obj */, jint geofenceId) {
if (gnssGeofencingIface != nullptr) {
auto result = gnssGeofencingIface->pauseGeofence(geofenceId);
- return boolToJbool(result.getStatus().isOk());
+ return boolToJbool(result.isOk());
} else {
ALOGE("Geofence interface not available");
}
@@ -1417,7 +1410,7 @@ static jboolean android_location_GnssLocationProvider_resume_geofence(JNIEnv* /*
jobject /* obj */, jint geofenceId, jint monitor_transition) {
if (gnssGeofencingIface != nullptr) {
auto result = gnssGeofencingIface->resumeGeofence(geofenceId, monitor_transition);
- return boolToJbool(result.getStatus().isOk());
+ return boolToJbool(result.isOk());
} else {
ALOGE("Geofence interface not available");
}
@@ -1463,7 +1456,7 @@ static jboolean android_location_GnssLocationProvider_stop_measurement_collectio
}
auto result = gnssMeasurementIface->close();
- return boolToJbool(result.getStatus().isOk());
+ return boolToJbool(result.isOk());
}
static jboolean android_location_GnssLocationProvider_is_navigation_message_supported(
@@ -1505,7 +1498,7 @@ static jboolean android_location_GnssLocationProvider_stop_navigation_message_co
}
auto result = gnssNavigationMessageIface->close();
- return boolToJbool(result.getStatus().isOk());
+ return boolToJbool(result.isOk());
}
static jboolean android_location_GnssLocationProvider_set_emergency_supl_pdn(JNIEnv*,
@@ -1517,7 +1510,7 @@ static jboolean android_location_GnssLocationProvider_set_emergency_supl_pdn(JNI
}
auto result = gnssConfigurationIface->setEmergencySuplPdn(emergencySuplPdn);
- if (result.getStatus().isOk()) {
+ if (result.isOk()) {
return result;
} else {
return JNI_FALSE;
@@ -1532,7 +1525,7 @@ static jboolean android_location_GnssLocationProvider_set_supl_version(JNIEnv*,
return JNI_FALSE;
}
auto result = gnssConfigurationIface->setSuplVersion(version);
- if (result.getStatus().isOk()) {
+ if (result.isOk()) {
return result;
} else {
return JNI_FALSE;
@@ -1548,7 +1541,7 @@ static jboolean android_location_GnssLocationProvider_set_supl_es(JNIEnv*,
}
auto result = gnssConfigurationIface->setSuplEs(suplEs);
- if (result.getStatus().isOk()) {
+ if (result.isOk()) {
return result;
} else {
return JNI_FALSE;
@@ -1564,7 +1557,7 @@ static jboolean android_location_GnssLocationProvider_set_supl_mode(JNIEnv*,
}
auto result = gnssConfigurationIface->setSuplMode(mode);
- if (result.getStatus().isOk()) {
+ if (result.isOk()) {
return result;
} else {
return JNI_FALSE;
@@ -1580,7 +1573,7 @@ static jboolean android_location_GnssLocationProvider_set_gps_lock(JNIEnv*,
}
auto result = gnssConfigurationIface->setGpsLock(gpsLock);
- if (result.getStatus().isOk()) {
+ if (result.isOk()) {
return result;
} else {
return JNI_FALSE;
@@ -1597,7 +1590,7 @@ static jboolean android_location_GnssLocationProvider_set_lpp_profile(JNIEnv*,
auto result = gnssConfigurationIface->setLppProfile(lppProfile);
- if (result.getStatus().isOk()) {
+ if (result.isOk()) {
return result;
} else {
return JNI_FALSE;
@@ -1613,7 +1606,7 @@ static jboolean android_location_GnssLocationProvider_set_gnss_pos_protocol_sele
}
auto result = gnssConfigurationIface->setGlonassPositioningProtocol(gnssPosProtocol);
- if (result.getStatus().isOk()) {
+ if (result.isOk()) {
return result;
} else {
return JNI_FALSE;
diff --git a/services/coverage/Android.mk b/services/coverage/Android.mk
new file mode 100644
index 000000000000..da99994d6b4c
--- /dev/null
+++ b/services/coverage/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.coverage
+
+LOCAL_SRC_FILES += \
+ $(call all-java-files-under,java)
+
+LOCAL_JAVA_LIBRARIES := jacocoagent
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/coverage/java/com/android/server/coverage/CoverageService.java b/services/coverage/java/com/android/server/coverage/CoverageService.java
new file mode 100644
index 000000000000..d600aa8c4276
--- /dev/null
+++ b/services/coverage/java/com/android/server/coverage/CoverageService.java
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ */
+
+package com.android.server.coverage;
+
+import android.os.Binder;
+import android.os.ParcelFileDescriptor;
+import android.os.ShellCallback;
+import android.os.ShellCommand;
+import android.os.ResultReceiver;
+
+import org.jacoco.agent.rt.RT;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * A service that responds to `cmd coverage ...` and provides a mechanism for dumping code coverage
+ * information from the system server process.
+ * @hide
+ */
+public class CoverageService extends Binder {
+
+ public static final String COVERAGE_SERVICE = "coverage";
+ public static final boolean ENABLED;
+
+ static {
+ // This service should only be enabled if org.jacoco.agent.rt.RT was added to the build
+ boolean shouldEnable = true;
+ try {
+ Class.forName("org.jacoco.agent.rt.RT");
+ } catch (ClassNotFoundException e) {
+ shouldEnable = false;
+ }
+ ENABLED = shouldEnable;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+ String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
+ new CoverageCommand().exec(this, in, out, err, args, callback, resultReceiver);
+ }
+
+ /**
+ * A {@link ShellCommand} implementation for performing coverage shell commands.
+ */
+ private static class CoverageCommand extends ShellCommand {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int onCommand(String cmd) {
+ if ("dump".equals(cmd)) {
+ return onDump();
+ } else if ("reset".equals(cmd)) {
+ return onReset();
+ } else {
+ return handleDefaultCommands(cmd);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onHelp() {
+ PrintWriter pw = getOutPrintWriter();
+ pw.println("Coverage commands:");
+ pw.println(" help");
+ pw.println(" Print this help text.");
+ pw.println(" dump [FILE]");
+ pw.println(" Dump code coverage to FILE.");
+ pw.println(" reset");
+ pw.println(" Reset coverage information.");
+ }
+
+ /**
+ * Perform the "dump" command to write the collected execution data to a file.
+ *
+ * @return The command result.
+ */
+ private int onDump() {
+ // Figure out where to dump the coverage data
+ String dest = getNextArg();
+ if (dest == null) {
+ dest = "/data/local/tmp/coverage.ec";
+ } else {
+ File f = new File(dest);
+ if (f.isDirectory()) {
+ dest = new File(f, "coverage.ec").getAbsolutePath();
+ }
+ }
+
+ // Try to open the destination file
+ ParcelFileDescriptor fd = openOutputFileForSystem(dest);
+ if (fd == null) {
+ return -1;
+ }
+
+ // Write the execution data to the file
+ try (BufferedOutputStream output = new BufferedOutputStream(
+ new ParcelFileDescriptor.AutoCloseOutputStream(fd))) {
+ output.write(RT.getAgent().getExecutionData(false));
+ output.flush();
+ getOutPrintWriter().println(String.format("Dumped coverage data to %s", dest));
+ } catch (IOException e) {
+ getErrPrintWriter().println("Failed to dump coverage data: " + e.getMessage());
+ return -1;
+ }
+
+ return 0;
+ }
+
+ /**
+ * Perform the "reset" command to clear the collected execution data.
+ *
+ * @return The command result.
+ */
+ private int onReset() {
+ RT.getAgent().reset();
+ getOutPrintWriter().println("Reset coverage data");
+ return 0;
+ }
+ }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 22f9f3a05563..e5c8d02c4fd1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5980,9 +5980,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
throw new IllegalArgumentException("Invalid component " + admin
+ " for device owner");
}
- final boolean hasIncompatibleAccounts = hasIncompatibleAccountsNoLock(userId, admin);
+ final boolean hasIncompatibleAccountsOrNonAdb =
+ hasIncompatibleAccountsOrNonAdbNoLock(userId, admin);
synchronized (this) {
- enforceCanSetDeviceOwnerLocked(admin, userId, hasIncompatibleAccounts);
+ enforceCanSetDeviceOwnerLocked(admin, userId, hasIncompatibleAccountsOrNonAdb);
final ActiveAdmin activeAdmin = getActiveAdminUncheckedLocked(admin, userId);
if (activeAdmin == null
|| getUserData(userId).mRemovingAdmins.contains(admin)) {
@@ -6218,9 +6219,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
throw new IllegalArgumentException("Component " + who
+ " not installed for userId:" + userHandle);
}
- final boolean hasIncompatibleAccounts = hasIncompatibleAccountsNoLock(userHandle, who);
+ final boolean hasIncompatibleAccountsOrNonAdb =
+ hasIncompatibleAccountsOrNonAdbNoLock(userHandle, who);
synchronized (this) {
- enforceCanSetProfileOwnerLocked(who, userHandle, hasIncompatibleAccounts);
+ enforceCanSetProfileOwnerLocked(who, userHandle, hasIncompatibleAccountsOrNonAdb);
if (getActiveAdminUncheckedLocked(who, userHandle) == null
|| getUserData(userHandle).mRemovingAdmins.contains(who)) {
@@ -6553,10 +6555,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* The profile owner can only be set before the user setup phase has completed,
* except for:
* - SYSTEM_UID
- * - adb unless hasIncompatibleAccounts is true.
+ * - adb unless hasIncompatibleAccountsOrNonAdb is true.
*/
private void enforceCanSetProfileOwnerLocked(@Nullable ComponentName owner, int userHandle,
- boolean hasIncompatibleAccounts) {
+ boolean hasIncompatibleAccountsOrNonAdb) {
UserInfo info = getUserInfo(userHandle);
if (info == null) {
// User doesn't exist.
@@ -6576,7 +6578,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
if (isAdb()) {
if ((mIsWatch || hasUserSetupCompleted(userHandle))
- && hasIncompatibleAccounts) {
+ && hasIncompatibleAccountsOrNonAdb) {
throw new IllegalStateException("Not allowed to set the profile owner because "
+ "there are already some accounts on the profile");
}
@@ -6594,13 +6596,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* permission.
*/
private void enforceCanSetDeviceOwnerLocked(@Nullable ComponentName owner, int userId,
- boolean hasIncompatibleAccounts) {
+ boolean hasIncompatibleAccountsOrNonAdb) {
if (!isAdb()) {
enforceCanManageProfileAndDeviceOwners();
}
final int code = checkDeviceOwnerProvisioningPreConditionLocked(
- owner, userId, isAdb(), hasIncompatibleAccounts);
+ owner, userId, isAdb(), hasIncompatibleAccountsOrNonAdb);
switch (code) {
case CODE_OK:
return;
@@ -8909,7 +8911,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* except for adb command if no accounts or additional users are present on the device.
*/
private int checkDeviceOwnerProvisioningPreConditionLocked(@Nullable ComponentName owner,
- int deviceOwnerUserId, boolean isAdb, boolean hasIncompatibleAccounts) {
+ int deviceOwnerUserId, boolean isAdb, boolean hasIncompatibleAccountsOrNonAdb) {
if (mOwners.hasDeviceOwner()) {
return CODE_HAS_DEVICE_OWNER;
}
@@ -8929,7 +8931,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (mUserManager.getUserCount() > 1) {
return CODE_NONSYSTEM_USER_EXISTS;
}
- if (hasIncompatibleAccounts) {
+ if (hasIncompatibleAccountsOrNonAdb) {
return CODE_ACCOUNTS_NOT_EMPTY;
}
} else {
@@ -8956,9 +8958,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private int checkDeviceOwnerProvisioningPreCondition(int deviceOwnerUserId) {
synchronized (this) {
- // hasIncompatibleAccounts doesn't matter since the caller is not adb.
+ // hasIncompatibleAccountsOrNonAdb doesn't matter since the caller is not adb.
return checkDeviceOwnerProvisioningPreConditionLocked(/* owner unknown */ null,
- deviceOwnerUserId, /* isAdb= */ false, /* hasIncompatibleAccounts=*/ true);
+ deviceOwnerUserId, /* isAdb= */ false,
+ /* hasIncompatibleAccountsOrNonAdb=*/ true);
}
}
@@ -9857,9 +9860,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* ..._DISALLOWED, return true.
* - Otherwise return false.
*
+ * If the caller is *not* ADB, it also returns true. The returned value shouldn't be used
+ * when the caller is not ADB.
+ *
* DO NOT CALL IT WITH THE DPMS LOCK HELD.
*/
- private boolean hasIncompatibleAccountsNoLock(int userId, @Nullable ComponentName owner) {
+ private boolean hasIncompatibleAccountsOrNonAdbNoLock(
+ int userId, @Nullable ComponentName owner) {
+ if (!isAdb()) {
+ return true;
+ }
if (Thread.holdsLock(this)) {
Slog.wtf(LOG_TAG, "hasIncompatibleAccountsNoLock() called with the DPMS lock held.");
return true;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 7ccae2c323e4..1d550d294560 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -63,6 +63,7 @@ import com.android.server.camera.CameraService;
import com.android.server.clipboard.ClipboardService;
import com.android.server.connectivity.IpConnectivityMetrics;
import com.android.server.connectivity.MetricsLoggerService;
+import com.android.server.coverage.CoverageService;
import com.android.server.devicepolicy.DevicePolicyManagerService;
import com.android.server.display.DisplayManagerService;
import com.android.server.display.NightDisplayService;
@@ -1260,6 +1261,12 @@ public final class SystemServer {
traceEnd();
}
+ if (!disableNonCoreServices && CoverageService.ENABLED) {
+ traceBeginAndSlog("AddCoverageService");
+ ServiceManager.addService(CoverageService.COVERAGE_SERVICE, new CoverageService());
+ traceEnd();
+ }
+
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_PRINTING)) {
traceBeginAndSlog("StartPrintManager");
mSystemServiceManager.startService(PRINT_MANAGER_SERVICE_CLASS);
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);
+ }
+ }
+ }
}
+
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
index 746310217c38..24893a142b20 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -47,14 +47,15 @@ public class TaskStackContainersTests extends WindowTestsBase {
// Test that always-on-top stack can't be moved to position other than top.
final TaskStack stack1 = createTaskStackOnDisplay(sDisplayContent);
final TaskStack stack2 = createTaskStackOnDisplay(sDisplayContent);
- sDisplayContent.addStackToDisplay(PINNED_STACK_ID, true);
- final TaskStack pinnedStack = sWm.mStackIdToStack.get(PINNED_STACK_ID);
+ final TaskStack pinnedStack = addPinnedStack();
final WindowContainer taskStackContainer = stack1.getParent();
final int stack1Pos = taskStackContainer.mChildren.indexOf(stack1);
final int stack2Pos = taskStackContainer.mChildren.indexOf(stack2);
final int pinnedStackPos = taskStackContainer.mChildren.indexOf(pinnedStack);
+ assertGreaterThan(pinnedStackPos, stack2Pos);
+ assertGreaterThan(stack2Pos, stack1Pos);
taskStackContainer.positionChildAt(WindowContainer.POSITION_BOTTOM, pinnedStack, false);
assertEquals(taskStackContainer.mChildren.get(stack1Pos), stack1);
@@ -66,4 +67,43 @@ public class TaskStackContainersTests extends WindowTestsBase {
assertEquals(taskStackContainer.mChildren.get(stack2Pos), stack2);
assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), pinnedStack);
}
+ @Test
+ public void testStackPositionBelowPinnedStack() throws Exception {
+ // Test that no stack can be above pinned stack.
+ final TaskStack pinnedStack = addPinnedStack();
+ final TaskStack stack1 = createTaskStackOnDisplay(sDisplayContent);
+
+ final WindowContainer taskStackContainer = stack1.getParent();
+
+ final int stackPos = taskStackContainer.mChildren.indexOf(stack1);
+ final int pinnedStackPos = taskStackContainer.mChildren.indexOf(pinnedStack);
+ assertGreaterThan(pinnedStackPos, stackPos);
+
+ taskStackContainer.positionChildAt(WindowContainer.POSITION_TOP, stack1, false);
+ assertEquals(taskStackContainer.mChildren.get(stackPos), stack1);
+ assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), pinnedStack);
+
+ taskStackContainer.positionChildAt(taskStackContainer.mChildren.size() - 1, stack1, false);
+ assertEquals(taskStackContainer.mChildren.get(stackPos), stack1);
+ assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), pinnedStack);
+ }
+
+ private TaskStack addPinnedStack() {
+ TaskStack pinnedStack = sWm.mStackIdToStack.get(PINNED_STACK_ID);
+ if (pinnedStack == null) {
+ sDisplayContent.addStackToDisplay(PINNED_STACK_ID, true);
+ pinnedStack = sWm.mStackIdToStack.get(PINNED_STACK_ID);
+ }
+
+ if (!pinnedStack.isVisible()) {
+ // Stack should contain visible app window to be considered visible.
+ final Task pinnedTask = createTaskInStack(pinnedStack, 0 /* userId */);
+ assertFalse(pinnedStack.isVisible());
+ final TestAppWindowToken pinnedApp = new TestAppWindowToken(sDisplayContent);
+ pinnedTask.addChild(pinnedApp, 0 /* addPos */);
+ assertTrue(pinnedStack.isVisible());
+ }
+
+ return pinnedStack;
+ }
}