Merge "Keep track of all bound services."
diff --git a/api/current.txt b/api/current.txt
index 8892b24..f90ab4b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -39666,6 +39666,7 @@
field public static final int SHOW_SOURCE_ACTIVITY = 16; // 0x10
field public static final int SHOW_SOURCE_APPLICATION = 8; // 0x8
field public static final int SHOW_SOURCE_ASSIST_GESTURE = 4; // 0x4
+ field public static final int SHOW_SOURCE_PUSH_TO_TALK = 32; // 0x20
field public static final int SHOW_WITH_ASSIST = 1; // 0x1
field public static final int SHOW_WITH_SCREENSHOT = 2; // 0x2
}
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 89408cc..8914535 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -302,7 +302,6 @@
private int mResultCode;
private int mExitCoordinatorIndex;
private PendingIntent mUsageTimeReport;
- private boolean mLockTaskMode = false;
private int mLaunchDisplayId = INVALID_DISPLAY;
@WindowConfiguration.WindowingMode
private int mLaunchWindowingMode = WINDOWING_MODE_UNDEFINED;
@@ -310,6 +309,7 @@
private int mLaunchActivityType = ACTIVITY_TYPE_UNDEFINED;
private int mLaunchTaskId = -1;
private int mSplitScreenCreateMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
+ private boolean mLockTaskMode = false;
private boolean mDisallowEnterPictureInPictureWhileLaunching;
private boolean mTaskOverlay;
private boolean mTaskOverlayCanResume;
@@ -946,7 +946,7 @@
mAnimationFinishedListener = IRemoteCallback.Stub.asInterface(
opts.getBinder(KEY_ANIMATION_FINISHED_LISTENER));
}
- mRotationAnimationHint = opts.getInt(KEY_ROTATION_ANIMATION_HINT);
+ mRotationAnimationHint = opts.getInt(KEY_ROTATION_ANIMATION_HINT, -1);
mAppVerificationBundle = opts.getBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE);
if (opts.containsKey(KEY_SPECS_FUTURE)) {
mSpecsFuture = IAppTransitionAnimationSpecsFuture.Stub.asInterface(opts.getBinder(
@@ -1442,17 +1442,37 @@
b.putInt(KEY_EXIT_COORDINATOR_INDEX, mExitCoordinatorIndex);
break;
}
- b.putBoolean(KEY_LOCK_TASK_MODE, mLockTaskMode);
- b.putInt(KEY_LAUNCH_DISPLAY_ID, mLaunchDisplayId);
- b.putInt(KEY_LAUNCH_WINDOWING_MODE, mLaunchWindowingMode);
- b.putInt(KEY_LAUNCH_ACTIVITY_TYPE, mLaunchActivityType);
- b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId);
- b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay);
- b.putBoolean(KEY_TASK_OVERLAY_CAN_RESUME, mTaskOverlayCanResume);
- b.putBoolean(KEY_AVOID_MOVE_TO_FRONT, mAvoidMoveToFront);
- b.putInt(KEY_SPLIT_SCREEN_CREATE_MODE, mSplitScreenCreateMode);
- b.putBoolean(KEY_DISALLOW_ENTER_PICTURE_IN_PICTURE_WHILE_LAUNCHING,
- mDisallowEnterPictureInPictureWhileLaunching);
+ if (mLockTaskMode) {
+ b.putBoolean(KEY_LOCK_TASK_MODE, mLockTaskMode);
+ }
+ if (mLaunchDisplayId != INVALID_DISPLAY) {
+ b.putInt(KEY_LAUNCH_DISPLAY_ID, mLaunchDisplayId);
+ }
+ if (mLaunchWindowingMode != WINDOWING_MODE_UNDEFINED) {
+ b.putInt(KEY_LAUNCH_WINDOWING_MODE, mLaunchWindowingMode);
+ }
+ if (mLaunchActivityType != ACTIVITY_TYPE_UNDEFINED) {
+ b.putInt(KEY_LAUNCH_ACTIVITY_TYPE, mLaunchActivityType);
+ }
+ if (mLaunchTaskId != -1) {
+ b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId);
+ }
+ if (mTaskOverlay) {
+ b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay);
+ }
+ if (mTaskOverlayCanResume) {
+ b.putBoolean(KEY_TASK_OVERLAY_CAN_RESUME, mTaskOverlayCanResume);
+ }
+ if (mAvoidMoveToFront) {
+ b.putBoolean(KEY_AVOID_MOVE_TO_FRONT, mAvoidMoveToFront);
+ }
+ if (mSplitScreenCreateMode != SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT) {
+ b.putInt(KEY_SPLIT_SCREEN_CREATE_MODE, mSplitScreenCreateMode);
+ }
+ if (mDisallowEnterPictureInPictureWhileLaunching) {
+ b.putBoolean(KEY_DISALLOW_ENTER_PICTURE_IN_PICTURE_WHILE_LAUNCHING,
+ mDisallowEnterPictureInPictureWhileLaunching);
+ }
if (mAnimSpecs != null) {
b.putParcelableArray(KEY_ANIM_SPECS, mAnimSpecs);
}
@@ -1462,7 +1482,9 @@
if (mSpecsFuture != null) {
b.putBinder(KEY_SPECS_FUTURE, mSpecsFuture.asBinder());
}
- b.putInt(KEY_ROTATION_ANIMATION_HINT, mRotationAnimationHint);
+ if (mRotationAnimationHint != -1) {
+ b.putInt(KEY_ROTATION_ANIMATION_HINT, mRotationAnimationHint);
+ }
if (mAppVerificationBundle != null) {
b.putBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE, mAppVerificationBundle);
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 5e7f1e4..bbdc532 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4153,8 +4153,11 @@
* Called by a device or profile owner, or delegated certificate installer, to generate a
* new private/public key pair. If the device supports key generation via secure hardware,
* this method is useful for creating a key in KeyChain that never left the secure hardware.
- *
* Access to the key is controlled the same way as in {@link #installKeyPair}.
+ *
+ * <p>Because this method might take several seconds to complete, it should only be called from
+ * a worker thread. This method returns {@code null} when called from the main thread.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
* {@code null} if calling from a delegated certificate installer.
* @param algorithm The key generation algorithm, see {@link java.security.KeyPairGenerator}.
diff --git a/core/java/android/app/timezone/RulesState.aidl b/core/java/android/app/timezone/RulesState.aidl
index f789120..665220d 100644
--- a/core/java/android/app/timezone/RulesState.aidl
+++ b/core/java/android/app/timezone/RulesState.aidl
@@ -14,4 +14,6 @@
* limitations under the License.
*/
+package android.app.timezone;
+
parcelable RulesState;
\ No newline at end of file
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 7adea6a8..ef0dce3 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -642,8 +642,7 @@
* tool. This integer encodes the package, type, and resource
* entry. The value 0 is an invalid identifier.
*
- * @return Resource dimension value multiplied by the appropriate
- * metric.
+ * @return Resource dimension value multiplied by the appropriate metric to convert to pixels.
*
* @throws NotFoundException Throws NotFoundException if the given ID does not exist.
*
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index cd177c4..26223f7 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -109,6 +109,12 @@
*/
public static final int SHOW_SOURCE_ACTIVITY = 1<<4;
+ /**
+ * Flag for use with {@link #onShow}: indicates that the voice interaction service was invoked
+ * from a physical button.
+ */
+ public static final int SHOW_SOURCE_PUSH_TO_TALK = 1 << 5;
+
final Context mContext;
final HandlerCaller mHandlerCaller;
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 6b7b89c..c037cd0 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -33,6 +33,8 @@
public static final String FFLAG_PREFIX = "sys.fflag.";
public static final String FFLAG_OVERRIDE_PREFIX = FFLAG_PREFIX + "override.";
+ public static final String PERSIST_PREFIX = "persist." + FFLAG_OVERRIDE_PREFIX;
+ public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
private static final Map<String, String> DEFAULT_FLAGS;
static {
@@ -42,6 +44,7 @@
DEFAULT_FLAGS.put("settings_audio_switcher", "true");
DEFAULT_FLAGS.put("settings_systemui_theme", "true");
DEFAULT_FLAGS.put("settings_dynamic_homepage", "false");
+ DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "true");
}
/**
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index 47bda53..496bc9f 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -29,6 +29,7 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
+import android.graphics.Region.Op;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -325,14 +326,9 @@
* @hide
*/
public static DisplayCutout fromBoundingRect(int left, int top, int right, int bottom) {
- Path path = new Path();
- path.reset();
- path.moveTo(left, top);
- path.lineTo(left, bottom);
- path.lineTo(right, bottom);
- path.lineTo(right, top);
- path.close();
- return fromBounds(path);
+ Region r = Region.obtain();
+ r.set(left, top, right, bottom);
+ return fromBounds(r);
}
/**
@@ -340,26 +336,19 @@
*
* @hide
*/
- public static DisplayCutout fromBounds(Path path) {
- RectF clipRect = new RectF();
- path.computeBounds(clipRect, false /* unused */);
- Region clipRegion = Region.obtain();
- clipRegion.set((int) clipRect.left, (int) clipRect.top,
- (int) clipRect.right, (int) clipRect.bottom);
-
- Region bounds = new Region();
- bounds.setPath(path, clipRegion);
- clipRegion.recycle();
- return new DisplayCutout(ZERO_RECT, bounds, false /* copyArguments */);
+ public static DisplayCutout fromBounds(Region region) {
+ return new DisplayCutout(ZERO_RECT, region, false /* copyArguments */);
}
/**
- * Creates the bounding path according to @android:string/config_mainBuiltInDisplayCutout.
+ * Creates the display cutout according to
+ * @android:string/config_mainBuiltInDisplayCutoutRectApproximation, which is the closest
+ * rectangle-base approximation of the cutout.
*
* @hide
*/
- public static DisplayCutout fromResources(Resources res, int displayWidth, int displayHeight) {
- return fromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout),
+ public static DisplayCutout fromResourcesRectApproximation(Resources res, int displayWidth, int displayHeight) {
+ return fromSpec(res.getString(R.string.config_mainBuiltInDisplayCutoutRectApproximation),
displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT);
}
@@ -369,7 +358,8 @@
* @hide
*/
public static Path pathFromResources(Resources res, int displayWidth, int displayHeight) {
- return pathAndDisplayCutoutFromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout),
+ return pathAndDisplayCutoutFromSpec(
+ res.getString(R.string.config_mainBuiltInDisplayCutout),
displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT).first;
}
@@ -417,6 +407,7 @@
}
final Path p;
+ final Region r = Region.obtain();
try {
p = PathParser.createPathFromPathData(spec);
} catch (Throwable e) {
@@ -431,6 +422,8 @@
m.postTranslate(offsetX, 0);
p.transform(m);
+ addToRegion(p, r);
+
if (bottomSpec != null) {
final Path bottomPath;
try {
@@ -443,9 +436,10 @@
m.postTranslate(0, displayHeight);
bottomPath.transform(m);
p.addPath(bottomPath);
+ addToRegion(bottomPath, r);
}
- final Pair<Path, DisplayCutout> result = new Pair<>(p, fromBounds(p));
+ final Pair<Path, DisplayCutout> result = new Pair<>(p, fromBounds(r));
synchronized (CACHE_LOCK) {
sCachedSpec = spec;
sCachedDisplayWidth = displayWidth;
@@ -456,6 +450,14 @@
return result;
}
+ private static void addToRegion(Path p, Region r) {
+ final RectF rectF = new RectF();
+ final Rect rect = new Rect();
+ p.computeBounds(rectF, false /* unused */);
+ rectF.round(rect);
+ r.op(rect, Op.UNION);
+ }
+
private static Region boundingRectsToRegion(List<Rect> rects) {
Region result = Region.obtain();
if (rects != null) {
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index fbb99e4..75d714f 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -122,25 +122,25 @@
mUidEntries.put(callingUid, uidEntry);
}
+ CallStat callStat;
if (mDetailedTracking) {
// Find CallStat entry and update its total time
- CallStat callStat = uidEntry.getOrCreate(s.callStat);
- callStat.callCount++;
- callStat.cpuTimeMicros += duration;
- callStat.latencyMicros += latencyDuration;
+ callStat = uidEntry.getOrCreate(s.callStat);
callStat.exceptionCount += s.exceptionThrown ? 1 : 0;
- callStat.maxLatencyMicros = Math.max(callStat.maxLatencyMicros, latencyDuration);
callStat.maxRequestSizeBytes =
Math.max(callStat.maxRequestSizeBytes, parcelRequestSize);
callStat.maxReplySizeBytes =
Math.max(callStat.maxReplySizeBytes, parcelReplySize);
} else {
// update sampled timings in the beginning of each interval
- if (s.cpuTimeStarted >= 0) {
- s.sampledCallStat.cpuTimeMicros += duration;
- s.sampledCallStat.latencyMicros += latencyDuration;
- }
- s.sampledCallStat.callCount++;
+ callStat = s.sampledCallStat;
+ }
+ callStat.callCount++;
+ if (s.cpuTimeStarted >= 0) {
+ callStat.cpuTimeMicros += duration;
+ callStat.maxCpuTimeMicros = Math.max(callStat.maxCpuTimeMicros, duration);
+ callStat.latencyMicros += latencyDuration;
+ callStat.maxLatencyMicros = Math.max(callStat.maxLatencyMicros, latencyDuration);
}
uidEntry.cpuTimeMicros += duration;
@@ -189,7 +189,7 @@
StringBuilder sb = new StringBuilder();
if (mDetailedTracking) {
pw.println("Per-UID raw data " + datasetSizeDesc
- + "(uid, call_desc, cpu_time_micros, latency_time_micros, "
+ + "(uid, call_desc, cpu_time_micros, max_cpu_time_micros, latency_time_micros, "
+ "max_latency_time_micros, exception_count, max_request_size_bytes, "
+ "max_reply_size_bytes, call_count):");
List<UidEntry> topEntries = verbose ? entries
@@ -200,6 +200,7 @@
sb.append(" ")
.append(uidEntry.uid).append(",").append(e)
.append(',').append(e.cpuTimeMicros)
+ .append(',').append(e.maxCpuTimeMicros)
.append(',').append(e.latencyMicros)
.append(',').append(e.maxLatencyMicros)
.append(',').append(e.exceptionCount)
@@ -260,7 +261,7 @@
return Binder.getCallingUid();
}
- private long getElapsedRealtimeMicro() {
+ protected long getElapsedRealtimeMicro() {
return SystemClock.elapsedRealtimeNanos() / 1000;
}
@@ -288,11 +289,13 @@
public String className;
public int msg;
public long cpuTimeMicros;
+ public long maxCpuTimeMicros;
public long latencyMicros;
public long maxLatencyMicros;
+ public long callCount;
+ // The following fields are only computed if mDetailedTracking is set.
public long maxRequestSizeBytes;
public long maxReplySizeBytes;
- public long callCount;
public long exceptionCount;
CallStat() {
diff --git a/core/java/com/android/internal/util/DumpUtils.java b/core/java/com/android/internal/util/DumpUtils.java
index 7fd83bc..f6d80a5 100644
--- a/core/java/com/android/internal/util/DumpUtils.java
+++ b/core/java/com/android/internal/util/DumpUtils.java
@@ -34,9 +34,18 @@
/**
* Helper functions for dumping the state of system services.
* Test:
- atest /android/pi-dev/frameworks/base/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
+ atest FrameworksCoreTests:DumpUtilsTest
*/
public final class DumpUtils {
+
+ /**
+ * List of component names that should be dumped in the bug report critical section.
+ *
+ * @hide
+ */
+ public static final ComponentName[] CRITICAL_SECTION_COMPONENTS = {
+ new ComponentName("com.android.systemui", "com.android.systemui.SystemUIService")
+ };
private static final String TAG = "DumpUtils";
private static final boolean DEBUG = false;
@@ -213,6 +222,45 @@
}
/**
+ * Return whether a package should be dumped in the critical section.
+ */
+ private static boolean isCriticalPackage(@Nullable ComponentName cname) {
+ if (cname == null) {
+ return false;
+ }
+
+ for (int i = 0; i < CRITICAL_SECTION_COMPONENTS.length; i++) {
+ if (cname.equals(CRITICAL_SECTION_COMPONENTS[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return whether a package name is considered to be part of the platform and in the critical
+ * section.
+ *
+ * @hide
+ */
+ public static boolean isPlatformCriticalPackage(@Nullable ComponentName.WithComponentName wcn) {
+ return (wcn != null) && isPlatformPackage(wcn.getComponentName()) &&
+ isCriticalPackage(wcn.getComponentName());
+ }
+
+ /**
+ * Return whether a package name is considered to be part of the platform but not in the the
+ * critical section.
+ *
+ * @hide
+ */
+ public static boolean isPlatformNonCriticalPackage(
+ @Nullable ComponentName.WithComponentName wcn) {
+ return (wcn != null) && isPlatformPackage(wcn.getComponentName()) &&
+ !isCriticalPackage(wcn.getComponentName());
+ }
+
+ /**
* Used for dumping providers and services. Return a predicate for a given filter string.
* @hide
*/
@@ -238,6 +286,16 @@
return DumpUtils::isNonPlatformPackage;
}
+ // Dump all platform-critical?
+ if ("all-platform-critical".equals(filterString)) {
+ return DumpUtils::isPlatformCriticalPackage;
+ }
+
+ // Dump all platform-non-critical?
+ if ("all-platform-non-critical".equals(filterString)) {
+ return DumpUtils::isPlatformNonCriticalPackage;
+ }
+
// Is the filter a component name? If so, do an exact match.
final ComponentName filterCname = ComponentName.unflattenFromString(filterString);
if (filterCname != null) {
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index aef48fa..fae4b10b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2966,6 +2966,14 @@
-->
<string translatable="false" name="config_mainBuiltInDisplayCutout"></string>
+ <!-- Like config_mainBuiltInDisplayCutout, but this path is used to report the
+ one single bounding rect per device edge to the app via
+ {@link DisplayCutout#getBoundingRect}. Note that this path should try to match the visual
+ appearance of the cutout as much as possible, and may be smaller than
+ config_mainBuiltInDisplayCutout
+ -->
+ <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@string/config_mainBuiltInDisplayCutout</string>
+
<!-- Whether the display cutout region of the main built-in display should be forced to
black in software (to avoid aliasing or emulate a cutout that is not physically existent).
-->
@@ -3487,4 +3495,7 @@
<!-- Whether or not we should show the option to show battery percentage -->
<bool name="config_battery_percentage_setting_available">true</bool>
+
+ <!-- Whether or not battery saver should be "sticky" when manually enabled. -->
+ <bool name="config_batterySaverStickyBehaviourDisabled">false</bool>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6054180..99001e3 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3364,6 +3364,7 @@
<java-symbol type="string" name="global_action_logout" />
<java-symbol type="string" name="config_mainBuiltInDisplayCutout" />
+ <java-symbol type="string" name="config_mainBuiltInDisplayCutoutRectApproximation" />
<java-symbol type="drawable" name="messaging_user" />
<java-symbol type="bool" name="config_fillMainBuiltInDisplayCutout" />
<java-symbol type="drawable" name="ic_logout" />
@@ -3405,6 +3406,7 @@
<java-symbol type="string" name="notification_app_name_settings" />
<java-symbol type="integer" name="config_lowBatteryAutoTriggerDefaultLevel" />
+ <java-symbol type="bool" name="config_batterySaverStickyBehaviourDisabled" />
<!-- For car devices -->
<java-symbol type="string" name="car_loading_profile" />
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
index b7fef13..18263ab 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
@@ -155,6 +155,42 @@
}
@Test
+ public void testMaxCpu() {
+ TestBinderCallsStats bcs = new TestBinderCallsStats(true);
+ Binder binder = new Binder();
+ BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
+ bcs.time += 50;
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
+
+ callSession = bcs.callStarted(binder, 1);
+ bcs.time += 10;
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
+
+ List<BinderCallsStats.CallStat> callStatsList =
+ bcs.getUidEntries().get(TEST_UID).getCallStatsList();
+
+ assertEquals(50, callStatsList.get(0).maxCpuTimeMicros);
+ }
+
+ @Test
+ public void testMaxLatency() {
+ TestBinderCallsStats bcs = new TestBinderCallsStats(true);
+ Binder binder = new Binder();
+ BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
+ bcs.elapsedTime += 5;
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
+
+ callSession = bcs.callStarted(binder, 1);
+ bcs.elapsedTime += 1;
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
+
+ List<BinderCallsStats.CallStat> callStatsList =
+ bcs.getUidEntries().get(TEST_UID).getCallStatsList();
+
+ assertEquals(5, callStatsList.get(0).maxLatencyMicros);
+ }
+
+ @Test
public void testGetHighestValues() {
List<Integer> list = Arrays.asList(1, 2, 3, 4);
List<Integer> highestValues = BinderCallsStats
@@ -165,6 +201,7 @@
static class TestBinderCallsStats extends BinderCallsStats {
int callingUid = TEST_UID;
long time = 1234;
+ long elapsedTime = 0;
TestBinderCallsStats(boolean detailedTracking) {
super(detailedTracking);
@@ -176,6 +213,11 @@
}
@Override
+ protected long getElapsedRealtimeMicro() {
+ return elapsedTime;
+ }
+
+ @Override
protected int getCallingUid() {
return callingUid;
}
diff --git a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
index 45b19bc..a44b860 100644
--- a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
@@ -15,8 +15,11 @@
*/
package com.android.internal.util;
+import static com.android.internal.util.DumpUtils.CRITICAL_SECTION_COMPONENTS;
import static com.android.internal.util.DumpUtils.filterRecord;
import static com.android.internal.util.DumpUtils.isNonPlatformPackage;
+import static com.android.internal.util.DumpUtils.isPlatformCriticalPackage;
+import static com.android.internal.util.DumpUtils.isPlatformNonCriticalPackage;
import static com.android.internal.util.DumpUtils.isPlatformPackage;
import android.content.ComponentName;
@@ -25,7 +28,7 @@
/**
* Run with:
- atest /android/pi-dev/frameworks/base/core/tests/coretests/src/com/android/internal/util/DumpTest.java
+ atest FrameworksCoreTests:DumpUtilsTest
*/
public class DumpUtilsTest extends TestCase {
@@ -89,6 +92,32 @@
assertTrue(isNonPlatformPackage(wcn("com.google.def/abc")));
}
+ public void testIsPlatformCriticalPackage() {
+ for (final ComponentName componentName : CRITICAL_SECTION_COMPONENTS) {
+ assertTrue(isPlatformCriticalPackage(() -> componentName));
+ assertTrue(isPlatformPackage(componentName));
+ }
+ assertFalse(isPlatformCriticalPackage(wcn("com.google.p/abc")));
+ assertFalse(isPlatformCriticalPackage(wcn("com.android.def/abc")));
+ assertFalse(isPlatformCriticalPackage(wcn("com.android.abc")));
+ assertFalse(isPlatformCriticalPackage(wcn("com.android")));
+ assertFalse(isPlatformCriticalPackage(wcn(null)));
+ assertFalse(isPlatformCriticalPackage(null));
+ }
+
+ public void testIsPlatformNonCriticalPackage() {
+ for (final ComponentName componentName : CRITICAL_SECTION_COMPONENTS) {
+ assertFalse(isPlatformNonCriticalPackage(() -> componentName));
+ }
+ assertTrue(isPlatformNonCriticalPackage(wcn("android/abc")));
+ assertTrue(isPlatformNonCriticalPackage(wcn("android.abc/abc")));
+ assertTrue(isPlatformNonCriticalPackage(wcn("com.android.def/abc")));
+
+ assertFalse(isPlatformNonCriticalPackage(wcn("com.google.def/abc")));
+ assertFalse(isPlatformNonCriticalPackage(wcn(null)));
+ assertFalse(isPlatformNonCriticalPackage(null));
+ }
+
public void testFilterRecord() {
assertFalse(filterRecord(null).test(wcn("com.google.p/abc")));
assertFalse(filterRecord(null).test(wcn("com.android.p/abc")));
@@ -105,6 +134,19 @@
assertFalse(filterRecord("all-non-platform").test(wcn("com.android.p/abc")));
assertFalse(filterRecord("all-non-platform").test(wcn(null)));
+ for (final ComponentName componentName : CRITICAL_SECTION_COMPONENTS) {
+ assertTrue(filterRecord("all-platform-critical").test((() -> componentName)));
+ assertFalse(filterRecord("all-platform-non-critical").test((() -> componentName)));
+ assertTrue(filterRecord("all-platform").test((() -> componentName)));
+ }
+ assertFalse(filterRecord("all-platform-critical").test(wcn("com.google.p/abc")));
+ assertFalse(filterRecord("all-platform-critical").test(wcn("com.android.p/abc")));
+ assertFalse(filterRecord("all-platform-critical").test(wcn(null)));
+
+ assertTrue(filterRecord("all-platform-non-critical").test(wcn("com.android.p/abc")));
+ assertFalse(filterRecord("all-platform-non-critical").test(wcn("com.google.p/abc")));
+ assertFalse(filterRecord("all-platform-non-critical").test(wcn(null)));
+
// Partial string match.
assertTrue(filterRecord("abc").test(wcn("com.google.p/.abc")));
assertFalse(filterRecord("abc").test(wcn("com.google.p/.def")));
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
index 8a1c4ef..94efc71 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
@@ -16,6 +16,7 @@
package com.android.settingslib.fuelgauge;
+import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -90,6 +91,13 @@
if (TextUtils.equals(pkg, defaultDialer)) {
return true;
}
+
+ final DevicePolicyManager devicePolicyManager = mAppContext.getSystemService(
+ DevicePolicyManager.class);
+ if (devicePolicyManager.packageHasActiveAdmins(pkg)) {
+ return true;
+ }
+
return false;
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
index a23eebc..23087a9 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
@@ -21,8 +21,10 @@
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -51,7 +53,8 @@
@Mock
private IDeviceIdleController mDeviceIdleService;
-
+ @Mock
+ private DevicePolicyManager mDevicePolicyManager;
private PowerWhitelistBackend mPowerWhitelistBackend;
private ShadowPackageManager mPackageManager;
private Context mContext;
@@ -59,7 +62,8 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mContext = RuntimeEnvironment.application;
+ mContext = spy(RuntimeEnvironment.application);
+ doReturn(mContext).when(mContext).getApplicationContext();
doReturn(new String[] {}).when(mDeviceIdleService).getFullPowerWhitelist();
doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelist();
doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelistExceptIdle();
@@ -67,6 +71,7 @@
doNothing().when(mDeviceIdleService).removePowerSaveWhitelistApp(anyString());
mPackageManager = Shadow.extract(mContext.getPackageManager());
mPackageManager.setSystemFeature(PackageManager.FEATURE_TELEPHONY, true);
+ doReturn(mDevicePolicyManager).when(mContext).getSystemService(DevicePolicyManager.class);
mPowerWhitelistBackend = new PowerWhitelistBackend(mContext, mDeviceIdleService);
}
@@ -123,6 +128,13 @@
}
@Test
+ public void isWhitelisted_shouldWhitelistActiveDeviceAdminApp() {
+ doReturn(true).when(mDevicePolicyManager).packageHasActiveAdmins(PACKAGE_ONE);
+
+ assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
+ }
+
+ @Test
public void testIsSystemWhitelisted() throws Exception {
doReturn(new String[] {PACKAGE_ONE}).when(mDeviceIdleService).getSystemPowerWhitelist();
mPowerWhitelistBackend.refreshList();
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index eab4b97..a5616d5 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -339,19 +339,17 @@
android:exported="false">
</activity>
- <!-- Springboard for launching the share activity -->
- <receiver android:name=".screenshot.GlobalScreenshot$ScreenshotActionReceiver"
- android:process=":screenshot"
+ <!-- Springboard for launching the share and edit activity. This needs to be in the main
+ system ui process since we need to notify the status bar to dismiss the keyguard -->
+ <receiver android:name=".screenshot.GlobalScreenshot$ActionProxyReceiver"
android:exported="false" />
<!-- Callback for dismissing screenshot notification after a share target is picked -->
<receiver android:name=".screenshot.GlobalScreenshot$TargetChosenReceiver"
- android:process=":screenshot"
android:exported="false" />
<!-- Callback for deleting screenshot notification -->
<receiver android:name=".screenshot.GlobalScreenshot$DeleteScreenshotReceiver"
- android:process=":screenshot"
android:exported="false" />
<!-- started from UsbDeviceSettingsManager -->
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 6bc0965..721e9c5 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -48,10 +48,10 @@
<string name="keyguard_enter_your_pin">Enter your PIN</string>
<!-- Instructions telling the user to enter their pattern to unlock the keyguard [CHAR LIMIT=30] -->
- <string name="keyguard_enter_your_pattern">Enter your Pattern</string>
+ <string name="keyguard_enter_your_pattern">Enter your pattern</string>
<!-- Instructions telling the user to enter their text password to unlock the keyguard [CHAR LIMIT=30] -->
- <string name="keyguard_enter_your_password">Enter your Password</string>
+ <string name="keyguard_enter_your_password">Enter your password</string>
<!-- Instructions telling the user that they entered the wrong pin while trying
to unlock the keyguard. Displayed in one line in a large font. -->
@@ -146,9 +146,9 @@
<!-- Message shown in pattern unlock after some number of unsuccessful attempts -->
<string name="kg_forgot_pattern_button_text">Forgot Pattern</string>
<!-- Message shown when user enters wrong pattern -->
- <string name="kg_wrong_pattern">Wrong Pattern</string>
+ <string name="kg_wrong_pattern">Wrong pattern</string>
<!-- Message shown when user enters wrong password -->
- <string name="kg_wrong_password">Wrong Password</string>
+ <string name="kg_wrong_password">Wrong password</string>
<!-- Message shown when user enters wrong PIN -->
<string name="kg_wrong_pin">Wrong PIN</string>
<!-- Countdown message shown after too many failed unlock attempts -->
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index 1e5b77e..70ca055 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -99,7 +99,7 @@
long token = Binder.clearCallingIdentity();
try {
mHandler.post(() -> {
- StatusBar statusBar = ((SystemUIApplication) mContext).getComponent(
+ StatusBar statusBar = SysUiServiceProvider.getComponent(mContext,
StatusBar.class);
if (statusBar != null) {
statusBar.showScreenPinningRequest(taskId, false /* allowCancel */);
@@ -152,7 +152,7 @@
public Rect getNonMinimizedSplitScreenSecondaryBounds() {
long token = Binder.clearCallingIdentity();
try {
- Divider divider = ((SystemUIApplication) mContext).getComponent(Divider.class);
+ Divider divider = SysUiServiceProvider.getComponent(mContext, Divider.class);
if (divider != null) {
return divider.getView().getNonMinimizedSplitScreenSecondaryBounds();
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index b7ff984..f30b073 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -113,9 +113,7 @@
// The display buffers will be empty and need to be filled.
mHost.dozeTimeTick();
// The first frame may arrive when the display isn't ready yet.
- mHandler.postDelayed(mWakeLock.wrap(mHost::dozeTimeTick), 100);
- // The the delayed frame may arrive when the display isn't ready yet either.
- mHandler.postDelayed(mWakeLock.wrap(mHost::dozeTimeTick), 1000);
+ mHandler.postDelayed(mWakeLock.wrap(mHost::dozeTimeTick), 500);
}
scheduleTimeTick();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index b9d1021..120fa42 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2103,6 +2103,9 @@
pw.print(" mDrawnCallback: "); pw.println(mDrawnCallback);
}
+ /**
+ * @param aodShowing true when AOD - or ambient mode - is showing.
+ */
public void setAodShowing(boolean aodShowing) {
setShowingLocked(mShowing, aodShowing);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 7e4acc2..63a65d0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -48,6 +48,7 @@
import com.android.systemui.Dependency;
import com.android.systemui.OverviewProxyService;
+import com.android.systemui.SysUiServiceProvider;
import com.google.android.collect.Lists;
import com.android.internal.logging.MetricsLogger;
@@ -1095,7 +1096,7 @@
}
private StatusBar getStatusBar() {
- return ((SystemUIApplication) mContext).getComponent(StatusBar.class);
+ return SysUiServiceProvider.getComponent(mContext, StatusBar.class);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java
index 2c1158d..b4212d3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java
@@ -21,6 +21,7 @@
import android.os.IBinder;
import android.util.Log;
+import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.SystemUIApplication;
/**
@@ -40,8 +41,7 @@
@Override
public IBinder onBind(Intent intent) {
- SystemUIApplication app = (SystemUIApplication) getApplication();
- Recents recents = app.getComponent(Recents.class);
+ Recents recents = SysUiServiceProvider.getComponent(this, Recents.class);
if (DEBUG) {
Log.d(TAG, "onBind: " + recents);
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 64ccba8..0ea941f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -16,9 +16,11 @@
package com.android.systemui.screenshot;
+import static android.content.Context.NOTIFICATION_SERVICE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-
-import static com.android.systemui.screenshot.GlobalScreenshot.SHARING_INTENT;
+import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_ACTION_INTENT;
+import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_CANCEL_NOTIFICATION;
+import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_DISALLOW_ENTER_PIP;
import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_SCREENSHOT;
import android.animation.Animator;
@@ -26,7 +28,6 @@
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.Notification;
import android.app.Notification.BigPictureStyle;
@@ -56,9 +57,9 @@
import android.os.Environment;
import android.os.PowerManager;
import android.os.Process;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.MediaStore;
+import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Slog;
@@ -73,12 +74,13 @@
import android.view.animation.Interpolator;
import android.widget.ImageView;
import android.widget.Toast;
-
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.R;
+import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.SystemUI;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.util.NotificationChannels;
-
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
@@ -277,7 +279,12 @@
values.put(MediaStore.Images.ImageColumns.SIZE, new File(mImageFilePath).length());
Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
- // Create a share intent
+ // Note: Both the share and edit actions are proxied through ActionProxyReceiver in
+ // order to do some common work like dismissing the keyguard and sending
+ // closeSystemWindows
+
+ // Create a share intent, this will always go through the chooser activity first which
+ // should not trigger auto-enter PiP
String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime));
String subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate);
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
@@ -286,37 +293,47 @@
sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- // Create a share action for the notification. Note, we proxy the call to
- // ScreenshotActionReceiver because RemoteViews currently forces an activity options
- // on the PendingIntent being launched, and since we don't want to trigger the share
- // sheet in this case, we start the chooser activity directly in
- // ScreenshotActionReceiver.
+ PendingIntent chooserAction = PendingIntent.getBroadcast(context, 0,
+ new Intent(context, GlobalScreenshot.TargetChosenReceiver.class),
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
+ Intent sharingChooserIntent = Intent.createChooser(sharingIntent, null,
+ chooserAction.getIntentSender())
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ // Create a share action for the notification
PendingIntent shareAction = PendingIntent.getBroadcast(context, 0,
- new Intent(context, GlobalScreenshot.ScreenshotActionReceiver.class)
- .putExtra(SHARING_INTENT, sharingIntent),
+ new Intent(context, GlobalScreenshot.ActionProxyReceiver.class)
+ .putExtra(EXTRA_ACTION_INTENT, sharingChooserIntent)
+ .putExtra(EXTRA_DISALLOW_ENTER_PIP, true),
PendingIntent.FLAG_CANCEL_CURRENT);
Notification.Action.Builder shareActionBuilder = new Notification.Action.Builder(
R.drawable.ic_screenshot_share,
r.getString(com.android.internal.R.string.share), shareAction);
mNotificationBuilder.addAction(shareActionBuilder.build());
+ // Create an edit intent, if a specific package is provided as the editor, then launch
+ // that directly
+ String editorPackage = context.getString(R.string.config_screenshotEditor);
Intent editIntent = new Intent(Intent.ACTION_EDIT);
+ if (!TextUtils.isEmpty(editorPackage)) {
+ editIntent.setComponent(ComponentName.unflattenFromString(editorPackage));
+ }
editIntent.setType("image/png");
editIntent.setData(uri);
editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
editIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
- // Create a edit action for the notification the same way.
+ // Create a edit action
PendingIntent editAction = PendingIntent.getBroadcast(context, 1,
- new Intent(context, GlobalScreenshot.ScreenshotActionReceiver.class)
- .putExtra(SHARING_INTENT, editIntent),
+ new Intent(context, GlobalScreenshot.ActionProxyReceiver.class)
+ .putExtra(EXTRA_ACTION_INTENT, editIntent)
+ .putExtra(EXTRA_CANCEL_NOTIFICATION, editIntent.getComponent() != null),
PendingIntent.FLAG_CANCEL_CURRENT);
Notification.Action.Builder editActionBuilder = new Notification.Action.Builder(
R.drawable.ic_screenshot_edit,
r.getString(com.android.internal.R.string.screenshot_edit), editAction);
mNotificationBuilder.addAction(editActionBuilder.build());
-
// Create a delete action for the notification
PendingIntent deleteAction = PendingIntent.getBroadcast(context, 0,
new Intent(context, GlobalScreenshot.DeleteScreenshotReceiver.class)
@@ -429,7 +446,9 @@
class GlobalScreenshot {
static final String SCREENSHOT_URI_ID = "android:screenshot_uri_id";
- static final String SHARING_INTENT = "android:screenshot_sharing_intent";
+ static final String EXTRA_ACTION_INTENT = "android:screenshot_action_intent";
+ static final String EXTRA_CANCEL_NOTIFICATION = "android:screenshot_cancel_notification";
+ static final String EXTRA_DISALLOW_ENTER_PIP = "android:screenshot_disallow_enter_pip";
private static final int SCREENSHOT_FLASH_TO_PEAK_DURATION = 130;
private static final int SCREENSHOT_DROP_IN_DURATION = 430;
@@ -452,7 +471,6 @@
private NotificationManager mNotificationManager;
private Display mDisplay;
private DisplayMetrics mDisplayMetrics;
- private Matrix mDisplayMatrix;
private Bitmap mScreenBitmap;
private View mScreenshotLayout;
@@ -482,7 +500,6 @@
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// Inflate the screenshot layout
- mDisplayMatrix = new Matrix();
mScreenshotLayout = layoutInflater.inflate(R.layout.global_screenshot, null);
mBackgroundView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_background);
mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot);
@@ -512,7 +529,7 @@
mWindowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mNotificationManager =
- (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
mDisplay = mWindowManager.getDefaultDisplay();
mDisplayMetrics = new DisplayMetrics();
mDisplay.getRealMetrics(mDisplayMetrics);
@@ -562,21 +579,6 @@
}
/**
- * @return the current display rotation in degrees
- */
- private float getDegreesForRotation(int value) {
- switch (value) {
- case Surface.ROTATION_90:
- return 360f - 90f;
- case Surface.ROTATION_180:
- return 360f - 180f;
- case Surface.ROTATION_270:
- return 360f - 270f;
- }
- return 0f;
- }
-
- /**
* Takes a screenshot of the current display and shows an animation.
*/
private void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible,
@@ -891,52 +893,39 @@
}
/**
- * Receiver to proxy the share or edit intent.
+ * Receiver to proxy the share or edit intent, used to clean up the notification and send
+ * appropriate signals to the system (ie. to dismiss the keyguard if necessary).
*/
- public static class ScreenshotActionReceiver extends BroadcastReceiver {
+ public static class ActionProxyReceiver extends BroadcastReceiver {
@Override
- public void onReceive(Context context, Intent intent) {
- try {
- ActivityManager.getService().closeSystemDialogs(SYSTEM_DIALOG_REASON_SCREENSHOT);
- } catch (RemoteException e) {
- }
+ public void onReceive(Context context, final Intent intent) {
+ Runnable startActivityRunnable = () -> {
+ ActivityManagerWrapper.getInstance().closeSystemWindows(
+ SYSTEM_DIALOG_REASON_SCREENSHOT);
- Intent actionIntent = intent.getParcelableExtra(SHARING_INTENT);
-
- // If this is an edit & default editor exists, route straight there.
- String editorPackage = context.getResources().getString(R.string.config_screenshotEditor);
- if (actionIntent.getAction() == Intent.ACTION_EDIT &&
- editorPackage != null && editorPackage.length() > 0) {
- actionIntent.setComponent(ComponentName.unflattenFromString(editorPackage));
- final NotificationManager nm =
- (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- nm.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT);
- } else {
- PendingIntent chooseAction = PendingIntent.getBroadcast(context, 0,
- new Intent(context, GlobalScreenshot.TargetChosenReceiver.class),
- PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
- actionIntent = Intent.createChooser(actionIntent, null,
- chooseAction.getIntentSender())
- .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
- }
-
- ActivityOptions opts = ActivityOptions.makeBasic();
- opts.setDisallowEnterPictureInPictureWhileLaunching(true);
-
- context.startActivityAsUser(actionIntent, opts.toBundle(), UserHandle.CURRENT);
+ Intent actionIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT);
+ if (intent.getBooleanExtra(EXTRA_CANCEL_NOTIFICATION, false)) {
+ cancelScreenshotNotification(context);
+ }
+ ActivityOptions opts = ActivityOptions.makeBasic();
+ opts.setDisallowEnterPictureInPictureWhileLaunching(
+ intent.getBooleanExtra(EXTRA_DISALLOW_ENTER_PIP, false));
+ context.startActivityAsUser(actionIntent, opts.toBundle(),UserHandle.CURRENT);
+ };
+ StatusBar statusBar = SysUiServiceProvider.getComponent(context, StatusBar.class);
+ statusBar.executeRunnableDismissingKeyguard(startActivityRunnable, null,
+ true /* dismissShade */, true /* afterKeyguardGone */, true /* deferred */);
}
}
/**
- * Removes the notification for a screenshot after a share or edit target is chosen.
+ * Removes the notification for a screenshot after a share target is chosen.
*/
public static class TargetChosenReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- // Clear the notification
- final NotificationManager nm =
- (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- nm.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT);
+ // Clear the notification only after the user has chosen a share action
+ cancelScreenshotNotification(context);
}
}
@@ -950,14 +939,18 @@
return;
}
- // Clear the notification
- final NotificationManager nm =
- (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- final Uri uri = Uri.parse(intent.getStringExtra(SCREENSHOT_URI_ID));
- nm.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT);
+ // Clear the notification when the image is deleted
+ cancelScreenshotNotification(context);
// And delete the image from the media store
+ final Uri uri = Uri.parse(intent.getStringExtra(SCREENSHOT_URI_ID));
new DeleteImageInBackgroundTask(context).execute(uri);
}
}
+
+ private static void cancelScreenshotNotification(Context context) {
+ final NotificationManager nm =
+ (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
+ nm.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index ae1da56..e3e791d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -4733,7 +4733,6 @@
boolean dozing = mDozingRequested && mState == StatusBarState.KEYGUARD
|| mBiometricUnlockController.getMode()
== BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
- final boolean alwaysOn = DozeParameters.getInstance(mContext).getAlwaysOn();
// When in wake-and-unlock we may not have received a change to mState
// but we still should not be dozing, manually set to false.
if (mBiometricUnlockController.getMode() ==
@@ -4742,7 +4741,7 @@
}
if (mDozing != dozing) {
mDozing = dozing;
- mKeyguardViewMediator.setAodShowing(mDozing && alwaysOn);
+ mKeyguardViewMediator.setAodShowing(mDozing);
mStatusBarWindowManager.setDozing(mDozing);
mStatusBarKeyguardViewManager.setDozing(mDozing);
if (mAmbientIndicationContainer instanceof DozeReceiver) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index a4e184b..052e8e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -665,11 +665,15 @@
int width = MeasureSpec.getSize(widthMeasureSpec);
int childWidthSpec = MeasureSpec.makeMeasureSpec(width - mSidePaddings * 2,
MeasureSpec.getMode(widthMeasureSpec));
+ // Don't constrain the height of the children so we know how big they'd like to be
+ int childHeightSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec),
+ MeasureSpec.UNSPECIFIED);
+
// We need to measure all children even the GONE ones, such that the heights are calculated
// correctly as they are used to calculate how many we can fit on the screen.
final int size = getChildCount();
for (int i = 0; i < size; i++) {
- measureChild(getChildAt(i), childWidthSpec, heightMeasureSpec);
+ measureChild(getChildAt(i), childWidthSpec, childHeightSpec);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
index a901e88..b835909 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
@@ -23,7 +23,7 @@
*/
public class DelayedWakeLock implements WakeLock {
- private static final long RELEASE_DELAY_MS = 140;
+ private static final long RELEASE_DELAY_MS = 100;
private final Handler mHandler;
private final WakeLock mInner;
diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml
index 80d8066..9254b4d 100644
--- a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml
@@ -37,6 +37,8 @@
@right
</string>
+ <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string>
+
<!-- Whether the display cutout region of the main built-in display should be forced to
black in software (to avoid aliasing or emulate a cutout that is not physically existent).
-->
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml
index ca261f9..80c997a 100644
--- a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml
@@ -49,6 +49,8 @@
@dp
</string>
+ <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string>
+
<!-- Whether the display cutout region of the main built-in display should be forced to
black in software (to avoid aliasing or emulate a cutout that is not physically existent).
-->
diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml
index c22b2e7..6fb3c7f 100644
--- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml
@@ -40,6 +40,8 @@
@dp
</string>
+ <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string>
+
<!-- Whether the display cutout region of the main built-in display should be forced to
black in software (to avoid aliasing or emulate a cutout that is not physically existent).
-->
diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml
index 401e092..7c29ffb 100644
--- a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml
@@ -40,6 +40,8 @@
@dp
</string>
+ <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string>
+
<!-- Whether the display cutout region of the main built-in display should be forced to
black in software (to avoid aliasing or emulate a cutout that is not physically existent).
-->
diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml
index f328b83..5fb8b9e 100644
--- a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml
@@ -40,6 +40,8 @@
@dp
</string>
+ <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string>
+
<!-- Whether the display cutout region of the main built-in display should be forced to
black in software (to avoid aliasing or emulate a cutout that is not physically existent).
-->
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 33fc5e5..15c0468 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -470,6 +470,9 @@
// Counts the occurrences of each link speed (Mbps) level
// with rssi (dBm) and rssi^2 sums (dBm^2)
repeated LinkSpeedCount link_speed_counts = 121;
+
+ // Number of times the SarManager failed to register SAR sensor listener
+ optional int32 num_sar_sensor_registration_failures = 122;
}
// Information that gets logged for every WiFi connection.
@@ -1611,4 +1614,4 @@
// Firmware alert code. Only valid when the event was triggered by a firmware alert, otherwise -1.
optional int32 firmware_alert_code = 10 [default = -1];
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index aa426d3..78b7385 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -53,12 +53,16 @@
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.os.UserManagerInternal.UserRestrictionsListener;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
+import android.text.TextUtils;
+import android.util.FeatureFlagUtils;
+import android.util.Log;
import android.util.Slog;
import android.util.StatsLog;
@@ -386,6 +390,15 @@
mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
+ // TODO: We need a more generic way to initialize the persist keys of FeatureFlagUtils
+ boolean isHearingAidEnabled;
+ String value = SystemProperties.get(FeatureFlagUtils.PERSIST_PREFIX + FeatureFlagUtils.HEARING_AID_SETTINGS);
+ if (!TextUtils.isEmpty(value)) {
+ isHearingAidEnabled = Boolean.parseBoolean(value);
+ Log.v(TAG, "set feature flag HEARING_AID_SETTINGS to " + isHearingAidEnabled);
+ FeatureFlagUtils.setEnabled(context, FeatureFlagUtils.HEARING_AID_SETTINGS, isHearingAidEnabled);
+ }
+
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
filter.addAction(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 3c94a34..2054e0a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2229,6 +2229,7 @@
updateCapabilities(oldScore, nai, nai.networkCapabilities);
// If score has changed, rebroadcast to NetworkFactories. b/17726566
if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai);
+ if (valid) handleFreshlyValidatedNetwork(nai);
}
updateInetCondition(nai);
// Let the NetworkAgent know the state of its network
@@ -2323,6 +2324,16 @@
mDefaultRequest.networkCapabilities, nai.networkCapabilities);
}
+ private void handleFreshlyValidatedNetwork(NetworkAgentInfo nai) {
+ if (nai == null) return;
+ // If the Private DNS mode is opportunistic, reprogram the DNS servers
+ // in order to restart a validation pass from within netd.
+ final PrivateDnsConfig cfg = mDnsManager.getPrivateDnsConfig();
+ if (cfg.useTls && TextUtils.isEmpty(cfg.hostname)) {
+ updateDnses(nai.linkProperties, null, nai.network.netId);
+ }
+ }
+
private void handlePrivateDnsSettingsChanged() {
final PrivateDnsConfig cfg = mDnsManager.getPrivateDnsConfig();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cc3d73f..456b676 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -581,8 +581,6 @@
// Whether we should use SCHED_FIFO for UI and RenderThreads.
private boolean mUseFifoUiScheduling = false;
- private static final String SYSUI_COMPONENT_NAME = "com.android.systemui/.SystemUIService";
-
BroadcastQueue mFgBroadcastQueue;
BroadcastQueue mBgBroadcastQueue;
// Convenient for easy iteration over the queues. Foreground is first
@@ -639,7 +637,7 @@
boolean asProto) {
if (asProto) return;
doDump(fd, pw, new String[]{"activities"}, asProto);
- doDump(fd, pw, new String[]{"service", SYSUI_COMPONENT_NAME}, asProto);
+ doDump(fd, pw, new String[]{"service", "all-platform-critical"}, asProto);
}
@Override
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index b9a279a..21ae048 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -31,8 +31,6 @@
import android.os.PowerManager;
import android.os.SystemProperties;
import android.os.Trace;
-import android.text.TextUtils;
-import android.util.PathParser;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
@@ -404,8 +402,8 @@
&& SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) {
mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND;
}
- mInfo.displayCutout = DisplayCutout.fromResources(res, mInfo.width,
- mInfo.height);
+ mInfo.displayCutout = DisplayCutout.fromResourcesRectApproximation(res,
+ mInfo.width, mInfo.height);
mInfo.type = Display.TYPE_BUILT_IN;
mInfo.densityDpi = (int)(phys.density * 160 + 0.5f);
mInfo.xDpi = phys.xDpi;
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 75b9f13..1ab05ec 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -443,6 +443,8 @@
pw.println(prefix + "fullscreenIntent=" + notification.fullScreenIntent);
pw.println(prefix + "contentIntent=" + notification.contentIntent);
pw.println(prefix + "deleteIntent=" + notification.deleteIntent);
+ pw.println(prefix + "number=" + notification.number);
+ pw.println(prefix + "groupAlertBehavior=" + notification.getGroupAlertBehavior());
pw.print(prefix + "tickerText=");
if (!TextUtils.isEmpty(notification.tickerText)) {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 24fd331..669d556 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -1182,11 +1182,8 @@
}
private void showZenUpgradeNotification(int zen) {
- final boolean isWatch = mContext.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_WATCH);
final boolean showNotification = mIsBootComplete
&& zen != Global.ZEN_MODE_OFF
- && !isWatch
&& Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 0) != 0;
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index dd6d71e..4c88bf4 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -72,7 +72,7 @@
@GuardedBy("mLock")
private int mBatteryLevel;
- /** Whether the battery level is considered to be "low" or not.*/
+ /** Whether the battery level is considered to be "low" or not. */
@GuardedBy("mLock")
private boolean mIsBatteryLevelLow;
@@ -84,6 +84,9 @@
@GuardedBy("mLock")
private boolean mSettingBatterySaverEnabledSticky;
+ /** Config flag to track if battery saver's sticky behaviour is disabled. */
+ private final boolean mBatterySaverStickyBehaviourDisabled;
+
/**
* Previously known value of Global.LOW_POWER_MODE_TRIGGER_LEVEL.
* (Currently only used in dumpsys.)
@@ -124,6 +127,9 @@
mLock = lock;
mContext = context;
mBatterySaverController = batterySaverController;
+
+ mBatterySaverStickyBehaviourDisabled = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled);
}
private boolean isBatterySaverEnabled() {
@@ -304,7 +310,7 @@
BatterySaverController.REASON_PLUGGED_IN,
"Plugged in");
- } else if (mSettingBatterySaverEnabledSticky) {
+ } else if (mSettingBatterySaverEnabledSticky && !mBatterySaverStickyBehaviourDisabled) {
// Re-enable BS.
enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ true,
BatterySaverController.REASON_STICKY_RESTORE,
@@ -383,8 +389,9 @@
putGlobalSetting(Global.LOW_POWER_MODE, enable ? 1 : 0);
if (manual) {
- mSettingBatterySaverEnabledSticky = enable;
- putGlobalSetting(Global.LOW_POWER_MODE_STICKY, enable ? 1 : 0);
+ mSettingBatterySaverEnabledSticky = !mBatterySaverStickyBehaviourDisabled && enable;
+ putGlobalSetting(Global.LOW_POWER_MODE_STICKY,
+ mSettingBatterySaverEnabledSticky ? 1 : 0);
}
mBatterySaverController.enableBatterySaver(enable, intReason);
@@ -449,6 +456,8 @@
pw.println(mSettingBatterySaverEnabledSticky);
pw.print(" mSettingBatterySaverTriggerThreshold=");
pw.println(mSettingBatterySaverTriggerThreshold);
+ pw.print(" mBatterySaverStickyBehaviourDisabled=");
+ pw.println(mBatterySaverStickyBehaviourDisabled);
}
}
diff --git a/services/core/java/com/android/server/slice/PinnedSliceState.java b/services/core/java/com/android/server/slice/PinnedSliceState.java
index 4e7fb96..e139ab8 100644
--- a/services/core/java/com/android/server/slice/PinnedSliceState.java
+++ b/services/core/java/com/android/server/slice/PinnedSliceState.java
@@ -154,8 +154,8 @@
}
ContentProviderClient getClient() {
- ContentProviderClient client =
- mService.getContext().getContentResolver().acquireContentProviderClient(mUri);
+ ContentProviderClient client = mService.getContext().getContentResolver()
+ .acquireUnstableContentProviderClient(mUri);
if (client == null) return null;
client.setDetectNotResponding(SLICE_TIMEOUT);
return client;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index f74216a..0ca8e1a 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1249,11 +1249,21 @@
cutout, mInitialDisplayWidth, mInitialDisplayHeight);
}
final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
- final Path bounds = cutout.getBounds().getBoundaryPath();
+ final List<Rect> bounds = WmDisplayCutout.computeSafeInsets(
+ cutout, mInitialDisplayWidth, mInitialDisplayHeight)
+ .getDisplayCutout().getBoundingRects();
transformPhysicalToLogicalCoordinates(rotation, mInitialDisplayWidth, mInitialDisplayHeight,
mTmpMatrix);
- bounds.transform(mTmpMatrix);
- return WmDisplayCutout.computeSafeInsets(DisplayCutout.fromBounds(bounds),
+ final Region region = Region.obtain();
+ for (int i = 0; i < bounds.size(); i++) {
+ final Rect rect = bounds.get(i);
+ final RectF rectF = new RectF(bounds.get(i));
+ mTmpMatrix.mapRect(rectF);
+ rectF.round(rect);
+ region.op(rect, Op.UNION);
+ }
+
+ return WmDisplayCutout.computeSafeInsets(DisplayCutout.fromBounds(region),
rotated ? mInitialDisplayHeight : mInitialDisplayWidth,
rotated ? mInitialDisplayWidth : mInitialDisplayHeight);
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 281e0a8..a626663 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -40,6 +40,7 @@
import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
+import android.os.Trace;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
@@ -620,6 +621,8 @@
private void updateInputWindows(boolean inDrag) {
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "updateInputWindows");
+
// TODO: multi-display
navInputConsumer = getInputConsumer(INPUT_CONSUMER_NAVIGATION, DEFAULT_DISPLAY);
pipInputConsumer = getInputConsumer(INPUT_CONSUMER_PIP, DEFAULT_DISPLAY);
@@ -645,6 +648,8 @@
mService.mInputManager.setInputWindows(mInputWindowHandles, mFocusedInputWindowHandle);
clearInputWindowHandlesLw();
+
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 399078a..54703b3 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2180,8 +2180,6 @@
result |= mInTouchMode ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0;
- mInputMonitor.updateInputWindowsLw(true /*force*/);
-
if (DEBUG_LAYOUT) {
Slog.v(TAG_WM, "Relayout complete " + win + ": outFrame=" + outFrame.toShortString());
}
@@ -5666,9 +5664,9 @@
boolean imWindowChanged = false;
if (mInputMethodWindow != null) {
final WindowState prevTarget = mInputMethodTarget;
+
final WindowState newTarget =
displayContent.computeImeTarget(true /* updateImeTarget*/);
-
imWindowChanged = prevTarget != newTarget;
if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityOptionsTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityOptionsTest.java
new file mode 100644
index 0000000..28b37c5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityOptionsTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2018 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.am;
+
+import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
+import static org.junit.Assert.assertEquals;
+
+import android.app.ActivityOptions;
+import android.os.Bundle;
+import android.os.Debug;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.FlakyTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * atest FrameworksServicesTests:ActivityOptionsTest
+ */
+@MediumTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ActivityOptionsTest {
+
+ @Test
+ public void testMerge_NoClobber() {
+ // Construct some options with set values
+ ActivityOptions opts = ActivityOptions.makeBasic();
+ opts.setLaunchDisplayId(Integer.MAX_VALUE);
+ opts.setLaunchActivityType(ACTIVITY_TYPE_STANDARD);
+ opts.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ opts.setAvoidMoveToFront();
+ opts.setLaunchTaskId(Integer.MAX_VALUE);
+ opts.setLockTaskEnabled(true);
+ opts.setRotationAnimationHint(ROTATION_ANIMATION_ROTATE);
+ opts.setTaskOverlay(true, true);
+ opts.setSplitScreenCreateMode(SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT);
+ Bundle optsBundle = opts.toBundle();
+
+ // Try and merge the constructed options with a new set of options
+ optsBundle.putAll(ActivityOptions.makeBasic().toBundle());
+
+ // Ensure the set values are not clobbered
+ ActivityOptions restoredOpts = ActivityOptions.fromBundle(optsBundle);
+ assertEquals(Integer.MAX_VALUE, restoredOpts.getLaunchDisplayId());
+ assertEquals(ACTIVITY_TYPE_STANDARD, restoredOpts.getLaunchActivityType());
+ assertEquals(WINDOWING_MODE_FULLSCREEN, restoredOpts.getLaunchWindowingMode());
+ assertEquals(true, restoredOpts.getAvoidMoveToFront());
+ assertEquals(Integer.MAX_VALUE, restoredOpts.getLaunchTaskId());
+ assertEquals(true, restoredOpts.getLockTaskMode());
+ assertEquals(ROTATION_ANIMATION_ROTATE, restoredOpts.getRotationAnimationHint());
+ assertEquals(true, restoredOpts.getTaskOverlay());
+ assertEquals(true, restoredOpts.canTaskOverlayResume());
+ assertEquals(SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT,
+ restoredOpts.getSplitScreenCreateMode());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
index 2c47a94..1d37802 100644
--- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
@@ -37,6 +37,7 @@
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.os.IBinder;
import android.os.UserHandle;
import android.support.test.InstrumentationRegistry;
@@ -172,15 +173,14 @@
}
private static DisplayCutout displayCutoutForRotation(int rotation) {
- Path p = new Path();
- p.addRect(DISPLAY_WIDTH / 4, 0, DISPLAY_WIDTH * 3 / 4, DISPLAY_CUTOUT_HEIGHT,
- Path.Direction.CCW);
+ RectF rectF = new RectF(DISPLAY_WIDTH / 4, 0, DISPLAY_WIDTH * 3 / 4, DISPLAY_CUTOUT_HEIGHT);
Matrix m = new Matrix();
transformPhysicalToLogicalCoordinates(rotation, DISPLAY_WIDTH, DISPLAY_HEIGHT, m);
- p.transform(m);
+ m.mapRect(rectF);
- return DisplayCutout.fromBounds(p);
+ return DisplayCutout.fromBoundingRect((int) rectF.left, (int) rectF.top,
+ (int) rectF.right, (int) rectF.bottom);
}
static class TestContextWrapper extends ContextWrapper {
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
index 5b24725..0764a56 100644
--- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
@@ -23,6 +23,7 @@
import static org.mockito.Mockito.when;
import android.content.ContentResolver;
+import android.content.res.Resources;
import android.provider.Settings.Global;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -48,12 +49,18 @@
private BatterySaverController mMockBatterySaverController;
private Device mDevice;
private TestableBatterySaverStateMachine mTarget;
+ private Resources mMockResources;
private class MyMockContext extends MockContext {
@Override
public ContentResolver getContentResolver() {
return mMockContextResolver;
}
+
+ @Override
+ public Resources getResources() {
+ return mMockResources;
+ }
}
private DevicePersistedState mPersistedState;
@@ -157,11 +164,15 @@
mMockContext = new MyMockContext();
mMockContextResolver = mock(ContentResolver.class);
mMockBatterySaverController = mock(BatterySaverController.class);
+ mMockResources = mock(Resources.class);
doAnswer((inv) -> mDevice.batterySaverEnabled = inv.getArgument(0))
.when(mMockBatterySaverController).enableBatterySaver(anyBoolean(), anyInt());
when(mMockBatterySaverController.isEnabled())
.thenAnswer((inv) -> mDevice.batterySaverEnabled);
+ when(mMockResources.getBoolean(
+ com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled))
+ .thenReturn(false);
mPersistedState = new DevicePersistedState();
initDevice();
@@ -173,7 +184,6 @@
mTarget = new TestableBatterySaverStateMachine();
mDevice.pushBatteryStatus();
- mDevice.pushGlobalSettings();
mTarget.onBootCompleted();
}
@@ -498,8 +508,83 @@
}
@Test
- public void testNoAutoBatterySaver_fromAdb() {
+ public void testAutoBatterySaver_withStickyDisabled() {
+ when(mMockResources.getBoolean(
+ com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled))
+ .thenReturn(true);
+ initDevice();
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+ mTarget.setBatterySaverEnabledManually(true);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(100, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ mDevice.setBatteryLevel(30);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(30, mPersistedState.batteryLevel);
+ assertEquals(true, mPersistedState.batteryLow);
+
+ mDevice.setBatteryLevel(80);
+
+ assertEquals(false, mDevice.batterySaverEnabled); // Not sticky.
+ assertEquals(80, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ mDevice.setPowered(true);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(80, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ mDevice.setBatteryLevel(30);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(30, mPersistedState.batteryLevel);
+ assertEquals(true, mPersistedState.batteryLow);
+
+ mDevice.setPowered(false);
+
+ assertEquals(true, mDevice.batterySaverEnabled); // Restores BS.
+ assertEquals(30, mPersistedState.batteryLevel);
+ assertEquals(true, mPersistedState.batteryLow);
+
+ mDevice.setPowered(true);
+ mDevice.setBatteryLevel(90);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(90, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ initDevice();
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(90, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ mDevice.setPowered(false);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(90, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ mTarget.setBatterySaverEnabledManually(false);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(90, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ initDevice();
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(90, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+ }
+
+ @Test
+ public void testNoAutoBatterySaver_fromAdb() {
assertEquals(0, mDevice.getLowPowerModeTriggerLevel());
assertEquals(false, mDevice.batterySaverEnabled);
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
index 3c4e333..82e0fbe 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
@@ -1,16 +1,16 @@
package com.android.server.slice;
+import static android.testing.TestableContentResolver.UNSTABLE;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -71,11 +71,12 @@
mSliceService = mock(SliceManagerService.class);
when(mSliceService.getContext()).thenReturn(mContext);
when(mSliceService.getLock()).thenReturn(new Object());
- when(mSliceService.getHandler()).thenReturn(new Handler(TestableLooper.get(this).getLooper()));
+ when(mSliceService.getHandler()).thenReturn(
+ new Handler(TestableLooper.get(this).getLooper()));
mContentProvider = mock(ContentProvider.class);
mIContentProvider = mock(IContentProvider.class);
when(mContentProvider.getIContentProvider()).thenReturn(mIContentProvider);
- mContext.getContentResolver().addProvider(AUTH, mContentProvider);
+ mContext.getContentResolver().addProvider(AUTH, mContentProvider, UNSTABLE);
mPinnedSliceManager = new PinnedSliceState(mSliceService, TEST_URI, "pkg");
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 7e86966..2b6928e 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -121,6 +121,8 @@
/**
* Get reference signal received quality
+ *
+ * @return the RSRQ if available or Integer.MAX_VALUE if unavailable.
*/
public int getRsrq() {
return mRsrq;
@@ -128,13 +130,17 @@
/**
* Get reference signal signal-to-noise ratio
+ *
+ * @return the RSSNR if available or Integer.MAX_VALUE if unavailable.
*/
public int getRssnr() {
return mRssnr;
}
/**
- * Get reference signal received power
+ * Get reference signal received power in dBm
+ *
+ * @return the RSRP of the measured cell.
*/
public int getRsrp() {
return mRsrp;
@@ -142,13 +148,17 @@
/**
* Get channel quality indicator
+ *
+ * @return the CQI if available or Integer.MAX_VALUE if unavailable.
*/
public int getCqi() {
return mCqi;
}
/**
- * Get signal strength as dBm
+ * Get signal strength in dBm
+ *
+ * @return the RSRP of the measured cell.
*/
@Override
public int getDbm() {
@@ -175,7 +185,8 @@
* Get the timing advance value for LTE, as a value in range of 0..1282.
* Integer.MAX_VALUE is reported when there is no active RRC
* connection. Refer to 3GPP 36.213 Sec 4.2.3
- * @return the LTE timing advance, if available.
+ *
+ * @return the LTE timing advance if available or Integer.MAX_VALUE if unavailable.
*/
public int getTimingAdvance() {
return mTimingAdvance;
diff --git a/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java b/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java
index b763c78..b4b5ca7 100644
--- a/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java
+++ b/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java
@@ -30,6 +30,7 @@
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
+import android.os.Trace;
import java.util.ArrayList;
import java.util.Collections;
@@ -42,6 +43,7 @@
public TouchLatencyView(Context context, AttributeSet attrs) {
super(context, attrs);
+ Trace.beginSection("TouchLatencyView constructor");
setOnTouchListener(this);
setWillNotDraw(false);
mBluePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -63,48 +65,56 @@
mBallY = 100.0f;
mVelocityX = 7.0f;
mVelocityY = 7.0f;
+ Trace.endSection();
}
@Override
public boolean onTouch(View view, MotionEvent event) {
+ Trace.beginSection("TouchLatencyView onTouch");
int action = event.getActionMasked();
if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE) {
mTouching = true;
invalidate();
+
+ mTouchX = event.getX();
+ mTouchY = event.getY();
} else if (action == MotionEvent.ACTION_UP) {
mTouching = false;
invalidate();
- return true;
- } else {
- return true;
}
- mTouchX = event.getX();
- mTouchY = event.getY();
+ Trace.endSection();
return true;
}
private void drawTouch(Canvas canvas) {
- if (!mTouching) {
- Log.d(LOG_TAG, "Filling background");
+ Trace.beginSection("TouchLatencyView drawTouch");
+
+ try {
+ if (!mTouching) {
+ Log.d(LOG_TAG, "Filling background");
+ canvas.drawColor(BACKGROUND_COLOR);
+ return;
+ }
+
+ float deltaX = (mTouchX - mLastDrawnX);
+ float deltaY = (mTouchY - mLastDrawnY);
+ float scaleFactor = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY) * 1.5f;
+
+ mLastDrawnX = mTouchX;
+ mLastDrawnY = mTouchY;
+
canvas.drawColor(BACKGROUND_COLOR);
- return;
+ canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + 3 * scaleFactor, mRedPaint);
+ canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + 2 * scaleFactor, mYellowPaint);
+ canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + scaleFactor, mGreenPaint);
+ canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS, mBluePaint);
+ } finally {
+ Trace.endSection();
}
-
- float deltaX = (mTouchX - mLastDrawnX);
- float deltaY = (mTouchY - mLastDrawnY);
- float scaleFactor = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY) * 1.5f;
-
- mLastDrawnX = mTouchX;
- mLastDrawnY = mTouchY;
-
- canvas.drawColor(BACKGROUND_COLOR);
- canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + 3 * scaleFactor, mRedPaint);
- canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + 2 * scaleFactor, mYellowPaint);
- canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + scaleFactor, mGreenPaint);
- canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS, mBluePaint);
}
private void drawBall(Canvas canvas) {
+ Trace.beginSection("TouchLatencyView drawBall");
int width = canvas.getWidth();
int height = canvas.getHeight();
@@ -141,25 +151,29 @@
canvas.drawColor(BACKGROUND_COLOR);
canvas.drawOval(left, top, right, bottom, mYellowPaint);
invalidate();
+ Trace.endSection();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
-
+ Trace.beginSection("TouchLatencyView onDraw");
if (mMode == 0) {
drawTouch(canvas);
} else {
drawBall(canvas);
}
+ Trace.endSection();
}
public void changeMode(MenuItem item) {
+ Trace.beginSection("TouchLatencyView changeMode");
final int NUM_MODES = 2;
final String modes[] = {"Touch", "Ball"};
mMode = (mMode + 1) % NUM_MODES;
invalidate();
item.setTitle(modes[mMode]);
+ Trace.endSection();
}
private Paint mBluePaint, mGreenPaint, mYellowPaint, mRedPaint;
@@ -178,21 +192,26 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ Trace.beginSection("TouchLatencyActivity onCreate");
setContentView(R.layout.activity_touch_latency);
mTouchView = findViewById(R.id.canvasView);
+ Trace.endSection();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
+ Trace.beginSection("TouchLatencyActivity onCreateOptionsMenu");
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_touch_latency, menu);
+ Trace.endSection();
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
+ Trace.beginSection("TouchLatencyActivity onOptionsItemSelected");
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
@@ -203,6 +222,7 @@
mTouchView.changeMode(item);
}
+ Trace.endSection();
return super.onOptionsItemSelected(item);
}
diff --git a/tests/testables/src/android/testing/TestableContentResolver.java b/tests/testables/src/android/testing/TestableContentResolver.java
index 0850916..a0afef8 100644
--- a/tests/testables/src/android/testing/TestableContentResolver.java
+++ b/tests/testables/src/android/testing/TestableContentResolver.java
@@ -20,6 +20,7 @@
import android.content.IContentProvider;
import android.database.ContentObserver;
import android.net.Uri;
+import android.util.ArrayMap;
import android.util.ArraySet;
import com.google.android.collect.Maps;
@@ -35,7 +36,11 @@
*/
public class TestableContentResolver extends ContentResolver {
- private final Map<String, ContentProvider> mProviders = Maps.newHashMap();
+ public static final int STABLE = 1;
+ public static final int UNSTABLE = 2;
+
+ private final Map<String, ContentProvider> mProviders = new ArrayMap<>();
+ private final Map<String, ContentProvider> mUnstableProviders = new ArrayMap<>();
private final ContentResolver mParent;
private final ArraySet<ContentProvider> mInUse = new ArraySet<>();
private boolean mFallbackToExisting;
@@ -62,7 +67,23 @@
* subclasses, or null.
*/
public void addProvider(String name, ContentProvider provider) {
- mProviders.put(name, provider);
+ addProvider(name, provider, STABLE | UNSTABLE);
+ }
+
+ /**
+ * Adds access to a provider based on its authority
+ *
+ * @param name The authority name associated with the provider.
+ * @param provider An instance of {@link android.content.ContentProvider} or one of its
+ * subclasses, or null.
+ */
+ public void addProvider(String name, ContentProvider provider, int flags) {
+ if ((flags & STABLE) != 0) {
+ mProviders.put(name, provider);
+ }
+ if ((flags & UNSTABLE) != 0) {
+ mUnstableProviders.put(name, provider);
+ }
}
@Override
@@ -98,7 +119,7 @@
@Override
protected IContentProvider acquireUnstableProvider(Context c, String name) {
- final ContentProvider provider = mProviders.get(name);
+ final ContentProvider provider = mUnstableProviders.get(name);
if (provider != null) {
return provider.getIContentProvider();
} else {
@@ -128,7 +149,8 @@
@Override
public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
if (!mFallbackToExisting) return;
- if (!mProviders.containsKey(uri.getAuthority())) {
+ if (!mProviders.containsKey(uri.getAuthority())
+ && !mUnstableProviders.containsKey(uri.getAuthority())) {
super.notifyChange(uri, observer, syncToNetwork);
}
}
diff --git a/tests/testables/tests/src/android/testing/TestableContentResolverTest.java b/tests/testables/tests/src/android/testing/TestableContentResolverTest.java
new file mode 100644
index 0000000..71afda0
--- /dev/null
+++ b/tests/testables/tests/src/android/testing/TestableContentResolverTest.java
@@ -0,0 +1,61 @@
+package android.testing;
+
+import android.content.ContentProvider;
+import android.content.IContentProvider;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class TestableContentResolverTest {
+
+ @Rule
+ public TestableContext mContext = new TestableContext(InstrumentationRegistry.getContext());
+ private TestableContentResolver mContentResolver;
+
+ @Before
+ public void setup() {
+ mContentResolver = new TestableContentResolver(mContext);
+ mContentResolver.setFallbackToExisting(false);
+ }
+
+ @Test
+ public void testDefaultContentProvider() {
+ ContentProvider provider = Mockito.mock(ContentProvider.class);
+ IContentProvider iprovider = Mockito.mock(IContentProvider.class);
+ Mockito.when(provider.getIContentProvider()).thenReturn(iprovider);
+ mContentResolver.addProvider("test", provider);
+
+ Assert.assertEquals(iprovider, mContentResolver.acquireProvider(mContext, "test"));
+ Assert.assertEquals(iprovider, mContentResolver.acquireUnstableProvider(mContext, "test"));
+ }
+
+ @Test
+ public void testStableContentProvider() {
+ ContentProvider provider = Mockito.mock(ContentProvider.class);
+ IContentProvider iprovider = Mockito.mock(IContentProvider.class);
+ Mockito.when(provider.getIContentProvider()).thenReturn(iprovider);
+ mContentResolver.addProvider("test", provider, TestableContentResolver.STABLE);
+
+ Assert.assertEquals(iprovider, mContentResolver.acquireProvider(mContext, "test"));
+ Assert.assertNull(mContentResolver.acquireUnstableProvider(mContext, "test"));
+ }
+
+ @Test
+ public void testUnstableContentProvider() {
+ ContentProvider provider = Mockito.mock(ContentProvider.class);
+ IContentProvider iprovider = Mockito.mock(IContentProvider.class);
+ Mockito.when(provider.getIContentProvider()).thenReturn(iprovider);
+ mContentResolver.addProvider("test", provider, TestableContentResolver.UNSTABLE);
+
+ Assert.assertEquals(iprovider, mContentResolver.acquireUnstableProvider(mContext, "test"));
+ Assert.assertNull(mContentResolver.acquireProvider(mContext, "test"));
+ }
+}
diff --git a/tools/aapt2/StringPool.cpp b/tools/aapt2/StringPool.cpp
index b37e1fb..8eabd32 100644
--- a/tools/aapt2/StringPool.cpp
+++ b/tools/aapt2/StringPool.cpp
@@ -367,7 +367,7 @@
static bool EncodeString(const std::string& str, const bool utf8, BigBuffer* out,
IDiagnostics* diag) {
if (utf8) {
- const std::string& encoded = str;
+ const std::string& encoded = util::Utf8ToModifiedUtf8(str);
const ssize_t utf16_length = utf8_to_utf16_length(
reinterpret_cast<const uint8_t*>(encoded.data()), encoded.size());
CHECK(utf16_length >= 0);
diff --git a/tools/aapt2/StringPool_test.cpp b/tools/aapt2/StringPool_test.cpp
index 4b3afe2..0778564 100644
--- a/tools/aapt2/StringPool_test.cpp
+++ b/tools/aapt2/StringPool_test.cpp
@@ -303,6 +303,25 @@
}
}
+TEST(StringPoolTest, FlattenModifiedUTF8) {
+ using namespace android; // For NO_ERROR on Windows.
+ StdErrDiagnostics diag;
+ StringPool pool;
+ StringPool::Ref ref_a = pool.MakeRef("\xF0\x90\x90\x80"); // 𐐀 (U+10400)
+ StringPool::Ref ref_b = pool.MakeRef("foo \xF0\x90\x90\xB7 bar"); // 𐐷 (U+10437)
+ StringPool::Ref ref_c = pool.MakeRef("\xF0\x90\x90\x80\xF0\x90\x90\xB7");
+
+ BigBuffer buffer(1024);
+ StringPool::FlattenUtf8(&buffer, pool, &diag);
+ std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
+
+ // Check that the 4 byte utf-8 codepoint is encoded using 2 3 byte surrogate pairs
+ ResStringPool test;
+ ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR);
+ EXPECT_THAT(util::GetString(test, 0), Eq("\xED\xA0\x81\xED\xB0\x80"));
+ EXPECT_THAT(util::GetString(test, 1), Eq("foo \xED\xA0\x81\xED\xB0\xB7 bar"));
+ EXPECT_THAT(util::GetString(test, 2), Eq("\xED\xA0\x81\xED\xB0\x80\xED\xA0\x81\xED\xB0\xB7"));
+}
TEST(StringPoolTest, MaxEncodingLength) {
StdErrDiagnostics diag;
diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp
index d1c9ca1..9bef54e5 100644
--- a/tools/aapt2/util/Util.cpp
+++ b/tools/aapt2/util/Util.cpp
@@ -297,6 +297,53 @@
return true;
}
+std::string Utf8ToModifiedUtf8(const std::string& utf8) {
+ // Java uses Modified UTF-8 which only supports the 1, 2, and 3 byte formats of UTF-8. To encode
+ // 4 byte UTF-8 codepoints, Modified UTF-8 allows the use of surrogate pairs in the same format
+ // of CESU-8 surrogate pairs. Calculate the size of the utf8 string with all 4 byte UTF-8
+ // codepoints replaced with 2 3 byte surrogate pairs
+ size_t modified_size = 0;
+ const size_t size = utf8.size();
+ for (size_t i = 0; i < size; i++) {
+ if (((uint8_t) utf8[i] >> 4) == 0xF) {
+ modified_size += 6;
+ i += 3;
+ } else {
+ modified_size++;
+ }
+ }
+
+ // Early out if no 4 byte codepoints are found
+ if (size == modified_size) {
+ return utf8;
+ }
+
+ std::string output;
+ output.reserve(modified_size);
+ for (size_t i = 0; i < size; i++) {
+ if (((uint8_t) utf8[i] >> 4) == 0xF) {
+ auto codepoint = (char32_t) utf32_from_utf8_at(utf8.data(), size, i, nullptr);
+
+ // Calculate the high and low surrogates as UTF-16 would
+ char32_t high = ((codepoint - 0x10000) / 0x400) + 0xD800;
+ char32_t low = ((codepoint - 0x10000) % 0x400) + 0xDC00;
+
+ // Encode each surrogate in UTF-8
+ output.push_back((char) (0xE4 | ((high >> 12) & 0xF)));
+ output.push_back((char) (0x80 | ((high >> 6) & 0x3F)));
+ output.push_back((char) (0x80 | (high & 0x3F)));
+ output.push_back((char) (0xE4 | ((low >> 12) & 0xF)));
+ output.push_back((char) (0x80 | ((low >> 6) & 0x3F)));
+ output.push_back((char) (0x80 | (low & 0x3F)));
+ i += 3;
+ } else {
+ output.push_back(utf8[i]);
+ }
+ }
+
+ return output;
+}
+
std::u16string Utf8ToUtf16(const StringPiece& utf8) {
ssize_t utf16_length = utf8_to_utf16_length(
reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length());
diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h
index 0eb35d1..36b7333 100644
--- a/tools/aapt2/util/Util.h
+++ b/tools/aapt2/util/Util.h
@@ -197,6 +197,9 @@
return error_.empty();
}
+// Converts a UTF8 string into Modified UTF8
+std::string Utf8ToModifiedUtf8(const std::string& utf8);
+
// Converts a UTF8 string to a UTF16 string.
std::u16string Utf8ToUtf16(const android::StringPiece& utf8);
std::string Utf16ToUtf8(const android::StringPiece16& utf16);