Merge "fix return behavior of deleteKeyphraseSoundModel"
diff --git a/Android.bp b/Android.bp
index afdd832..1f17932 100644
--- a/Android.bp
+++ b/Android.bp
@@ -482,6 +482,7 @@
"android.hardware.thermal-V2.0-java",
"android.hardware.tv.input-V1.0-java-constants",
"android.hardware.tv.tuner-V1.0-java-constants",
+ "android.hardware.tv.tuner-V1.1-java-constants",
"android.hardware.usb-V1.0-java-constants",
"android.hardware.usb-V1.1-java-constants",
"android.hardware.usb-V1.2-java-constants",
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 4aab65e..8ac9842 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -70,6 +70,7 @@
"android.hardware.thermal-V2.0-java",
"android.hardware.tv.input-V1.0-java-constants",
"android.hardware.tv.tuner-V1.0-java-constants",
+ "android.hardware.tv.tuner-V1.1-java-constants",
"android.hardware.usb-V1.0-java-constants",
"android.hardware.usb-V1.1-java-constants",
"android.hardware.usb.gadget-V1.0-java",
@@ -121,7 +122,6 @@
droidstubs {
name: "api-stubs-docs",
defaults: ["metalava-full-api-stubs-default"],
- removed_dex_api_filename: "removed-dex.txt",
arg_files: [
"core/res/AndroidManifest.xml",
],
@@ -142,7 +142,6 @@
baseline_file: "api/lint-baseline.txt",
},
},
- jdiff_enabled: true,
}
droidstubs {
@@ -183,7 +182,6 @@
droidstubs {
name: "system-api-stubs-docs",
defaults: ["metalava-full-api-stubs-default"],
- removed_dex_api_filename: "system-removed-dex.txt",
arg_files: [
"core/res/AndroidManifest.xml",
],
@@ -204,7 +202,6 @@
baseline_file: "api/system-lint-baseline.txt",
},
},
- jdiff_enabled: true,
}
droidstubs {
@@ -236,7 +233,11 @@
arg_files: [
"core/res/AndroidManifest.xml",
],
- args: metalava_framework_docs_args + " --show-annotation android.annotation.TestApi",
+ args: metalava_framework_docs_args
+ + " --show-annotation android.annotation.TestApi"
+ + " --show-for-stub-purposes-annotation android.annotation.SystemApi\\("
+ + "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS"
+ + "\\)",
check_api: {
current: {
api_file: "api/test-current.txt",
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
index ecd1499..1be68f5 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
@@ -135,7 +135,6 @@
final int mHeight;
final Point mOutSurfaceSize = new Point();
final SurfaceControl mOutSurfaceControl;
- final SurfaceControl mOutBlastSurfaceControl = new SurfaceControl();
final IntSupplier mViewVisibility;
@@ -158,7 +157,7 @@
session.relayout(mWindow, mParams, mWidth, mHeight,
mViewVisibility.getAsInt(), mFlags, mFrameNumber, mOutFrames,
mOutMergedConfiguration, mOutSurfaceControl, mOutInsetsState, mOutControls,
- mOutSurfaceSize, mOutBlastSurfaceControl);
+ mOutSurfaceSize);
}
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 1a81587..81f22fe 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -2179,7 +2179,7 @@
if (getContext().getResources().getBoolean(
com.android.internal.R.bool.config_autoPowerModePrefetchLocation)) {
mLocationRequest = new LocationRequest.Builder(/*intervalMillis=*/ 0)
- .setQuality(LocationRequest.ACCURACY_FINE)
+ .setQuality(LocationRequest.QUALITY_HIGH_ACCURACY)
.setMaxUpdates(1)
.build();
}
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
index f672e4b..45ea233 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
@@ -16,10 +16,13 @@
package com.android.server.alarm;
+import static android.app.AlarmManager.ELAPSED_REALTIME;
import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
import static android.app.AlarmManager.RTC;
import static android.app.AlarmManager.RTC_WAKEUP;
+import static com.android.server.alarm.AlarmManagerService.clampPositive;
+
import android.app.AlarmManager;
import android.app.IAlarmListener;
import android.app.PendingIntent;
@@ -32,8 +35,28 @@
import java.text.SimpleDateFormat;
import java.util.Date;
+/**
+ * Class to describe an alarm that is used to the set the kernel timer that returns when the timer
+ * expires. The timer will wake up the device if the alarm is a "wakeup" alarm.
+ */
class Alarm {
+ private static final int NUM_POLICIES = 2;
+ /**
+ * Index used to store the time the alarm was requested to expire. To be used with
+ * {@link #setPolicyElapsed(int, long)}
+ */
+ public static final int REQUESTER_POLICY_INDEX = 0;
+ /**
+ * Index used to store the earliest time the alarm can expire based on app-standby policy.
+ * To be used with {@link #setPolicyElapsed(int, long)}
+ */
+ public static final int APP_STANDBY_POLICY_INDEX = 1;
+
public final int type;
+ /**
+ * The original trigger time supplied by the caller. This can be in the elapsed or rtc time base
+ * depending on the type of this alarm
+ */
public final long origWhen;
public final boolean wakeup;
public final PendingIntent operation;
@@ -47,42 +70,40 @@
public final int creatorUid;
public final String packageName;
public final String sourcePackage;
+ public final long windowLength;
+ public final long repeatInterval;
public int count;
- public long when;
- public long windowLength;
- public long whenElapsed; // 'when' in the elapsed time base
- public long maxWhenElapsed; // also in the elapsed time base
- // Expected alarm expiry time before app standby deferring is applied.
- public long expectedWhenElapsed;
- public long expectedMaxWhenElapsed;
- public long repeatInterval;
+ /** The earliest time this alarm is eligible to fire according to each policy */
+ private long[] mPolicyWhenElapsed;
+ /** The ultimate delivery time to be used for this alarm */
+ private long mWhenElapsed;
+ private long mMaxWhenElapsed;
public AlarmManagerService.PriorityClass priorityClass;
- Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen,
- long _interval, PendingIntent _op, IAlarmListener _rec, String _listenerTag,
- WorkSource _ws, int _flags, AlarmManager.AlarmClockInfo _info,
- int _uid, String _pkgName) {
- type = _type;
- origWhen = _when;
- wakeup = _type == AlarmManager.ELAPSED_REALTIME_WAKEUP
- || _type == AlarmManager.RTC_WAKEUP;
- when = _when;
- whenElapsed = _whenElapsed;
- expectedWhenElapsed = _whenElapsed;
- windowLength = _windowLength;
- maxWhenElapsed = expectedMaxWhenElapsed = AlarmManagerService.clampPositive(_maxWhen);
- repeatInterval = _interval;
- operation = _op;
- listener = _rec;
- listenerTag = _listenerTag;
- statsTag = makeTag(_op, _listenerTag, _type);
- workSource = _ws;
- flags = _flags;
- alarmClock = _info;
- uid = _uid;
- packageName = _pkgName;
+ Alarm(int type, long when, long requestedWhenElapsed, long windowLength, long interval,
+ PendingIntent op, IAlarmListener rec, String listenerTag, WorkSource ws, int flags,
+ AlarmManager.AlarmClockInfo info, int uid, String pkgName) {
+ this.type = type;
+ origWhen = when;
+ wakeup = type == AlarmManager.ELAPSED_REALTIME_WAKEUP
+ || type == AlarmManager.RTC_WAKEUP;
+ mPolicyWhenElapsed = new long[NUM_POLICIES];
+ mPolicyWhenElapsed[REQUESTER_POLICY_INDEX] = requestedWhenElapsed;
+ mWhenElapsed = requestedWhenElapsed;
+ this.windowLength = windowLength;
+ mMaxWhenElapsed = clampPositive(requestedWhenElapsed + windowLength);
+ repeatInterval = interval;
+ operation = op;
+ listener = rec;
+ this.listenerTag = listenerTag;
+ statsTag = makeTag(op, listenerTag, type);
+ workSource = ws;
+ this.flags = flags;
+ alarmClock = info;
+ this.uid = uid;
+ packageName = pkgName;
sourcePackage = (operation != null) ? operation.getCreatorPackage() : packageName;
- creatorUid = (operation != null) ? operation.getCreatorUid() : uid;
+ creatorUid = (operation != null) ? operation.getCreatorUid() : this.uid;
}
public static String makeTag(PendingIntent pi, String tag, int type) {
@@ -91,13 +112,6 @@
return (pi != null) ? pi.getTag(alarmString) : (alarmString + tag);
}
- public AlarmManagerService.WakeupEvent makeWakeupEvent(long nowRTC) {
- return new AlarmManagerService.WakeupEvent(nowRTC, creatorUid,
- (operation != null)
- ? operation.getIntent().getAction()
- : ("<listener>:" + listenerTag));
- }
-
// Returns true if either matches
public boolean matches(PendingIntent pi, IAlarmListener rec) {
return (operation != null)
@@ -109,6 +123,65 @@
return packageName.equals(sourcePackage);
}
+ /**
+ * Get the earliest time this alarm is allowed to expire based on the given policy.
+ *
+ * @param policyIndex The index of the policy. One of [{@link #REQUESTER_POLICY_INDEX},
+ * {@link #APP_STANDBY_POLICY_INDEX}].
+ */
+ public long getPolicyElapsed(int policyIndex) {
+ return mPolicyWhenElapsed[policyIndex];
+ }
+
+ /**
+ * Get the earliest time that this alarm should be delivered to the requesting app.
+ */
+ public long getWhenElapsed() {
+ return mWhenElapsed;
+ }
+
+ /**
+ * Get the latest time that this alarm should be delivered to the requesting app. Will be equal
+ * to {@link #getWhenElapsed()} in case this is an exact alarm.
+ */
+ public long getMaxWhenElapsed() {
+ return mMaxWhenElapsed;
+ }
+
+ /**
+ * Set the earliest time this alarm can expire based on the passed policy index.
+ *
+ * @return {@code true} if this change resulted in a change in the ultimate delivery time (or
+ * time window in the case of inexact alarms) of this alarm.
+ * @see #getWhenElapsed()
+ * @see #getMaxWhenElapsed()
+ * @see #getPolicyElapsed(int)
+ */
+ public boolean setPolicyElapsed(int policyIndex, long policyElapsed) {
+ mPolicyWhenElapsed[policyIndex] = policyElapsed;
+ return updateWhenElapsed();
+ }
+
+ /**
+ * @return {@code true} if either {@link #mWhenElapsed} or {@link #mMaxWhenElapsed} changes
+ * due to this call.
+ */
+ private boolean updateWhenElapsed() {
+ final long oldWhenElapsed = mWhenElapsed;
+ mWhenElapsed = 0;
+ for (int i = 0; i < NUM_POLICIES; i++) {
+ mWhenElapsed = Math.max(mWhenElapsed, mPolicyWhenElapsed[i]);
+ }
+
+ final long oldMaxWhenElapsed = mMaxWhenElapsed;
+ // windowLength should always be >= 0 here.
+ final long maxRequestedElapsed = clampPositive(
+ mPolicyWhenElapsed[REQUESTER_POLICY_INDEX] + windowLength);
+ mMaxWhenElapsed = Math.max(maxRequestedElapsed, mWhenElapsed);
+
+ return (oldWhenElapsed != mWhenElapsed) || (oldMaxWhenElapsed != mMaxWhenElapsed);
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder(128);
@@ -116,11 +189,11 @@
sb.append(Integer.toHexString(System.identityHashCode(this)));
sb.append(" type ");
sb.append(type);
- sb.append(" when ");
- sb.append(when);
+ sb.append(" origWhen ");
+ sb.append(origWhen);
sb.append(" ");
sb.append(" whenElapsed ");
- sb.append(whenElapsed);
+ sb.append(getWhenElapsed());
sb.append(" ");
sb.append(sourcePackage);
sb.append('}');
@@ -136,30 +209,46 @@
dump(ipw, nowELAPSED, sdf);
}
+ private static String policyIndexToString(int index) {
+ switch (index) {
+ case REQUESTER_POLICY_INDEX:
+ return "requester";
+ case APP_STANDBY_POLICY_INDEX:
+ return "app_standby";
+ default:
+ return "unknown";
+ }
+ }
+
+ public static String typeToString(int type) {
+ switch (type) {
+ case RTC:
+ return "RTC";
+ case RTC_WAKEUP:
+ return "RTC_WAKEUP";
+ case ELAPSED_REALTIME:
+ return "ELAPSED";
+ case ELAPSED_REALTIME_WAKEUP:
+ return "ELAPSED_WAKEUP";
+ default:
+ return "--unknown--";
+ }
+ }
+
public void dump(IndentingPrintWriter ipw, long nowELAPSED, SimpleDateFormat sdf) {
final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
ipw.print("tag=");
ipw.println(statsTag);
ipw.print("type=");
- ipw.print(type);
- ipw.print(" expectedWhenElapsed=");
- TimeUtils.formatDuration(expectedWhenElapsed, nowELAPSED, ipw);
- ipw.print(" expectedMaxWhenElapsed=");
- TimeUtils.formatDuration(expectedMaxWhenElapsed, nowELAPSED, ipw);
- ipw.print(" whenElapsed=");
- TimeUtils.formatDuration(whenElapsed, nowELAPSED, ipw);
- ipw.print(" maxWhenElapsed=");
- TimeUtils.formatDuration(maxWhenElapsed, nowELAPSED, ipw);
- ipw.print(" when=");
+ ipw.print(typeToString(type));
+ ipw.print(" origWhen=");
if (isRtc) {
- ipw.print(sdf.format(new Date(when)));
+ ipw.print(sdf.format(new Date(origWhen)));
} else {
- TimeUtils.formatDuration(when, nowELAPSED, ipw);
+ TimeUtils.formatDuration(origWhen, nowELAPSED, ipw);
}
- ipw.println();
-
- ipw.print("window=");
+ ipw.print(" window=");
TimeUtils.formatDuration(windowLength, ipw);
ipw.print(" repeatInterval=");
ipw.print(repeatInterval);
@@ -168,6 +257,19 @@
ipw.print(" flags=0x");
ipw.println(Integer.toHexString(flags));
+ ipw.print("policyWhenElapsed:");
+ for (int i = 0; i < NUM_POLICIES; i++) {
+ ipw.print(" " + policyIndexToString(i) + "=");
+ TimeUtils.formatDuration(mPolicyWhenElapsed[i], nowELAPSED, ipw);
+ }
+ ipw.println();
+
+ ipw.print("whenElapsed=");
+ TimeUtils.formatDuration(getWhenElapsed(), nowELAPSED, ipw);
+ ipw.print(" maxWhenElapsed=");
+ TimeUtils.formatDuration(mMaxWhenElapsed, nowELAPSED, ipw);
+ ipw.println();
+
if (alarmClock != null) {
ipw.println("Alarm clock:");
@@ -177,9 +279,10 @@
ipw.print(" showIntent=");
ipw.println(alarmClock.getShowIntent());
}
- ipw.print("operation=");
- ipw.println(operation);
-
+ if (operation != null) {
+ ipw.print("operation=");
+ ipw.println(operation);
+ }
if (listener != null) {
ipw.print("listener=");
ipw.println(listener.asBinder());
@@ -191,7 +294,7 @@
proto.write(AlarmProto.TAG, statsTag);
proto.write(AlarmProto.TYPE, type);
- proto.write(AlarmProto.TIME_UNTIL_WHEN_ELAPSED_MS, whenElapsed - nowElapsed);
+ proto.write(AlarmProto.TIME_UNTIL_WHEN_ELAPSED_MS, getWhenElapsed() - nowElapsed);
proto.write(AlarmProto.WINDOW_LENGTH_MS, windowLength);
proto.write(AlarmProto.REPEAT_INTERVAL_MS, repeatInterval);
proto.write(AlarmProto.COUNT, count);
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 05910a5..82819da 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -26,6 +26,9 @@
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.os.UserHandle.USER_SYSTEM;
+import static com.android.server.alarm.Alarm.APP_STANDBY_POLICY_INDEX;
+import static com.android.server.alarm.Alarm.REQUESTER_POLICY_INDEX;
+
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.Activity;
@@ -727,9 +730,9 @@
}
// within each class, sort by nominal delivery time
- if (lhs.whenElapsed < rhs.whenElapsed) {
+ if (lhs.getWhenElapsed() < rhs.getWhenElapsed()) {
return -1;
- } else if (lhs.whenElapsed > rhs.whenElapsed) {
+ } else if (lhs.getWhenElapsed() > rhs.getWhenElapsed()) {
return 1;
}
@@ -798,9 +801,12 @@
this(context, new Injector(context));
}
+ private static boolean isRtc(int type) {
+ return (type == RTC || type == RTC_WAKEUP);
+ }
+
private long convertToElapsed(long when, int type) {
- final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
- if (isRtc) {
+ if (isRtc(type)) {
when -= mInjector.getCurrentTimeMillis() - mInjector.getElapsedRealtime();
}
return when;
@@ -823,13 +829,29 @@
}
// The RTC clock has moved arbitrarily, so we need to recalculate all the RTC alarm deliveries.
- void reevaluateRtcAlarms(final long nowElapsed) {
+ void reevaluateRtcAlarms() {
synchronized (mLock) {
- final ArrayList<Alarm> rtcAlarms = mAlarmStore.remove(a -> (a.type == RTC
- || a.type == RTC_WAKEUP));
- for (final Alarm a : rtcAlarms) {
- restoreAlarmLocked(a, nowElapsed);
- setImplLocked(a);
+ boolean changed = mAlarmStore.updateAlarmDeliveries(a -> {
+ if (!isRtc(a.type)) {
+ return false;
+ }
+ return restoreRequestedTime(a);
+ });
+
+ if (mNextWakeFromIdle != null && isRtc(mNextWakeFromIdle.type)) {
+ // The next wake from idle got updated due to the rtc time change, implying we need
+ // to update the time we have to come out of idle too.
+ changed |= mAlarmStore.updateAlarmDeliveries(a -> {
+ if (a != mPendingIdleUntil) {
+ return false;
+ }
+ return adjustIdleUntilTime(a);
+ });
+ }
+
+ if (changed) {
+ rescheduleKernelAlarmsLocked();
+ // Only time shifted, so the next alarm clock will not change
}
}
}
@@ -844,7 +866,7 @@
boolean reorderAlarmsBasedOnStandbyBuckets(ArraySet<Pair<String, Integer>> targetPackages) {
final long start = mStatLogger.getTime();
- final boolean changed = mAlarmStore.recalculateAlarmDeliveries(a -> {
+ final boolean changed = mAlarmStore.updateAlarmDeliveries(a -> {
final Pair<String, Integer> packageUser =
Pair.create(a.sourcePackage, UserHandle.getUserId(a.creatorUid));
if (targetPackages != null && !targetPackages.contains(packageUser)) {
@@ -857,23 +879,8 @@
return changed;
}
- private void restoreAlarmLocked(Alarm a, long nowElapsed) {
- a.when = a.origWhen;
- long whenElapsed = convertToElapsed(a.when, a.type);
- final long maxElapsed;
- if (a.windowLength == AlarmManager.WINDOW_EXACT) {
- // Exact
- maxElapsed = whenElapsed;
- } else {
- // Not exact. Preserve any explicit window, otherwise recalculate
- // the window based on the alarm's new futurity. Note that this
- // reflects a policy of preferring timely to deferred delivery.
- maxElapsed = (a.windowLength > 0)
- ? clampPositive(whenElapsed + a.windowLength)
- : maxTriggerTime(nowElapsed, whenElapsed, a.repeatInterval);
- }
- a.expectedWhenElapsed = a.whenElapsed = whenElapsed;
- a.expectedMaxWhenElapsed = a.maxWhenElapsed = maxElapsed;
+ private boolean restoreRequestedTime(Alarm a) {
+ return a.setPolicyElapsed(REQUESTER_POLICY_INDEX, convertToElapsed(a.origWhen, a.type));
}
static long clampPositive(long val) {
@@ -973,14 +980,17 @@
// Recurring alarms may have passed several alarm intervals while the
// alarm was kept pending. Send the appropriate trigger count.
if (alarm.repeatInterval > 0) {
- alarm.count += (nowELAPSED - alarm.expectedWhenElapsed) / alarm.repeatInterval;
+ alarm.count += (nowELAPSED - alarm.getPolicyElapsed(REQUESTER_POLICY_INDEX))
+ / alarm.repeatInterval;
// Also schedule its next recurrence
final long delta = alarm.count * alarm.repeatInterval;
- final long nextElapsed = alarm.expectedWhenElapsed + delta;
- setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength,
- maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
- alarm.repeatInterval, alarm.operation, null, null, alarm.flags,
- alarm.workSource, alarm.alarmClock, alarm.uid, alarm.packageName);
+ final long nextElapsed = alarm.getPolicyElapsed(REQUESTER_POLICY_INDEX) + delta;
+ final long nextMaxElapsed = maxTriggerTime(nowELAPSED, nextElapsed,
+ alarm.repeatInterval);
+ setImplLocked(alarm.type, alarm.origWhen + delta, nextElapsed,
+ nextMaxElapsed - nextElapsed, alarm.repeatInterval, alarm.operation, null,
+ null, alarm.flags, alarm.workSource, alarm.alarmClock, alarm.uid,
+ alarm.packageName);
// Kernel alarms will be rescheduled as needed in setImplLocked
}
}
@@ -1026,18 +1036,10 @@
if (mPendingWhileIdleAlarms.size() > 0) {
ArrayList<Alarm> alarms = mPendingWhileIdleAlarms;
mPendingWhileIdleAlarms = new ArrayList<>();
- final long nowElapsed = mInjector.getElapsedRealtime();
for (int i = alarms.size() - 1; i >= 0; i--) {
- Alarm a = alarms.get(i);
- restoreAlarmLocked(a, nowElapsed);
- setImplLocked(a);
+ setImplLocked(alarms.get(i));
}
}
-
- // Reschedule everything.
- rescheduleKernelAlarmsLocked();
- updateNextAlarmClockLocked();
-
}
static final class InFlight {
@@ -1449,6 +1451,11 @@
}
}
+ if ((flags & AlarmManager.FLAG_IDLE_UNTIL) != 0) {
+ // Do not support windows for idle-until alarms.
+ windowLength = AlarmManager.WINDOW_EXACT;
+ }
+
// Sanity check the window length. This will catch people mistakenly
// trying to pass an end-of-window timestamp rather than a duration.
if (windowLength > AlarmManager.INTERVAL_HALF_DAY) {
@@ -1515,17 +1522,17 @@
Slog.w(TAG, errorMsg);
throw new IllegalStateException(errorMsg);
}
- setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
- interval, operation, directReceiver, listenerTag, flags, workSource,
- alarmClock, callingUid, callingPackage);
+ setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, interval, operation,
+ directReceiver, listenerTag, flags, workSource, alarmClock, callingUid,
+ callingPackage);
}
}
private void setImplLocked(int type, long when, long whenElapsed, long windowLength,
- long maxWhen, long interval, PendingIntent operation, IAlarmListener directReceiver,
+ long interval, PendingIntent operation, IAlarmListener directReceiver,
String listenerTag, int flags, WorkSource workSource,
AlarmManager.AlarmClockInfo alarmClock, int callingUid, String callingPackage) {
- Alarm a = new Alarm(type, when, whenElapsed, windowLength, maxWhen, interval,
+ final Alarm a = new Alarm(type, when, whenElapsed, windowLength, interval,
operation, directReceiver, listenerTag, workSource, flags, alarmClock,
callingUid, callingPackage);
if (mActivityManagerInternal.isAppStartModeDisabled(callingUid, callingPackage)) {
@@ -1560,72 +1567,55 @@
}
/**
- * Adjusts the idle-until alarm delivery time based on the upcoming wake-from-idle alarm.
+ * An alarm with {@link AlarmManager#FLAG_IDLE_UNTIL} is a special alarm that will put the
+ * system into idle until it goes off. We need to pull it earlier if there are existing alarms
+ * that have requested to bring us out of idle at an earlier time.
*
* @param alarm The alarm to adjust
* @return true if the alarm delivery time was updated.
*/
private boolean adjustIdleUntilTime(Alarm alarm) {
- if ((alarm.flags & AlarmManager.FLAG_IDLE_UNTIL) != 0) {
+ if ((alarm.flags & AlarmManager.FLAG_IDLE_UNTIL) == 0) {
return false;
}
- // This is a special alarm that will put the system into idle until it goes off.
- // The caller has given the time they want this to happen at, however we need
- // to pull that earlier if there are existing alarms that have requested to
- // bring us out of idle at an earlier time.
- if (mNextWakeFromIdle != null && alarm.whenElapsed > mNextWakeFromIdle.whenElapsed) {
- alarm.when = alarm.whenElapsed = alarm.maxWhenElapsed = mNextWakeFromIdle.whenElapsed;
+ restoreRequestedTime(alarm);
+ long triggerBeforeFuzz = alarm.getPolicyElapsed(REQUESTER_POLICY_INDEX);
+ if (mNextWakeFromIdle != null && triggerBeforeFuzz > mNextWakeFromIdle.getWhenElapsed()) {
+ triggerBeforeFuzz = mNextWakeFromIdle.getWhenElapsed();
}
// Add fuzz to make the alarm go off some time before the actual desired time.
- final long nowElapsed = mInjector.getElapsedRealtime();
- final int fuzz = fuzzForDuration(alarm.whenElapsed - nowElapsed);
+ final int fuzz = fuzzForDuration(alarm.getWhenElapsed() - mInjector.getElapsedRealtime());
+ final int delta;
if (fuzz > 0) {
if (mRandom == null) {
mRandom = new Random();
}
- final int delta = mRandom.nextInt(fuzz);
- alarm.whenElapsed -= delta;
- if (false) {
- Slog.d(TAG, "Alarm when: " + alarm.whenElapsed);
- Slog.d(TAG, "Delta until alarm: " + (alarm.whenElapsed - nowElapsed));
- Slog.d(TAG, "Applied fuzz: " + fuzz);
- Slog.d(TAG, "Final delta: " + delta);
- Slog.d(TAG, "Final when: " + alarm.whenElapsed);
- }
- alarm.when = alarm.maxWhenElapsed = alarm.whenElapsed;
+ delta = mRandom.nextInt(fuzz);
+ } else {
+ delta = 0;
}
+ alarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, triggerBeforeFuzz - delta);
return true;
}
/**
- * Adjusts the alarm delivery time based on the current app standby bucket.
+ * Adjusts the alarm's policy time for app_standby.
*
- * @param alarm The alarm to adjust
- * @return true if the alarm delivery time was updated.
+ * @param alarm The alarm to update.
+ * @return {@code true} if the actual delivery time of the given alarm was updated due to
+ * adjustments made in this call.
*/
private boolean adjustDeliveryTimeBasedOnBucketLocked(Alarm alarm) {
- if (isExemptFromAppStandby(alarm)) {
- return false;
+ final long nowElapsed = mInjector.getElapsedRealtime();
+ if (isExemptFromAppStandby(alarm) || mAppStandbyParole) {
+ return alarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, nowElapsed);
}
- if (mAppStandbyParole) {
- if (alarm.whenElapsed > alarm.expectedWhenElapsed) {
- // We did defer this alarm earlier, restore original requirements
- alarm.whenElapsed = alarm.expectedWhenElapsed;
- alarm.maxWhenElapsed = alarm.expectedMaxWhenElapsed;
- return true;
- }
- return false;
- }
- final long oldWhenElapsed = alarm.whenElapsed;
- final long oldMaxWhenElapsed = alarm.maxWhenElapsed;
final String sourcePackage = alarm.sourcePackage;
final int sourceUserId = UserHandle.getUserId(alarm.creatorUid);
final int standbyBucket = mUsageStatsManagerInternal.getAppStandbyBucket(
- sourcePackage, sourceUserId, mInjector.getElapsedRealtime());
+ sourcePackage, sourceUserId, nowElapsed);
- // Quota deferring implementation:
- boolean deferred = false;
final int wakeupsInWindow = mAppWakeupHistory.getTotalWakeupsInWindow(sourcePackage,
sourceUserId);
if (standbyBucket == UsageStatsManager.STANDBY_BUCKET_RESTRICTED) {
@@ -1635,14 +1625,9 @@
if (wakeupsInWindow > 0) {
final long lastWakeupTime = mAppWakeupHistory.getNthLastWakeupForPackage(
sourcePackage, sourceUserId, mConstants.APP_STANDBY_RESTRICTED_QUOTA);
- if (mInjector.getElapsedRealtime() - lastWakeupTime
- < mConstants.APP_STANDBY_RESTRICTED_WINDOW) {
- final long minElapsed =
- lastWakeupTime + mConstants.APP_STANDBY_RESTRICTED_WINDOW;
- if (alarm.expectedWhenElapsed < minElapsed) {
- alarm.whenElapsed = alarm.maxWhenElapsed = minElapsed;
- deferred = true;
- }
+ if ((nowElapsed - lastWakeupTime) < mConstants.APP_STANDBY_RESTRICTED_WINDOW) {
+ return alarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX,
+ lastWakeupTime + mConstants.APP_STANDBY_RESTRICTED_WINDOW);
}
}
} else {
@@ -1651,7 +1636,7 @@
final long minElapsed;
if (quotaForBucket <= 0) {
// Just keep deferring for a day till the quota changes
- minElapsed = mInjector.getElapsedRealtime() + MILLIS_IN_DAY;
+ minElapsed = nowElapsed + MILLIS_IN_DAY;
} else {
// Suppose the quota for window was q, and the qth last delivery time for this
// package was t(q) then the next delivery must be after t(q) + <window_size>
@@ -1659,19 +1644,11 @@
sourcePackage, sourceUserId, quotaForBucket);
minElapsed = t + mConstants.APP_STANDBY_WINDOW;
}
- if (alarm.expectedWhenElapsed < minElapsed) {
- alarm.whenElapsed = alarm.maxWhenElapsed = minElapsed;
- deferred = true;
- }
+ return alarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, minElapsed);
}
}
- if (!deferred) {
- // Restore original requirements in case they were changed earlier.
- alarm.whenElapsed = alarm.expectedWhenElapsed;
- alarm.maxWhenElapsed = alarm.expectedMaxWhenElapsed;
- }
-
- return (oldWhenElapsed != alarm.whenElapsed || oldMaxWhenElapsed != alarm.maxWhenElapsed);
+ // wakeupsInWindow are less than the permitted quota, hence no deferring is needed.
+ return alarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, nowElapsed);
}
private static boolean isAllowedWhileIdle(Alarm a) {
@@ -1691,7 +1668,7 @@
ent.tag = a.operation.getTag("");
ent.op = "SET";
ent.elapsedRealtime = mInjector.getElapsedRealtime();
- ent.argRealtime = a.whenElapsed;
+ ent.argRealtime = a.getWhenElapsed();
mAllowWhileIdleDispatches.add(ent);
if (mPendingIdleUntil == null) {
IdleDispatchEntry ent2 = new IdleDispatchEntry();
@@ -1704,6 +1681,7 @@
if ((mPendingIdleUntil != a) && (mPendingIdleUntil != null)) {
Slog.wtfStack(TAG, "setImplLocked: idle until changed from " + mPendingIdleUntil
+ " to " + a);
+ mAlarmStore.remove(mPendingIdleUntil::equals);
}
mPendingIdleUntil = a;
final ArrayList<Alarm> notAllowedWhileIdleAlarms = mAlarmStore.remove(
@@ -1718,18 +1696,16 @@
}
}
if ((a.flags & AlarmManager.FLAG_WAKE_FROM_IDLE) != 0) {
- if (mNextWakeFromIdle == null || mNextWakeFromIdle.whenElapsed > a.whenElapsed) {
+ if (mNextWakeFromIdle == null || mNextWakeFromIdle.getWhenElapsed()
+ > a.getWhenElapsed()) {
mNextWakeFromIdle = a;
// If this wake from idle is earlier than whatever was previously scheduled,
- // and we are currently idling, then we need to rebatch alarms in case the idle
- // until time needs to be updated.
+ // and we are currently idling, then the idle-until time needs to be updated.
if (mPendingIdleUntil != null) {
- final long nowElapsed = mInjector.getElapsedRealtime();
- mAlarmStore.recalculateAlarmDeliveries(alarm -> {
+ mAlarmStore.updateAlarmDeliveries(alarm -> {
if (alarm != mPendingIdleUntil) {
return false;
}
- restoreAlarmLocked(alarm, nowElapsed);
return adjustIdleUntilTime(alarm);
});
}
@@ -2563,7 +2539,7 @@
long getNextWakeFromIdleTimeImpl() {
synchronized (mLock) {
- return mNextWakeFromIdle != null ? mNextWakeFromIdle.whenElapsed : Long.MAX_VALUE;
+ return mNextWakeFromIdle != null ? mNextWakeFromIdle.getWhenElapsed() : Long.MAX_VALUE;
}
}
@@ -2784,12 +2760,11 @@
restorePending = true;
}
if (mNextWakeFromIdle != null && mNextWakeFromIdle.matches(operation, directReceiver)) {
- mNextWakeFromIdle = null;
- mAlarmStore.recalculateAlarmDeliveries(alarm -> {
+ mNextWakeFromIdle = mAlarmStore.getNextWakeFromIdleAlarm();
+ mAlarmStore.updateAlarmDeliveries(alarm -> {
if (alarm != mPendingIdleUntil) {
return false;
}
- restoreAlarmLocked(alarm, mInjector.getElapsedRealtime());
return adjustIdleUntilTime(alarm);
});
}
@@ -2834,15 +2809,14 @@
mPendingBackgroundAlarms.removeAt(i);
}
}
- // If we're currently keying off of this app's alarms for doze transitions,
- // make sure to reset to other triggers.
+ // If we're currently using this app's alarms to come out of doze,
+ // make sure to reset to any remaining WAKE_FROM_IDLE alarms.
if (mNextWakeFromIdle != null && mNextWakeFromIdle.uid == uid) {
- mNextWakeFromIdle = null;
- mAlarmStore.recalculateAlarmDeliveries(alarm -> {
+ mNextWakeFromIdle = mAlarmStore.getNextWakeFromIdleAlarm();
+ mAlarmStore.updateAlarmDeliveries(alarm -> {
if (alarm != mPendingIdleUntil) {
return false;
}
- restoreAlarmLocked(alarm, mInjector.getElapsedRealtime());
return adjustIdleUntilTime(alarm);
});
}
@@ -2906,15 +2880,14 @@
mPendingBackgroundAlarms.removeAt(i);
}
}
- // If we're currently keying off of this app's alarms for doze transitions,
- // make sure to reset to other triggers.
+ // If we're currently using this app's alarms to come out of doze,
+ // make sure to reset to any remaining WAKE_FROM_IDLE alarms.
if (removedNextWakeFromIdle.value) {
- mNextWakeFromIdle = null;
- mAlarmStore.recalculateAlarmDeliveries(alarm -> {
+ mNextWakeFromIdle = mAlarmStore.getNextWakeFromIdleAlarm();
+ mAlarmStore.updateAlarmDeliveries(alarm -> {
if (alarm != mPendingIdleUntil) {
return false;
}
- restoreAlarmLocked(alarm, mInjector.getElapsedRealtime());
return adjustIdleUntilTime(alarm);
});
}
@@ -3071,20 +3044,6 @@
}
}
- private static final String labelForType(int type) {
- switch (type) {
- case RTC:
- return "RTC";
- case RTC_WAKEUP:
- return "RTC_WAKEUP";
- case ELAPSED_REALTIME:
- return "ELAPSED";
- case ELAPSED_REALTIME_WAKEUP:
- return "ELAPSED_WAKEUP";
- }
- return "--unknown--";
- }
-
private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
String prefix, long nowELAPSED, SimpleDateFormat sdf) {
final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, prefix, prefix);
@@ -3095,7 +3054,7 @@
long nowELAPSED, SimpleDateFormat sdf) {
for (int i = list.size() - 1; i >= 0; i--) {
final Alarm a = list.get(i);
- final String label = labelForType(a.type);
+ final String label = Alarm.typeToString(a.type);
ipw.print(label);
ipw.print(" #");
ipw.print(i);
@@ -3125,6 +3084,9 @@
}
final String sourcePackage = alarm.sourcePackage;
final int sourceUid = alarm.creatorUid;
+ if (UserHandle.isCore(sourceUid)) {
+ return false;
+ }
return (mAppStateTracker != null) &&
mAppStateTracker.areAlarmsRestricted(sourceUid, sourcePackage,
exemptOnBatterySaver);
@@ -3169,11 +3131,7 @@
// Whoops, it hasn't been long enough since the last ALLOW_WHILE_IDLE
// alarm went off for this app. Reschedule the alarm to be in the
// correct time period.
- alarm.expectedWhenElapsed = alarm.whenElapsed = minTime;
- if (alarm.maxWhenElapsed < minTime) {
- alarm.maxWhenElapsed = minTime;
- }
- alarm.expectedMaxWhenElapsed = alarm.maxWhenElapsed;
+ alarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, minTime);
if (RECORD_DEVICE_IDLE_ALARMS) {
IdleDispatchEntry ent = new IdleDispatchEntry();
ent.uid = alarm.uid;
@@ -3213,12 +3171,11 @@
restorePendingWhileIdleAlarmsLocked();
}
if (mNextWakeFromIdle == alarm) {
- mNextWakeFromIdle = null;
- mAlarmStore.recalculateAlarmDeliveries(a -> {
+ mNextWakeFromIdle = mAlarmStore.getNextWakeFromIdleAlarm();
+ mAlarmStore.updateAlarmDeliveries(a -> {
if (a != mPendingIdleUntil) {
return false;
}
- restoreAlarmLocked(a, nowELAPSED);
return adjustIdleUntilTime(a);
});
}
@@ -3228,14 +3185,17 @@
if (alarm.repeatInterval > 0) {
// this adjustment will be zero if we're late by
// less than one full repeat interval
- alarm.count += (nowELAPSED - alarm.expectedWhenElapsed) / alarm.repeatInterval;
+ alarm.count += (nowELAPSED - alarm.getPolicyElapsed(REQUESTER_POLICY_INDEX))
+ / alarm.repeatInterval;
// Also schedule its next recurrence
final long delta = alarm.count * alarm.repeatInterval;
- final long nextElapsed = alarm.expectedWhenElapsed + delta;
- setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength,
- maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
- alarm.repeatInterval, alarm.operation, null, null, alarm.flags,
- alarm.workSource, alarm.alarmClock, alarm.uid, alarm.packageName);
+ final long nextElapsed = alarm.getPolicyElapsed(REQUESTER_POLICY_INDEX) + delta;
+ final long nextMaxElapsed = maxTriggerTime(nowELAPSED, nextElapsed,
+ alarm.repeatInterval);
+ setImplLocked(alarm.type, alarm.origWhen + delta, nextElapsed,
+ nextMaxElapsed - nextElapsed, alarm.repeatInterval, alarm.operation, null,
+ null, alarm.flags, alarm.workSource, alarm.alarmClock, alarm.uid,
+ alarm.packageName);
}
if (alarm.wakeup) {
@@ -3277,7 +3237,7 @@
}
}
- static int fuzzForDuration(long duration) {
+ int fuzzForDuration(long duration) {
if (duration < 15 * 60 * 1000) {
// If the duration until the time is less than 15 minutes, the maximum fuzz
// is the duration.
@@ -3480,7 +3440,7 @@
FrameworkStatsLog.write(FrameworkStatsLog.WALL_CLOCK_TIME_SHIFTED, nowRTC);
removeImpl(null, mTimeTickTrigger);
removeImpl(mDateChangeSender, null);
- reevaluateRtcAlarms(nowELAPSED);
+ reevaluateRtcAlarms();
mClockReceiver.scheduleTimeTickEvent();
mClockReceiver.scheduleDateChangedEvent();
synchronized (mLock) {
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java
index 9fdbb8b..7a846b9 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java
@@ -48,6 +48,15 @@
ArrayList<Alarm> remove(Predicate<Alarm> whichAlarms);
/**
+ * Gets the earliest alarm with the flag {@link android.app.AlarmManager#FLAG_WAKE_FROM_IDLE}
+ * based on {@link Alarm#getWhenElapsed()}.
+ *
+ * @return An alarm object matching the description above or {@code null} if no such alarm was
+ * found.
+ */
+ Alarm getNextWakeFromIdleAlarm();
+
+ /**
* Returns the total number of alarms in this store.
*/
int size();
@@ -71,7 +80,7 @@
/**
* Removes all alarms that are pending delivery at the given time.
*
- * @param nowElapsed The time at which delivery eligibility is evaluated.
+ * @param nowElapsed The time at which delivery eligibility is evaluated.
* @return The list of alarms pending at the given time.
*/
ArrayList<Alarm> removePendingAlarms(long nowElapsed);
@@ -82,7 +91,7 @@
*
* @return {@code true} if any of the alarm deliveries changed due to this call.
*/
- boolean recalculateAlarmDeliveries(AlarmDeliveryCalculator deliveryCalculator);
+ boolean updateAlarmDeliveries(AlarmDeliveryCalculator deliveryCalculator);
/**
* Returns all the alarms in the form of a list.
@@ -97,6 +106,7 @@
* Primary useful for debugging. Can be called from the
* {@link android.os.Binder#dump(FileDescriptor PrintWriter, String[]) dump} method of the
* caller.
+ *
* @param ipw The {@link IndentingPrintWriter} to write to.
* @param nowElapsed the time when the dump is requested in the
* {@link SystemClock#elapsedRealtime()
@@ -112,7 +122,7 @@
/**
* A functional interface used to update the alarm. Used to describe the update in
- * {@link #recalculateAlarmDeliveries(AlarmDeliveryCalculator)}
+ * {@link #updateAlarmDeliveries(AlarmDeliveryCalculator)}
*/
@FunctionalInterface
interface AlarmDeliveryCalculator {
@@ -125,3 +135,4 @@
boolean updateAlarmDelivery(Alarm a);
}
}
+
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java
index 91c0c05..cbfe80b 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java
@@ -66,8 +66,8 @@
};
private static final Comparator<Alarm> sIncreasingTimeOrder = (a1, a2) -> {
- long when1 = a1.whenElapsed;
- long when2 = a2.whenElapsed;
+ long when1 = a1.getWhenElapsed();
+ long when2 = a2.getWhenElapsed();
if (when1 > when2) {
return 1;
}
@@ -99,11 +99,28 @@
}
if (!removed.isEmpty()) {
mSize -= removed.size();
+ // Not needed if only whole batches were removed, but keeping existing behavior.
rebatchAllAlarms();
}
return removed;
}
+ @Override
+ public Alarm getNextWakeFromIdleAlarm() {
+ for (final Batch batch : mAlarmBatches) {
+ if ((batch.mFlags & AlarmManager.FLAG_WAKE_FROM_IDLE) == 0) {
+ continue;
+ }
+ for (int i = 0; i < batch.size(); i++) {
+ final Alarm a = batch.get(i);
+ if ((a.flags & AlarmManager.FLAG_WAKE_FROM_IDLE) != 0) {
+ return a;
+ }
+ }
+ }
+ return null;
+ }
+
private void rebatchAllAlarms() {
final long start = mStatLogger.getTime();
final ArrayList<Batch> oldBatches = (ArrayList<Batch>) mAlarmBatches.clone();
@@ -157,7 +174,7 @@
}
@Override
- public boolean recalculateAlarmDeliveries(AlarmDeliveryCalculator deliveryCalculator) {
+ public boolean updateAlarmDeliveries(AlarmDeliveryCalculator deliveryCalculator) {
boolean changed = false;
for (final Batch b : mAlarmBatches) {
for (int i = 0; i < b.size(); i++) {
@@ -204,7 +221,7 @@
private void insertAndBatchAlarm(Alarm alarm) {
final int whichBatch = ((alarm.flags & AlarmManager.FLAG_STANDALONE) != 0) ? -1
- : attemptCoalesce(alarm.whenElapsed, alarm.maxWhenElapsed);
+ : attemptCoalesce(alarm.getWhenElapsed(), alarm.getMaxWhenElapsed());
if (whichBatch < 0) {
addBatch(mAlarmBatches, new Batch(alarm));
@@ -247,8 +264,8 @@
final ArrayList<Alarm> mAlarms = new ArrayList<>();
Batch(Alarm seed) {
- mStart = seed.whenElapsed;
- mEnd = clampPositive(seed.maxWhenElapsed);
+ mStart = seed.getWhenElapsed();
+ mEnd = clampPositive(seed.getMaxWhenElapsed());
mFlags = seed.flags;
mAlarms.add(seed);
}
@@ -276,12 +293,12 @@
if (DEBUG_BATCH) {
Slog.v(TAG, "Adding " + alarm + " to " + this);
}
- if (alarm.whenElapsed > mStart) {
- mStart = alarm.whenElapsed;
+ if (alarm.getWhenElapsed() > mStart) {
+ mStart = alarm.getWhenElapsed();
newStart = true;
}
- if (alarm.maxWhenElapsed < mEnd) {
- mEnd = alarm.maxWhenElapsed;
+ if (alarm.getMaxWhenElapsed() < mEnd) {
+ mEnd = alarm.getMaxWhenElapsed();
}
mFlags |= alarm.flags;
@@ -309,11 +326,11 @@
Slog.wtf(TAG, "Removed TIME_TICK alarm");
}
} else {
- if (alarm.whenElapsed > newStart) {
- newStart = alarm.whenElapsed;
+ if (alarm.getWhenElapsed() > newStart) {
+ newStart = alarm.getWhenElapsed();
}
- if (alarm.maxWhenElapsed < newEnd) {
- newEnd = alarm.maxWhenElapsed;
+ if (alarm.getMaxWhenElapsed() < newEnd) {
+ newEnd = alarm.getMaxWhenElapsed();
}
newFlags |= alarm.flags;
i++;
diff --git a/api/current.txt b/api/current.txt
index fc1a265..97e5f4e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2889,6 +2889,7 @@
field public static final int GESTURE_2_FINGER_DOUBLE_TAP = 20; // 0x14
field public static final int GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD = 40; // 0x28
field public static final int GESTURE_2_FINGER_SINGLE_TAP = 19; // 0x13
+ field public static final int GESTURE_2_FINGER_SINGLE_TAP_AND_HOLD = 43; // 0x2b
field public static final int GESTURE_2_FINGER_SWIPE_DOWN = 26; // 0x1a
field public static final int GESTURE_2_FINGER_SWIPE_LEFT = 27; // 0x1b
field public static final int GESTURE_2_FINGER_SWIPE_RIGHT = 28; // 0x1c
@@ -2897,11 +2898,13 @@
field public static final int GESTURE_3_FINGER_DOUBLE_TAP = 23; // 0x17
field public static final int GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD = 41; // 0x29
field public static final int GESTURE_3_FINGER_SINGLE_TAP = 22; // 0x16
+ field public static final int GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD = 44; // 0x2c
field public static final int GESTURE_3_FINGER_SWIPE_DOWN = 30; // 0x1e
field public static final int GESTURE_3_FINGER_SWIPE_LEFT = 31; // 0x1f
field public static final int GESTURE_3_FINGER_SWIPE_RIGHT = 32; // 0x20
field public static final int GESTURE_3_FINGER_SWIPE_UP = 29; // 0x1d
field public static final int GESTURE_3_FINGER_TRIPLE_TAP = 24; // 0x18
+ field public static final int GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD = 45; // 0x2d
field public static final int GESTURE_4_FINGER_DOUBLE_TAP = 38; // 0x26
field public static final int GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD = 42; // 0x2a
field public static final int GESTURE_4_FINGER_SINGLE_TAP = 37; // 0x25
@@ -10664,12 +10667,15 @@
field public static final String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
field public static final String ACTION_PACKAGE_DATA_CLEARED = "android.intent.action.PACKAGE_DATA_CLEARED";
field public static final String ACTION_PACKAGE_FIRST_LAUNCH = "android.intent.action.PACKAGE_FIRST_LAUNCH";
+ field public static final String ACTION_PACKAGE_FULLY_LOADED = "android.intent.action.PACKAGE_FULLY_LOADED";
field public static final String ACTION_PACKAGE_FULLY_REMOVED = "android.intent.action.PACKAGE_FULLY_REMOVED";
field @Deprecated public static final String ACTION_PACKAGE_INSTALL = "android.intent.action.PACKAGE_INSTALL";
field public static final String ACTION_PACKAGE_NEEDS_VERIFICATION = "android.intent.action.PACKAGE_NEEDS_VERIFICATION";
field public static final String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED";
field public static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED";
field public static final String ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED";
+ field public static final String ACTION_PACKAGE_STARTABLE = "android.intent.action.PACKAGE_STARTABLE";
+ field public static final String ACTION_PACKAGE_UNSTARTABLE = "android.intent.action.PACKAGE_UNSTARTABLE";
field public static final String ACTION_PACKAGE_VERIFIED = "android.intent.action.PACKAGE_VERIFIED";
field public static final String ACTION_PASTE = "android.intent.action.PASTE";
field public static final String ACTION_PICK = "android.intent.action.PICK";
@@ -10834,6 +10840,7 @@
field public static final String EXTRA_TIMEZONE = "time-zone";
field public static final String EXTRA_TITLE = "android.intent.extra.TITLE";
field public static final String EXTRA_UID = "android.intent.extra.UID";
+ field public static final String EXTRA_UNSTARTABLE_REASON = "android.intent.extra.UNSTARTABLE_REASON";
field public static final String EXTRA_USER = "android.intent.extra.USER";
field public static final int FILL_IN_ACTION = 1; // 0x1
field public static final int FILL_IN_CATEGORIES = 4; // 0x4
@@ -11707,7 +11714,10 @@
method public android.graphics.drawable.Drawable getIcon(int);
method public CharSequence getLabel();
method public String getName();
+ method public float getProgress();
method public android.os.UserHandle getUser();
+ method public boolean isLoading();
+ method public boolean isStartable();
}
public class LauncherApps {
@@ -11747,6 +11757,7 @@
ctor public LauncherApps.Callback();
method public abstract void onPackageAdded(String, android.os.UserHandle);
method public abstract void onPackageChanged(String, android.os.UserHandle);
+ method public void onPackageProgressChanged(@NonNull String, @NonNull android.os.UserHandle, float);
method public abstract void onPackageRemoved(String, android.os.UserHandle);
method public abstract void onPackagesAvailable(String[], android.os.UserHandle, boolean);
method public void onPackagesSuspended(String[], android.os.UserHandle);
@@ -12293,6 +12304,9 @@
field public static final int SYNCHRONOUS = 2; // 0x2
field @Nullable public static final java.util.List<java.security.cert.Certificate> TRUST_ALL;
field @NonNull public static final java.util.List<java.security.cert.Certificate> TRUST_NONE;
+ field public static final int UNSTARTABLE_REASON_CONNECTION_ERROR = 1; // 0x1
+ field public static final int UNSTARTABLE_REASON_INSUFFICIENT_STORAGE = 2; // 0x2
+ field public static final int UNSTARTABLE_REASON_UNKNOWN = 0; // 0x0
field public static final int VERIFICATION_ALLOW = 1; // 0x1
field public static final int VERIFICATION_REJECT = -1; // 0xffffffff
field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff
@@ -24089,9 +24103,13 @@
method @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMaxUpdates();
method @FloatRange(from=0, to=java.lang.Float.MAX_VALUE) public float getMinUpdateDistanceMeters();
method @IntRange(from=0) public long getMinUpdateIntervalMillis();
+ method public int getQuality();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationRequest> CREATOR;
field public static final long PASSIVE_INTERVAL = 9223372036854775807L; // 0x7fffffffffffffffL
+ field public static final int QUALITY_BALANCED_POWER_ACCURACY = 102; // 0x66
+ field public static final int QUALITY_HIGH_ACCURACY = 100; // 0x64
+ field public static final int QUALITY_LOW_POWER = 104; // 0x68
}
public static final class LocationRequest.Builder {
@@ -24104,6 +24122,7 @@
method @NonNull public android.location.LocationRequest.Builder setMaxUpdates(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
method @NonNull public android.location.LocationRequest.Builder setMinUpdateDistanceMeters(@FloatRange(from=0, to=java.lang.Float.MAX_VALUE) float);
method @NonNull public android.location.LocationRequest.Builder setMinUpdateIntervalMillis(@IntRange(from=0) long);
+ method @NonNull public android.location.LocationRequest.Builder setQuality(int);
}
public interface OnNmeaMessageListener {
@@ -25456,6 +25475,7 @@
public static final class MediaCodec.CryptoInfo {
ctor public MediaCodec.CryptoInfo();
+ method @NonNull public android.media.MediaCodec.CryptoInfo.Pattern getPattern();
method public void set(int, @NonNull int[], @NonNull int[], @NonNull byte[], @NonNull byte[], int);
method public void setPattern(android.media.MediaCodec.CryptoInfo.Pattern);
field public byte[] iv;
@@ -44100,11 +44120,13 @@
method public long getLastAudiblyAlertedMillis();
method public String getOverrideGroupKey();
method public int getRank();
+ method @Nullable public android.content.pm.ShortcutInfo getShortcutInfo();
method @NonNull public java.util.List<android.app.Notification.Action> getSmartActions();
method @NonNull public java.util.List<java.lang.CharSequence> getSmartReplies();
method public int getSuppressedVisualEffects();
method public int getUserSentiment();
method public boolean isAmbient();
+ method public boolean isConversation();
method public boolean isSuspended();
method public boolean matchesInterruptionFilter();
field public static final int USER_SENTIMENT_NEGATIVE = -1; // 0xffffffff
@@ -48440,6 +48462,7 @@
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getDeviceSoftwareVersion();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<java.lang.String> getEquivalentHomePlmns();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String[] getForbiddenPlmns();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getGroupIdLevel1();
method public String getIccAuthentication(int, int, String);
@@ -48464,7 +48487,7 @@
method @Deprecated public int getPhoneCount();
method public int getPhoneType();
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE}) public int getPreferredOpportunisticDataSubscription();
- method @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public android.telephony.ServiceState getServiceState();
+ method @Nullable @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public android.telephony.ServiceState getServiceState();
method @Nullable public android.telephony.SignalStrength getSignalStrength();
method public int getSimCarrierId();
method @Nullable public CharSequence getSimCarrierIdName();
@@ -48487,7 +48510,7 @@
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailAlphaTag();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getVoiceNetworkType();
- method public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle);
+ method @Nullable public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle);
method public boolean hasCarrierPrivileges();
method public boolean hasIccCard();
method @Deprecated public boolean iccCloseLogicalChannel(int);
@@ -53721,11 +53744,12 @@
method @Nullable public android.net.Uri getLinkUri();
method public int getSource();
field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
- field public static final int SOURCE_AUTOFILL = 3; // 0x3
- field public static final int SOURCE_CLIPBOARD = 0; // 0x0
- field public static final int SOURCE_DRAG_AND_DROP = 2; // 0x2
- field public static final int SOURCE_INPUT_METHOD = 1; // 0x1
- field public static final int SOURCE_PROCESS_TEXT = 4; // 0x4
+ field public static final int SOURCE_APP = 0; // 0x0
+ field public static final int SOURCE_AUTOFILL = 4; // 0x4
+ field public static final int SOURCE_CLIPBOARD = 1; // 0x1
+ field public static final int SOURCE_DRAG_AND_DROP = 3; // 0x3
+ field public static final int SOURCE_INPUT_METHOD = 2; // 0x2
+ field public static final int SOURCE_PROCESS_TEXT = 5; // 0x5
}
public static final class OnReceiveContentCallback.Payload.Builder {
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index dc92b52..e825b62 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -1,10 +1,20 @@
// Signature format: 2.0
package android.app {
+ public class ActivityManager {
+ method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void addHomeVisibilityListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.HomeVisibilityListener);
+ method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void removeHomeVisibilityListener(@NonNull android.app.HomeVisibilityListener);
+ }
+
public class AppOpsManager {
field public static final String OPSTR_NO_ISOLATED_STORAGE = "android:no_isolated_storage";
}
+ public abstract class HomeVisibilityListener {
+ ctor public HomeVisibilityListener();
+ method public abstract void onHomeVisibilityChanged(boolean);
+ }
+
public class NotificationManager {
method public boolean hasEnabledNotificationListener(@NonNull String, @NonNull android.os.UserHandle);
field public static final String ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED = "android.app.action.NOTIFICATION_LISTENER_ENABLED_CHANGED";
@@ -178,6 +188,18 @@
}
+package android.telephony {
+
+ public abstract class CellSignalStrength {
+ method public static int getNumSignalStrengthLevels();
+ }
+
+ public class TelephonyManager {
+ method @NonNull public static int[] getAllNetworkTypes();
+ }
+
+}
+
package android.util {
public class AtomicFile {
diff --git a/api/system-current.txt b/api/system-current.txt
index 1404f7e..c62e1b9 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -122,6 +122,7 @@
field public static final String MANAGE_FACTORY_RESET_PROTECTION = "android.permission.MANAGE_FACTORY_RESET_PROTECTION";
field public static final String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
field public static final String MANAGE_MUSIC_RECOGNITION = "android.permission.MANAGE_MUSIC_RECOGNITION";
+ field public static final String MANAGE_NOTIFICATION_LISTENERS = "android.permission.MANAGE_NOTIFICATION_LISTENERS";
field public static final String MANAGE_ONE_TIME_PERMISSION_SESSIONS = "android.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS";
field public static final String MANAGE_ROLE_HOLDERS = "android.permission.MANAGE_ROLE_HOLDERS";
field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
@@ -674,8 +675,10 @@
public class NotificationManager {
method @NonNull public java.util.List<java.lang.String> getAllowedAssistantAdjustments();
method @Nullable public android.content.ComponentName getAllowedNotificationAssistant();
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public java.util.List<android.content.ComponentName> getEnabledNotificationListeners();
method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName);
method public void setNotificationAssistantAccessGranted(@Nullable android.content.ComponentName, boolean);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public void setNotificationListenerAccessGranted(@NonNull android.content.ComponentName, boolean);
field @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) public static final String ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL = "android.app.action.CLOSE_NOTIFICATION_HANDLER_PANEL";
field @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) public static final String ACTION_OPEN_NOTIFICATION_HANDLER_PANEL = "android.app.action.OPEN_NOTIFICATION_HANDLER_PANEL";
field @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) public static final String ACTION_TOGGLE_NOTIFICATION_HANDLER_PANEL = "android.app.action.TOGGLE_NOTIFICATION_HANDLER_PANEL";
@@ -4171,7 +4174,6 @@
method @Deprecated public long getInterval();
method @Deprecated public int getNumUpdates();
method @Deprecated @NonNull public String getProvider();
- method public int getQuality();
method @Deprecated public float getSmallestDisplacement();
method @NonNull public android.os.WorkSource getWorkSource();
method public boolean isHiddenFromAppOps();
@@ -4190,11 +4192,11 @@
method @Deprecated @NonNull public android.location.LocationRequest setQuality(int);
method @Deprecated @NonNull public android.location.LocationRequest setSmallestDisplacement(float);
method @Deprecated public void setWorkSource(@Nullable android.os.WorkSource);
- field public static final int ACCURACY_BLOCK = 102; // 0x66
- field public static final int ACCURACY_CITY = 104; // 0x68
- field public static final int ACCURACY_FINE = 100; // 0x64
- field public static final int POWER_HIGH = 203; // 0xcb
- field public static final int POWER_LOW = 201; // 0xc9
+ field @Deprecated public static final int ACCURACY_BLOCK = 102; // 0x66
+ field @Deprecated public static final int ACCURACY_CITY = 104; // 0x68
+ field @Deprecated public static final int ACCURACY_FINE = 100; // 0x64
+ field @Deprecated public static final int POWER_HIGH = 203; // 0xcb
+ field @Deprecated public static final int POWER_LOW = 201; // 0xc9
field @Deprecated public static final int POWER_NONE = 200; // 0xc8
}
@@ -4202,7 +4204,6 @@
method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LocationRequest.Builder setHiddenFromAppOps(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest.Builder setLocationSettingsIgnored(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.location.LocationRequest.Builder setLowPower(boolean);
- method @NonNull public android.location.LocationRequest.Builder setQuality(int);
method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
}
@@ -4769,6 +4770,22 @@
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.DvbDeviceInfo> CREATOR;
}
+ public final class TunedInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getAppTag();
+ method public int getAppType();
+ method @Nullable public android.net.Uri getChannelUri();
+ method @NonNull public String getInputId();
+ method public boolean isForeground();
+ method public boolean isRecordingSession();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int APP_TAG_SELF = 0; // 0x0
+ field public static final int APP_TYPE_NON_SYSTEM = 3; // 0x3
+ field public static final int APP_TYPE_SELF = 1; // 0x1
+ field public static final int APP_TYPE_SYSTEM = 2; // 0x2
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.TunedInfo> CREATOR;
+ }
+
public final class TvContentRatingSystemInfo implements android.os.Parcelable {
method public static android.media.tv.TvContentRatingSystemInfo createTvContentRatingSystemInfo(int, android.content.pm.ApplicationInfo);
method public int describeContents();
@@ -4884,6 +4901,7 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void addBlockedRating(@NonNull android.media.tv.TvContentRating);
method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public boolean captureFrame(String, android.view.Surface, android.media.tv.TvStreamConfig);
method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public java.util.List<android.media.tv.TvStreamConfig> getAvailableTvStreamConfigList(String);
+ method @NonNull @RequiresPermission("com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS") public java.util.List<android.media.tv.TunedInfo> getCurrentTunedInfos();
method @NonNull @RequiresPermission("android.permission.DVB_DEVICE") public java.util.List<android.media.tv.DvbDeviceInfo> getDvbDeviceList();
method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public java.util.List<android.media.tv.TvInputHardwareInfo> getHardwareList();
method @RequiresPermission(android.Manifest.permission.READ_CONTENT_RATING_SYSTEMS) public java.util.List<android.media.tv.TvContentRatingSystemInfo> getTvContentRatingSystemList();
@@ -4909,6 +4927,10 @@
method public abstract void onStreamConfigChanged(android.media.tv.TvStreamConfig[]);
}
+ public abstract static class TvInputManager.TvInputCallback {
+ method public void onCurrentTunedInfosUpdated(@NonNull java.util.List<android.media.tv.TunedInfo>);
+ }
+
public abstract class TvInputService extends android.app.Service {
method @Nullable public android.media.tv.TvInputInfo onHardwareAdded(android.media.tv.TvInputHardwareInfo);
method @Nullable public String onHardwareRemoved(android.media.tv.TvInputHardwareInfo);
@@ -5036,6 +5058,7 @@
method @Nullable public android.media.tv.tuner.DemuxCapabilities getDemuxCapabilities();
method @Nullable public android.media.tv.tuner.frontend.FrontendInfo getFrontendInfo();
method @Nullable public android.media.tv.tuner.frontend.FrontendStatus getFrontendStatus(@NonNull int[]);
+ method public int linkFrontendToCiCam(int);
method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_DESCRAMBLER) public android.media.tv.tuner.Descrambler openDescrambler();
method @Nullable public android.media.tv.tuner.dvr.DvrPlayback openDvrPlayback(long, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.dvr.OnPlaybackStatusChangedListener);
method @Nullable public android.media.tv.tuner.dvr.DvrRecorder openDvrRecorder(long, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.dvr.OnRecordStatusChangedListener);
@@ -5049,9 +5072,14 @@
method public void setResourceLostListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.Tuner.OnResourceLostListener);
method public void shareFrontendFromTuner(@NonNull android.media.tv.tuner.Tuner);
method public int tune(@NonNull android.media.tv.tuner.frontend.FrontendSettings);
+ method public int unlinkFrontendToCiCam(int);
method public void updateResourcePriority(int, int);
field public static final int INVALID_AV_SYNC_ID = -1; // 0xffffffff
field public static final int INVALID_FILTER_ID = -1; // 0xffffffff
+ field public static final long INVALID_FILTER_ID_64BIT = -1L; // 0xffffffffffffffffL
+ field public static final int INVALID_FRONTEND_SETTING_FREQUENCY = -1; // 0xffffffff
+ field public static final int INVALID_LTS_ID = -1; // 0xffffffff
+ field public static final int INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM = -1; // 0xffffffff
field public static final int INVALID_STREAM_ID = 65535; // 0xffff
field public static final long INVALID_TIMESTAMP = -1L; // 0xffffffffffffffffL
field public static final int INVALID_TS_PID = 65535; // 0xffff
@@ -5071,15 +5099,22 @@
method public void onResourceLost(@NonNull android.media.tv.tuner.Tuner);
}
+ public final class TunerVersionChecker {
+ method public static int getTunerVersion();
+ field public static final int TUNER_VERSION_1_0 = 65536; // 0x10000
+ field public static final int TUNER_VERSION_1_1 = 65537; // 0x10001
+ field public static final int TUNER_VERSION_UNKNOWN = 0; // 0x0
+ }
+
}
package android.media.tv.tuner.dvr {
public class DvrPlayback implements java.lang.AutoCloseable {
- method public int attachFilter(@NonNull android.media.tv.tuner.filter.Filter);
+ method @Deprecated public int attachFilter(@NonNull android.media.tv.tuner.filter.Filter);
method public void close();
method public int configure(@NonNull android.media.tv.tuner.dvr.DvrSettings);
- method public int detachFilter(@NonNull android.media.tv.tuner.filter.Filter);
+ method @Deprecated public int detachFilter(@NonNull android.media.tv.tuner.filter.Filter);
method public int flush();
method public long read(long);
method public long read(@NonNull byte[], long, long);
@@ -5204,6 +5239,7 @@
method public int configure(@NonNull android.media.tv.tuner.filter.FilterConfiguration);
method public int flush();
method public int getId();
+ method public long getId64Bit();
method public int read(@NonNull byte[], long, long);
method public int setDataSource(@Nullable android.media.tv.tuner.filter.Filter);
method public int start();
@@ -5255,16 +5291,19 @@
method @NonNull public static android.media.tv.tuner.filter.IpFilterConfiguration.Builder builder();
method @NonNull @Size(min=4, max=16) public byte[] getDstIpAddress();
method public int getDstPort();
+ method public int getIpFilterContextId();
method @NonNull @Size(min=4, max=16) public byte[] getSrcIpAddress();
method public int getSrcPort();
method public int getType();
method public boolean isPassthrough();
+ field public static final int INVALID_IP_FILTER_CONTEXT_ID = -1; // 0xffffffff
}
public static final class IpFilterConfiguration.Builder {
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration build();
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setDstIpAddress(@NonNull byte[]);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setDstPort(int);
+ method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setIpFilterContextId(int);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setPassthrough(boolean);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setSrcIpAddress(@NonNull byte[]);
@@ -5304,6 +5343,8 @@
public class MmtpRecordEvent extends android.media.tv.tuner.filter.FilterEvent {
method public long getDataLength();
+ method public int getMpuSequenceNumber();
+ method public long getPts();
method public int getScHevcIndexMask();
}
@@ -5466,6 +5507,7 @@
public class TsRecordEvent extends android.media.tv.tuner.filter.FilterEvent {
method public long getDataLength();
method public int getPacketId();
+ method public long getPts();
method public int getScIndexMask();
method public int getTsIndexMask();
}
@@ -5481,9 +5523,13 @@
public class AnalogFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
method @NonNull public static android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder builder();
+ method public int getAftFlag();
method public int getSifStandard();
method public int getSignalType();
method public int getType();
+ field public static final int AFT_FLAG_FALSE = 2; // 0x2
+ field public static final int AFT_FLAG_TRUE = 1; // 0x1
+ field public static final int AFT_FLAG_UNDEFINED = 0; // 0x0
field public static final int SIF_AUTO = 1; // 0x1
field public static final int SIF_BG = 2; // 0x2
field public static final int SIF_BG_A2 = 4; // 0x4
@@ -5516,6 +5562,7 @@
public static class AnalogFrontendSettings.Builder {
method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings build();
+ method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setAftFlag(int);
method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setFrequency(int);
method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setSifStandard(int);
method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setSignalType(int);
@@ -5631,6 +5678,69 @@
method @NonNull public android.media.tv.tuner.frontend.AtscFrontendSettings.Builder setModulation(int);
}
+ public class DtmbFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
+ method public int getBandwidthCapability();
+ method public int getCodeRateCapability();
+ method public int getGuardIntervalCapability();
+ method public int getModulationCapability();
+ method public int getTimeInterleaveModeCapability();
+ method public int getTransmissionModeCapability();
+ }
+
+ public class DtmbFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
+ method @NonNull public static android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder builder();
+ method public int getBandwidth();
+ method public int getCodeRate();
+ method public int getGuardInterval();
+ method public int getModulation();
+ method public int getTimeInterleaveMode();
+ method public int getTransmissionMode();
+ method public int getType();
+ field public static final int BANDWIDTH_6MHZ = 4; // 0x4
+ field public static final int BANDWIDTH_8MHZ = 2; // 0x2
+ field public static final int BANDWIDTH_AUTO = 1; // 0x1
+ field public static final int BANDWIDTH_UNDEFINED = 0; // 0x0
+ field public static final int CODERATE_2_5 = 2; // 0x2
+ field public static final int CODERATE_3_5 = 4; // 0x4
+ field public static final int CODERATE_4_5 = 8; // 0x8
+ field public static final int CODERATE_AUTO = 1; // 0x1
+ field public static final int CODERATE_UNDEFINED = 0; // 0x0
+ field public static final int GUARD_INTERVAL_AUTO = 1; // 0x1
+ field public static final int GUARD_INTERVAL_PN_420_CONST = 16; // 0x10
+ field public static final int GUARD_INTERVAL_PN_420_VARIOUS = 2; // 0x2
+ field public static final int GUARD_INTERVAL_PN_595_CONST = 4; // 0x4
+ field public static final int GUARD_INTERVAL_PN_945_CONST = 32; // 0x20
+ field public static final int GUARD_INTERVAL_PN_945_VARIOUS = 8; // 0x8
+ field public static final int GUARD_INTERVAL_PN_RESERVED = 64; // 0x40
+ field public static final int GUARD_INTERVAL_UNDEFINED = 0; // 0x0
+ field public static final int MODULATION_CONSTELLATION_16QAM = 8; // 0x8
+ field public static final int MODULATION_CONSTELLATION_32QAM = 16; // 0x10
+ field public static final int MODULATION_CONSTELLATION_4QAM = 2; // 0x2
+ field public static final int MODULATION_CONSTELLATION_4QAM_NR = 4; // 0x4
+ field public static final int MODULATION_CONSTELLATION_64QAM = 32; // 0x20
+ field public static final int MODULATION_CONSTELLATION_AUTO = 1; // 0x1
+ field public static final int MODULATION_CONSTELLATION_UNDEFINED = 0; // 0x0
+ field public static final int TIME_INTERLEAVE_MODE_AUTO = 1; // 0x1
+ field public static final int TIME_INTERLEAVE_MODE_TIMER_INT_240 = 2; // 0x2
+ field public static final int TIME_INTERLEAVE_MODE_TIMER_INT_720 = 4; // 0x4
+ field public static final int TIME_INTERLEAVE_MODE_UNDEFINED = 0; // 0x0
+ field public static final int TRANSMISSION_MODE_AUTO = 1; // 0x1
+ field public static final int TRANSMISSION_MODE_C1 = 2; // 0x2
+ field public static final int TRANSMISSION_MODE_C3780 = 4; // 0x4
+ field public static final int TRANSMISSION_MODE_UNDEFINED = 0; // 0x0
+ }
+
+ public static final class DtmbFrontendSettings.Builder {
+ method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings build();
+ method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setBandwidth(int);
+ method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setCodeRate(int);
+ method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setFrequency(int);
+ method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setGuardInterval(int);
+ method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setModulation(int);
+ method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setTimeInterleaveMode(int);
+ method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setTransmissionMode(int);
+ }
+
public class DvbcFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
method public int getAnnexCapability();
method public int getFecCapability();
@@ -5645,6 +5755,7 @@
method public int getOuterFec();
method public int getSpectralInversion();
method public int getSymbolRate();
+ method public int getTimeInterleaveMode();
method public int getType();
field public static final int ANNEX_A = 1; // 0x1
field public static final int ANNEX_B = 2; // 0x2
@@ -5660,9 +5771,20 @@
field public static final int OUTER_FEC_OUTER_FEC_NONE = 1; // 0x1
field public static final int OUTER_FEC_OUTER_FEC_RS = 2; // 0x2
field public static final int OUTER_FEC_UNDEFINED = 0; // 0x0
- field public static final int SPECTRAL_INVERSION_INVERTED = 2; // 0x2
- field public static final int SPECTRAL_INVERSION_NORMAL = 1; // 0x1
- field public static final int SPECTRAL_INVERSION_UNDEFINED = 0; // 0x0
+ field @Deprecated public static final int SPECTRAL_INVERSION_INVERTED = 2; // 0x2
+ field @Deprecated public static final int SPECTRAL_INVERSION_NORMAL = 1; // 0x1
+ field @Deprecated public static final int SPECTRAL_INVERSION_UNDEFINED = 0; // 0x0
+ field public static final int TIME_INTERLEAVE_MODE_128_1_0 = 2; // 0x2
+ field public static final int TIME_INTERLEAVE_MODE_128_1_1 = 4; // 0x4
+ field public static final int TIME_INTERLEAVE_MODE_128_2 = 128; // 0x80
+ field public static final int TIME_INTERLEAVE_MODE_128_3 = 256; // 0x100
+ field public static final int TIME_INTERLEAVE_MODE_128_4 = 512; // 0x200
+ field public static final int TIME_INTERLEAVE_MODE_16_8 = 32; // 0x20
+ field public static final int TIME_INTERLEAVE_MODE_32_4 = 16; // 0x10
+ field public static final int TIME_INTERLEAVE_MODE_64_2 = 8; // 0x8
+ field public static final int TIME_INTERLEAVE_MODE_8_16 = 64; // 0x40
+ field public static final int TIME_INTERLEAVE_MODE_AUTO = 1; // 0x1
+ field public static final int TIME_INTERLEAVE_MODE_UNDEFINED = 0; // 0x0
}
public static class DvbcFrontendSettings.Builder {
@@ -5674,6 +5796,7 @@
method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setOuterFec(int);
method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setSpectralInversion(int);
method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setSymbolRate(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setTimeInterleaveMode(int);
}
public class DvbsCodeRate {
@@ -5705,6 +5828,7 @@
method public int getModulation();
method public int getPilot();
method public int getRolloff();
+ method public int getScanType();
method public int getStandard();
method public int getSymbolRate();
method public int getType();
@@ -5735,6 +5859,11 @@
field public static final int ROLLOFF_0_35 = 1; // 0x1
field public static final int ROLLOFF_0_5 = 6; // 0x6
field public static final int ROLLOFF_UNDEFINED = 0; // 0x0
+ field public static final int SCAN_TYPE_DIRECT = 1; // 0x1
+ field public static final int SCAN_TYPE_DISEQC = 2; // 0x2
+ field public static final int SCAN_TYPE_JESS = 4; // 0x4
+ field public static final int SCAN_TYPE_UNDEFINED = 0; // 0x0
+ field public static final int SCAN_TYPE_UNICABLE = 3; // 0x3
field public static final int STANDARD_AUTO = 1; // 0x1
field public static final int STANDARD_S = 2; // 0x2
field public static final int STANDARD_S2 = 4; // 0x4
@@ -5752,6 +5881,7 @@
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setModulation(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setPilot(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setRolloff(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setScanType(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setStandard(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setSymbolRate(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setVcmMode(int);
@@ -5804,10 +5934,14 @@
field public static final int CODERATE_AUTO = 1; // 0x1
field public static final int CODERATE_UNDEFINED = 0; // 0x0
field public static final int CONSTELLATION_16QAM = 4; // 0x4
+ field public static final int CONSTELLATION_16QAM_R = 64; // 0x40
field public static final int CONSTELLATION_256QAM = 16; // 0x10
+ field public static final int CONSTELLATION_256QAM_R = 256; // 0x100
field public static final int CONSTELLATION_64QAM = 8; // 0x8
+ field public static final int CONSTELLATION_64QAM_R = 128; // 0x80
field public static final int CONSTELLATION_AUTO = 1; // 0x1
field public static final int CONSTELLATION_QPSK = 2; // 0x2
+ field public static final int CONSTELLATION_QPSK_R = 32; // 0x20
field public static final int CONSTELLATION_UNDEFINED = 0; // 0x0
field public static final int GUARD_INTERVAL_19_128 = 64; // 0x40
field public static final int GUARD_INTERVAL_19_256 = 128; // 0x80
@@ -5841,6 +5975,9 @@
field public static final int TRANSMISSION_MODE_4K = 8; // 0x8
field public static final int TRANSMISSION_MODE_8K = 4; // 0x4
field public static final int TRANSMISSION_MODE_AUTO = 1; // 0x1
+ field public static final int TRANSMISSION_MODE_EXTENDED_16K = 256; // 0x100
+ field public static final int TRANSMISSION_MODE_EXTENDED_32K = 512; // 0x200
+ field public static final int TRANSMISSION_MODE_EXTENDED_8K = 128; // 0x80
field public static final int TRANSMISSION_MODE_UNDEFINED = 0; // 0x0
}
@@ -5878,8 +6015,12 @@
}
public abstract class FrontendSettings {
+ method public int getEndFrequency();
method public int getFrequency();
+ method public int getFrontendSpectralInversion();
method public abstract int getType();
+ method @IntRange(from=1) public void setEndFrequency(int);
+ method public void setSpectralInversion(int);
field public static final long FEC_11_15 = 4194304L; // 0x400000L
field public static final long FEC_11_20 = 8388608L; // 0x800000L
field public static final long FEC_11_45 = 16777216L; // 0x1000000L
@@ -5917,9 +6058,13 @@
field public static final long FEC_9_20 = 2097152L; // 0x200000L
field public static final long FEC_AUTO = 1L; // 0x1L
field public static final long FEC_UNDEFINED = 0L; // 0x0L
+ field public static final int FRONTEND_SPECTRAL_INVERSION_INVERTED = 2; // 0x2
+ field public static final int FRONTEND_SPECTRAL_INVERSION_NORMAL = 1; // 0x1
+ field public static final int FRONTEND_SPECTRAL_INVERSION_UNDEFINED = 0; // 0x0
field public static final int TYPE_ANALOG = 1; // 0x1
field public static final int TYPE_ATSC = 2; // 0x2
field public static final int TYPE_ATSC3 = 3; // 0x3
+ field public static final int TYPE_DTMB = 10; // 0xa
field public static final int TYPE_DVBC = 4; // 0x4
field public static final int TYPE_DVBS = 5; // 0x5
field public static final int TYPE_DVBT = 6; // 0x6
@@ -11027,6 +11172,25 @@
field public static final String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming";
}
+ public final class ModemActivityInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.telephony.ModemActivityInfo getDelta(@NonNull android.telephony.ModemActivityInfo);
+ method public long getIdleTimeMillis();
+ method public static int getNumTxPowerLevels();
+ method public long getReceiveTimeMillis();
+ method public long getSleepTimeMillis();
+ method public long getTimestampMillis();
+ method public long getTransmitDurationMillisAtPowerLevel(int);
+ method @NonNull public android.util.Range<java.lang.Integer> getTransmitPowerRange(int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ModemActivityInfo> CREATOR;
+ field public static final int TX_POWER_LEVEL_0 = 0; // 0x0
+ field public static final int TX_POWER_LEVEL_1 = 1; // 0x1
+ field public static final int TX_POWER_LEVEL_2 = 2; // 0x2
+ field public static final int TX_POWER_LEVEL_3 = 3; // 0x3
+ field public static final int TX_POWER_LEVEL_4 = 4; // 0x4
+ }
+
public final class NetworkRegistrationInfo implements android.os.Parcelable {
method @Nullable public android.telephony.DataSpecificRegistrationInfo getDataSpecificInfo();
method public int getRegistrationState();
@@ -11520,7 +11684,6 @@
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDeviceSoftwareVersion(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEmergencyNumberDbVersion();
- method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<java.lang.String> getEquivalentHomePlmns();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Map<java.lang.Integer,java.lang.Integer> getLogicalToPhysicalSlotMapping();
diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt
index 7195144..773ecd03 100644
--- a/api/system-lint-baseline.txt
+++ b/api/system-lint-baseline.txt
@@ -159,8 +159,6 @@
MissingNullability: android.telephony.ModemActivityInfo#writeToParcel(android.os.Parcel, int) parameter #0:
-MissingNullability: android.telephony.ModemActivityInfo.TransmitPower#toString():
-
MissingNullability: android.telephony.NetworkService#onUnbind(android.content.Intent) parameter #0:
MissingNullability: android.telephony.SmsCbCmasInfo#toString():
diff --git a/api/test-current.txt b/api/test-current.txt
index 7666337..c58a2a2 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -14,6 +14,7 @@
field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
field public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
field public static final String MANAGE_CRATES = "android.permission.MANAGE_CRATES";
+ field public static final String MANAGE_NOTIFICATION_LISTENERS = "android.permission.MANAGE_NOTIFICATION_LISTENERS";
field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
field public static final String NETWORK_SETTINGS = "android.permission.NETWORK_SETTINGS";
field public static final String NETWORK_STACK = "android.permission.NETWORK_STACK";
@@ -79,20 +80,22 @@
}
public class ActivityManager {
+ method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void addHomeVisibilityListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.HomeVisibilityListener);
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int);
method public void alwaysShowUnsupportedCompileSdkWarning(android.content.ComponentName);
method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void forceStopPackage(String);
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getPackageImportance(String);
method public long getTotalRam();
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getUidImportance(int);
- method @RequiresPermission("android.permission.INJECT_EVENTS") public void holdLock(int);
+ method @RequiresPermission(android.Manifest.permission.INJECT_EVENTS) public void holdLock(int);
method public static boolean isHighEndGfx();
method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void killProcessesWhenImperceptible(@NonNull int[], @NonNull String);
+ method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void removeHomeVisibilityListener(@NonNull android.app.HomeVisibilityListener);
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
method @RequiresPermission(android.Manifest.permission.RESET_APP_ERRORS) public void resetAppErrors();
method public static void resumeAppSwitches() throws android.os.RemoteException;
method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int);
- method @RequiresPermission("android.permission.MANAGE_USERS") public boolean switchUser(@NonNull android.os.UserHandle);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean switchUser(@NonNull android.os.UserHandle);
field public static final int PROCESS_CAPABILITY_ALL = 7; // 0x7
field public static final int PROCESS_CAPABILITY_ALL_EXPLICIT = 1; // 0x1
field public static final int PROCESS_CAPABILITY_ALL_IMPLICIT = 6; // 0x6
@@ -201,12 +204,12 @@
public class AppOpsManager {
method @RequiresPermission("android.permission.MANAGE_APPOPS") public void addHistoricalOps(@NonNull android.app.AppOpsManager.HistoricalOps);
method @RequiresPermission("android.permission.MANAGE_APPOPS") public void clearHistory();
- method @Nullable @RequiresPermission("android.permission.GET_APP_OPS_STATS") public android.app.RuntimeAppOpAccessMessage collectRuntimeAppOpAccessMessage();
- method @RequiresPermission("android.permission.GET_APP_OPS_STATS") public void getHistoricalOps(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
+ method @Nullable @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public android.app.RuntimeAppOpAccessMessage collectRuntimeAppOpAccessMessage();
+ method @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public void getHistoricalOps(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
method @RequiresPermission("android.permission.MANAGE_APPOPS") public void getHistoricalOpsFromDiskRaw(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @Nullable java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
method public static int getNumOps();
method public static String[] getOpStrs();
- method @NonNull @RequiresPermission("android.permission.GET_APP_OPS_STATS") public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, @NonNull String, @Nullable java.lang.String...);
+ method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, @NonNull String, @Nullable java.lang.String...);
method public boolean isOperationActive(int, int, String);
method @RequiresPermission("android.permission.MANAGE_APPOPS") public void offsetHistory(long);
method public static int opToDefaultMode(@NonNull String);
@@ -452,10 +455,15 @@
}
public class DreamManager {
- method @RequiresPermission("android.permission.READ_DREAM_STATE") public boolean isDreaming();
- method @RequiresPermission("android.permission.WRITE_DREAM_STATE") public void setActiveDream(@NonNull android.content.ComponentName);
- method @RequiresPermission("android.permission.WRITE_DREAM_STATE") public void startDream(@NonNull android.content.ComponentName);
- method @RequiresPermission("android.permission.WRITE_DREAM_STATE") public void stopDream();
+ method @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE) public boolean isDreaming();
+ method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void setActiveDream(@NonNull android.content.ComponentName);
+ method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void startDream(@NonNull android.content.ComponentName);
+ method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void stopDream();
+ }
+
+ public abstract class HomeVisibilityListener {
+ ctor public HomeVisibilityListener();
+ method public abstract void onHomeVisibilityChanged(boolean);
}
public final class NotificationChannel implements android.os.Parcelable {
@@ -487,9 +495,11 @@
method @NonNull public java.util.List<java.lang.String> getAllowedAssistantAdjustments();
method @Nullable public android.content.ComponentName getAllowedNotificationAssistant();
method public android.content.ComponentName getEffectsSuppressor();
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public java.util.List<android.content.ComponentName> getEnabledNotificationListeners();
method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName);
method public boolean matchesCallFilter(android.os.Bundle);
method public void setNotificationAssistantAccessGranted(@Nullable android.content.ComponentName, boolean);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public void setNotificationListenerAccessGranted(@NonNull android.content.ComponentName, boolean);
method public void updateNotificationChannel(@NonNull String, int, @NonNull android.app.NotificationChannel);
}
@@ -547,14 +557,14 @@
}
public class UiModeManager {
- method @RequiresPermission("android.permission.ENTER_CAR_MODE_PRIORITIZED") public void enableCarMode(@IntRange(from=0) int, int);
+ method @RequiresPermission(android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED) public void enableCarMode(@IntRange(from=0) int, int);
method public boolean isNightModeLocked();
method public boolean isUiModeLocked();
}
public class WallpaperManager {
method @Nullable public android.graphics.Bitmap getBitmap();
- method @RequiresPermission("android.permission.SET_WALLPAPER_COMPONENT") public boolean setWallpaperComponent(android.content.ComponentName);
+ method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT) public boolean setWallpaperComponent(android.content.ComponentName);
method public boolean shouldEnableWideColorGamut();
method @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) public boolean wallpaperSupportsWcg(int);
}
@@ -630,11 +640,11 @@
package android.app.backup {
public class BackupManager {
- method @RequiresPermission("android.permission.BACKUP") public android.content.Intent getConfigurationIntent(String);
- method @RequiresPermission("android.permission.BACKUP") public android.content.Intent getDataManagementIntent(String);
- method @Nullable @RequiresPermission("android.permission.BACKUP") public CharSequence getDataManagementIntentLabel(@NonNull String);
- method @Deprecated @Nullable @RequiresPermission("android.permission.BACKUP") public String getDataManagementLabel(@NonNull String);
- method @RequiresPermission("android.permission.BACKUP") public String getDestinationString(String);
+ method @RequiresPermission(android.Manifest.permission.BACKUP) public android.content.Intent getConfigurationIntent(String);
+ method @RequiresPermission(android.Manifest.permission.BACKUP) public android.content.Intent getDataManagementIntent(String);
+ method @Nullable @RequiresPermission(android.Manifest.permission.BACKUP) public CharSequence getDataManagementIntentLabel(@NonNull String);
+ method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.BACKUP) public String getDataManagementLabel(@NonNull String);
+ method @RequiresPermission(android.Manifest.permission.BACKUP) public String getDestinationString(String);
}
}
@@ -759,21 +769,21 @@
}
public class RoleControllerManager {
- method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void isApplicationVisibleForRole(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void isRoleVisible(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void isApplicationVisibleForRole(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void isRoleVisible(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
}
public final class RoleManager {
- method @RequiresPermission("android.permission.OBSERVE_ROLE_HOLDERS") public void addOnRoleHoldersChangedListenerAsUser(@NonNull java.util.concurrent.Executor, @NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
- method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void addRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_ROLE_HOLDERS) public void addOnRoleHoldersChangedListenerAsUser(@NonNull java.util.concurrent.Executor, @NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void addRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean addRoleHolderFromController(@NonNull String, @NonNull String);
- method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @NonNull @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public java.util.List<java.lang.String> getHeldRolesFromController(@NonNull String);
- method @NonNull @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
- method @NonNull @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
method @Nullable public String getSmsRoleHolder(int);
- method @RequiresPermission("android.permission.OBSERVE_ROLE_HOLDERS") public void removeOnRoleHoldersChangedListenerAsUser(@NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
- method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_ROLE_HOLDERS) public void removeOnRoleHoldersChangedListenerAsUser(@NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean removeRoleHolderFromController(@NonNull String, @NonNull String);
method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public void setRoleNamesFromController(@NonNull java.util.List<java.lang.String>);
field public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1; // 0x1
@@ -880,7 +890,7 @@
method public int getUserId();
method public void setAutofillOptions(@Nullable android.content.AutofillOptions);
method public void setContentCaptureOptions(@Nullable android.content.ContentCaptureOptions);
- method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.os.UserHandle);
+ method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.os.UserHandle);
field public static final String APP_INTEGRITY_SERVICE = "app_integrity";
field public static final String BUGREPORT_SERVICE = "bugreport";
field public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture";
@@ -899,7 +909,7 @@
}
public class Intent implements java.lang.Cloneable android.os.Parcelable {
- field @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public static final String ACTION_MANAGE_DEFAULT_APP = "android.intent.action.MANAGE_DEFAULT_APP";
+ field @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public static final String ACTION_MANAGE_DEFAULT_APP = "android.intent.action.MANAGE_DEFAULT_APP";
field public static final String ACTION_ROLLBACK_COMMITTED = "android.intent.action.ROLLBACK_COMMITTED";
field public static final String EXTRA_ORIGINATING_UID = "android.intent.extra.ORIGINATING_UID";
field public static final String EXTRA_ROLE_NAME = "android.intent.extra.ROLE_NAME";
@@ -999,7 +1009,7 @@
public static class PackageInstaller.SessionParams implements android.os.Parcelable {
method public void setEnableRollback(boolean);
method public void setEnableRollback(boolean, int);
- method @RequiresPermission("android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS") public void setGrantedRuntimePermissions(String[]);
+ method @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS) public void setGrantedRuntimePermissions(String[]);
method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setInstallAsApex();
method public void setInstallAsInstantApp(boolean);
method public void setInstallerPackageName(@Nullable String);
@@ -1011,25 +1021,25 @@
method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void addOnPermissionsChangeListener(@NonNull android.content.pm.PackageManager.OnPermissionsChangedListener);
method public abstract boolean arePermissionsIndividuallyControlled();
method @Nullable public String getContentCaptureServicePackageName();
- method @Nullable @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract String getDefaultBrowserPackageNameAsUser(int);
+ method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract String getDefaultBrowserPackageNameAsUser(int);
method @Nullable public String getDefaultTextClassifierPackageName();
method @Nullable public String getIncidentReportApproverPackageName();
method public abstract int getInstallReason(@NonNull String, @NonNull android.os.UserHandle);
method @NonNull public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplicationsAsUser(int, int);
- method @NonNull @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
method @Nullable public abstract String[] getNamesForUids(int[]);
method @NonNull public abstract String getPermissionControllerPackageName();
- method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS", "android.permission.GET_RUNTIME_PERMISSIONS"}) public abstract int getPermissionFlags(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
+ method @android.content.pm.PackageManager.PermissionFlags @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, android.Manifest.permission.GET_RUNTIME_PERMISSIONS}) public abstract int getPermissionFlags(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
method @NonNull public abstract String getServicesSystemSharedLibraryPackageName();
method @NonNull public abstract String getSharedSystemSharedLibraryPackageName();
method @Nullable public String getSystemTextClassifierPackageName();
method @Nullable public String getWellbeingPackageName();
- method @RequiresPermission("android.permission.GRANT_RUNTIME_PERMISSIONS") public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
- method @RequiresPermission("android.permission.INJECT_EVENTS") public void holdLock(int);
+ method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
+ method @RequiresPermission(android.Manifest.permission.INJECT_EVENTS) public void holdLock(int);
method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void removeOnPermissionsChangeListener(@NonNull android.content.pm.PackageManager.OnPermissionsChangedListener);
- method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
- method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull String);
- method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS"}) public abstract void updatePermissionFlags(@NonNull String, @NonNull String, int, int, @NonNull android.os.UserHandle);
+ method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
+ method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull String);
+ method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS}) public abstract void updatePermissionFlags(@NonNull String, @NonNull String, @android.content.pm.PackageManager.PermissionFlags int, @android.content.pm.PackageManager.PermissionFlags int, @NonNull android.os.UserHandle);
field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
field public static final String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption";
field public static final int FLAG_PERMISSION_APPLY_RESTRICTION = 16384; // 0x4000
@@ -1227,20 +1237,19 @@
package android.hardware.biometrics {
public class BiometricManager {
- method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public android.hardware.biometrics.BiometricTestSession getTestSession();
+ method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public android.hardware.biometrics.BiometricTestSession createTestSession(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public java.util.List<android.hardware.biometrics.SensorProperties> getSensorProperties();
}
public class BiometricTestSession implements java.lang.AutoCloseable {
- method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void authenticateReject(int, int);
- method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void authenticateSuccess(int, int);
+ method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void acceptAuthentication(int);
+ method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void cleanupInternalState(int);
method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void close();
- method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void enableTestHal(int, boolean);
- method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void enrollFinish(int, int);
- method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void enrollStart(int, int);
- method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public java.util.List<android.hardware.biometrics.SensorProperties> getSensorProperties();
- method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void internalCleanup(int, int);
- method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void notifyAcquired(int, int);
- method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void notifyError(int, int);
+ method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void finishEnroll(int);
+ method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void notifyAcquired(int);
+ method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void notifyError(int);
+ method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void rejectAuthentication(int);
+ method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void startEnroll(int);
}
public class SensorProperties {
@@ -1343,7 +1352,7 @@
}
public final class DisplayManager {
- method @RequiresPermission("android.permission.ACCESS_AMBIENT_LIGHT_STATS") public java.util.List<android.hardware.display.AmbientBrightnessDayStats> getAmbientBrightnessStats();
+ method @RequiresPermission(android.Manifest.permission.ACCESS_AMBIENT_LIGHT_STATS) public java.util.List<android.hardware.display.AmbientBrightnessDayStats> getAmbientBrightnessStats();
method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public android.hardware.display.BrightnessConfiguration getBrightnessConfiguration();
method @RequiresPermission(android.Manifest.permission.BRIGHTNESS_SLIDER_USAGE) public java.util.List<android.hardware.display.BrightnessChangeEvent> getBrightnessEvents();
method @Nullable @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public android.hardware.display.BrightnessConfiguration getDefaultBrightnessConfiguration();
@@ -1361,7 +1370,8 @@
package android.hardware.fingerprint {
@Deprecated public class FingerprintManager {
- method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public android.hardware.biometrics.BiometricTestSession getTestSession();
+ method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public android.hardware.biometrics.BiometricTestSession createTestSession(int);
+ method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public java.util.List<android.hardware.biometrics.SensorProperties> getSensorProperties();
}
}
@@ -1370,7 +1380,7 @@
public final class HdmiControlManager {
method @Nullable public android.hardware.hdmi.HdmiSwitchClient getSwitchClient();
- method @RequiresPermission("android.permission.HDMI_CEC") public void setStandbyMode(boolean);
+ method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setStandbyMode(boolean);
field public static final String ACTION_OSD_MESSAGE = "android.hardware.hdmi.action.OSD_MESSAGE";
field public static final int AVR_VOLUME_MUTED = 101; // 0x65
field public static final int CLEAR_TIMER_STATUS_CEC_DISABLE = 162; // 0xa2
@@ -1481,11 +1491,9 @@
field public static final int PORT_OUTPUT = 1; // 0x1
}
- public class HdmiSwitchClient {
+ public class HdmiSwitchClient extends android.hardware.hdmi.HdmiClient {
method public int getDeviceType();
method @NonNull public java.util.List<android.hardware.hdmi.HdmiPortInfo> getPortInfo();
- method public void sendKeyEvent(int, boolean);
- method public void sendVendorCommand(int, byte[], boolean);
}
}
@@ -1756,7 +1764,7 @@
method @NonNull public String[] getBackgroundThrottlingWhitelist();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
method @NonNull public String[] getIgnoreSettingsWhitelist();
- method @Deprecated @Nullable @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public java.util.List<java.lang.String> getProviderPackages(@NonNull String);
+ method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public java.util.List<java.lang.String> getProviderPackages(@NonNull String);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
@@ -1769,15 +1777,15 @@
method public boolean isHiddenFromAppOps();
method public boolean isLocationSettingsIgnored();
method public boolean isLowPower();
- field public static final int ACCURACY_BLOCK = 102; // 0x66
- field public static final int ACCURACY_CITY = 104; // 0x68
- field public static final int ACCURACY_FINE = 100; // 0x64
- field public static final int POWER_HIGH = 203; // 0xcb
- field public static final int POWER_LOW = 201; // 0xc9
+ field @Deprecated public static final int ACCURACY_BLOCK = 102; // 0x66
+ field @Deprecated public static final int ACCURACY_CITY = 104; // 0x68
+ field @Deprecated public static final int ACCURACY_FINE = 100; // 0x64
+ field @Deprecated public static final int POWER_HIGH = 203; // 0xcb
+ field @Deprecated public static final int POWER_LOW = 201; // 0xc9
}
public static final class LocationRequest.Builder {
- method @NonNull @RequiresPermission("android.permission.UPDATE_APP_OPS_STATS") public android.location.LocationRequest.Builder setHiddenFromAppOps(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LocationRequest.Builder setHiddenFromAppOps(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest.Builder setLocationSettingsIgnored(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.location.LocationRequest.Builder setLowPower(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
@@ -1812,12 +1820,12 @@
}
public class AudioManager {
- method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
method public boolean hasRegisteredDynamicPolicy();
- method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
- method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
- method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
- method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public void unregisterAudioPolicyAsync(@NonNull android.media.audiopolicy.AudioPolicy);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicyAsync(@NonNull android.media.audiopolicy.AudioPolicy);
field public static final int SUCCESS = 0; // 0x0
}
@@ -2132,6 +2140,21 @@
}
+package android.media.tv.tuner {
+
+ public final class TunerVersionChecker {
+ method public static int getMajorVersion(int);
+ method public static int getMinorVersion(int);
+ method public static int getTunerVersion();
+ method public static boolean isHigherOrEqualVersionTo(int);
+ method public static boolean supportTunerVersion(int);
+ field public static final int TUNER_VERSION_1_0 = 65536; // 0x10000
+ field public static final int TUNER_VERSION_1_1 = 65537; // 0x10001
+ field public static final int TUNER_VERSION_UNKNOWN = 0; // 0x0
+ }
+
+}
+
package android.metrics {
public class LogMaker {
@@ -2310,15 +2333,15 @@
method @NonNull public android.net.NetworkCapabilities build();
method @NonNull public android.net.NetworkCapabilities.Builder removeCapability(int);
method @NonNull public android.net.NetworkCapabilities.Builder removeTransportType(int);
- method @NonNull @RequiresPermission("android.permission.NETWORK_FACTORY") public android.net.NetworkCapabilities.Builder setAdministratorUids(@NonNull int[]);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAdministratorUids(@NonNull int[]);
method @NonNull public android.net.NetworkCapabilities.Builder setLinkDownstreamBandwidthKbps(int);
method @NonNull public android.net.NetworkCapabilities.Builder setLinkUpstreamBandwidthKbps(int);
method @NonNull public android.net.NetworkCapabilities.Builder setNetworkSpecifier(@Nullable android.net.NetworkSpecifier);
- method @NonNull @RequiresPermission("android.permission.NETWORK_FACTORY") public android.net.NetworkCapabilities.Builder setOwnerUid(int);
- method @NonNull @RequiresPermission("android.permission.NETWORK_FACTORY") public android.net.NetworkCapabilities.Builder setRequestorPackageName(@Nullable String);
- method @NonNull @RequiresPermission("android.permission.NETWORK_FACTORY") public android.net.NetworkCapabilities.Builder setRequestorUid(int);
- method @NonNull @RequiresPermission("android.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP") public android.net.NetworkCapabilities.Builder setSignalStrength(int);
- method @NonNull @RequiresPermission("android.permission.NETWORK_FACTORY") public android.net.NetworkCapabilities.Builder setSsid(@Nullable String);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setOwnerUid(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorPackageName(@Nullable String);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorUid(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkCapabilities.Builder setSignalStrength(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setSsid(@Nullable String);
method @NonNull public android.net.NetworkCapabilities.Builder setTransportInfo(@Nullable android.net.TransportInfo);
}
@@ -2376,100 +2399,6 @@
method public void teardownTestNetwork(@NonNull android.net.Network);
}
- public final class TetheredClient implements android.os.Parcelable {
- ctor public TetheredClient(@NonNull android.net.MacAddress, @NonNull java.util.Collection<android.net.TetheredClient.AddressInfo>, int);
- method public int describeContents();
- method @NonNull public java.util.List<android.net.TetheredClient.AddressInfo> getAddresses();
- method @NonNull public android.net.MacAddress getMacAddress();
- method public int getTetheringType();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient> CREATOR;
- }
-
- public static final class TetheredClient.AddressInfo implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.net.LinkAddress getAddress();
- method @Nullable public String getHostname();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient.AddressInfo> CREATOR;
- }
-
- public class TetheringManager {
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback);
- method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener);
- method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
- method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering();
- method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int);
- method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback);
- field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED";
- field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY";
- field public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
- field public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
- field public static final String EXTRA_ERRORED_TETHER = "erroredArray";
- field public static final int TETHERING_BLUETOOTH = 2; // 0x2
- field public static final int TETHERING_ETHERNET = 5; // 0x5
- field public static final int TETHERING_INVALID = -1; // 0xffffffff
- field public static final int TETHERING_NCM = 4; // 0x4
- field public static final int TETHERING_USB = 1; // 0x1
- field public static final int TETHERING_WIFI = 0; // 0x0
- field public static final int TETHERING_WIFI_P2P = 3; // 0x3
- field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc
- field public static final int TETHER_ERROR_DISABLE_FORWARDING_ERROR = 9; // 0x9
- field public static final int TETHER_ERROR_ENABLE_FORWARDING_ERROR = 8; // 0x8
- field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd
- field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa
- field public static final int TETHER_ERROR_INTERNAL_ERROR = 5; // 0x5
- field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf
- field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe
- field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
- field public static final int TETHER_ERROR_PROVISIONING_FAILED = 11; // 0xb
- field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2
- field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6
- field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4
- field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
- field public static final int TETHER_ERROR_UNKNOWN_TYPE = 16; // 0x10
- field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
- field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
- field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2
- field public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1; // 0x1
- field public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0; // 0x0
- }
-
- public static interface TetheringManager.OnTetheringEntitlementResultListener {
- method public void onTetheringEntitlementResult(int);
- }
-
- public static interface TetheringManager.StartTetheringCallback {
- method public default void onTetheringFailed(int);
- method public default void onTetheringStarted();
- }
-
- public static interface TetheringManager.TetheringEventCallback {
- method public default void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
- method public default void onError(@NonNull String, int);
- method public default void onOffloadStatusChanged(int);
- method public default void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
- method public default void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
- method public default void onTetheringSupported(boolean);
- method public default void onUpstreamChanged(@Nullable android.net.Network);
- }
-
- public static class TetheringManager.TetheringRequest {
- method @Nullable public android.net.LinkAddress getClientStaticIpv4Address();
- method @Nullable public android.net.LinkAddress getLocalIpv4Address();
- method public boolean getShouldShowEntitlementUi();
- method public int getTetheringType();
- method public boolean isExemptFromEntitlementCheck();
- }
-
- public static class TetheringManager.TetheringRequest.Builder {
- ctor public TetheringManager.TetheringRequest.Builder(int);
- method @NonNull public android.net.TetheringManager.TetheringRequest build();
- method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean);
- method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setShouldShowEntitlementUi(boolean);
- method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress);
- }
-
public class TrafficStats {
method public static long getLoopbackRxBytes();
method public static long getLoopbackRxPackets();
@@ -2669,7 +2598,7 @@
package android.os {
public class BatteryManager {
- method @RequiresPermission("android.permission.POWER_SAVER") public boolean setChargingStateUpdateDelayMillis(int);
+ method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public boolean setChargingStateUpdateDelayMillis(int);
}
public final class BugreportManager {
@@ -2713,7 +2642,7 @@
}
public class DeviceIdleManager {
- method @RequiresPermission("android.permission.DEVICE_POWER") public void endIdle(@NonNull String);
+ method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void endIdle(@NonNull String);
method @NonNull public String[] getSystemPowerWhitelist();
method @NonNull public String[] getSystemPowerWhitelistExceptIdle();
}
@@ -2966,21 +2895,21 @@
}
public final class PowerManager {
- method @RequiresPermission("android.permission.POWER_SAVER") public int getPowerSaveModeTrigger();
- method @RequiresPermission("android.permission.DEVICE_POWER") public void setBatteryDischargePrediction(@NonNull java.time.Duration, boolean);
- method @RequiresPermission("android.permission.POWER_SAVER") public boolean setDynamicPowerSaveHint(boolean, int);
- method @RequiresPermission(anyOf={"android.permission.DEVICE_POWER", "android.permission.POWER_SAVER"}) public boolean setPowerSaveModeEnabled(boolean);
+ method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public int getPowerSaveModeTrigger();
+ method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void setBatteryDischargePrediction(@NonNull java.time.Duration, boolean);
+ method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public boolean setDynamicPowerSaveHint(boolean, int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setPowerSaveModeEnabled(boolean);
field public static final String ACTION_ENHANCED_DISCHARGE_PREDICTION_CHANGED = "android.os.action.ENHANCED_DISCHARGE_PREDICTION_CHANGED";
field public static final int POWER_SAVE_MODE_TRIGGER_DYNAMIC = 1; // 0x1
field public static final int POWER_SAVE_MODE_TRIGGER_PERCENTAGE = 0; // 0x0
}
public class PowerWhitelistManager {
- method @RequiresPermission("android.permission.DEVICE_POWER") public void addToWhitelist(@NonNull String);
- method @RequiresPermission("android.permission.DEVICE_POWER") public void addToWhitelist(@NonNull java.util.List<java.lang.String>);
- method @RequiresPermission("android.permission.DEVICE_POWER") public void removeFromWhitelist(@NonNull String);
- method @RequiresPermission("android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST") public void whitelistAppTemporarily(@NonNull String, long);
- method @RequiresPermission("android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST") public long whitelistAppTemporarilyForEvent(@NonNull String, int, @NonNull String);
+ method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull String);
+ method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull java.util.List<java.lang.String>);
+ method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void removeFromWhitelist(@NonNull String);
+ method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String, long);
+ method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String, int, @NonNull String);
field public static final int EVENT_MMS = 2; // 0x2
field public static final int EVENT_SMS = 1; // 0x1
field public static final int EVENT_UNSPECIFIED = 0; // 0x0
@@ -3046,8 +2975,8 @@
}
public class SystemConfigManager {
- method @NonNull @RequiresPermission("android.permission.READ_CARRIER_APP_INFO") public java.util.Set<java.lang.String> getDisabledUntilUsedPreinstalledCarrierApps();
- method @NonNull @RequiresPermission("android.permission.READ_CARRIER_APP_INFO") public java.util.Map<java.lang.String,java.util.List<java.lang.String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
+ method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Set<java.lang.String> getDisabledUntilUsedPreinstalledCarrierApps();
+ method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Map<java.lang.String,java.util.List<java.lang.String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
}
public class SystemProperties {
@@ -3076,7 +3005,7 @@
}
public class UserManager {
- method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.CREATE_USERS"}) public boolean hasBaseUserRestriction(@NonNull String, @NonNull android.os.UserHandle);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean hasBaseUserRestriction(@NonNull String, @NonNull android.os.UserHandle);
method public static boolean isSplitSystemUser();
field public static final String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED";
}
@@ -3136,10 +3065,10 @@
}
public abstract class Vibrator {
- method @RequiresPermission("android.permission.ACCESS_VIBRATOR_STATE") public void addVibratorStateListener(@NonNull android.os.Vibrator.OnVibratorStateChangedListener);
- method @RequiresPermission("android.permission.ACCESS_VIBRATOR_STATE") public void addVibratorStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.os.Vibrator.OnVibratorStateChangedListener);
- method @RequiresPermission("android.permission.ACCESS_VIBRATOR_STATE") public boolean isVibrating();
- method @RequiresPermission("android.permission.ACCESS_VIBRATOR_STATE") public void removeVibratorStateListener(@NonNull android.os.Vibrator.OnVibratorStateChangedListener);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE) public void addVibratorStateListener(@NonNull android.os.Vibrator.OnVibratorStateChangedListener);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE) public void addVibratorStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.os.Vibrator.OnVibratorStateChangedListener);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE) public boolean isVibrating();
+ method @RequiresPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE) public void removeVibratorStateListener(@NonNull android.os.Vibrator.OnVibratorStateChangedListener);
}
public static interface Vibrator.OnVibratorStateChangedListener {
@@ -3238,12 +3167,12 @@
public class DynamicSystemClient {
ctor public DynamicSystemClient(@NonNull android.content.Context);
- method @RequiresPermission("android.permission.INSTALL_DYNAMIC_SYSTEM") public void bind();
+ method @RequiresPermission(android.Manifest.permission.INSTALL_DYNAMIC_SYSTEM) public void bind();
method public void setOnStatusChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.os.image.DynamicSystemClient.OnStatusChangedListener);
method public void setOnStatusChangedListener(@NonNull android.os.image.DynamicSystemClient.OnStatusChangedListener);
- method @RequiresPermission("android.permission.INSTALL_DYNAMIC_SYSTEM") public void start(@NonNull android.net.Uri, long);
- method @RequiresPermission("android.permission.INSTALL_DYNAMIC_SYSTEM") public void start(@NonNull android.net.Uri, long, long);
- method @RequiresPermission("android.permission.INSTALL_DYNAMIC_SYSTEM") public void unbind();
+ method @RequiresPermission(android.Manifest.permission.INSTALL_DYNAMIC_SYSTEM) public void start(@NonNull android.net.Uri, long);
+ method @RequiresPermission(android.Manifest.permission.INSTALL_DYNAMIC_SYSTEM) public void start(@NonNull android.net.Uri, long, long);
+ method @RequiresPermission(android.Manifest.permission.INSTALL_DYNAMIC_SYSTEM) public void unbind();
field public static final int CAUSE_ERROR_EXCEPTION = 6; // 0x6
field public static final int CAUSE_ERROR_INVALID_URL = 4; // 0x4
field public static final int CAUSE_ERROR_IO = 3; // 0x3
@@ -3297,13 +3226,13 @@
package android.permission {
public final class PermissionControllerManager {
- method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.RESTORE_RUNTIME_PERMISSIONS"}) public void applyStagedRuntimePermissionBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @RequiresPermission("android.permission.GET_RUNTIME_PERMISSIONS") public void countPermissionApps(@NonNull java.util.List<java.lang.String>, int, @NonNull android.permission.PermissionControllerManager.OnCountPermissionAppsResultCallback, @Nullable android.os.Handler);
- method @RequiresPermission("android.permission.GET_RUNTIME_PERMISSIONS") public void getAppPermissions(@NonNull String, @NonNull android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback, @Nullable android.os.Handler);
- method @RequiresPermission("android.permission.GET_RUNTIME_PERMISSIONS") public void getRuntimePermissionBackup(@NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<byte[]>);
- method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public void revokeRuntimePermission(@NonNull String, @NonNull String);
- method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public void revokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull java.util.concurrent.Executor, @NonNull android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback);
- method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.RESTORE_RUNTIME_PERMISSIONS"}) public void stageAndApplyRuntimePermissionsBackup(@NonNull byte[], @NonNull android.os.UserHandle);
+ method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.RESTORE_RUNTIME_PERMISSIONS}) public void applyStagedRuntimePermissionBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+ method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public void countPermissionApps(@NonNull java.util.List<java.lang.String>, int, @NonNull android.permission.PermissionControllerManager.OnCountPermissionAppsResultCallback, @Nullable android.os.Handler);
+ method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public void getAppPermissions(@NonNull String, @NonNull android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback, @Nullable android.os.Handler);
+ method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public void getRuntimePermissionBackup(@NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<byte[]>);
+ method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public void revokeRuntimePermission(@NonNull String, @NonNull String);
+ method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public void revokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull java.util.concurrent.Executor, @NonNull android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.RESTORE_RUNTIME_PERMISSIONS}) public void stageAndApplyRuntimePermissionsBackup(@NonNull byte[], @NonNull android.os.UserHandle);
field public static final int COUNT_ONLY_WHEN_GRANTED = 1; // 0x1
field public static final int COUNT_WHEN_SYSTEM = 2; // 0x2
field public static final int REASON_INSTALLER_POLICY_VIOLATION = 2; // 0x2
@@ -3324,9 +3253,9 @@
}
public final class PermissionManager {
- method @IntRange(from=0) @RequiresPermission(anyOf={"android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY", android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public int getRuntimePermissionsVersion();
+ method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public int getRuntimePermissionsVersion();
method @NonNull public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions();
- method @RequiresPermission(anyOf={"android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY", android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
}
public static final class PermissionManager.SplitPermissionInfo {
@@ -3392,14 +3321,14 @@
}
public final class DeviceConfig {
- method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static void addOnPropertiesChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
- method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static boolean getBoolean(@NonNull String, @NonNull String, boolean);
- method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static float getFloat(@NonNull String, @NonNull String, float);
- method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static int getInt(@NonNull String, @NonNull String, int);
- method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static long getLong(@NonNull String, @NonNull String, long);
- method @NonNull @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static android.provider.DeviceConfig.Properties getProperties(@NonNull String, @NonNull java.lang.String...);
- method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getProperty(@NonNull String, @NonNull String);
- method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getString(@NonNull String, @NonNull String, @Nullable String);
+ method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertiesChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
+ method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static boolean getBoolean(@NonNull String, @NonNull String, boolean);
+ method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static float getFloat(@NonNull String, @NonNull String, float);
+ method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static int getInt(@NonNull String, @NonNull String, int);
+ method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static long getLong(@NonNull String, @NonNull String, long);
+ method @NonNull @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static android.provider.DeviceConfig.Properties getProperties(@NonNull String, @NonNull java.lang.String...);
+ method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getProperty(@NonNull String, @NonNull String);
+ method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getString(@NonNull String, @NonNull String, @Nullable String);
method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String);
method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperties(@NonNull android.provider.DeviceConfig.Properties) throws android.provider.DeviceConfig.BadConfigException;
@@ -3450,12 +3379,6 @@
method @NonNull public static android.net.Uri setManageMode(@NonNull android.net.Uri);
}
- public final class MediaStore {
- method @NonNull @WorkerThread public static android.net.Uri scanFile(@NonNull android.content.ContentResolver, @NonNull java.io.File);
- method @WorkerThread public static void scanVolume(@NonNull android.content.ContentResolver, @NonNull String);
- method @WorkerThread public static void waitForIdle(@NonNull android.content.ContentResolver);
- }
-
public final class Settings {
field public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
field public static final String ACTION_MANAGE_APP_OVERLAY_PERMISSION = "android.settings.MANAGE_APP_OVERLAY_PERMISSION";
@@ -3472,6 +3395,7 @@
field public static final String DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD = "dynamic_power_savings_disable_threshold";
field public static final String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled";
field public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions";
+ field public static final String HIDDEN_API_POLICY = "hidden_api_policy";
field public static final String HIDE_ERROR_DIALOGS = "hide_error_dialogs";
field public static final String LOCATION_GLOBAL_KILL_SWITCH = "location_global_kill_switch";
field public static final String LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST = "location_ignore_settings_package_whitelist";
@@ -3487,6 +3411,11 @@
public static final class Settings.Secure extends android.provider.Settings.NameValueTable {
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static void resetToDefaults(@NonNull android.content.ContentResolver, @Nullable String);
field public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED = "accessibility_display_magnification_enabled";
+ field public static final String ACCESSIBILITY_MAGNIFICATION_CAPABILITY = "accessibility_magnification_capability";
+ field public static final String ACCESSIBILITY_MAGNIFICATION_MODE = "accessibility_magnification_mode";
+ field public static final int ACCESSIBILITY_MAGNIFICATION_MODE_ALL = 3; // 0x3
+ field public static final int ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN = 1; // 0x1
+ field public static final int ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW = 2; // 0x2
field public static final String ACCESSIBILITY_SHORTCUT_TARGET_SERVICE = "accessibility_shortcut_target_service";
field public static final String ANR_SHOW_BACKGROUND = "anr_show_background";
field public static final String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = "autofill_field_classification";
@@ -4214,6 +4143,27 @@
field public static final String MBMS_STREAMING_SERVICE_OVERRIDE_METADATA = "mbms-streaming-service-override";
}
+ public final class ModemActivityInfo implements android.os.Parcelable {
+ ctor public ModemActivityInfo(long, int, int, @NonNull int[], int);
+ method public int describeContents();
+ method @NonNull public android.telephony.ModemActivityInfo getDelta(@NonNull android.telephony.ModemActivityInfo);
+ method public long getIdleTimeMillis();
+ method public static int getNumTxPowerLevels();
+ method public long getReceiveTimeMillis();
+ method public long getSleepTimeMillis();
+ method public long getTimestampMillis();
+ method public long getTransmitDurationMillisAtPowerLevel(int);
+ method @NonNull public android.util.Range<java.lang.Integer> getTransmitPowerRange(int);
+ method public boolean isValid();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ModemActivityInfo> CREATOR;
+ field public static final int TX_POWER_LEVEL_0 = 0; // 0x0
+ field public static final int TX_POWER_LEVEL_1 = 1; // 0x1
+ field public static final int TX_POWER_LEVEL_2 = 2; // 0x2
+ field public static final int TX_POWER_LEVEL_3 = 3; // 0x3
+ field public static final int TX_POWER_LEVEL_4 = 4; // 0x4
+ }
+
public final class NetworkRegistrationInfo implements android.os.Parcelable {
method @Nullable public android.telephony.DataSpecificRegistrationInfo getDataSpecificInfo();
method public int getRegistrationState();
@@ -4256,8 +4206,8 @@
method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int);
method @Deprecated public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber);
method public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber, int);
- field @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public static final int LISTEN_OUTGOING_EMERGENCY_CALL = 268435456; // 0x10000000
- field @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 536870912; // 0x20000000
+ field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_CALL = 268435456; // 0x10000000
+ field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 536870912; // 0x20000000
}
public final class PreciseDataConnectionState implements android.os.Parcelable {
@@ -4298,10 +4248,10 @@
public class TelephonyManager {
method public int addDevicePolicyOverrideApn(@NonNull android.content.Context, @NonNull android.telephony.data.ApnSetting);
method public int checkCarrierPrivilegesForPackage(String);
- method @Nullable @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public android.content.ComponentName getAndUpdateDefaultRespondViaMessageApplication();
+ method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getAndUpdateDefaultRespondViaMessageApplication();
method public int getCarrierIdListVersion();
method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
- method @Nullable @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public android.content.ComponentName getDefaultRespondViaMessageApplication();
+ method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getDefaultRespondViaMessageApplication();
method @NonNull public java.util.List<android.telephony.data.ApnSetting> getDevicePolicyOverrideApns(@NonNull android.content.Context);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEmergencyNumberDbVersion();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1AlphaTag();
@@ -4309,13 +4259,13 @@
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isMobileDataPolicyEnabled(int);
method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile();
- method @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public void resetOtaEmergencyNumberDbFilePath();
+ method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void resetOtaEmergencyNumberDbFilePath();
method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String);
method public void setCarrierTestOverride(String, String, String, String, String, String, String, String, String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMobileDataPolicyEnabledStatus(int, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSystemSelectionChannels(@NonNull java.util.List<android.telephony.RadioAccessSpecifier>, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSystemSelectionChannels(@NonNull java.util.List<android.telephony.RadioAccessSpecifier>);
- method @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public void updateOtaEmergencyNumberDbFilePath(@NonNull android.os.ParcelFileDescriptor);
+ method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void updateOtaEmergencyNumberDbFilePath(@NonNull android.os.ParcelFileDescriptor);
field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe
field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
@@ -5398,7 +5348,7 @@
}
public interface WindowManager extends android.view.ViewManager {
- method @RequiresPermission("android.permission.INJECT_EVENTS") public default void holdLock(int);
+ method @RequiresPermission(android.Manifest.permission.INJECT_EVENTS) public default void holdLock(int);
method public default void setShouldShowIme(int, boolean);
method public default void setShouldShowSystemDecors(int, boolean);
method public default void setShouldShowWithInsecureKeyguard(int, boolean);
@@ -5419,11 +5369,11 @@
public final class AccessibilityManager {
method public void addAccessibilityServicesStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener, @Nullable android.os.Handler);
- method @NonNull @RequiresPermission("android.permission.MANAGE_ACCESSIBILITY") public java.util.List<java.lang.String> getAccessibilityShortcutTargets(int);
- method @RequiresPermission("android.permission.MANAGE_ACCESSIBILITY") public void performAccessibilityShortcut();
- method @RequiresPermission("android.permission.MANAGE_ACCESSIBILITY") public void registerSystemAction(@NonNull android.app.RemoteAction, int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public java.util.List<java.lang.String> getAccessibilityShortcutTargets(int);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public void performAccessibilityShortcut();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public void registerSystemAction(@NonNull android.app.RemoteAction, int);
method public void removeAccessibilityServicesStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener);
- method @RequiresPermission("android.permission.MANAGE_ACCESSIBILITY") public void unregisterSystemAction(int);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public void unregisterSystemAction(int);
}
public static interface AccessibilityManager.AccessibilityServicesStateChangeListener {
@@ -5766,6 +5716,15 @@
field public static final int FEATURE_WINDOW_TOKENS = 2; // 0x2
}
+ public final class TaskAppearedInfo implements android.os.Parcelable {
+ ctor public TaskAppearedInfo(@NonNull android.app.ActivityManager.RunningTaskInfo, @NonNull android.view.SurfaceControl);
+ method public int describeContents();
+ method @NonNull public android.view.SurfaceControl getLeash();
+ method @NonNull public android.app.ActivityManager.RunningTaskInfo getTaskInfo();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskAppearedInfo> CREATOR;
+ }
+
public class TaskOrganizer extends android.window.WindowOrganizer {
ctor public TaskOrganizer();
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public android.app.ActivityManager.RunningTaskInfo createRootTask(int, int);
@@ -5777,10 +5736,10 @@
method @BinderThread public void onTaskAppeared(@NonNull android.app.ActivityManager.RunningTaskInfo, @NonNull android.view.SurfaceControl);
method @BinderThread public void onTaskInfoChanged(@NonNull android.app.ActivityManager.RunningTaskInfo);
method @BinderThread public void onTaskVanished(@NonNull android.app.ActivityManager.RunningTaskInfo);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void registerOrganizer();
+ method @CallSuper @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public java.util.List<android.window.TaskAppearedInfo> registerOrganizer();
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setInterceptBackPressedOnTaskRoot(@NonNull android.window.WindowContainerToken, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setLaunchRoot(int, @NonNull android.window.WindowContainerToken);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void unregisterOrganizer();
+ method @CallSuper @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void unregisterOrganizer();
}
public final class WindowContainerToken implements android.os.Parcelable {
diff --git a/api/test-lint-baseline.txt b/api/test-lint-baseline.txt
index 91a09e3..0440d1a 100644
--- a/api/test-lint-baseline.txt
+++ b/api/test-lint-baseline.txt
@@ -2511,6 +2511,8 @@
NoSettingsProvider: android.provider.Settings.Global#HIDDEN_API_BLACKLIST_EXEMPTIONS:
+NoSettingsProvider: android.provider.Settings.Global#HIDDEN_API_POLICY:
+
NoSettingsProvider: android.provider.Settings.Global#HIDE_ERROR_DIALOGS:
NoSettingsProvider: android.provider.Settings.Global#LOCATION_GLOBAL_KILL_SWITCH:
@@ -2530,6 +2532,16 @@
NoSettingsProvider: android.provider.Settings.Global#USE_OPEN_WIFI_PACKAGE:
NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED:
+
+NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_CAPABILITY:
+
+NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE:
+
+NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_ALL:
+
+NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN:
+
+NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW:
NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE:
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 4beb748..091e9a7 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -266,7 +266,7 @@
147 [(module) = "framework", (module) = "statsd"];
BiometricSystemHealthIssueDetected biometric_system_health_issue_detected =
148 [(module) = "framework"];
- BubbleUIChanged bubble_ui_changed = 149 [(module) = "sysui"];
+ BubbleUIChanged bubble_ui_changed = 149 [(module) = "framework"];
ScheduledJobConstraintChanged scheduled_job_constraint_changed =
150 [(module) = "framework"];
BluetoothActiveDeviceChanged bluetooth_active_device_changed =
@@ -3834,6 +3834,12 @@
// App startup time (until call to Activity#reportFullyDrawn()).
optional int64 app_startup_time_millis = 6;
+ // The compiler filter used when when the package was optimized.
+ optional int32 package_optimization_compilation_filter = 7;
+
+ // The reason why the package was optimized.
+ optional int32 package_optimization_compilation_reason = 8;
+
enum SourceType {
UNAVAILABLE = 0;
LAUNCHER = 1;
@@ -3841,11 +3847,11 @@
LOCKSCREEN = 3;
}
// The type of the startup source.
- optional SourceType source_type = 7;
+ optional SourceType source_type = 9;
// The time from the startup source to the beginning of handling the startup event.
// -1 means not available.
- optional int32 source_event_delay_millis = 8;
+ optional int32 source_event_delay_millis = 10;
}
/**
@@ -5269,12 +5275,23 @@
* Event to track Jank for various system interactions.
*
* Logged from:
- * frameworks/base/core/java/android/os/aot/FrameTracker.java
+ * frameworks/base/core/java/com/android/internal/jank/FrameTracker.java
*/
message UIInteractionFrameInfoReported {
enum InteractionType {
UNKNOWN = 0;
NOTIFICATION_SHADE_SWIPE = 1;
+ SHADE_EXPAND_COLLAPSE_LOCK = 2;
+ SHADE_SCROLL_FLING = 3;
+ SHADE_ROW_EXPAND = 4;
+ SHADE_ROW_SWIPE = 5;
+ SHADE_QS_EXPAND_COLLAPSE = 6;
+ SHADE_QS_SCROLL_SWIPE = 7;
+ LAUNCHER_APP_LAUNCH_FROM_RECENTS = 8;
+ LAUNCHER_APP_LAUNCH_FROM_ICON = 9;
+ LAUNCHER_APP_CLOSE_TO_HOME = 10;
+ LAUNCHER_APP_CLOSE_TO_PIP = 11;
+ LAUNCHER_QUICK_SWITCH = 12;
}
optional InteractionType interaction_type = 1;
diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
index 93795d4..d32f5a9 100644
--- a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
+++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
@@ -516,6 +516,21 @@
return false;
}
}
+ for (int i = 0; i < config.duration_metric_size(); i++, metricIndex++) {
+ const DurationMetric& metric = config.duration_metric(i);
+ set<int64_t> conditionDependencies({metric.what()});
+ if (metric.has_condition()) {
+ conditionDependencies.insert(metric.condition());
+ }
+ if (!determineMetricUpdateStatus(
+ config, metric, metric.id(), METRIC_TYPE_DURATION, /*matcherDependencies=*/{},
+ conditionDependencies, metric.slice_by_state(), metric.links(),
+ oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
+ replacedMatchers, replacedConditions, replacedStates,
+ metricsToUpdate[metricIndex])) {
+ return false;
+ }
+ }
for (int i = 0; i < config.event_metric_size(); i++, metricIndex++) {
const EventMetric& metric = config.event_metric(i);
set<int64_t> conditionDependencies;
@@ -538,8 +553,7 @@
if (metric.has_condition()) {
conditionDependencies.insert(metric.condition());
}
- set<int64_t> matcherDependencies;
- matcherDependencies.insert(metric.what());
+ set<int64_t> matcherDependencies({metric.what()});
if (metric.has_trigger_event()) {
matcherDependencies.insert(metric.trigger_event());
}
@@ -552,7 +566,7 @@
return false;
}
}
- // TODO: determine update status for value, duration metrics.
+ // TODO: determine update status for value metrics.
return true;
}
diff --git a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
index 60705cf..a20be15 100644
--- a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
+++ b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
@@ -155,6 +155,20 @@
return metric;
}
+DurationMetric createDurationMetric(string name, int64_t what, optional<int64_t> condition,
+ vector<int64_t> states) {
+ DurationMetric metric;
+ metric.set_id(StringToId(name));
+ metric.set_what(what);
+ metric.set_bucket(TEN_MINUTES);
+ if (condition) {
+ metric.set_condition(condition.value());
+ }
+ for (const int64_t state : states) {
+ metric.add_slice_by_state(state);
+ }
+ return metric;
+}
} // anonymous namespace
TEST_F(ConfigUpdateTest, TestSimpleMatcherPreserve) {
@@ -1398,6 +1412,130 @@
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
+TEST_F(ConfigUpdateTest, TestDurationMetricPreserve) {
+ StatsdConfig config;
+ AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = startMatcher;
+ AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = stopMatcher;
+
+ Predicate what = CreateScreenIsOnPredicate();
+ *config.add_predicate() = what;
+ Predicate condition = CreateScreenIsOffPredicate();
+ *config.add_predicate() = condition;
+
+ State sliceState = CreateScreenState();
+ *config.add_state() = sliceState;
+
+ *config.add_duration_metric() =
+ createDurationMetric("DURATION1", what.id(), condition.id(), {sliceState.id()});
+ EXPECT_TRUE(initConfig(config));
+
+ unordered_map<int64_t, int> metricToActivationMap;
+ vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
+ EXPECT_TRUE(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
+ metricToActivationMap,
+ /*replacedMatchers*/ {}, /*replacedConditions=*/{},
+ /*replacedStates=*/{}, metricsToUpdate));
+ EXPECT_EQ(metricsToUpdate[0], UPDATE_PRESERVE);
+}
+
+TEST_F(ConfigUpdateTest, TestDurationMetricDefinitionChange) {
+ StatsdConfig config;
+ AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = startMatcher;
+ AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = stopMatcher;
+
+ Predicate what = CreateScreenIsOnPredicate();
+ *config.add_predicate() = what;
+
+ *config.add_duration_metric() = createDurationMetric("DURATION1", what.id(), nullopt, {});
+ EXPECT_TRUE(initConfig(config));
+
+ config.mutable_duration_metric(0)->set_aggregation_type(DurationMetric::MAX_SPARSE);
+
+ unordered_map<int64_t, int> metricToActivationMap;
+ vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
+ EXPECT_TRUE(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
+ metricToActivationMap, /*replacedMatchers*/ {},
+ /*replacedConditions=*/{}, /*replacedStates=*/{},
+ metricsToUpdate));
+ EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
+}
+
+TEST_F(ConfigUpdateTest, TestDurationMetricWhatChanged) {
+ StatsdConfig config;
+ AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = startMatcher;
+ AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = stopMatcher;
+
+ Predicate what = CreateScreenIsOnPredicate();
+ *config.add_predicate() = what;
+
+ *config.add_duration_metric() = createDurationMetric("DURATION1", what.id(), nullopt, {});
+ EXPECT_TRUE(initConfig(config));
+
+ unordered_map<int64_t, int> metricToActivationMap;
+ vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
+ EXPECT_TRUE(determineAllMetricUpdateStatuses(
+ config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
+ /*replacedMatchers*/ {}, /*replacedConditions=*/{what.id()},
+ /*replacedStates=*/{}, metricsToUpdate));
+ EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
+}
+
+TEST_F(ConfigUpdateTest, TestDurationMetricConditionChanged) {
+ StatsdConfig config;
+ AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = startMatcher;
+ AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = stopMatcher;
+
+ Predicate what = CreateScreenIsOnPredicate();
+ *config.add_predicate() = what;
+ Predicate condition = CreateScreenIsOffPredicate();
+ *config.add_predicate() = condition;
+
+ *config.add_duration_metric() = createDurationMetric("DURATION", what.id(), condition.id(), {});
+ EXPECT_TRUE(initConfig(config));
+
+ unordered_map<int64_t, int> metricToActivationMap;
+ vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
+ EXPECT_TRUE(determineAllMetricUpdateStatuses(
+ config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
+ /*replacedMatchers*/ {}, /*replacedConditions=*/{condition.id()},
+ /*replacedStates=*/{}, metricsToUpdate));
+ EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
+}
+
+TEST_F(ConfigUpdateTest, TestDurationMetricStateChange) {
+ StatsdConfig config;
+ AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = startMatcher;
+ AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = stopMatcher;
+
+ Predicate what = CreateScreenIsOnPredicate();
+ *config.add_predicate() = what;
+
+ State sliceState = CreateScreenState();
+ *config.add_state() = sliceState;
+
+ *config.add_duration_metric() =
+ createDurationMetric("DURATION1", what.id(), nullopt, {sliceState.id()});
+ EXPECT_TRUE(initConfig(config));
+
+ unordered_map<int64_t, int> metricToActivationMap;
+ vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
+ EXPECT_TRUE(determineAllMetricUpdateStatuses(
+ config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
+ /*replacedMatchers*/ {}, /*replacedConditions=*/{},
+ /*replacedStates=*/{sliceState.id()}, metricsToUpdate));
+ EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
+}
+
TEST_F(ConfigUpdateTest, TestUpdateEventMetrics) {
StatsdConfig config;
diff --git a/core/java/android/accessibilityservice/AccessibilityGestureEvent.java b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
index 25729ab..e3139eb 100644
--- a/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
+++ b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
@@ -20,6 +20,7 @@
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_DOUBLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SINGLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SINGLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_DOWN;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_LEFT;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_RIGHT;
@@ -28,11 +29,13 @@
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_DOUBLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SINGLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_DOWN;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_LEFT;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_RIGHT;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_UP;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_TRIPLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_DOUBLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SINGLE_TAP;
@@ -85,13 +88,16 @@
/** @hide */
@IntDef(prefix = { "GESTURE_" }, value = {
GESTURE_2_FINGER_SINGLE_TAP,
+ GESTURE_2_FINGER_SINGLE_TAP_AND_HOLD,
GESTURE_2_FINGER_DOUBLE_TAP,
GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD,
GESTURE_2_FINGER_TRIPLE_TAP,
GESTURE_3_FINGER_SINGLE_TAP,
+ GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD,
GESTURE_3_FINGER_DOUBLE_TAP,
GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD,
GESTURE_3_FINGER_TRIPLE_TAP,
+ GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD,
GESTURE_DOUBLE_TAP,
GESTURE_DOUBLE_TAP_AND_HOLD,
GESTURE_SWIPE_UP,
@@ -180,15 +186,21 @@
private static String eventTypeToString(int eventType) {
switch (eventType) {
case GESTURE_2_FINGER_SINGLE_TAP: return "GESTURE_2_FINGER_SINGLE_TAP";
+ case GESTURE_2_FINGER_SINGLE_TAP_AND_HOLD:
+ return "GESTURE_2_FINGER_SINGLE_TAP_AND_HOLD";
case GESTURE_2_FINGER_DOUBLE_TAP: return "GESTURE_2_FINGER_DOUBLE_TAP";
case GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD:
return "GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD";
case GESTURE_2_FINGER_TRIPLE_TAP: return "GESTURE_2_FINGER_TRIPLE_TAP";
case GESTURE_3_FINGER_SINGLE_TAP: return "GESTURE_3_FINGER_SINGLE_TAP";
+ case GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD:
+ return "GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD";
case GESTURE_3_FINGER_DOUBLE_TAP: return "GESTURE_3_FINGER_DOUBLE_TAP";
case GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD:
return "GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD";
case GESTURE_3_FINGER_TRIPLE_TAP: return "GESTURE_3_FINGER_TRIPLE_TAP";
+ case GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD:
+ return "GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD";
case GESTURE_4_FINGER_SINGLE_TAP: return "GESTURE_4_FINGER_SINGLE_TAP";
case GESTURE_4_FINGER_DOUBLE_TAP: return "GESTURE_4_FINGER_DOUBLE_TAP";
case GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD:
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index b5b0ce3..7c6d448 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -421,6 +421,15 @@
/** The user has performed a three-finger double tap and hold gesture on the touch screen. */
public static final int GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD = 41;
+ /** The user has performed a two-finger single-tap and hold gesture on the touch screen. */
+ public static final int GESTURE_2_FINGER_SINGLE_TAP_AND_HOLD = 43;
+
+ /** The user has performed a three-finger single-tap and hold gesture on the touch screen. */
+ public static final int GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD = 44;
+
+ /** The user has performed a three-finger triple-tap and hold gesture on the touch screen. */
+ public static final int GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD = 45;
+
/** The user has performed a two-finger double tap and hold gesture on the touch screen. */
public static final int GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD = 42;
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index e75d2f6..30efb48 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -100,6 +100,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Locale;
+import java.util.concurrent.Executor;
/**
* <p>
@@ -4752,31 +4753,43 @@
}
/**
- * Register with {@link HomeVisibilityObserver} with ActivityManager.
- * TODO: b/144351078 expose as SystemApi
+ * Register to be notified when the visibility of the home screen changes.
+ *
+ * @param executor The executor on which the listener should be called.
+ * @param listener The listener that is called when home visibility changes.
* @hide
*/
- public void registerHomeVisibilityObserver(@NonNull HomeVisibilityObserver observer) {
- Preconditions.checkNotNull(observer);
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+ public void addHomeVisibilityListener(@NonNull Executor executor,
+ @NonNull HomeVisibilityListener listener) {
+ Preconditions.checkNotNull(listener);
+ Preconditions.checkNotNull(executor);
try {
- observer.init(mContext, this);
- getService().registerProcessObserver(observer.mObserver);
+ listener.init(mContext, executor, this);
+ getService().registerProcessObserver(listener.mObserver);
// Notify upon first registration.
- observer.onHomeVisibilityChanged(observer.mIsHomeActivityVisible);
+ executor.execute(() ->
+ listener.onHomeVisibilityChanged(listener.mIsHomeActivityVisible));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Unregister with {@link HomeVisibilityObserver} with ActivityManager.
- * TODO: b/144351078 expose as SystemApi
+ * Removes a listener that was previously added with {@link #addHomeVisibilityListener}.
+ *
+ * @param listener The listener that was previously added.
* @hide
*/
- public void unregisterHomeVisibilityObserver(@NonNull HomeVisibilityObserver observer) {
- Preconditions.checkNotNull(observer);
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+ public void removeHomeVisibilityListener(@NonNull HomeVisibilityListener listener) {
+ Preconditions.checkNotNull(listener);
try {
- getService().unregisterProcessObserver(observer.mObserver);
+ getService().unregisterProcessObserver(listener.mObserver);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 155de36..c5bc356 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -7911,7 +7911,7 @@
*
* @param op The op to note
* @param proxiedUid The uid to note the op for {@code null}
- * @param proxiedUid The package name the uid belongs to
+ * @param proxiedPackageName The package name the uid belongs to
* @param proxiedAttributionTag The proxied {@link Context#createAttributionContext
* attribution tag} or {@code null} for default attribution
* @param message A message describing the reason the op was noted
@@ -7939,17 +7939,7 @@
*Like {@link #startProxyOp(String, int, String, String, String)} but instead
* of throwing a {@link SecurityException} it returns {@link #MODE_ERRORED}.
*
- * @param op The op to note
- * @param proxiedUid The uid to note the op for {@code null}
- * @param proxiedUid The package name the uid belongs to
- * @param proxiedAttributionTag The proxied {@link Context#createAttributionContext
- * attribution tag} or {@code null} for default attribution
- * @param message A message describing the reason the op was noted*
- * <p>This API requires package with the {@code proxiedPackageName} to belong to
- * {@code proxiedUid}.
- *
- * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or {@link #MODE_IGNORED}
- * if it is not allowed and should be silently ignored (without causing the app to crash).
+ * @see #startProxyOp(String, int, String, String, String)
*/
public int startProxyOpNoThrow(@NonNull String op, int proxiedUid,
@NonNull String proxiedPackageName, @Nullable String proxiedAttributionTag,
diff --git a/core/java/android/app/HomeVisibilityListener.java b/core/java/android/app/HomeVisibilityListener.java
new file mode 100644
index 0000000..c6e5699
--- /dev/null
+++ b/core/java/android/app/HomeVisibilityListener.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2020 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 android.app;
+
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.content.Context;
+import android.os.Binder;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * A listener that will be invoked when the visibility of the home screen changes.
+ * Register this callback via {@link ActivityManager#addHomeVisibilityListener}
+ * @hide
+ */
+// This is a single-method listener that needs a bunch of supporting code, so it can't be an
+// interface
+@SuppressLint("ListenerInterface")
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+@TestApi
+public abstract class HomeVisibilityListener {
+ private Context mContext;
+ private ActivityManager mActivityManager;
+ private Executor mExecutor;
+ /** @hide */
+ android.app.IProcessObserver.Stub mObserver;
+ /** @hide */
+ boolean mIsHomeActivityVisible;
+
+ /** @hide */
+ void init(Context context, Executor executor, ActivityManager activityManager) {
+ mContext = context;
+ mActivityManager = activityManager;
+ mIsHomeActivityVisible = isHomeActivityVisible();
+ mExecutor = executor;
+ }
+
+ /**
+ * Called when the visibility of the home screen changes.
+ *
+ * @param isHomeActivityVisible Whether the home screen activity is now visible.
+ */
+ public abstract void onHomeVisibilityChanged(boolean isHomeActivityVisible);
+
+ public HomeVisibilityListener() {
+ mObserver = new android.app.IProcessObserver.Stub() {
+ @Override
+ public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
+ refreshHomeVisibility();
+ }
+
+ @Override
+ public void onForegroundServicesChanged(int pid, int uid, int fgServiceTypes) {
+ }
+
+ @Override
+ public void onProcessDied(int pid, int uid) {
+ refreshHomeVisibility();
+ }
+
+ private void refreshHomeVisibility() {
+ boolean isHomeActivityVisible = isHomeActivityVisible();
+ if (mIsHomeActivityVisible != isHomeActivityVisible) {
+ mIsHomeActivityVisible = isHomeActivityVisible;
+ Binder.withCleanCallingIdentity(() ->
+ mExecutor.execute(() ->
+ onHomeVisibilityChanged(mIsHomeActivityVisible)));
+ }
+ }
+ };
+ }
+
+ private boolean isHomeActivityVisible() {
+ List<ActivityManager.RunningTaskInfo> tasks = mActivityManager.getRunningTasks(1);
+ if (tasks == null || tasks.isEmpty()) {
+ return false;
+ }
+
+ String top = tasks.get(0).topActivity.getPackageName();
+ if (top == null) {
+ return false;
+ }
+
+ // We can assume that the screen is idle if the home application is in the foreground.
+ String defaultHomePackage = mContext.getPackageManager()
+ .getHomeActivities(new ArrayList<>()).getPackageName();
+ if (Objects.equals(top, defaultHomePackage)) {
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/core/java/android/app/HomeVisibilityObserver.java b/core/java/android/app/HomeVisibilityObserver.java
deleted file mode 100644
index 8422c6f..0000000
--- a/core/java/android/app/HomeVisibilityObserver.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2020 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 android.app;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-
-import java.util.List;
-
-/**
- * An observer / callback to create and register by
- * {@link ActivityManager#registerHomeVisibilityObserver} so that it's triggered when
- * visibility of home page changes.
- * TODO: b/144351078 expose as SystemApi
- * @hide
- */
-public abstract class HomeVisibilityObserver {
- private Context mContext;
- private ActivityManager mActivityManager;
- /** @hide */
- IProcessObserver.Stub mObserver;
- /** @hide */
- boolean mIsHomeActivityVisible;
-
- /** @hide */
- void init(Context context, ActivityManager activityManager) {
- mContext = context;
- mActivityManager = activityManager;
- mIsHomeActivityVisible = isHomeActivityVisible();
- }
-
- /**
- * The API that needs implemented and will be triggered when activity on home page changes.
- */
- public abstract void onHomeVisibilityChanged(boolean isHomeActivityVisible);
-
- public HomeVisibilityObserver() {
- mObserver = new IProcessObserver.Stub() {
- @Override
- public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
- boolean isHomeActivityVisible = isHomeActivityVisible();
- if (mIsHomeActivityVisible != isHomeActivityVisible) {
- mIsHomeActivityVisible = isHomeActivityVisible;
- onHomeVisibilityChanged(mIsHomeActivityVisible);
- }
- }
-
- @Override
- public void onForegroundServicesChanged(int pid, int uid, int fgServiceTypes) {
- }
-
- @Override
- public void onProcessDied(int pid, int uid) {
- }
- };
- }
-
- private boolean isHomeActivityVisible() {
- List<ActivityManager.RunningTaskInfo> tasks = mActivityManager.getRunningTasks(1);
- if (tasks == null || tasks.isEmpty()) {
- return false;
- }
-
- String top = tasks.get(0).topActivity.getPackageName();
- if (top == null) {
- return false;
- }
-
- // We can assume that the screen is idle if the home application is in the foreground.
- final Intent intent = new Intent(Intent.ACTION_MAIN, null);
- intent.addCategory(Intent.CATEGORY_HOME);
-
- ResolveInfo info = mContext.getPackageManager().resolveActivity(intent,
- PackageManager.MATCH_DEFAULT_ONLY);
- if (info != null && top.equals(info.activityInfo.packageName)) {
- return true;
- }
-
- return false;
- }
-}
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 66007e5..7530229 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -165,7 +165,8 @@
int getTaskForActivity(in IBinder token, in boolean onlyRoot);
/** Finish all activities that were started for result from the specified activity. */
void finishSubActivity(in IBinder token, in String resultWho, int requestCode);
- ParceledListSlice getRecentTasks(int maxNum, int flags, int userId);
+ ParceledListSlice<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, int flags,
+ int userId);
boolean willActivityBeVisible(in IBinder token);
void setRequestedOrientation(in IBinder token, int requestedOrientation);
int getRequestedOrientation(in IBinder token);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0d682d6..5438062 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2240,7 +2240,8 @@
.setTicker(tickerText)
.setContentTitle(contentTitle)
.setContentText(contentText)
- .setContentIntent(PendingIntent.getActivity(context, 0, contentIntent, 0))
+ .setContentIntent(PendingIntent.getActivity(
+ context, 0, contentIntent, PendingIntent.FLAG_MUTABLE))
.buildInto(this);
}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index fe89366..d442f5f 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1567,8 +1567,20 @@
}
}
- /** @hide */
- public void setNotificationListenerAccessGranted(ComponentName listener, boolean granted) {
+ /**
+ * Grants/revokes Notification Listener access to the given component for current user.
+ * To grant access for a particular user, obtain this service by using the {@link Context}
+ * provided by {@link Context#createPackageContextAsUser}
+ *
+ * @param listener Name of component to grant/revoke access
+ * @param granted Grant/revoke access
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS)
+ public void setNotificationListenerAccessGranted(
+ @NonNull ComponentName listener, boolean granted) {
INotificationManager service = getService();
try {
service.setNotificationListenerAccessGranted(listener, granted);
@@ -1610,6 +1622,21 @@
}
}
+ /**
+ * Gets the list of enabled notification listener components for current user.
+ * To query for a particular user, obtain this service by using the {@link Context}
+ * provided by {@link Context#createPackageContextAsUser}
+ *
+ * @return the list of {@link ComponentName}s of the notification listeners
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS)
+ public @NonNull List<ComponentName> getEnabledNotificationListeners() {
+ return getEnabledNotificationListeners(mContext.getUserId());
+ }
+
/** @hide */
public List<ComponentName> getEnabledNotificationListeners(int userId) {
INotificationManager service = getService();
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index e8937a8..8054cdb 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -363,6 +363,7 @@
* parameters. May return null only if {@link #FLAG_NO_CREATE} has been
* supplied.
*/
+ @SuppressWarnings("AndroidFrameworkPendingIntentMutability")
public static PendingIntent getActivity(Context context, int requestCode,
Intent intent, @Flags int flags) {
return getActivity(context, requestCode, intent, flags, null);
@@ -489,6 +490,7 @@
* parameters. May return null only if {@link #FLAG_NO_CREATE} has been
* supplied.
*/
+ @SuppressWarnings("AndroidFrameworkPendingIntentMutability")
public static PendingIntent getActivities(Context context, int requestCode,
@NonNull Intent[] intents, @Flags int flags) {
return getActivities(context, requestCode, intents, flags, null);
@@ -611,6 +613,7 @@
* parameters. May return null only if {@link #FLAG_NO_CREATE} has been
* supplied.
*/
+ @SuppressWarnings("AndroidFrameworkPendingIntentMutability")
public static PendingIntent getBroadcast(Context context, int requestCode,
Intent intent, @Flags int flags) {
return getBroadcastAsUser(context, requestCode, intent, flags, context.getUser());
diff --git a/core/java/android/app/Presentation.java b/core/java/android/app/Presentation.java
index 7a18b81..ad90364 100644
--- a/core/java/android/app/Presentation.java
+++ b/core/java/android/app/Presentation.java
@@ -16,30 +16,28 @@
package android.app;
-import static android.content.Context.DISPLAY_SERVICE;
-import static android.content.Context.WINDOW_SERVICE;
+import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION;
import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
+import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Resources;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
-import android.os.Binder;
+import android.os.Build;
import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.util.DisplayMetrics;
-import android.util.Log;
+import android.os.Looper;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.Display;
import android.view.Gravity;
import android.view.Window;
import android.view.WindowManager;
-import android.view.WindowManagerImpl;
+import android.view.WindowManager.LayoutParams.WindowType;
+import com.android.internal.util.Preconditions;
/**
* Base class for presentations.
* <p>
@@ -153,11 +151,10 @@
public class Presentation extends Dialog {
private static final String TAG = "Presentation";
- private static final int MSG_CANCEL = 1;
-
private final Display mDisplay;
private final DisplayManager mDisplayManager;
- private final IBinder mToken = new Binder();
+ private final Handler mHandler = new Handler(Preconditions.checkNotNull(Looper.myLooper(),
+ "Presentation must be constructed on a looper thread."));
/**
* Creates a new presentation that is attached to the specified display
@@ -179,6 +176,11 @@
* @param outerContext The context of the application that is showing the presentation.
* The presentation will create its own context (see {@link #getContext()}) based
* on this context and information about the associated display.
+ * From {@link android.os.Build.VERSION_CODES#S}, the presentation will create its own window
+ * context based on this context, information about the associated display. Customizing window
+ * type by {@link Window#setType(int) #getWindow#setType(int)} causes the mismatch of the window
+ * and the created window context, which leads to
+ * {@link android.view.WindowManager.InvalidDisplayException} when invoking {@link #show()}.
* @param display The display to which the presentation should be attached.
* @param theme A style resource describing the theme to use for the window.
* See <a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">
@@ -187,24 +189,53 @@
* <var>outerContext</var>. If 0, the default presentation theme will be used.
*/
public Presentation(Context outerContext, Display display, int theme) {
- super(createPresentationContext(outerContext, display, theme), theme, false);
+ this(outerContext, display, theme, INVALID_WINDOW_TYPE);
+ }
+
+ /**
+ * Creates a new presentation that is attached to the specified display
+ * using the optionally specified theme, and override the default window type for the
+ * presentation.
+ * @param outerContext The context of the application that is showing the presentation.
+ * The presentation will create its own context (see {@link #getContext()}) based
+ * on this context and information about the associated display.
+ * From {@link android.os.Build.VERSION_CODES#S}, the presentation will create its own window
+ * context based on this context, information about the associated display and the window type.
+ * If the window type is not specified, the presentation will choose the default type for the
+ * presentation.
+ * @param display The display to which the presentation should be attached.
+ * @param theme A style resource describing the theme to use for the window.
+ * See <a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">
+ * Style and Theme Resources</a> for more information about defining and using
+ * styles. This theme is applied on top of the current theme in
+ * <var>outerContext</var>. If 0, the default presentation theme will be used.
+ * @param type Window type.
+ *
+ * @hide
+ */
+ public Presentation(@NonNull Context outerContext, @NonNull Display display, int theme,
+ @WindowType int type) {
+ super(createPresentationContext(outerContext, display, theme, type), theme, false);
mDisplay = display;
- mDisplayManager = (DisplayManager)getContext().getSystemService(DISPLAY_SERVICE);
-
- final int windowType =
- (display.getFlags() & Display.FLAG_PRIVATE) != 0 ? TYPE_PRIVATE_PRESENTATION
- : TYPE_PRESENTATION;
+ mDisplayManager = getContext().getSystemService(DisplayManager.class);
final Window w = getWindow();
final WindowManager.LayoutParams attr = w.getAttributes();
- attr.token = mToken;
w.setAttributes(attr);
w.setGravity(Gravity.FILL);
- w.setType(windowType);
+ w.setType(getWindowType(type, display));
setCanceledOnTouchOutside(false);
}
+ private static @WindowType int getWindowType(@WindowType int type, @NonNull Display display) {
+ if (type != INVALID_WINDOW_TYPE) {
+ return type;
+ }
+ return (display.getFlags() & Display.FLAG_PRIVATE) != 0 ? TYPE_PRIVATE_PRESENTATION
+ : TYPE_PRESENTATION;
+ }
+
/**
* Gets the {@link Display} that this presentation appears on.
*
@@ -229,16 +260,6 @@
protected void onStart() {
super.onStart();
mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
-
- // Since we were not watching for display changes until just now, there is a
- // chance that the display metrics have changed. If so, we will need to
- // dismiss the presentation immediately. This case is expected
- // to be rare but surprising, so we'll write a log message about it.
- if (!isConfigurationStillValid()) {
- Log.i(TAG, "Presentation is being dismissed because the "
- + "display metrics have changed since it was created.");
- mHandler.sendEmptyMessage(MSG_CANCEL);
- }
}
@Override
@@ -273,10 +294,6 @@
* Called by the system when the properties of the {@link Display} to which
* the presentation is attached have changed.
*
- * If the display metrics have changed (for example, if the display has been
- * resized or rotated), then the system automatically calls
- * {@link #cancel} to dismiss the presentation.
- *
* @see #getDisplay
*/
public void onDisplayChanged() {
@@ -289,28 +306,16 @@
private void handleDisplayChanged() {
onDisplayChanged();
-
- // We currently do not support configuration changes for presentations
- // (although we could add that feature with a bit more work).
- // If the display metrics have changed in any way then the current configuration
- // is invalid and the application must recreate the presentation to get
- // a new context.
- if (!isConfigurationStillValid()) {
- Log.i(TAG, "Presentation is being dismissed because the "
- + "display metrics have changed since it was created.");
- cancel();
- }
}
- private boolean isConfigurationStillValid() {
- DisplayMetrics dm = new DisplayMetrics();
- mDisplay.getMetrics(dm);
- return dm.equalsPhysical(getResources().getDisplayMetrics());
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "{@code N/A}")
+ private static Context createPresentationContext(Context outerContext, Display display,
+ int theme) {
+ return createPresentationContext(outerContext, display, theme, INVALID_WINDOW_TYPE);
}
- @UnsupportedAppUsage
private static Context createPresentationContext(
- Context outerContext, Display display, int theme) {
+ Context outerContext, Display display, int theme, @WindowType int type) {
if (outerContext == null) {
throw new IllegalArgumentException("outerContext must not be null");
}
@@ -318,31 +323,15 @@
throw new IllegalArgumentException("display must not be null");
}
- Context displayContext = outerContext.createDisplayContext(display);
+ Context windowContext = outerContext.createDisplayContext(display)
+ .createWindowContext(getWindowType(type, display), null /* options */);
if (theme == 0) {
TypedValue outValue = new TypedValue();
- displayContext.getTheme().resolveAttribute(
+ windowContext.getTheme().resolveAttribute(
com.android.internal.R.attr.presentationTheme, outValue, true);
theme = outValue.resourceId;
}
-
- // Derive the display's window manager from the outer window manager.
- // We do this because the outer window manager have some extra information
- // such as the parent window, which is important if the presentation uses
- // an application window type.
- final WindowManagerImpl outerWindowManager =
- (WindowManagerImpl)outerContext.getSystemService(WINDOW_SERVICE);
- final WindowManagerImpl displayWindowManager =
- outerWindowManager.createPresentationWindowManager(displayContext);
- return new ContextThemeWrapper(displayContext, theme) {
- @Override
- public Object getSystemService(String name) {
- if (WINDOW_SERVICE.equals(name)) {
- return displayWindowManager;
- }
- return super.getSystemService(name);
- }
- };
+ return new ContextThemeWrapper(windowContext, theme);
}
private final DisplayListener mDisplayListener = new DisplayListener() {
@@ -364,15 +353,4 @@
}
}
};
-
- private final Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_CANCEL:
- cancel();
- break;
- }
- }
- };
}
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index 3e3a956..04a12af 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -206,6 +206,10 @@
private static final String TAG = "PropertyInvalidatedCache";
private static final boolean DEBUG = false;
private static final boolean VERIFY = false;
+ // If this is true, dumpsys will dump the cache entries along with cache statistics.
+ // Most of the time this causes dumpsys to fail because the output stream is too
+ // large. Only set it to true in development images.
+ private static final boolean DETAILED = false;
// Per-Cache performance counters. As some cache instances are declared static,
@GuardedBy("mLock")
@@ -912,14 +916,13 @@
" Current Size: %d, Max Size: %d, HW Mark: %d, Overflows: %d",
mCache.size(), mMaxEntries, mHighWaterMark, mMissOverflow));
pw.println(String.format(" Enabled: %s", mDisabled ? "false" : "true"));
+ pw.println("");
Set<Map.Entry<Query, Result>> cacheEntries = mCache.entrySet();
- if (cacheEntries.size() == 0) {
- pw.println("");
+ if (!DETAILED || cacheEntries.size() == 0) {
return;
}
- pw.println("");
pw.println(" Contents:");
for (Map.Entry<Query, Result> entry : cacheEntries) {
String key = Objects.toString(entry.getKey());
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 90401ad..b020c70 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -81,6 +81,7 @@
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.IAuthService;
import android.hardware.camera2.CameraManager;
+import android.hardware.devicestate.DeviceStateManager;
import android.hardware.display.ColorDisplayManager;
import android.hardware.display.DisplayManager;
import android.hardware.face.FaceManager;
@@ -1348,6 +1349,12 @@
throws ServiceNotFoundException {
return new DreamManager(ctx);
}});
+ registerService(Context.DEVICE_STATE_SERVICE, DeviceStateManager.class,
+ new CachedServiceFetcher<DeviceStateManager>() {
+ @Override
+ public DeviceStateManager createService(ContextImpl ctx) {
+ return new DeviceStateManager();
+ }});
sInitializing = true;
try {
@@ -1404,6 +1411,7 @@
case Context.CONTENT_CAPTURE_MANAGER_SERVICE:
case Context.APP_PREDICTION_SERVICE:
case Context.INCREMENTAL_SERVICE:
+ case Context.ETHERNET_SERVICE:
return null;
}
Slog.wtf(TAG, "Manager wrapper not available: " + name);
diff --git a/core/java/android/app/TaskStackBuilder.java b/core/java/android/app/TaskStackBuilder.java
index b99b327..e238046 100644
--- a/core/java/android/app/TaskStackBuilder.java
+++ b/core/java/android/app/TaskStackBuilder.java
@@ -264,6 +264,7 @@
*
* @return The obtained PendingIntent
*/
+ @SuppressWarnings("AndroidFrameworkPendingIntentMutability")
public PendingIntent getPendingIntent(int requestCode, @PendingIntent.Flags int flags,
Bundle options) {
if (mIntents.isEmpty()) {
@@ -278,6 +279,7 @@
/**
* @hide
*/
+ @SuppressWarnings("AndroidFrameworkPendingIntentMutability")
public PendingIntent getPendingIntent(int requestCode, int flags, Bundle options,
UserHandle user) {
if (mIntents.isEmpty()) {
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 79f05a3..eedf958 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -852,15 +852,6 @@
}
/**
- * Returns true if this container may be scaled without resizing, and windows within may need
- * to be configured as such.
- * @hide
- */
- public boolean windowsAreScaleable() {
- return mWindowingMode == WINDOWING_MODE_PINNED;
- }
-
- /**
* Returns true if windows in this container should be given move animations by default.
* @hide
*/
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 9c216a3..c4157cf 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3508,6 +3508,7 @@
PERMISSION_SERVICE,
LIGHTS_SERVICE,
//@hide: PEOPLE_SERVICE,
+ //@hide: DEVICE_STATE_SERVICE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ServiceName {}
@@ -5246,6 +5247,14 @@
public static final String PEOPLE_SERVICE = "people";
/**
+ * Use with {@link #getSystemService(String)} to access device state service.
+ *
+ * @see #getSystemService(String)
+ * @hide
+ */
+ public static final String DEVICE_STATE_SERVICE = "device_state";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 2f1254f..a14e21b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2744,7 +2744,6 @@
* </ul>
*
* <p class="note">This is a protected intent that can only be sent by the system.
- * @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGE_STARTABLE = "android.intent.action.PACKAGE_STARTABLE";
@@ -2755,13 +2754,13 @@
* <ul>
* <li> {@link #EXTRA_UID} containing the integer uid assigned to the package. </li>
* <li> {@link #EXTRA_PACKAGE_NAME} containing the package name. </li>
- * <li> {@link #EXTRA_REASON} containing the integer indicating the reason for the state change,
+ * <li> {@link #EXTRA_UNSTARTABLE_REASON} containing the integer indicating the reason for
+ * the state change,
* @see PackageManager.UnstartableReason
* </li>
* </ul>
*
* <p class="note">This is a protected intent that can only be sent by the system.
- * @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGE_UNSTARTABLE =
@@ -2776,7 +2775,6 @@
* </ul>
*
* <p class="note">This is a protected intent that can only be sent by the system.
- * @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGE_FULLY_LOADED =
@@ -6015,6 +6013,13 @@
*/
public static final String EXTRA_LOCUS_ID = "android.intent.extra.LOCUS_ID";
+ /**
+ * Intent extra: the reason that the package associated with this intent has become unstartable.
+ *
+ * <p>Type: String
+ */
+ public static final String EXTRA_UNSTARTABLE_REASON = "android.intent.extra.UNSTARTABLE_REASON";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Intent flags (see mFlags variable).
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index 389458b..d9ecf46 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -21,9 +21,9 @@
import android.content.Intent;
import android.content.IntentSender;
import android.content.LocusId;
-import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IOnAppsChangedListener;
+import android.content.pm.LauncherActivityInfoInternal;
import android.content.pm.LauncherApps;
import android.content.pm.ShortcutQueryWrapper;
import android.content.pm.IPackageInstallerCallback;
@@ -47,7 +47,7 @@
void removeOnAppsChangedListener(in IOnAppsChangedListener listener);
ParceledListSlice getLauncherActivities(
String callingPackage, String packageName, in UserHandle user);
- ActivityInfo resolveActivity(
+ LauncherActivityInfoInternal resolveLauncherActivityInternal(
String callingPackage, in ComponentName component, in UserHandle user);
void startSessionDetailsActivityAsUser(in IApplicationThread caller, String callingPackage,
String callingFeatureId, in PackageInstaller.SessionInfo sessionInfo,
diff --git a/core/java/android/content/pm/IOnAppsChangedListener.aidl b/core/java/android/content/pm/IOnAppsChangedListener.aidl
index fcb1de0..f24ed80 100644
--- a/core/java/android/content/pm/IOnAppsChangedListener.aidl
+++ b/core/java/android/content/pm/IOnAppsChangedListener.aidl
@@ -33,4 +33,5 @@
in Bundle launcherExtras);
void onPackagesUnsuspended(in UserHandle user, in String[] packageNames);
void onShortcutChanged(in UserHandle user, String packageName, in ParceledListSlice shortcuts);
+ void onPackageProgressChanged(in UserHandle user, String packageName, float progress);
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 30f3325..c32d344 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -31,7 +31,6 @@
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageDeleteObserver2;
import android.content.pm.IPackageDataObserver;
-import android.content.pm.IPackageLoadingProgressCallback;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.IntentFilterVerificationInfo;
diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java
index 67deb82..ead80d0 100644
--- a/core/java/android/content/pm/LauncherActivityInfo.java
+++ b/core/java/android/content/pm/LauncherActivityInfo.java
@@ -16,7 +16,6 @@
package android.content.pm;
-import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -35,28 +34,19 @@
private static final String TAG = "LauncherActivityInfo";
private final PackageManager mPm;
-
- @UnsupportedAppUsage
- private ActivityInfo mActivityInfo;
- private ComponentName mComponentName;
private UserHandle mUser;
+ private final LauncherActivityInfoInternal mInternal;
/**
* Create a launchable activity object for a given ResolveInfo and user.
*
* @param context The context for fetching resources.
- * @param info ResolveInfo from which to create the LauncherActivityInfo.
- * @param user The UserHandle of the profile to which this activity belongs.
- */
- LauncherActivityInfo(Context context, ActivityInfo info, UserHandle user) {
- this(context);
- mActivityInfo = info;
- mComponentName = new ComponentName(info.packageName, info.name);
- mUser = user;
- }
- LauncherActivityInfo(Context context) {
+ */
+ LauncherActivityInfo(Context context, UserHandle user, LauncherActivityInfoInternal internal) {
mPm = context.getPackageManager();
+ mUser = user;
+ mInternal = internal;
}
/**
@@ -65,7 +55,7 @@
* @return ComponentName of the activity
*/
public ComponentName getComponentName() {
- return mComponentName;
+ return mInternal.getComponentName();
}
/**
@@ -90,7 +80,28 @@
*/
public CharSequence getLabel() {
// TODO: Go through LauncherAppsService
- return mActivityInfo.loadLabel(mPm);
+ return mInternal.getActivityInfo().loadLabel(mPm);
+ }
+
+ /**
+ * @return whether the package is startable.
+ */
+ public boolean isStartable() {
+ return mInternal.getIncrementalStatesInfo().isStartable();
+ }
+
+ /**
+ * @return whether the package is still loading.
+ */
+ public boolean isLoading() {
+ return mInternal.getIncrementalStatesInfo().isLoading();
+ }
+
+ /**
+ * @return Package loading progress
+ */
+ public float getProgress() {
+ return mInternal.getIncrementalStatesInfo().getProgress();
}
/**
@@ -103,20 +114,20 @@
*/
public Drawable getIcon(int density) {
// TODO: Go through LauncherAppsService
- final int iconRes = mActivityInfo.getIconResource();
+ final int iconRes = mInternal.getActivityInfo().getIconResource();
Drawable icon = null;
// Get the preferred density icon from the app's resources
if (density != 0 && iconRes != 0) {
try {
- final Resources resources
- = mPm.getResourcesForApplication(mActivityInfo.applicationInfo);
+ final Resources resources = mPm.getResourcesForApplication(
+ mInternal.getActivityInfo().applicationInfo);
icon = resources.getDrawableForDensity(iconRes, density);
} catch (NameNotFoundException | Resources.NotFoundException exc) {
}
}
// Get the default density icon
if (icon == null) {
- icon = mActivityInfo.loadIcon(mPm);
+ icon = mInternal.getActivityInfo().loadIcon(mPm);
}
return icon;
}
@@ -128,7 +139,7 @@
* @hide remove before shipping
*/
public int getApplicationFlags() {
- return mActivityInfo.applicationInfo.flags;
+ return mInternal.getActivityInfo().flags;
}
/**
@@ -136,7 +147,7 @@
* @return
*/
public ApplicationInfo getApplicationInfo() {
- return mActivityInfo.applicationInfo;
+ return mInternal.getActivityInfo().applicationInfo;
}
/**
@@ -147,7 +158,7 @@
public long getFirstInstallTime() {
try {
// TODO: Go through LauncherAppsService
- return mPm.getPackageInfo(mActivityInfo.packageName,
+ return mPm.getPackageInfo(mInternal.getActivityInfo().packageName,
PackageManager.MATCH_UNINSTALLED_PACKAGES).firstInstallTime;
} catch (NameNotFoundException nnfe) {
// Sorry, can't find package
@@ -160,7 +171,7 @@
* @return the name from android:name for the acitivity.
*/
public String getName() {
- return mActivityInfo.name;
+ return mInternal.getActivityInfo().name;
}
/**
diff --git a/core/java/android/content/pm/LauncherActivityInfoInternal.aidl b/core/java/android/content/pm/LauncherActivityInfoInternal.aidl
new file mode 100644
index 0000000..5d98d54
--- /dev/null
+++ b/core/java/android/content/pm/LauncherActivityInfoInternal.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2020, 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 android.content.pm;
+
+parcelable LauncherActivityInfoInternal;
\ No newline at end of file
diff --git a/core/java/android/content/pm/LauncherActivityInfoInternal.java b/core/java/android/content/pm/LauncherActivityInfoInternal.java
new file mode 100644
index 0000000..22e9712
--- /dev/null
+++ b/core/java/android/content/pm/LauncherActivityInfoInternal.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 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 android.content.pm;
+
+import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ComponentName;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+public class LauncherActivityInfoInternal implements Parcelable {
+ @UnsupportedAppUsage
+ private ActivityInfo mActivityInfo;
+ private ComponentName mComponentName;
+ private IncrementalStatesInfo mIncrementalStatesInfo;
+
+ /**
+ * @param info ActivityInfo from which to create the LauncherActivityInfo.
+ * @param incrementalStatesInfo The package's states.
+ */
+ public LauncherActivityInfoInternal(ActivityInfo info,
+ IncrementalStatesInfo incrementalStatesInfo) {
+ mActivityInfo = info;
+ mComponentName = new ComponentName(info.packageName, info.name);
+ mIncrementalStatesInfo = incrementalStatesInfo;
+ }
+
+ public LauncherActivityInfoInternal(Parcel source) {
+ mActivityInfo = source.readParcelable(ActivityInfo.class.getClassLoader());
+ mComponentName = new ComponentName(mActivityInfo.packageName, mActivityInfo.name);
+ mIncrementalStatesInfo = source.readParcelable(
+ IncrementalStatesInfo.class.getClassLoader());
+ }
+
+ public ComponentName getComponentName() {
+ return mComponentName;
+ }
+
+ public ActivityInfo getActivityInfo() {
+ return mActivityInfo;
+ }
+
+ public IncrementalStatesInfo getIncrementalStatesInfo() {
+ return mIncrementalStatesInfo;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mActivityInfo, 0);
+ dest.writeParcelable(mIncrementalStatesInfo, 0);
+ }
+
+ public static final @android.annotation.NonNull Creator<LauncherActivityInfoInternal> CREATOR =
+ new Creator<LauncherActivityInfoInternal>() {
+ public LauncherActivityInfoInternal createFromParcel(Parcel source) {
+ return new LauncherActivityInfoInternal(source);
+ }
+ public LauncherActivityInfoInternal[] newArray(int size) {
+ return new LauncherActivityInfoInternal[size];
+ }
+ };
+}
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 1a694b3..b7af397 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -218,6 +218,7 @@
* Indicates that a package was modified in the specified profile.
* This can happen, for example, when the package is updated or when
* one or more components are enabled or disabled.
+ * It can also happen if package state has changed, i.e., package becomes unstartable.
*
* @param packageName The name of the package that has changed.
* @param user The UserHandle of the profile that generated the change.
@@ -323,6 +324,16 @@
public void onShortcutsChanged(@NonNull String packageName,
@NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
}
+
+ /**
+ * Indicates that the loading progress of an installed package has changed.
+ *
+ * @param packageName The name of the package that has changed.
+ * @param user The UserHandle of the profile that generated the change.
+ * @param progress The new progress value, between [0, 1].
+ */
+ public void onPackageProgressChanged(@NonNull String packageName,
+ @NonNull UserHandle user, float progress) {}
}
/**
@@ -715,16 +726,15 @@
public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) {
logErrorForInvalidProfileAccess(user);
try {
- ActivityInfo ai = mService.resolveActivity(mContext.getPackageName(),
- intent.getComponent(), user);
- if (ai != null) {
- LauncherActivityInfo info = new LauncherActivityInfo(mContext, ai, user);
- return info;
+ LauncherActivityInfoInternal ai = mService.resolveLauncherActivityInternal(
+ mContext.getPackageName(), intent.getComponent(), user);
+ if (ai == null) {
+ return null;
}
+ return new LauncherActivityInfo(mContext, user, ai);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -813,13 +823,13 @@
}
private List<LauncherActivityInfo> convertToActivityList(
- @Nullable ParceledListSlice<ResolveInfo> activities, UserHandle user) {
- if (activities == null) {
+ @Nullable ParceledListSlice<LauncherActivityInfoInternal> internals, UserHandle user) {
+ if (internals == null || internals.getList().isEmpty()) {
return Collections.EMPTY_LIST;
}
ArrayList<LauncherActivityInfo> lais = new ArrayList<>();
- for (ResolveInfo ri : activities.getList()) {
- LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri.activityInfo, user);
+ for (LauncherActivityInfoInternal internal : internals.getList()) {
+ LauncherActivityInfo lai = new LauncherActivityInfo(mContext, user, internal);
if (DEBUG) {
Log.v(TAG, "Returning activity for profile " + user + " : "
+ lai.getComponentName());
@@ -1667,6 +1677,19 @@
}
}
}
+
+ public void onPackageProgressChanged(UserHandle user, String packageName,
+ float progress) {
+ if (DEBUG) {
+ Log.d(TAG, "onPackageProgressChanged " + user.getIdentifier() + ","
+ + packageName + "," + progress);
+ }
+ synchronized (LauncherApps.this) {
+ for (CallbackMessageHandler callback : mCallbacks) {
+ callback.postOnPackageProgressChanged(user, packageName, progress);
+ }
+ }
+ }
};
private static class CallbackMessageHandler extends Handler {
@@ -1678,6 +1701,7 @@
private static final int MSG_SUSPENDED = 6;
private static final int MSG_UNSUSPENDED = 7;
private static final int MSG_SHORTCUT_CHANGED = 8;
+ private static final int MSG_LOADING_PROGRESS_CHANGED = 9;
private LauncherApps.Callback mCallback;
@@ -1688,6 +1712,7 @@
boolean replacing;
UserHandle user;
List<ShortcutInfo> shortcuts;
+ float mLoadingProgress;
}
public CallbackMessageHandler(Looper looper, LauncherApps.Callback callback) {
@@ -1727,6 +1752,10 @@
case MSG_SHORTCUT_CHANGED:
mCallback.onShortcutsChanged(info.packageName, info.shortcuts, info.user);
break;
+ case MSG_LOADING_PROGRESS_CHANGED:
+ mCallback.onPackageProgressChanged(info.packageName, info.user,
+ info.mLoadingProgress);
+ break;
}
}
@@ -1793,6 +1822,15 @@
info.shortcuts = shortcuts;
obtainMessage(MSG_SHORTCUT_CHANGED, info).sendToTarget();
}
+
+ public void postOnPackageProgressChanged(UserHandle user, String packageName,
+ float progress) {
+ CallbackInfo info = new CallbackInfo();
+ info.packageName = packageName;
+ info.user = user;
+ info.mLoadingProgress = progress;
+ obtainMessage(MSG_LOADING_PROGRESS_CHANGED, info).sendToTarget();
+ }
}
/**
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 1a992f5..32ae105 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3790,8 +3790,8 @@
* @hide
*/
@IntDef({UNSTARTABLE_REASON_UNKNOWN,
- UNSTARTABLE_REASON_DATALOADER_TRANSPORT,
- UNSTARTABLE_REASON_DATALOADER_STORAGE
+ UNSTARTABLE_REASON_CONNECTION_ERROR,
+ UNSTARTABLE_REASON_INSUFFICIENT_STORAGE
})
@Retention(RetentionPolicy.SOURCE)
public @interface UnstartableReason {}
@@ -3800,23 +3800,20 @@
* Unstartable state with no root cause specified. E.g., data loader seeing missing pages but
* unclear about the cause. This corresponds to a generic alert window shown to the user when
* the user attempts to launch the app.
- * @hide
*/
public static final int UNSTARTABLE_REASON_UNKNOWN = 0;
/**
- * Unstartable state after hint from dataloader of issues with the transport layer.
- * This corresponds to an alert window shown to the user indicating network errors.
- * @hide
+ * Unstartable state due to connection issues that interrupt package loading.
+ * This corresponds to an alert window shown to the user indicating connection errors.
*/
- public static final int UNSTARTABLE_REASON_DATALOADER_TRANSPORT = 1;
+ public static final int UNSTARTABLE_REASON_CONNECTION_ERROR = 1;
/**
* Unstartable state after encountering storage limitations.
* This corresponds to an alert window indicating limited storage.
- * @hide
*/
- public static final int UNSTARTABLE_REASON_DATALOADER_STORAGE = 2;
+ public static final int UNSTARTABLE_REASON_INSUFFICIENT_STORAGE = 2;
/** {@hide} */
public int getUserId() {
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 35ef53b..25c749b 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -35,6 +35,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
/**
* A class that contains biometric utilities. For authentication, see {@link BiometricPrompt}.
@@ -199,13 +201,24 @@
}
/**
+ * @return A list of {@link SensorProperties}
+ * @hide
+ */
+ @TestApi
+ @NonNull
+ @RequiresPermission(TEST_BIOMETRIC)
+ public List<SensorProperties> getSensorProperties() {
+ return new ArrayList<>(); // TODO(169459906)
+ }
+
+ /**
* Retrieves a test session for BiometricManager/BiometricPrompt.
* @hide
*/
@TestApi
@NonNull
@RequiresPermission(TEST_BIOMETRIC)
- public BiometricTestSession getTestSession() {
+ public BiometricTestSession createTestSession(int sensorId) {
return null; // TODO(169459906)
}
diff --git a/core/java/android/hardware/biometrics/BiometricTestSession.java b/core/java/android/hardware/biometrics/BiometricTestSession.java
index 719efa8..4c7aa27 100644
--- a/core/java/android/hardware/biometrics/BiometricTestSession.java
+++ b/core/java/android/hardware/biometrics/BiometricTestSession.java
@@ -23,10 +23,7 @@
import android.annotation.TestApi;
import android.content.Context;
import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.List;
+import android.util.ArraySet;
/**
* Common set of interfaces to test biometric-related APIs, including {@link BiometricPrompt} and
@@ -35,37 +32,20 @@
*/
@TestApi
public class BiometricTestSession implements AutoCloseable {
-
- private static final String TAG = "TestManager";
-
private final Context mContext;
- private final ITestService mTestService;
+ private final ITestSession mTestSession;
+
+ // Keep track of users that were tested, which need to be cleaned up when finishing.
+ private final ArraySet<Integer> mTestedUsers;
/**
* @hide
*/
- public BiometricTestSession(@NonNull Context context, @NonNull ITestService testService) {
+ public BiometricTestSession(@NonNull Context context, @NonNull ITestSession testSession) {
mContext = context;
- mTestService = testService;
- }
-
- /**
- * @return A list of {@link SensorProperties}
- */
- @NonNull
- @RequiresPermission(TEST_BIOMETRIC)
- public List<SensorProperties> getSensorProperties() {
- try {
- final List<SensorPropertiesInternal> internalProps =
- mTestService.getSensorPropertiesInternal(mContext.getOpPackageName());
- final List<SensorProperties> props = new ArrayList<>();
- for (SensorPropertiesInternal internalProp : internalProps) {
- props.add(new SensorProperties(internalProp.sensorId, internalProp.sensorStrength));
- }
- return props;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ mTestSession = testSession;
+ mTestedUsers = new ArraySet<>();
+ enableTestHal(true);
}
/**
@@ -75,105 +55,100 @@
* secure pathways such as HAT/Keystore are not testable, since they depend on the TEE or its
* equivalent for the secret key.
*
- * @param sensorId Sensor that this command applies to.
* @param enableTestHal If true, enable testing with a fake HAL instead of the real HAL.
*/
@RequiresPermission(TEST_BIOMETRIC)
- public void enableTestHal(int sensorId, boolean enableTestHal) {
+ private void enableTestHal(boolean enableTestHal) {
try {
- mTestService.enableTestHal(sensorId, enableTestHal);
+ mTestSession.enableTestHal(enableTestHal);
} catch (RemoteException e) {
- Log.e(TAG, "Remote exception", e);
+ throw e.rethrowFromSystemServer();
}
}
/**
* Starts the enrollment process. This should generally be used when the test HAL is enabled.
*
- * @param sensorId Sensor that this command applies to.
* @param userId User that this command applies to.
*/
@RequiresPermission(TEST_BIOMETRIC)
- public void enrollStart(int sensorId, int userId) {
+ public void startEnroll(int userId) {
try {
- mTestService.enrollStart(sensorId, userId);
+ mTestedUsers.add(userId);
+ mTestSession.startEnroll(userId);
} catch (RemoteException e) {
- Log.e(TAG, "Remote exception", e);
+ throw e.rethrowFromSystemServer();
}
}
/**
* Finishes the enrollment process. Simulates the HAL's callback.
*
- * @param sensorId Sensor that this command applies to.
* @param userId User that this command applies to.
*/
@RequiresPermission(TEST_BIOMETRIC)
- public void enrollFinish(int sensorId, int userId) {
+ public void finishEnroll(int userId) {
try {
- mTestService.enrollFinish(sensorId, userId);
+ mTestedUsers.add(userId);
+ mTestSession.finishEnroll(userId);
} catch (RemoteException e) {
- Log.e(TAG, "Remote exception", e);
+ throw e.rethrowFromSystemServer();
}
}
/**
* Simulates a successful authentication, but does not provide a valid HAT.
*
- * @param sensorId Sensor that this command applies to.
* @param userId User that this command applies to.
*/
@RequiresPermission(TEST_BIOMETRIC)
- public void authenticateSuccess(int sensorId, int userId) {
+ public void acceptAuthentication(int userId) {
try {
- mTestService.authenticateSuccess(sensorId, userId);
+ mTestSession.acceptAuthentication(userId);
} catch (RemoteException e) {
- Log.e(TAG, "Remote exception", e);
+ throw e.rethrowFromSystemServer();
}
}
/**
* Simulates a rejected attempt.
*
- * @param sensorId Sensor that this command applies to.
* @param userId User that this command applies to.
*/
@RequiresPermission(TEST_BIOMETRIC)
- public void authenticateReject(int sensorId, int userId) {
+ public void rejectAuthentication(int userId) {
try {
- mTestService.authenticateReject(sensorId, userId);
+ mTestSession.rejectAuthentication(userId);
} catch (RemoteException e) {
- Log.e(TAG, "Remote exception", e);
+ throw e.rethrowFromSystemServer();
}
}
/**
* Simulates an acquired message from the HAL.
*
- * @param sensorId Sensor that this command applies to.
* @param userId User that this command applies to.
*/
@RequiresPermission(TEST_BIOMETRIC)
- public void notifyAcquired(int sensorId, int userId) {
+ public void notifyAcquired(int userId) {
try {
- mTestService.notifyAcquired(sensorId, userId);
+ mTestSession.notifyAcquired(userId);
} catch (RemoteException e) {
- Log.e(TAG, "Remote exception", e);
+ throw e.rethrowFromSystemServer();
}
}
/**
* Simulates an error message from the HAL.
*
- * @param sensorId Sensor that this command applies to.
* @param userId User that this command applies to.
*/
@RequiresPermission(TEST_BIOMETRIC)
- public void notifyError(int sensorId, int userId) {
+ public void notifyError(int userId) {
try {
- mTestService.notifyError(sensorId, userId);
+ mTestSession.notifyError(userId);
} catch (RemoteException e) {
- Log.e(TAG, "Remote exception", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -182,21 +157,24 @@
* that isn't known by both sides are deleted. This should generally be used when the test
* HAL is disabled (e.g. to clean up after a test).
*
- * @param sensorId Sensor that this command applies to.
* @param userId User that this command applies to.
*/
@RequiresPermission(TEST_BIOMETRIC)
- public void internalCleanup(int sensorId, int userId) {
+ public void cleanupInternalState(int userId) {
try {
- mTestService.internalCleanup(sensorId, userId);
+ mTestSession.cleanupInternalState(userId);
} catch (RemoteException e) {
- Log.e(TAG, "Remote exception", e);
+ throw e.rethrowFromSystemServer();
}
}
@Override
@RequiresPermission(TEST_BIOMETRIC)
public void close() {
+ for (int user : mTestedUsers) {
+ cleanupInternalState(user);
+ }
+ enableTestHal(false);
}
}
diff --git a/core/java/android/hardware/biometrics/ITestService.aidl b/core/java/android/hardware/biometrics/ITestSession.aidl
similarity index 75%
rename from core/java/android/hardware/biometrics/ITestService.aidl
rename to core/java/android/hardware/biometrics/ITestSession.aidl
index 6373132..5677f65 100644
--- a/core/java/android/hardware/biometrics/ITestService.aidl
+++ b/core/java/android/hardware/biometrics/ITestSession.aidl
@@ -21,37 +21,34 @@
* A test service for FingerprintManager and BiometricPrompt.
* @hide
*/
-interface ITestService {
- // Returns a list of sensor properties supported by the interface.
- List<SensorPropertiesInternal> getSensorPropertiesInternal(String opPackageName);
-
+interface ITestSession {
// Switches the specified sensor to use a test HAL. In this mode, the framework will not invoke
// any methods on the real HAL implementation. This allows the framework to test a substantial
// portion of the framework code that would otherwise require human interaction. Note that
// secure pathways such as HAT/Keystore are not testable, since they depend on the TEE or its
// equivalent for the secret key.
- void enableTestHal(int sensorId, boolean enableTestHal);
+ void enableTestHal(boolean enableTestHal);
// Starts the enrollment process. This should generally be used when the test HAL is enabled.
- void enrollStart(int sensorId, int userId);
+ void startEnroll(int userId);
// Finishes the enrollment process. Simulates the HAL's callback.
- void enrollFinish(int sensorId, int userId);
+ void finishEnroll(int userId);
// Simulates a successful authentication, but does not provide a valid HAT.
- void authenticateSuccess(int sensorId, int userId);
+ void acceptAuthentication(int userId);
// Simulates a rejected attempt.
- void authenticateReject(int sensorId, int userId);
+ void rejectAuthentication(int userId);
// Simulates an acquired message from the HAL.
- void notifyAcquired(int sensorId, int userId);
+ void notifyAcquired(int userId);
// Simulates an error message from the HAL.
- void notifyError(int sensorId, int userId);
+ void notifyError(int userId);
// Matches the framework's cached enrollments against the HAL's enrollments. Any enrollment
// that isn't known by both sides are deleted. This should generally be used when the test
// HAL is disabled (e.g. to clean up after a test).
- void internalCleanup(int sensorId, int userId);
+ void cleanupInternalState(int userId);
}
diff --git a/core/java/android/hardware/devicestate/DeviceStateManager.java b/core/java/android/hardware/devicestate/DeviceStateManager.java
new file mode 100644
index 0000000..a52f983
--- /dev/null
+++ b/core/java/android/hardware/devicestate/DeviceStateManager.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2020 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 android.hardware.devicestate;
+
+import android.annotation.SystemService;
+import android.content.Context;
+
+/**
+ * Manages the state of the system for devices with user-configurable hardware like a foldable
+ * phone.
+ *
+ * @hide
+ */
+@SystemService(Context.DEVICE_STATE_SERVICE)
+public final class DeviceStateManager {
+ /** Invalid device state. */
+ public static final int INVALID_DEVICE_STATE = -1;
+
+ private DeviceStateManagerGlobal mGlobal;
+
+ public DeviceStateManager() {
+ mGlobal = DeviceStateManagerGlobal.getInstance();
+ }
+}
diff --git a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
new file mode 100644
index 0000000..4e7cf4a
--- /dev/null
+++ b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 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 android.hardware.devicestate;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.ServiceManager;
+
+/**
+ * Provides communication with the device state system service on behalf of applications.
+ *
+ * @see DeviceStateManager
+ * @hide
+ */
+final class DeviceStateManagerGlobal {
+ private static DeviceStateManagerGlobal sInstance;
+
+ /**
+ * Returns an instance of {@link DeviceStateManagerGlobal}. May return {@code null} if a
+ * connection with the device state service couldn't be established.
+ */
+ @Nullable
+ static DeviceStateManagerGlobal getInstance() {
+ synchronized (DeviceStateManagerGlobal.class) {
+ if (sInstance == null) {
+ IBinder b = ServiceManager.getService(Context.DEVICE_STATE_SERVICE);
+ if (b != null) {
+ sInstance = new DeviceStateManagerGlobal(IDeviceStateManager
+ .Stub.asInterface(b));
+ }
+ }
+ return sInstance;
+ }
+ }
+
+ @NonNull
+ private final IDeviceStateManager mDeviceStateManager;
+
+ private DeviceStateManagerGlobal(@NonNull IDeviceStateManager deviceStateManager) {
+ mDeviceStateManager = deviceStateManager;
+ }
+}
diff --git a/core/java/android/hardware/devicestate/IDeviceStateManager.aidl b/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
new file mode 100644
index 0000000..24913e9
--- /dev/null
+++ b/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2020, 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 android.hardware.devicestate;
+
+/** @hide */
+interface IDeviceStateManager {}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index dda1890b..fc14b89 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -16,6 +16,8 @@
package android.hardware.display;
+import static android.view.Display.DEFAULT_DISPLAY;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -381,6 +383,7 @@
addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_EXTERNAL);
addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY);
addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_VIRTUAL);
+ addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_INTERNAL);
}
return mTempDisplays.toArray(new Display[mTempDisplays.size()]);
} finally {
@@ -401,6 +404,9 @@
private void addPresentationDisplaysLocked(
ArrayList<Display> displays, int[] displayIds, int matchType) {
for (int i = 0; i < displayIds.length; i++) {
+ if (displayIds[i] == DEFAULT_DISPLAY) {
+ continue;
+ }
Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/);
if (display != null
&& (display.getFlags() & Display.FLAG_PRESENTATION) != 0
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 84c5ea5..c5f8dac 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -39,6 +39,7 @@
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricTestSession;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.biometrics.SensorProperties;
import android.os.Binder;
import android.os.CancellationSignal;
import android.os.CancellationSignal.OnCancelListener;
@@ -97,6 +98,24 @@
private Fingerprint mRemovalFingerprint;
private Handler mHandler;
+
+ /**
+ * Retrieves a list of properties for all fingerprint sensors on the device.
+ * @hide
+ */
+ @TestApi
+ @NonNull
+ @RequiresPermission(TEST_BIOMETRIC)
+ public List<SensorProperties> getSensorProperties() {
+ final List<SensorProperties> properties = new ArrayList<>();
+ final List<FingerprintSensorPropertiesInternal> internalProperties
+ = getSensorPropertiesInternal();
+ for (FingerprintSensorPropertiesInternal internalProp : internalProperties) {
+ properties.add(FingerprintSensorProperties.from(internalProp));
+ }
+ return properties;
+ }
+
/**
* Retrieves a test session for FingerprintManager.
* @hide
@@ -104,10 +123,10 @@
@TestApi
@NonNull
@RequiresPermission(TEST_BIOMETRIC)
- public BiometricTestSession getTestSession() {
+ public BiometricTestSession createTestSession(int sensorId) {
try {
return new BiometricTestSession(mContext,
- mService.getTestService(mContext.getOpPackageName()));
+ mService.createTestSession(sensorId, mContext.getOpPackageName()));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -636,13 +655,24 @@
}
/**
- * Finishes enrollment and cancels the current auth token.
+ * Revokes the current challenge.
* @hide
*/
@RequiresPermission(MANAGE_FINGERPRINT)
public void revokeChallenge() {
+ // On HALs with only single in-flight challenge such as IBiometricsFingerprint@2.1,
+ // this parameter is ignored.
+ revokeChallenge(0L);
+ }
+
+ /**
+ * Revokes the specified challenge.
+ * @hide
+ */
+ @RequiresPermission(MANAGE_FINGERPRINT)
+ public void revokeChallenge(long challenge) {
if (mService != null) try {
- mService.revokeChallenge(mToken, mContext.getOpPackageName());
+ mService.revokeChallenge(mToken, mContext.getOpPackageName(), challenge);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -867,21 +897,6 @@
}
/**
- * Retrieves a list of properties for all fingerprint sensors on the device.
- * @hide
- */
- @NonNull
- public List<FingerprintSensorProperties> getSensorProperties() {
- final List<FingerprintSensorProperties> properties = new ArrayList<>();
- final List<FingerprintSensorPropertiesInternal> internalProperties
- = getSensorPropertiesInternal();
- for (FingerprintSensorPropertiesInternal internalProp : internalProperties) {
- properties.add(FingerprintSensorProperties.from(internalProp));
- }
- return properties;
- }
-
- /**
* Get statically configured sensor properties.
* @hide
*/
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 518e3ca..cc086cf 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -17,7 +17,7 @@
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
-import android.hardware.biometrics.ITestService;
+import android.hardware.biometrics.ITestSession;
import android.hardware.fingerprint.IFingerprintClientActiveCallback;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.hardware.fingerprint.IUdfpsOverlayController;
@@ -32,8 +32,8 @@
*/
interface IFingerprintService {
- // Retrieves a test service
- ITestService getTestService(String opPackageName);
+ // Creates a test session with the specified sensorId
+ ITestSession createTestSession(int sensorId, String opPackageName);
// Retrieve static sensor properties for all fingerprint sensors
List<FingerprintSensorPropertiesInternal> getSensorPropertiesInternal(String opPackageName);
@@ -96,7 +96,7 @@
void generateChallenge(IBinder token, int sensorId, IFingerprintServiceReceiver receiver, String opPackageName);
// Finish an enrollment sequence and invalidate the authentication token
- void revokeChallenge(IBinder token, String opPackageName);
+ void revokeChallenge(IBinder token, String opPackageName, long challenge);
// Determine if a user has at least one enrolled fingerprint
boolean hasEnrolledFingerprints(int userId, String opPackageName);
diff --git a/core/java/android/net/NetworkProvider.java b/core/java/android/net/NetworkProvider.java
index 75086cf..d31218d 100644
--- a/core/java/android/net/NetworkProvider.java
+++ b/core/java/android/net/NetworkProvider.java
@@ -30,7 +30,7 @@
/**
* Base class for network providers such as telephony or Wi-Fi. NetworkProviders connect the device
- * to networks and makes them available to to the core network stack by creating
+ * to networks and makes them available to the core network stack by creating
* {@link NetworkAgent}s. The networks can then provide connectivity to apps and can be interacted
* with via networking APIs such as {@link ConnectivityManager}.
*
diff --git a/core/java/android/net/TEST_MAPPING b/core/java/android/net/TEST_MAPPING
new file mode 100644
index 0000000..abac811
--- /dev/null
+++ b/core/java/android/net/TEST_MAPPING
@@ -0,0 +1,20 @@
+{
+ "imports": [
+ {
+ // Also includes cts/tests/tests/net
+ "path": "frameworks/base/tests/net"
+ },
+ {
+ "path": "packages/modules/NetworkStack"
+ },
+ {
+ "path": "packages/modules/CaptivePortalLogin"
+ },
+ {
+ "path": "frameworks/base/packages/Tethering"
+ },
+ {
+ "path": "frameworks/opt/net/wifi"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/core/java/android/os/connectivity/CellularBatteryStats.java b/core/java/android/os/connectivity/CellularBatteryStats.java
index 121fd33..fc17002 100644
--- a/core/java/android/os/connectivity/CellularBatteryStats.java
+++ b/core/java/android/os/connectivity/CellularBatteryStats.java
@@ -109,7 +109,7 @@
CellSignalStrength.getNumSignalStrengthLevels()));
mTxTimeMs = Arrays.copyOfRange(
txTimeMs, 0,
- Math.min(txTimeMs.length, ModemActivityInfo.TX_POWER_LEVELS));
+ Math.min(txTimeMs.length, ModemActivityInfo.getNumTxPowerLevels()));
mMonitoredRailChargeConsumedMaMs = monitoredRailChargeConsumedMaMs;
}
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index d80a7e7..3cfa59b 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -609,7 +609,7 @@
/** @hide */
private static final PropertyInvalidatedCache<PermissionQuery, Integer> sPermissionCache =
new PropertyInvalidatedCache<PermissionQuery, Integer>(
- 16, CACHE_KEY_PACKAGE_INFO, "checkPermission") {
+ 2048, CACHE_KEY_PACKAGE_INFO, "checkPermission") {
@Override
protected Integer recompute(PermissionQuery query) {
return checkPermissionUncached(query.permission, query.pid, query.uid);
diff --git a/core/java/android/permission/Permissions.md b/core/java/android/permission/Permissions.md
index 0495495..4224b7a 100644
--- a/core/java/android/permission/Permissions.md
+++ b/core/java/android/permission/Permissions.md
@@ -848,7 +848,7 @@
@Test
fun onlySomeAppsAreAllowedToHavePermissionGranted() {
- assertThat(whitelistedPkgs).containsAllIn(
+ assertThat(whitelistedPkgs).containsAtLeastElementsIn(
context.packageManager.getInstalledPackages(MATCH_ALL)
.filter { pkg ->
context.checkPermission(android.Manifest.permission.MY_PRIVILEGED_PERMISSION, -1,
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7df9a5f..989efba 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9088,6 +9088,7 @@
* @see#ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW
* @hide
*/
+ @TestApi
public static final String ACCESSIBILITY_MAGNIFICATION_MODE =
"accessibility_magnification_mode";
@@ -9095,12 +9096,14 @@
* Magnification mode value that magnifies whole display.
* @hide
*/
+ @TestApi
public static final int ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN = 0x1;
/**
* Magnification mode value that magnifies magnify particular region in a window
* @hide
*/
+ @TestApi
public static final int ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW = 0x2;
/**
@@ -9108,6 +9111,7 @@
* region in a window.
* @hide
*/
+ @TestApi
public static final int ACCESSIBILITY_MAGNIFICATION_MODE_ALL = 0x3;
/**
@@ -9119,6 +9123,7 @@
* @see#ACCESSIBILITY_MAGNIFICATION_MODE_ALL
* @hide
*/
+ @TestApi
public static final String ACCESSIBILITY_MAGNIFICATION_CAPABILITY =
"accessibility_magnification_capability";
@@ -13407,6 +13412,7 @@
*
* @hide
*/
+ @TestApi
public static final String HIDDEN_API_POLICY = "hidden_api_policy";
/**
@@ -14585,6 +14591,19 @@
*/
public static final String MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH =
"maximum_obscuring_opacity_for_touch";
+
+ /**
+ * LatencyTracker settings.
+ *
+ * The following strings are supported as keys:
+ * <pre>
+ * enabled (boolean)
+ * sampling_interval (int)
+ * </pre>
+ *
+ * @hide
+ */
+ public static final String LATENCY_TRACKER = "latency_tracker";
}
/**
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index ebd114a..8f119fc 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1865,8 +1865,9 @@
}
/**
- * Returns whether this notification is a conversation notification.
- * @hide
+ * Returns whether this notification is a conversation notification, and would appear
+ * in the conversation section of the notification shade, on devices that separate that
+ * type of notification.
*/
public boolean isConversation() {
return mIsConversation;
@@ -1881,7 +1882,10 @@
}
/**
- * @hide
+ * Returns the shortcut information associated with this notification, if it is a
+ * {@link #isConversation() conversation notification}.
+ * <p>This might be null even if the notification is a conversation notification, if
+ * the posting app hasn't opted into the full conversation feature set yet.</p>
*/
public @Nullable ShortcutInfo getShortcutInfo() {
return mShortcutInfo;
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 0f46ffc..4d1337b 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -227,9 +227,6 @@
SurfaceControl mSurfaceControl = new SurfaceControl();
- // Unused relayout out-param
- SurfaceControl mTmpSurfaceControl = new SurfaceControl();
-
final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() {
{
mRequestedFormat = PixelFormat.RGBX_8888;
@@ -905,7 +902,7 @@
final int relayoutResult = mSession.relayout(
mWindow, mLayout, mWidth, mHeight,
View.VISIBLE, 0, -1, mWinFrames, mMergedConfiguration, mSurfaceControl,
- mInsetsState, mTempControls, mSurfaceSize, mTmpSurfaceControl);
+ mInsetsState, mTempControls, mSurfaceSize);
if (mSurfaceControl.isValid()) {
mSurfaceHolder.mSurface.copyFrom(mSurfaceControl);
}
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index e520d7c..b5080cd 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -181,7 +181,8 @@
private long mFrameIntervalNanos;
private boolean mDebugPrintNextFrameTimeDelta;
private int mFPSDivisor = 1;
- private long mLastVsyncId = FrameInfo.INVALID_VSYNC_ID;
+ private DisplayEventReceiver.VsyncEventData mLastVsyncEventData =
+ new DisplayEventReceiver.VsyncEventData();
/**
* Contains information about the current frame for jank-tracking,
@@ -664,7 +665,18 @@
* @hide
*/
public long getVsyncId() {
- return mLastVsyncId;
+ return mLastVsyncEventData.id;
+ }
+
+ /**
+ * Returns the frame deadline in {@link System#nanoTime()} timebase that it is allotted for the
+ * frame to be completed. Client are expected to call this function from their frame callback
+ * function. Calling this function from anywhere else will return an undefined value.
+ *
+ * @hide
+ */
+ public long getFrameDeadline() {
+ return mLastVsyncEventData.frameDeadline;
}
void setFPSDivisor(int divisor) {
@@ -673,7 +685,8 @@
ThreadedRenderer.setFPSDivisor(divisor);
}
- void doFrame(long frameTimeNanos, int frame, long frameTimelineVsyncId) {
+ void doFrame(long frameTimeNanos, int frame,
+ DisplayEventReceiver.VsyncEventData vsyncEventData) {
final long startNanos;
synchronized (mLock) {
if (!mFrameScheduled) {
@@ -723,10 +736,11 @@
}
}
- mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos, frameTimelineVsyncId);
+ mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos, vsyncEventData.id,
+ vsyncEventData.frameDeadline);
mFrameScheduled = false;
mLastFrameTimeNanos = frameTimeNanos;
- mLastVsyncId = frameTimelineVsyncId;
+ mLastVsyncEventData = vsyncEventData;
}
try {
@@ -910,7 +924,7 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DO_FRAME:
- doFrame(System.nanoTime(), 0, FrameInfo.INVALID_VSYNC_ID);
+ doFrame(System.nanoTime(), 0, new DisplayEventReceiver.VsyncEventData());
break;
case MSG_DO_SCHEDULE_VSYNC:
doScheduleVsync();
@@ -927,7 +941,7 @@
private boolean mHavePendingVsync;
private long mTimestampNanos;
private int mFrame;
- private long mFrameTimelineVsyncId;
+ private VsyncEventData mLastVsyncEventData = new VsyncEventData();
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource, CONFIG_CHANGED_EVENT_SUPPRESS);
@@ -938,7 +952,7 @@
// for the internal display implicitly.
@Override
public void onVsync(long timestampNanos, long physicalDisplayId, int frame,
- long frameTimelineVsyncId) {
+ VsyncEventData vsyncEventData) {
// Post the vsync event to the Handler.
// The idea is to prevent incoming vsync events from completely starving
// the message queue. If there are no messages in the queue with timestamps
@@ -961,7 +975,7 @@
mTimestampNanos = timestampNanos;
mFrame = frame;
- mFrameTimelineVsyncId = frameTimelineVsyncId;
+ mLastVsyncEventData = vsyncEventData;
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
@@ -970,7 +984,7 @@
@Override
public void run() {
mHavePendingVsync = false;
- doFrame(mTimestampNanos, mFrame, mFrameTimelineVsyncId);
+ doFrame(mTimestampNanos, mFrame, mLastVsyncEventData);
}
}
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index 51474d3..467d93e 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -17,6 +17,7 @@
package android.view;
import android.compat.annotation.UnsupportedAppUsage;
+import android.graphics.FrameInfo;
import android.os.Looper;
import android.os.MessageQueue;
import android.util.Log;
@@ -145,6 +146,26 @@
mMessageQueue = null;
}
+ static final class VsyncEventData {
+ // The frame timeline vsync id, used to correlate a frame
+ // produced by HWUI with the timeline data stored in Surface Flinger.
+ public final long id;
+
+ // The frame deadline timestamp in {@link System#nanoTime()} timebase that it is
+ // allotted for the frame to be completed.
+ public final long frameDeadline;
+
+ VsyncEventData(long id, long frameDeadline) {
+ this.id = id;
+ this.frameDeadline = frameDeadline;
+ }
+
+ VsyncEventData() {
+ this.id = FrameInfo.INVALID_VSYNC_ID;
+ this.frameDeadline = Long.MAX_VALUE;
+ }
+ }
+
/**
* Called when a vertical sync pulse is received.
* The recipient should render a frame and then call {@link #scheduleVsync}
@@ -154,11 +175,10 @@
* timebase.
* @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
* @param frame The frame number. Increases by one for each vertical sync interval.
- * @param frameTimelineVsyncId The frame timeline vsync id, used to correlate a frame
- * produced by HWUI with the timeline data stored in Surface Flinger.
+ * @param vsyncEventData The vsync event data.
*/
public void onVsync(long timestampNanos, long physicalDisplayId, int frame,
- long frameTimelineVsyncId) {
+ VsyncEventData vsyncEventData) {
}
/**
@@ -201,8 +221,9 @@
// Called from native code.
@SuppressWarnings("unused")
private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame,
- long frameTimelineVsyncId) {
- onVsync(timestampNanos, physicalDisplayId, frame, frameTimelineVsyncId);
+ long frameTimelineVsyncId, long frameDeadline) {
+ onVsync(timestampNanos, physicalDisplayId, frame,
+ new VsyncEventData(frameTimelineVsyncId, frameDeadline));
}
// Called from native code.
diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java
index 280a1c0..387787e 100644
--- a/core/java/android/view/FrameMetrics.java
+++ b/core/java/android/view/FrameMetrics.java
@@ -198,6 +198,7 @@
Index.ANIMATION_START,
Index.PERFORM_TRAVERSALS_START,
Index.DRAW_START,
+ Index.FRAME_DEADLINE,
Index.SYNC_QUEUED,
Index.SYNC_START,
Index.ISSUE_DRAW_COMMANDS_START,
@@ -216,13 +217,15 @@
int ANIMATION_START = 7;
int PERFORM_TRAVERSALS_START = 8;
int DRAW_START = 9;
- int SYNC_QUEUED = 10;
- int SYNC_START = 11;
- int ISSUE_DRAW_COMMANDS_START = 12;
- int SWAP_BUFFERS = 13;
- int FRAME_COMPLETED = 14;
+ int FRAME_DEADLINE = 10;
+ int SYNC_QUEUED = 11;
+ int SYNC_START = 12;
+ int ISSUE_DRAW_COMMANDS_START = 13;
+ int SWAP_BUFFERS = 14;
+ int FRAME_COMPLETED = 15;
- int FRAME_STATS_COUNT = 18; // must always be last
+ int FRAME_STATS_COUNT = 19; // must always be last and in sync with
+ // FrameInfoIndex::NumIndexes in libs/hwui/FrameInfo.h
}
/*
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index daab70a..c460f74 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -337,11 +337,16 @@
*/
boolean isDisplayRotationFrozen(int displayId);
- /**
+ /**
* Sets if display rotation is fixed to user specified value for given displayId.
*/
void setFixedToUserRotation(int displayId, int fixedToUserRotation);
+ /**
+ * Sets if all requested fixed orientation should be ignored for given displayId.
+ */
+ void setIgnoreOrientationRequest(int displayId, boolean ignoreOrientationRequest);
+
/**
* Screenshot the current wallpaper layer, including the whole screen.
*/
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 69a5faf..910fd90 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -98,9 +98,6 @@
* @param outSurface Object in which is placed the new display surface.
* @param insetsState The current insets state in the system.
* @param outSurfaceSize The width and height of the surface control
- * @param outBlastSurfaceControl A BLAST SurfaceControl allocated by the WindowManager
- * the SurfaceControl willl be managed by the client side, but the WindowManager
- * may use it as a deferTransaction barrier.
*
* @return int Result flags: {@link WindowManagerGlobal#RELAYOUT_SHOW_FOCUS},
* {@link WindowManagerGlobal#RELAYOUT_FIRST_TIME}.
@@ -110,7 +107,7 @@
int flags, long frameNumber, out ClientWindowFrames outFrames,
out MergedConfiguration outMergedConfiguration, out SurfaceControl outSurfaceControl,
out InsetsState insetsState, out InsetsSourceControl[] activeControls,
- out Point outSurfaceSize, out SurfaceControl outBlastSurfaceControl);
+ out Point outSurfaceSize);
/*
* Notify the window manager that an application is relaunching and
diff --git a/core/java/android/view/KeyEvent.aidl b/core/java/android/view/KeyEvent.aidl
index dc15ecf..1f6d16e 100644
--- a/core/java/android/view/KeyEvent.aidl
+++ b/core/java/android/view/KeyEvent.aidl
@@ -17,4 +17,4 @@
package android.view;
-parcelable KeyEvent;
+@JavaOnlyStableParcelable parcelable KeyEvent;
diff --git a/core/java/android/view/OnReceiveContentCallback.java b/core/java/android/view/OnReceiveContentCallback.java
index 73bcb93..a217ff6 100644
--- a/core/java/android/view/OnReceiveContentCallback.java
+++ b/core/java/android/view/OnReceiveContentCallback.java
@@ -134,46 +134,52 @@
final class Payload {
/**
- * Specifies the UI through which content is being inserted.
+ * Specifies the UI through which content is being inserted. Future versions of Android may
+ * support additional values.
*
* @hide
*/
- @IntDef(prefix = {"SOURCE_"}, value = {SOURCE_CLIPBOARD, SOURCE_INPUT_METHOD,
+ @IntDef(prefix = {"SOURCE_"}, value = {SOURCE_APP, SOURCE_CLIPBOARD, SOURCE_INPUT_METHOD,
SOURCE_DRAG_AND_DROP, SOURCE_AUTOFILL, SOURCE_PROCESS_TEXT})
@Retention(RetentionPolicy.SOURCE)
public @interface Source {}
/**
+ * Specifies that the operation was triggered by the app that contains the target view.
+ */
+ public static final int SOURCE_APP = 0;
+
+ /**
* Specifies that the operation was triggered by a paste from the clipboard (e.g. "Paste" or
* "Paste as plain text" action in the insertion/selection menu).
*/
- public static final int SOURCE_CLIPBOARD = 0;
+ public static final int SOURCE_CLIPBOARD = 1;
/**
* Specifies that the operation was triggered from the soft keyboard (also known as input
* method editor or IME). See https://developer.android.com/guide/topics/text/image-keyboard
* for more info.
*/
- public static final int SOURCE_INPUT_METHOD = 1;
+ public static final int SOURCE_INPUT_METHOD = 2;
/**
* Specifies that the operation was triggered by the drag/drop framework. See
* https://developer.android.com/guide/topics/ui/drag-drop for more info.
*/
- public static final int SOURCE_DRAG_AND_DROP = 2;
+ public static final int SOURCE_DRAG_AND_DROP = 3;
/**
* Specifies that the operation was triggered by the autofill framework. See
* https://developer.android.com/guide/topics/text/autofill for more info.
*/
- public static final int SOURCE_AUTOFILL = 3;
+ public static final int SOURCE_AUTOFILL = 4;
/**
* Specifies that the operation was triggered by a result from a
* {@link android.content.Intent#ACTION_PROCESS_TEXT PROCESS_TEXT} action in the selection
* menu.
*/
- public static final int SOURCE_PROCESS_TEXT = 4;
+ public static final int SOURCE_PROCESS_TEXT = 5;
/**
* Returns the symbolic name of the given source.
@@ -182,6 +188,7 @@
*/
static String sourceToString(@Source int source) {
switch (source) {
+ case SOURCE_APP: return "SOURCE_APP";
case SOURCE_CLIPBOARD: return "SOURCE_CLIPBOARD";
case SOURCE_INPUT_METHOD: return "SOURCE_INPUT_METHOD";
case SOURCE_DRAG_AND_DROP: return "SOURCE_DRAG_AND_DROP";
@@ -217,37 +224,11 @@
return String.valueOf(flags);
}
- /**
- * The data to be inserted.
- */
@NonNull private final ClipData mClip;
-
- /**
- * The source of the operation. See {@code SOURCE_} constants.
- */
private final @Source int mSource;
-
- /**
- * Optional flags that control the insertion behavior. See {@code FLAG_} constants.
- */
private final @Flags int mFlags;
-
- /**
- * Optional http/https URI for the content that may be provided by the IME. This is only
- * populated if the source is {@link #SOURCE_INPUT_METHOD} and if a non-empty
- * {@link android.view.inputmethod.InputContentInfo#getLinkUri linkUri} was passed by the
- * IME.
- */
- @Nullable
- private final Uri mLinkUri;
-
- /**
- * Optional additional metadata. If the source is {@link #SOURCE_INPUT_METHOD}, this will
- * include the {@link android.view.inputmethod.InputConnection#commitContent opts} passed by
- * the IME.
- */
- @Nullable
- private final Bundle mExtras;
+ @Nullable private final Uri mLinkUri;
+ @Nullable private final Bundle mExtras;
private Payload(Builder b) {
this.mClip = Objects.requireNonNull(b.mClip);
@@ -278,7 +259,8 @@
}
/**
- * The source of the operation. See {@code SOURCE_} constants.
+ * The source of the operation. See {@code SOURCE_} constants. Future versions of Android
+ * may pass additional values.
*/
public @Source int getSource() {
return mSource;
diff --git a/core/java/android/view/RemoteAccessibilityController.java b/core/java/android/view/RemoteAccessibilityController.java
new file mode 100644
index 0000000..bc0fab1b
--- /dev/null
+++ b/core/java/android/view/RemoteAccessibilityController.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2020 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 android.view;
+
+import android.graphics.Matrix;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.accessibility.IAccessibilityEmbeddedConnection;
+
+class RemoteAccessibilityController {
+ private static final String TAG = "RemoteAccessibilityController";
+ private int mHostId;
+ private RemoteAccessibilityEmbeddedConnection mConnectionWrapper;
+ private Matrix mScreenMatrixForEmbeddedHierarchy = new Matrix();
+ private final float[] mMatrixValues = new float[9];
+ private View mHostView;
+
+ RemoteAccessibilityController(View v) {
+ mHostView = v;
+ }
+
+ private void runOnUiThread(Runnable runnable) {
+ final Handler h = mHostView.getHandler();
+ if (h != null && h.getLooper() != Looper.myLooper()) {
+ h.post(runnable);
+ } else {
+ runnable.run();
+ }
+ }
+
+ void assosciateHierarchy(IAccessibilityEmbeddedConnection connection,
+ IBinder leashToken, int hostId) {
+ mHostId = hostId;
+
+ try {
+ leashToken = connection.associateEmbeddedHierarchy(
+ leashToken, mHostId);
+ setRemoteAccessibilityEmbeddedConnection(connection, leashToken);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Error in associateEmbeddedHierarchy " + e);
+ }
+ }
+
+ void disassosciateHierarchy() {
+ setRemoteAccessibilityEmbeddedConnection(null, null);
+ }
+
+ boolean alreadyAssociated(IAccessibilityEmbeddedConnection connection) {
+ if (mConnectionWrapper == null) {
+ return false;
+ }
+ return mConnectionWrapper.mConnection.equals(connection);
+ }
+
+ boolean connected() {
+ return mConnectionWrapper != null;
+ }
+
+ IBinder getLeashToken() {
+ return mConnectionWrapper.getLeashToken();
+ }
+
+ /**
+ * Wrapper of accessibility embedded connection for embedded view hierarchy.
+ */
+ private final class RemoteAccessibilityEmbeddedConnection implements IBinder.DeathRecipient {
+ private final IAccessibilityEmbeddedConnection mConnection;
+ private final IBinder mLeashToken;
+
+ RemoteAccessibilityEmbeddedConnection(IAccessibilityEmbeddedConnection connection,
+ IBinder leashToken) {
+ mConnection = connection;
+ mLeashToken = leashToken;
+ }
+
+ IAccessibilityEmbeddedConnection getConnection() {
+ return mConnection;
+ }
+
+ IBinder getLeashToken() {
+ return mLeashToken;
+ }
+
+ void linkToDeath() throws RemoteException {
+ mConnection.asBinder().linkToDeath(this, 0);
+ }
+
+ void unlinkToDeath() {
+ mConnection.asBinder().unlinkToDeath(this, 0);
+ }
+
+ @Override
+ public void binderDied() {
+ unlinkToDeath();
+ runOnUiThread(() -> {
+ if (mConnectionWrapper == this) {
+ mConnectionWrapper = null;
+ }
+ });
+ }
+ }
+
+ private void setRemoteAccessibilityEmbeddedConnection(
+ IAccessibilityEmbeddedConnection connection, IBinder leashToken) {
+ try {
+ if (mConnectionWrapper != null) {
+ mConnectionWrapper.getConnection()
+ .disassociateEmbeddedHierarchy();
+ mConnectionWrapper.unlinkToDeath();
+ mConnectionWrapper = null;
+ }
+ if (connection != null && leashToken != null) {
+ mConnectionWrapper =
+ new RemoteAccessibilityEmbeddedConnection(connection, leashToken);
+ mConnectionWrapper.linkToDeath();
+ }
+ } catch (RemoteException e) {
+ Log.d(TAG, "Error while setRemoteEmbeddedConnection " + e);
+ }
+ }
+
+ private RemoteAccessibilityEmbeddedConnection getRemoteAccessibilityEmbeddedConnection() {
+ return mConnectionWrapper;
+ }
+
+ void setScreenMatrix(Matrix m) {
+ // If the screen matrix is identity or doesn't change, do nothing.
+ if (m.isIdentity() || m.equals(mScreenMatrixForEmbeddedHierarchy)) {
+ return;
+ }
+
+ try {
+ final RemoteAccessibilityEmbeddedConnection wrapper =
+ getRemoteAccessibilityEmbeddedConnection();
+ if (wrapper == null) {
+ return;
+ }
+ m.getValues(mMatrixValues);
+ wrapper.getConnection().setScreenMatrix(mMatrixValues);
+ mScreenMatrixForEmbeddedHierarchy.set(m);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Error while setScreenMatrix " + e);
+ }
+ }
+
+
+
+
+
+
+}
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 5b0d950..0847a17 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -739,7 +739,7 @@
* Set the scaling mode to be used for this surfaces buffers
* @hide
*/
- void setScalingMode(@ScalingMode int scalingMode) {
+ public void setScalingMode(@ScalingMode int scalingMode) {
synchronized (mLock) {
checkNotReleasedLocked();
int err = nativeSetScalingMode(mNativeObject, scalingMode);
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index ed9deec..566ebf3 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -187,8 +187,6 @@
private static native void nativeReparent(long transactionObj, long nativeObject,
long newParentNativeObject);
private static native void nativeSeverChildren(long transactionObj, long nativeObject);
- private static native void nativeSetOverrideScalingMode(long transactionObj, long nativeObject,
- int scalingMode);
private static native Display.HdrCapabilities nativeGetHdrCapabilities(IBinder displayToken);
@@ -1521,16 +1519,6 @@
/**
* @hide
*/
- public void setOverrideScalingMode(int scalingMode) {
- checkNotReleased();
- synchronized(SurfaceControl.class) {
- sGlobalTransaction.setOverrideScalingMode(this, scalingMode);
- }
- }
-
- /**
- * @hide
- */
@UnsupportedAppUsage
public void setLayer(int zorder) {
checkNotReleased();
@@ -2989,16 +2977,6 @@
}
/**
- * @hide
- */
- public Transaction setOverrideScalingMode(SurfaceControl sc, int overrideScalingMode) {
- checkPreconditions(sc);
- nativeSetOverrideScalingMode(mNativeObject, sc.mNativeObject,
- overrideScalingMode);
- return this;
- }
-
- /**
* Fills the surface with the specified color.
* @param color A float array with three values to represent r, g, b in range [0..1]. An
* invalid color will remove the color fill.
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 78c71b8..7b6a4f8 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -41,7 +41,6 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
-import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.Settings;
import android.util.AttributeSet;
@@ -225,13 +224,12 @@
private SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction();
private SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
- private int mParentSurfaceGenerationId;
+ private int mParentSurfaceSequenceId;
- private RemoteAccessibilityEmbeddedConnection mRemoteAccessibilityEmbeddedConnection;
+ private RemoteAccessibilityController mRemoteAccessibilityController =
+ new RemoteAccessibilityController(this);
- private final Matrix mScreenMatrixForEmbeddedHierarchy = new Matrix();
private final Matrix mTmpMatrix = new Matrix();
- private final float[] mMatrixValues = new float[9];
SurfaceControlViewHost.SurfacePackage mSurfacePackage;
@@ -467,7 +465,7 @@
Transaction t = new SurfaceControl.Transaction();
t.setAlpha(mSurfaceControl, alpha);
t.deferTransactionUntil(mSurfaceControl,
- viewRoot.getRenderSurfaceControl(), frame);
+ viewRoot.getSurfaceControl(), frame);
t.apply();
}
}
@@ -827,7 +825,7 @@
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
updateRelativeZ(t);
t.deferTransactionUntil(mSurfaceControl,
- viewRoot.getRenderSurfaceControl(), frame);
+ viewRoot.getSurfaceControl(), frame);
t.apply();
}
}
@@ -927,6 +925,103 @@
}
}
+ private boolean performSurfaceTransaction(ViewRootImpl viewRoot, Translator translator,
+ boolean creating, boolean sizeChanged, boolean needBLASTSync) {
+ boolean realSizeChanged = false;
+
+ mSurfaceLock.lock();
+ try {
+ mDrawingStopped = !mVisible;
+
+ if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ + "Cur surface: " + mSurface);
+
+ // If we are creating the surface control or the parent surface has not
+ // changed, then set relative z. Otherwise allow the parent
+ // SurfaceChangedCallback to update the relative z. This is needed so that
+ // we do not change the relative z before the server is ready to swap the
+ // parent surface.
+ if (creating || (mParentSurfaceSequenceId == viewRoot.getSurfaceSequenceId())) {
+ updateRelativeZ(mTmpTransaction);
+ }
+ mParentSurfaceSequenceId = viewRoot.getSurfaceSequenceId();
+
+ if (mViewVisibility) {
+ mTmpTransaction.show(mSurfaceControl);
+ } else {
+ mTmpTransaction.hide(mSurfaceControl);
+ }
+
+ if (mSurfacePackage != null) {
+ reparentSurfacePackage(mTmpTransaction, mSurfacePackage);
+ }
+
+ updateBackgroundVisibility(mTmpTransaction);
+ updateBackgroundColor(mTmpTransaction);
+ if (mUseAlpha) {
+ float alpha = getFixedAlpha();
+ mTmpTransaction.setAlpha(mSurfaceControl, alpha);
+ mSurfaceAlpha = alpha;
+ }
+
+ // While creating the surface, we will set it's initial
+ // geometry. Outside of that though, we should generally
+ // leave it to the RenderThread.
+ //
+ // There is one more case when the buffer size changes we aren't yet
+ // prepared to sync (as even following the transaction applying
+ // we still need to latch a buffer).
+ // b/28866173
+ if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
+ onSetSurfacePositionAndScaleRT(mTmpTransaction, mSurfaceControl,
+ mScreenRect.left, /*positionLeft*/
+ mScreenRect.top /*positionTop*/ ,
+ mScreenRect.width() / (float) mSurfaceWidth /*postScaleX*/,
+ mScreenRect.height() / (float) mSurfaceHeight /*postScaleY*/);
+
+ // Set a window crop when creating the surface or changing its size to
+ // crop the buffer to the surface size since the buffer producer may
+ // use SCALING_MODE_SCALE and submit a larger size than the surface
+ // size.
+ if (mClipSurfaceToBounds && mClipBounds != null) {
+ mTmpTransaction.setWindowCrop(mSurfaceControl, mClipBounds);
+ } else {
+ mTmpTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
+ mSurfaceHeight);
+ }
+ } else if (needBLASTSync) {
+ viewRoot.setUseBLASTSyncTransaction();
+ }
+ mTmpTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
+ if (sizeChanged && !creating) {
+ setBufferSize(mTmpTransaction);
+ }
+
+ mTmpTransaction.apply();
+ updateEmbeddedAccessibilityMatrix();
+
+ mSurfaceFrame.left = 0;
+ mSurfaceFrame.top = 0;
+ if (translator == null) {
+ mSurfaceFrame.right = mSurfaceWidth;
+ mSurfaceFrame.bottom = mSurfaceHeight;
+ } else {
+ float appInvertedScale = translator.applicationInvertedScale;
+ mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
+ mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
+ }
+ final int surfaceWidth = mSurfaceFrame.right;
+ final int surfaceHeight = mSurfaceFrame.bottom;
+ realSizeChanged = mLastSurfaceWidth != surfaceWidth
+ || mLastSurfaceHeight != surfaceHeight;
+ mLastSurfaceWidth = surfaceWidth;
+ mLastSurfaceHeight = surfaceHeight;
+ } finally {
+ mSurfaceLock.unlock();
+ }
+ return realSizeChanged;
+ }
+
/** @hide */
protected void updateSurface() {
if (!mHaveFrame) {
@@ -965,7 +1060,6 @@
&& mRequestedVisible;
final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
- boolean redrawNeeded = false;
getLocationInSurface(mLocation);
final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
|| mWindowSpaceTop != mLocation[1];
@@ -988,7 +1082,7 @@
+ " top=" + (mWindowSpaceTop != mLocation[1]));
try {
- final boolean visible = mVisible = mRequestedVisible;
+ mVisible = mRequestedVisible;
mWindowSpaceLeft = mLocation[0];
mWindowSpaceTop = mLocation[1];
mSurfaceWidth = myWidth;
@@ -1014,119 +1108,26 @@
return;
}
- boolean realSizeChanged = false;
-
- mSurfaceLock.lock();
- try {
- mDrawingStopped = !visible;
-
- if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
- + "Cur surface: " + mSurface);
-
- // If we are creating the surface control or the parent surface has not
- // changed, then set relative z. Otherwise allow the parent
- // SurfaceChangedCallback to update the relative z. This is needed so that
- // we do not change the relative z before the server is ready to swap the
- // parent surface.
- if (creating || (mParentSurfaceGenerationId
- == viewRoot.mSurface.getGenerationId())) {
- updateRelativeZ(mTmpTransaction);
- }
- mParentSurfaceGenerationId = viewRoot.mSurface.getGenerationId();
-
- if (mViewVisibility) {
- mTmpTransaction.show(mSurfaceControl);
- } else {
- mTmpTransaction.hide(mSurfaceControl);
- }
-
- if (mSurfacePackage != null) {
- reparentSurfacePackage(mTmpTransaction, mSurfacePackage);
- }
-
- updateBackgroundVisibility(mTmpTransaction);
- updateBackgroundColor(mTmpTransaction);
- if (mUseAlpha) {
- mTmpTransaction.setAlpha(mSurfaceControl, alpha);
- mSurfaceAlpha = alpha;
- }
-
- // While creating the surface, we will set it's initial
- // geometry. Outside of that though, we should generally
- // leave it to the RenderThread.
- //
- // There is one more case when the buffer size changes we aren't yet
- // prepared to sync (as even following the transaction applying
- // we still need to latch a buffer).
- // b/28866173
- if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
- onSetSurfacePositionAndScaleRT(mTmpTransaction, mSurfaceControl,
- mScreenRect.left, /*positionLeft*/
- mScreenRect.top /*positionTop*/ ,
- mScreenRect.width() / (float) mSurfaceWidth /*postScaleX*/,
- mScreenRect.height() / (float) mSurfaceHeight /*postScaleY*/);
-
- // Set a window crop when creating the surface or changing its size to
- // crop the buffer to the surface size since the buffer producer may
- // use SCALING_MODE_SCALE and submit a larger size than the surface
- // size.
- if (mClipSurfaceToBounds && mClipBounds != null) {
- mTmpTransaction.setWindowCrop(mSurfaceControl, mClipBounds);
- } else {
- mTmpTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
- mSurfaceHeight);
- }
- } else if ((layoutSizeChanged || positionChanged || visibleChanged) &&
- viewRoot.useBLAST()) {
- viewRoot.setUseBLASTSyncTransaction();
- }
- mTmpTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
- if (sizeChanged && !creating) {
- setBufferSize(mTmpTransaction);
- }
-
- mTmpTransaction.apply();
- updateScreenMatrixForEmbeddedHierarchy();
-
- if (sizeChanged || creating) {
- redrawNeeded = true;
- }
-
- mSurfaceFrame.left = 0;
- mSurfaceFrame.top = 0;
- if (translator == null) {
- mSurfaceFrame.right = mSurfaceWidth;
- mSurfaceFrame.bottom = mSurfaceHeight;
- } else {
- float appInvertedScale = translator.applicationInvertedScale;
- mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
- mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
- }
-
- final int surfaceWidth = mSurfaceFrame.right;
- final int surfaceHeight = mSurfaceFrame.bottom;
- realSizeChanged = mLastSurfaceWidth != surfaceWidth
- || mLastSurfaceHeight != surfaceHeight;
- mLastSurfaceWidth = surfaceWidth;
- mLastSurfaceHeight = surfaceHeight;
- } finally {
- mSurfaceLock.unlock();
- }
+ final boolean needBLASTSync =
+ (layoutSizeChanged || positionChanged || visibleChanged) &&
+ viewRoot.useBLAST();
+ final boolean realSizeChanged = performSurfaceTransaction(viewRoot,
+ translator, creating, sizeChanged, needBLASTSync);
+ final boolean redrawNeeded = sizeChanged || creating ||
+ (mVisible && !mDrawFinished);
try {
- redrawNeeded |= visible && !mDrawFinished;
-
SurfaceHolder.Callback[] callbacks = null;
final boolean surfaceChanged = creating;
- if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
+ if (mSurfaceCreated && (surfaceChanged || (!mVisible && visibleChanged))) {
mSurfaceCreated = false;
notifySurfaceDestroyed();
}
copySurface(creating /* surfaceControlCreated */, sizeChanged);
- if (visible && mSurface.isValid()) {
+ if (mVisible && mSurface.isValid()) {
if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
mSurfaceCreated = true;
mIsCreating = true;
@@ -1352,7 +1353,7 @@
Rect position, long frameNumber) {
final ViewRootImpl viewRoot = getViewRootImpl();
if (frameNumber > 0 && viewRoot != null && !viewRoot.useBLAST()) {
- t.deferTransactionUntil(surface, viewRoot.getRenderSurfaceControl(),
+ t.deferTransactionUntil(surface, viewRoot.getSurfaceControl(),
frameNumber);
}
@@ -1470,7 +1471,7 @@
} else {
if (frameNumber > 0 && viewRoot != null && viewRoot.mSurface.isValid()) {
mRtTransaction.deferTransactionUntil(mSurfaceControl,
- viewRoot.getRenderSurfaceControl(), frameNumber);
+ viewRoot.getSurfaceControl(), frameNumber);
}
mRtTransaction.hide(mSurfaceControl);
if (mRtReleaseSurfaces) {
@@ -1754,7 +1755,7 @@
@Override
public void surfaceDestroyed() {
setWindowStopped(true);
- setRemoteAccessibilityEmbeddedConnection(null, null);
+ mRemoteAccessibilityController.disassosciateHierarchy();
}
/**
@@ -1834,14 +1835,12 @@
@Override
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfoInternal(info);
- final RemoteAccessibilityEmbeddedConnection wrapper =
- getRemoteAccessibilityEmbeddedConnection();
- if (wrapper == null) {
+ if (!mRemoteAccessibilityController.connected()) {
return;
}
// Add a leashed child when this SurfaceView embeds another view hierarchy. Getting this
// leashed child would return the root node in the embedded hierarchy
- info.addChild(wrapper.getLeashToken());
+ info.addChild(mRemoteAccessibilityController.getLeashToken());
}
@Override
@@ -1850,7 +1849,7 @@
// If developers explicitly set the important mode for it, don't change the mode.
// Only change the mode to important when this SurfaceView isn't explicitly set and has
// an embedded hierarchy.
- if (mRemoteAccessibilityEmbeddedConnection == null
+ if (!mRemoteAccessibilityController.connected()
|| mode != IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
return mode;
}
@@ -1859,74 +1858,13 @@
private void initEmbeddedHierarchyForAccessibility(SurfaceControlViewHost.SurfacePackage p) {
final IAccessibilityEmbeddedConnection connection = p.getAccessibilityEmbeddedConnection();
- final RemoteAccessibilityEmbeddedConnection wrapper =
- getRemoteAccessibilityEmbeddedConnection();
-
- // Do nothing if package is embedding the same view hierarchy.
- if (wrapper != null && wrapper.getConnection().equals(connection)) {
+ if (mRemoteAccessibilityController.alreadyAssociated(connection)) {
return;
}
+ mRemoteAccessibilityController.assosciateHierarchy(connection,
+ getViewRootImpl().mLeashToken, getAccessibilityViewId());
- // If this SurfaceView embeds a different view hierarchy, unlink the previous one first.
- setRemoteAccessibilityEmbeddedConnection(null, null);
-
- try {
- final IBinder leashToken = connection.associateEmbeddedHierarchy(
- getViewRootImpl().mLeashToken, getAccessibilityViewId());
- setRemoteAccessibilityEmbeddedConnection(connection, leashToken);
- } catch (RemoteException e) {
- Log.d(TAG, "Error while associateEmbeddedHierarchy " + e);
- }
- updateScreenMatrixForEmbeddedHierarchy();
- }
-
- private void setRemoteAccessibilityEmbeddedConnection(
- IAccessibilityEmbeddedConnection connection, IBinder leashToken) {
- try {
- if (mRemoteAccessibilityEmbeddedConnection != null) {
- mRemoteAccessibilityEmbeddedConnection.getConnection()
- .disassociateEmbeddedHierarchy();
- mRemoteAccessibilityEmbeddedConnection.unlinkToDeath();
- mRemoteAccessibilityEmbeddedConnection = null;
- }
- if (connection != null && leashToken != null) {
- mRemoteAccessibilityEmbeddedConnection =
- new RemoteAccessibilityEmbeddedConnection(connection, leashToken);
- mRemoteAccessibilityEmbeddedConnection.linkToDeath();
- }
- } catch (RemoteException e) {
- Log.d(TAG, "Error while setRemoteEmbeddedConnection " + e);
- }
- }
-
- private RemoteAccessibilityEmbeddedConnection getRemoteAccessibilityEmbeddedConnection() {
- return mRemoteAccessibilityEmbeddedConnection;
- }
-
- private void updateScreenMatrixForEmbeddedHierarchy() {
- getBoundsOnScreen(mTmpRect);
- mTmpMatrix.reset();
- mTmpMatrix.setTranslate(mTmpRect.left, mTmpRect.top);
- mTmpMatrix.postScale(mScreenRect.width() / (float) mSurfaceWidth,
- mScreenRect.height() / (float) mSurfaceHeight);
-
- // If the screen matrix is identity or doesn't change, do nothing.
- if (mTmpMatrix.isIdentity() || mTmpMatrix.equals(mScreenMatrixForEmbeddedHierarchy)) {
- return;
- }
-
- try {
- final RemoteAccessibilityEmbeddedConnection wrapper =
- getRemoteAccessibilityEmbeddedConnection();
- if (wrapper == null) {
- return;
- }
- mTmpMatrix.getValues(mMatrixValues);
- wrapper.getConnection().setScreenMatrix(mMatrixValues);
- mScreenMatrixForEmbeddedHierarchy.set(mTmpMatrix);
- } catch (RemoteException e) {
- Log.d(TAG, "Error while setScreenMatrix " + e);
- }
+ updateEmbeddedAccessibilityMatrix();
}
private void notifySurfaceDestroyed() {
@@ -1954,6 +1892,18 @@
}
}
+ void updateEmbeddedAccessibilityMatrix() {
+ if (!mRemoteAccessibilityController.connected()) {
+ return;
+ }
+ getBoundsOnScreen(mTmpRect);
+ mTmpMatrix.reset();
+ mTmpMatrix.setTranslate(mTmpRect.left, mTmpRect.top);
+ mTmpMatrix.postScale(mScreenRect.width() / (float) mSurfaceWidth,
+ mScreenRect.height() / (float) mSurfaceHeight);
+ mRemoteAccessibilityController.setScreenMatrix(mTmpMatrix);
+ }
+
@Override
protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction,
@Nullable Rect previouslyFocusedRect) {
@@ -1970,44 +1920,4 @@
+ "Exception requesting focus on embedded window", e);
}
}
-
- /**
- * Wrapper of accessibility embedded connection for embedded view hierarchy.
- */
- private final class RemoteAccessibilityEmbeddedConnection implements IBinder.DeathRecipient {
- private final IAccessibilityEmbeddedConnection mConnection;
- private final IBinder mLeashToken;
-
- RemoteAccessibilityEmbeddedConnection(IAccessibilityEmbeddedConnection connection,
- IBinder leashToken) {
- mConnection = connection;
- mLeashToken = leashToken;
- }
-
- IAccessibilityEmbeddedConnection getConnection() {
- return mConnection;
- }
-
- IBinder getLeashToken() {
- return mLeashToken;
- }
-
- void linkToDeath() throws RemoteException {
- mConnection.asBinder().linkToDeath(this, 0);
- }
-
- void unlinkToDeath() {
- mConnection.asBinder().unlinkToDeath(this, 0);
- }
-
- @Override
- public void binderDied() {
- unlinkToDeath();
- runOnUiThread(() -> {
- if (mRemoteAccessibilityEmbeddedConnection == this) {
- mRemoteAccessibilityEmbeddedConnection = null;
- }
- });
- }
- }
}
diff --git a/core/java/android/view/SyncRtSurfaceTransactionApplier.java b/core/java/android/view/SyncRtSurfaceTransactionApplier.java
index 062285f..bce78b5 100644
--- a/core/java/android/view/SyncRtSurfaceTransactionApplier.java
+++ b/core/java/android/view/SyncRtSurfaceTransactionApplier.java
@@ -60,7 +60,7 @@
if (mTargetViewRootImpl == null) {
return;
}
- mTargetSc = mTargetViewRootImpl.getRenderSurfaceControl();
+ mTargetSc = mTargetViewRootImpl.getSurfaceControl();
mTargetViewRootImpl.registerRtFrameCallback(frame -> {
if (mTargetSc == null || !mTargetSc.isValid()) {
return;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c430a4d..4f05a59 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -15165,6 +15165,42 @@
}
/**
+ * Called by the {@link android.view.inputmethod.InputMethodManager} to notify the application
+ * that the system has successfully initialized an {@link InputConnection} and it is ready for
+ * use.
+ *
+ * <p>The default implementation does nothing, since a view doesn't support input methods by
+ * default (see {@link #onCreateInputConnection}).
+ *
+ * @param inputConnection The {@link InputConnection} from {@link #onCreateInputConnection},
+ * after it's been fully initialized by the system.
+ * @param editorInfo The {@link EditorInfo} that was used to create the {@link InputConnection}.
+ * @param handler The dedicated {@link Handler} on which IPC method calls from input methods
+ * will be dispatched. This is the handler returned by {@link InputConnection#getHandler()}. If
+ * that method returns null, this parameter will be null also.
+ *
+ * @hide
+ */
+ public void onInputConnectionOpenedInternal(@NonNull InputConnection inputConnection,
+ @NonNull EditorInfo editorInfo, @Nullable Handler handler) {}
+
+ /**
+ * Called by the {@link android.view.inputmethod.InputMethodManager} to notify the application
+ * that the {@link InputConnection} has been closed.
+ *
+ * <p>The default implementation does nothing, since a view doesn't support input methods by
+ * default (see {@link #onCreateInputConnection}).
+ *
+ * <p><strong>Note:</strong> This callback is not invoked if the view is already detached when
+ * the {@link InputConnection} is closed or the connection is not valid and managed by
+ * {@link com.android.server.inputmethod.InputMethodManagerService}.
+ * TODO(b/170645312): Before un-hiding this API, handle the detached view scenario.
+ *
+ * @hide
+ */
+ public void onInputConnectionClosedInternal() {}
+
+ /**
* Called by the {@link android.view.inputmethod.InputMethodManager}
* when a view who is not the current
* input connection target is trying to make a call on the manager. The
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e00ff7e..5235740 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -105,6 +105,7 @@
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.FrameInfo;
+import android.graphics.HardwareRenderer;
import android.graphics.HardwareRenderer.FrameDrawingCallback;
import android.graphics.Insets;
import android.graphics.Matrix;
@@ -519,7 +520,6 @@
@UnsupportedAppUsage
public final Surface mSurface = new Surface();
private final SurfaceControl mSurfaceControl = new SurfaceControl();
- private SurfaceControl mBlastSurfaceControl = new SurfaceControl();
private BLASTBufferQueue mBlastBufferQueue;
@@ -702,6 +702,11 @@
private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks;
+ /**
+ * Increment this value when the surface has been replaced.
+ */
+ private int mSurfaceSequenceId = 0;
+
private String mTag = TAG;
public ViewRootImpl(Context context, Display display) {
@@ -1808,7 +1813,7 @@
mBoundsLayer = new SurfaceControl.Builder(mSurfaceSession)
.setContainerLayer()
.setName("Bounds for - " + getTitle().toString())
- .setParent(getRenderSurfaceControl())
+ .setParent(getSurfaceControl())
.setCallsite("ViewRootImpl.getBoundsLayer")
.build();
setBoundsLayerCrop(mTransaction);
@@ -1818,22 +1823,19 @@
}
Surface getOrCreateBLASTSurface(int width, int height) {
- if (mSurfaceControl == null
- || !mSurfaceControl.isValid()
- || mBlastSurfaceControl == null
- || !mBlastSurfaceControl.isValid()) {
+ if (!mSurfaceControl.isValid()) {
return null;
}
Surface ret = null;
if (mBlastBufferQueue == null) {
mBlastBufferQueue = new BLASTBufferQueue(mTag,
- mBlastSurfaceControl, width, height, mEnableTripleBuffering);
+ mSurfaceControl, width, height, mEnableTripleBuffering);
// We only return the Surface the first time, as otherwise
// it hasn't changed and there is no need to update.
ret = mBlastBufferQueue.createSurface();
} else {
- mBlastBufferQueue.update(mBlastSurfaceControl, width, height);
+ mBlastBufferQueue.update(mSurfaceControl, width, height);
}
return ret;
@@ -1855,7 +1857,7 @@
private boolean updateBoundsLayer(SurfaceControl.Transaction t) {
if (mBoundsLayer != null) {
setBoundsLayerCrop(t);
- t.deferTransactionUntil(mBoundsLayer, getRenderSurfaceControl(),
+ t.deferTransactionUntil(mBoundsLayer, getSurfaceControl(),
mSurface.getNextFrameNumber());
return true;
}
@@ -1864,7 +1866,7 @@
private void prepareSurfaces(boolean sizeChanged) {
final SurfaceControl.Transaction t = mTransaction;
- final SurfaceControl sc = getRenderSurfaceControl();
+ final SurfaceControl sc = getSurfaceControl();
if (!sc.isValid()) return;
boolean applyTransaction = updateBoundsLayer(t);
@@ -1885,7 +1887,6 @@
mSurface.release();
mSurfaceControl.release();
- mBlastSurfaceControl.release();
// We should probably add an explicit dispose.
mBlastBufferQueue = null;
}
@@ -2613,7 +2614,7 @@
boolean surfaceSizeChanged = false;
boolean surfaceCreated = false;
boolean surfaceDestroyed = false;
- /* True if surface generation id changes. */
+ // True if surface generation id changes or relayout result is RELAYOUT_RES_SURFACE_CHANGED.
boolean surfaceReplaced = false;
final boolean windowAttributesChanged = mWindowAttributesChanged;
@@ -2708,6 +2709,7 @@
updateColorModeIfNeeded(lp.getColorMode());
surfaceCreated = !hadSurface && mSurface.isValid();
surfaceDestroyed = hadSurface && !mSurface.isValid();
+
// When using Blast, the surface generation id may not change when there's a new
// SurfaceControl. In that case, we also check relayout flag
// RELAYOUT_RES_SURFACE_CHANGED since it should indicate that WMS created a new
@@ -2716,6 +2718,9 @@
|| (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED)
== RELAYOUT_RES_SURFACE_CHANGED)
&& mSurface.isValid();
+ if (surfaceReplaced) {
+ mSurfaceSequenceId++;
+ }
if (cutoutChanged) {
mAttachInfo.mDisplayCutout.set(mPendingDisplayCutout);
@@ -3815,6 +3820,82 @@
}
}
+ /**
+ * The callback will run on the render thread.
+ */
+ private HardwareRenderer.FrameCompleteCallback createFrameCompleteCallback(Handler handler,
+ boolean reportNextDraw, ArrayList<Runnable> commitCallbacks) {
+ return frameNr -> {
+ // Use a new transaction here since mRtBLASTSyncTransaction can only be accessed by
+ // the render thread and mSurfaceChangedTransaction can only be accessed by the UI
+ // thread. The temporary transaction is used so mRtBLASTSyncTransaction can be merged
+ // with mSurfaceChangedTransaction without synchronization issues.
+ final Transaction t = new Transaction();
+ finishBLASTSyncOnRT(!mSendNextFrameToWm, t);
+ handler.postAtFrontOfQueue(() -> {
+ mSurfaceChangedTransaction.merge(t);
+ if (reportNextDraw) {
+ // TODO: Use the frame number
+ pendingDrawFinished();
+ }
+ if (commitCallbacks != null) {
+ for (int i = 0; i < commitCallbacks.size(); i++) {
+ commitCallbacks.get(i).run();
+ }
+ }
+ });
+ };
+ }
+
+ private boolean addFrameCompleteCallbackIfNeeded() {
+ if (mAttachInfo.mThreadedRenderer == null || !mAttachInfo.mThreadedRenderer.isEnabled()) {
+ return false;
+ }
+
+ ArrayList<Runnable> commitCallbacks = mAttachInfo.mTreeObserver
+ .captureFrameCommitCallbacks();
+ final boolean needFrameCompleteCallback =
+ mNextDrawUseBLASTSyncTransaction || mReportNextDraw
+ || (commitCallbacks != null && commitCallbacks.size() > 0);
+ if (needFrameCompleteCallback) {
+ mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(
+ createFrameCompleteCallback(mAttachInfo.mHandler, mReportNextDraw,
+ commitCallbacks));
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * The callback will run on a worker thread pool from the render thread.
+ */
+ private HardwareRenderer.FrameDrawingCallback createFrameDrawingCallback() {
+ return frame -> {
+ mRtNextFrameReportedConsumeWithBlast = true;
+ if (mBlastBufferQueue != null) {
+ // We don't need to synchronize mRtBLASTSyncTransaction here since it's not
+ // being modified and only sent to BlastBufferQueue.
+ mBlastBufferQueue.setNextTransaction(mRtBLASTSyncTransaction);
+ }
+ };
+ }
+
+ private void addFrameCallbackIfNeeded() {
+ if (!mNextDrawUseBLASTSyncTransaction) {
+ return;
+ }
+
+ // Frame callbacks will always occur after submitting draw requests and before
+ // the draw actually occurs. This will ensure that we set the next transaction
+ // for the frame that's about to get drawn and not on a previous frame that.
+ //
+ // This is thread safe since mRtNextFrameReportConsumeWithBlast will only be
+ // modified in onFrameDraw and then again in onFrameComplete. This is to ensure the
+ // next frame completed should be reported with the blast sync transaction.
+ registerRtFrameCallback(createFrameDrawingCallback());
+ mNextDrawUseBLASTSyncTransaction = false;
+ }
+
private void performDraw() {
if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
return;
@@ -3828,58 +3909,14 @@
mIsDrawing = true;
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
- boolean usingAsyncReport = false;
- boolean reportNextDraw = mReportNextDraw; // Capture the original value
- if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {
- ArrayList<Runnable> commitCallbacks = mAttachInfo.mTreeObserver
- .captureFrameCommitCallbacks();
- final boolean needFrameCompleteCallback = mNextDrawUseBLASTSyncTransaction ||
- (commitCallbacks != null && commitCallbacks.size() > 0) ||
- mReportNextDraw;
- usingAsyncReport = mReportNextDraw;
- if (needFrameCompleteCallback) {
- final Handler handler = mAttachInfo.mHandler;
- mAttachInfo.mThreadedRenderer.setFrameCompleteCallback((long frameNr) -> {
- finishBLASTSync(!mSendNextFrameToWm);
- handler.postAtFrontOfQueue(() -> {
- if (reportNextDraw) {
- // TODO: Use the frame number
- pendingDrawFinished();
- }
- if (commitCallbacks != null) {
- for (int i = 0; i < commitCallbacks.size(); i++) {
- commitCallbacks.get(i).run();
- }
- }
- });
- });
- }
- }
+ boolean usingAsyncReport = addFrameCompleteCallbackIfNeeded();
+ addFrameCallbackIfNeeded();
try {
- if (mNextDrawUseBLASTSyncTransaction) {
- // Frame callbacks will always occur after submitting draw requests and before
- // the draw actually occurs. This will ensure that we set the next transaction
- // for the frame that's about to get drawn and not on a previous frame that.
- //
- // This is thread safe since mRtNextFrameReportConsumeWithBlast will only be
- // modified in onFrameDraw and then again in onFrameComplete. This is to ensure the
- // next frame completed should be reported with the blast sync transaction.
- registerRtFrameCallback(frame -> {
- mRtNextFrameReportedConsumeWithBlast = true;
- if (mBlastBufferQueue != null) {
- // We don't need to synchronize mRtBLASTSyncTransaction here since it's not
- // being modified and only sent to BlastBufferQueue.
- mBlastBufferQueue.setNextTransaction(mRtBLASTSyncTransaction);
- }
- });
- mNextDrawUseBLASTSyncTransaction = false;
- }
boolean canUseAsync = draw(fullRedrawNeeded);
if (usingAsyncReport && !canUseAsync) {
mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(null);
usingAsyncReport = false;
- finishBLASTSync(true /* apply */);
}
} finally {
mIsDrawing = false;
@@ -7447,7 +7484,7 @@
(int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
mTmpFrames, mPendingMergedConfiguration, mSurfaceControl, mTempInsets,
- mTempControls, mSurfaceSize, mBlastSurfaceControl);
+ mTempControls, mSurfaceSize);
mPendingDisplayCutout.set(mTmpFrames.displayCutout);
mPendingBackDropFrame.set(mTmpFrames.backdropFrame);
if (mSurfaceControl.isValid()) {
@@ -9844,7 +9881,12 @@
mNextDrawUseBLASTSyncTransaction = true;
}
- private void finishBLASTSync(boolean apply) {
+ /**
+ * This should only be called from the render thread.
+ */
+ private void finishBLASTSyncOnRT(boolean apply, Transaction t) {
+ // This is safe to modify on the render thread since the only other place it's modified
+ // is on the UI thread when the render thread is paused.
mSendNextFrameToWm = false;
if (mRtNextFrameReportedConsumeWithBlast) {
mRtNextFrameReportedConsumeWithBlast = false;
@@ -9855,7 +9897,7 @@
if (apply) {
mRtBLASTSyncTransaction.apply();
} else {
- mSurfaceChangedTransaction.merge(mRtBLASTSyncTransaction);
+ t.merge(mRtBLASTSyncTransaction);
}
}
}
@@ -9868,17 +9910,6 @@
return mRtBLASTSyncTransaction;
}
- /**
- * @hide
- */
- public SurfaceControl getRenderSurfaceControl() {
- if (useBLAST()) {
- return mBlastSurfaceControl;
- } else {
- return mSurfaceControl;
- }
- }
-
@Override
public void onDescendantUnbufferedRequested() {
mUnbufferedInputSource = mView.mUnbufferedInputSource;
@@ -9895,4 +9926,8 @@
boolean useBLAST() {
return mUseBLASTAdapter && !mForceDisableBLAST;
}
+
+ int getSurfaceSequenceId() {
+ return mSurfaceSequenceId;
+ }
}
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index dbd8184..0c221ed 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -227,8 +227,7 @@
int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
- InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
- SurfaceControl outBLASTSurfaceControl) {
+ InsetsSourceControl[] outActiveControls, Point outSurfaceSize) {
final State state;
synchronized (this) {
state = mStateForWindow.get(window.asBinder());
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index d80d230..f6d6fde 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -199,7 +199,7 @@
* <b>Window state changed</b> - represents the event of a change to a section of
* the user interface that is visually distinct. Should be sent from either the
* root view of a window or from a view that is marked as a pane
- * {@link android.view.View#setAccessibilityPaneTitle(CharSequence)}. Not that changes
+ * {@link android.view.View#setAccessibilityPaneTitle(CharSequence)}. Note that changes
* to true windows are represented by {@link #TYPE_WINDOWS_CHANGED}.</br>
* <em>Type:</em> {@link #TYPE_WINDOW_STATE_CHANGED}</br>
* <em>Properties:</em></br>
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index b8f04159..5785999 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1006,6 +1006,24 @@
return;
}
closeConnection();
+
+ // Notify the app that the InputConnection was closed.
+ final View servedView = mServedView.get();
+ if (servedView != null) {
+ final Handler handler = servedView.getHandler();
+ // The handler is null if the view is already detached. When that's the case, for
+ // now, we simply don't dispatch this callback.
+ if (handler != null) {
+ if (DEBUG) {
+ Log.v(TAG, "Calling View.onInputConnectionClosed: view=" + servedView);
+ }
+ if (handler.getLooper().isCurrentThread()) {
+ servedView.onInputConnectionClosedInternal();
+ } else {
+ handler.post(servedView::onInputConnectionClosedInternal);
+ }
+ }
+ }
}
@Override
@@ -1940,6 +1958,8 @@
InputConnection ic = view.onCreateInputConnection(tba);
if (DEBUG) Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic);
+ final Handler icHandler;
+ InputBindResult res = null;
synchronized (mH) {
// Now that we are locked again, validate that our state hasn't
// changed.
@@ -1976,7 +1996,6 @@
mCursorCandEnd = -1;
mCursorRect.setEmpty();
mCursorAnchorInfo = null;
- final Handler icHandler;
missingMethodFlags = InputConnectionInspector.getMissingMethodFlags(ic);
if ((missingMethodFlags & InputConnectionInspector.MissingMethodFlags.GET_HANDLER)
!= 0) {
@@ -1990,6 +2009,7 @@
} else {
servedContext = null;
missingMethodFlags = 0;
+ icHandler = null;
}
mServedInputConnectionWrapper = servedContext;
@@ -1997,7 +2017,7 @@
if (DEBUG) Log.v(TAG, "START INPUT: view=" + dumpViewInfo(view) + " ic="
+ ic + " tba=" + tba + " startInputFlags="
+ InputMethodDebug.startInputFlagsToString(startInputFlags));
- final InputBindResult res = mService.startInputOrWindowGainedFocus(
+ res = mService.startInputOrWindowGainedFocus(
startInputReason, mClient, windowGainingFocus, startInputFlags,
softInputMode, windowFlags, tba, servedContext, missingMethodFlags,
view.getContext().getApplicationInfo().targetSdkVersion);
@@ -2036,6 +2056,15 @@
}
}
+ // Notify the app that the InputConnection is initialized and ready for use.
+ if (ic != null && res != null && res.method != null) {
+ if (DEBUG) {
+ Log.v(TAG, "Calling View.onInputConnectionOpened: view= " + view
+ + ", ic=" + ic + ", tba=" + tba + ", handler=" + icHandler);
+ }
+ view.onInputConnectionOpenedInternal(ic, tba, icHandler);
+ }
+
return true;
}
diff --git a/core/java/android/webkit/UserPackage.java b/core/java/android/webkit/UserPackage.java
index 2e5ee04..5bcfa8b 100644
--- a/core/java/android/webkit/UserPackage.java
+++ b/core/java/android/webkit/UserPackage.java
@@ -34,7 +34,7 @@
private final UserInfo mUserInfo;
private final PackageInfo mPackageInfo;
- public static final int MINIMUM_SUPPORTED_SDK = Build.VERSION_CODES.R;
+ public static final int MINIMUM_SUPPORTED_SDK = Build.VERSION_CODES.S;
public UserPackage(UserInfo user, PackageInfo packageInfo) {
this.mUserInfo = user;
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 8790bbd..5fc9344 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -47,7 +47,7 @@
// visible for WebViewZygoteInit to look up the class by reflection and call preloadInZygote.
/** @hide */
private static final String CHROMIUM_WEBVIEW_FACTORY =
- "com.android.webview.chromium.WebViewChromiumFactoryProviderForR";
+ "com.android.webview.chromium.WebViewChromiumFactoryProviderForS";
private static final String CHROMIUM_WEBVIEW_FACTORY_METHOD = "create";
diff --git a/core/java/android/window/ITaskOrganizerController.aidl b/core/java/android/window/ITaskOrganizerController.aidl
index 12b16ff..3a84c1f 100644
--- a/core/java/android/window/ITaskOrganizerController.aidl
+++ b/core/java/android/window/ITaskOrganizerController.aidl
@@ -17,7 +17,9 @@
package android.window;
import android.app.ActivityManager;
+import android.content.pm.ParceledListSlice;
import android.window.ITaskOrganizer;
+import android.window.TaskAppearedInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -26,8 +28,11 @@
/**
* Register a TaskOrganizer to manage all the tasks with supported windowing modes.
+ *
+ * @return a list of the tasks that should be managed by the organizer, not including tasks
+ * created via {@link #createRootTask}.
*/
- void registerTaskOrganizer(ITaskOrganizer organizer);
+ ParceledListSlice<TaskAppearedInfo> registerTaskOrganizer(ITaskOrganizer organizer);
/**
* Unregisters a previously registered task organizer.
diff --git a/core/java/android/window/TaskAppearedInfo.aidl b/core/java/android/window/TaskAppearedInfo.aidl
new file mode 100644
index 0000000..13eba25f
--- /dev/null
+++ b/core/java/android/window/TaskAppearedInfo.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2020 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 android.window;
+
+/**
+ * Data object for the task info provided when a task is presented to an organizer.
+ * @hide
+ */
+parcelable TaskAppearedInfo;
+
diff --git a/core/java/android/window/TaskAppearedInfo.java b/core/java/android/window/TaskAppearedInfo.java
new file mode 100644
index 0000000..2ff331e
--- /dev/null
+++ b/core/java/android/window/TaskAppearedInfo.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 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 android.window;
+
+import android.annotation.NonNull;
+import android.annotation.TestApi;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.SurfaceControl;
+
+/**
+ * Data object for the task info provided when a task is presented to an organizer.
+ * @hide
+ */
+@TestApi
+public final class TaskAppearedInfo implements Parcelable {
+
+ @NonNull
+ private final RunningTaskInfo mTaskInfo;
+
+ @NonNull
+ private final SurfaceControl mLeash;
+
+ @NonNull
+ public static final Creator<TaskAppearedInfo> CREATOR = new Creator<TaskAppearedInfo>() {
+ @Override
+ public TaskAppearedInfo createFromParcel(Parcel source) {
+ final RunningTaskInfo taskInfo = source.readTypedObject(RunningTaskInfo.CREATOR);
+ final SurfaceControl leash = source.readTypedObject(SurfaceControl.CREATOR);
+ return new TaskAppearedInfo(taskInfo, leash);
+ }
+
+ @Override
+ public TaskAppearedInfo[] newArray(int size) {
+ return new TaskAppearedInfo[size];
+ }
+
+ };
+
+ public TaskAppearedInfo(@NonNull RunningTaskInfo taskInfo, @NonNull SurfaceControl leash) {
+ mTaskInfo = taskInfo;
+ mLeash = leash;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeTypedObject(mTaskInfo, flags);
+ dest.writeTypedObject(mLeash, flags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * @return the task info.
+ */
+ @NonNull
+ public RunningTaskInfo getTaskInfo() {
+ return mTaskInfo;
+ }
+
+ /**
+ * @return the leash for the task.
+ */
+ @NonNull
+ public SurfaceControl getLeash() {
+ return mLeash;
+ }
+}
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index a7cb642..909bb47 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -17,6 +17,7 @@
package android.window;
import android.annotation.BinderThread;
+import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -51,11 +52,16 @@
/**
* Register a TaskOrganizer to manage tasks as they enter a supported windowing mode.
+ *
+ * @return a list of the tasks that should be managed by the organizer, not including tasks
+ * created via {@link #createRootTask}.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
- public final void registerOrganizer() {
+ @CallSuper
+ @NonNull
+ public List<TaskAppearedInfo> registerOrganizer() {
try {
- mTaskOrganizerController.registerTaskOrganizer(mInterface);
+ return mTaskOrganizerController.registerTaskOrganizer(mInterface).getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -63,7 +69,8 @@
/** Unregisters a previously registered task organizer. */
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
- public final void unregisterOrganizer() {
+ @CallSuper
+ public void unregisterOrganizer() {
try {
mTaskOrganizerController.unregisterTaskOrganizer(mInterface);
} catch (RemoteException e) {
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index ba90154..eba4fd2 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -238,10 +238,10 @@
}
/**
- * Sets whether a container should ignore the orientation request from apps below it. It
- * currently only applies to {@link com.android.server.wm.TaskDisplayArea}. When {@code false},
- * it may rotate based on the orientation request; When {@code true}, it can never specify
- * orientation, but shows the fixed-orientation apps in the letterbox.
+ * Sets whether a container should ignore the orientation request from apps and windows below
+ * it. It currently only applies to {@link com.android.server.wm.DisplayArea}. When
+ * {@code false}, it may rotate based on the orientation request; When {@code true}, it can
+ * never specify orientation, but shows the fixed-orientation apps below it in the letterbox.
* @hide
*/
@NonNull
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index 491ddba..2b4e09d 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -80,6 +80,8 @@
"com.android.server.accessibility.MagnificationController";
public static final ComponentName MAGNIFICATION_COMPONENT_NAME =
new ComponentName("com.android.server.accessibility", "Magnification");
+ public static final ComponentName REDUCE_BRIGHT_COLORS_COMPONENT_NAME =
+ new ComponentName("com.android.server.accessibility", "ReduceBrightColors");
private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
@@ -126,6 +128,11 @@
Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
"1" /* Value to enable */, "0" /* Value to disable */,
R.string.color_correction_feature_name));
+ featuresMap.put(REDUCE_BRIGHT_COLORS_COMPONENT_NAME,
+ new ToggleableFrameworkFeatureInfo(
+ Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED,
+ "1" /* Value to enable */, "0" /* Value to disable */,
+ R.string.reduce_bright_colors_feature_name));
sFrameworkShortcutFeaturesMap = Collections.unmodifiableMap(featuresMap);
}
return sFrameworkShortcutFeaturesMap;
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
index a7c5f6d..9d06bb9 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
@@ -21,6 +21,7 @@
import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.REDUCE_BRIGHT_COLORS_COMPONENT_NAME;
import static com.android.internal.accessibility.util.AccessibilityUtils.getAccessibilityServiceFragmentType;
import static com.android.internal.accessibility.util.ShortcutUtils.isShortcutContained;
@@ -112,7 +113,7 @@
@ShortcutType int shortcutType) {
final List<AccessibilityTarget> targets = new ArrayList<>();
targets.addAll(getAccessibilityFilteredTargets(context, shortcutType));
- targets.addAll(getWhiteListingFeatureTargets(context, shortcutType));
+ targets.addAll(getAllowListingFeatureTargets(context, shortcutType));
return targets;
}
@@ -196,12 +197,12 @@
return targets;
}
- private static List<AccessibilityTarget> getWhiteListingFeatureTargets(Context context,
+ private static List<AccessibilityTarget> getAllowListingFeatureTargets(Context context,
@ShortcutType int shortcutType) {
final List<AccessibilityTarget> targets = new ArrayList<>();
- final InvisibleToggleWhiteListingFeatureTarget magnification =
- new InvisibleToggleWhiteListingFeatureTarget(context,
+ final InvisibleToggleAllowListingFeatureTarget magnification =
+ new InvisibleToggleAllowListingFeatureTarget(context,
shortcutType,
isShortcutContained(context, shortcutType, MAGNIFICATION_CONTROLLER_NAME),
MAGNIFICATION_CONTROLLER_NAME,
@@ -209,8 +210,8 @@
context.getDrawable(R.drawable.ic_accessibility_magnification),
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED);
- final ToggleWhiteListingFeatureTarget daltonizer =
- new ToggleWhiteListingFeatureTarget(context,
+ final ToggleAllowListingFeatureTarget daltonizer =
+ new ToggleAllowListingFeatureTarget(context,
shortcutType,
isShortcutContained(context, shortcutType,
DALTONIZER_COMPONENT_NAME.flattenToString()),
@@ -219,8 +220,8 @@
context.getDrawable(R.drawable.ic_accessibility_color_correction),
Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED);
- final ToggleWhiteListingFeatureTarget colorInversion =
- new ToggleWhiteListingFeatureTarget(context,
+ final ToggleAllowListingFeatureTarget colorInversion =
+ new ToggleAllowListingFeatureTarget(context,
shortcutType,
isShortcutContained(context, shortcutType,
COLOR_INVERSION_COMPONENT_NAME.flattenToString()),
@@ -229,9 +230,21 @@
context.getDrawable(R.drawable.ic_accessibility_color_inversion),
Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
+ // TODO: Update with shortcut icon
+ final ToggleAllowListingFeatureTarget reduceBrightColors =
+ new ToggleAllowListingFeatureTarget(context,
+ shortcutType,
+ isShortcutContained(context, shortcutType,
+ REDUCE_BRIGHT_COLORS_COMPONENT_NAME.flattenToString()),
+ REDUCE_BRIGHT_COLORS_COMPONENT_NAME.flattenToString(),
+ context.getString(R.string.reduce_bright_colors_feature_name),
+ null,
+ Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED);
+
targets.add(magnification);
targets.add(daltonizer);
targets.add(colorInversion);
+ targets.add(reduceBrightColors);
return targets;
}
diff --git a/core/java/com/android/internal/accessibility/dialog/InvisibleToggleWhiteListingFeatureTarget.java b/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAllowListingFeatureTarget.java
similarity index 91%
rename from core/java/com/android/internal/accessibility/dialog/InvisibleToggleWhiteListingFeatureTarget.java
rename to core/java/com/android/internal/accessibility/dialog/InvisibleToggleAllowListingFeatureTarget.java
index acd101b..e78036d 100644
--- a/core/java/com/android/internal/accessibility/dialog/InvisibleToggleWhiteListingFeatureTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAllowListingFeatureTarget.java
@@ -26,9 +26,9 @@
* Extension for {@link AccessibilityTarget} with {@link AccessibilityFragmentType#INVISIBLE_TOGGLE}
* type.
*/
-class InvisibleToggleWhiteListingFeatureTarget extends AccessibilityTarget {
+class InvisibleToggleAllowListingFeatureTarget extends AccessibilityTarget {
- InvisibleToggleWhiteListingFeatureTarget(Context context, @ShortcutType int shortcutType,
+ InvisibleToggleAllowListingFeatureTarget(Context context, @ShortcutType int shortcutType,
boolean isShortcutSwitched, String id, CharSequence label, Drawable icon, String key) {
super(context, shortcutType, AccessibilityFragmentType.INVISIBLE_TOGGLE,
isShortcutSwitched, id, label, icon, key);
diff --git a/core/java/com/android/internal/accessibility/dialog/ToggleWhiteListingFeatureTarget.java b/core/java/com/android/internal/accessibility/dialog/ToggleAllowListingFeatureTarget.java
similarity index 94%
rename from core/java/com/android/internal/accessibility/dialog/ToggleWhiteListingFeatureTarget.java
rename to core/java/com/android/internal/accessibility/dialog/ToggleAllowListingFeatureTarget.java
index 5ab9eb8..38aac70 100644
--- a/core/java/com/android/internal/accessibility/dialog/ToggleWhiteListingFeatureTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/ToggleAllowListingFeatureTarget.java
@@ -32,9 +32,9 @@
* Extension for {@link AccessibilityTarget} with {@link AccessibilityFragmentType#TOGGLE}
* type.
*/
-class ToggleWhiteListingFeatureTarget extends AccessibilityTarget {
+class ToggleAllowListingFeatureTarget extends AccessibilityTarget {
- ToggleWhiteListingFeatureTarget(Context context, @ShortcutType int shortcutType,
+ ToggleAllowListingFeatureTarget(Context context, @ShortcutType int shortcutType,
boolean isShortcutSwitched, String id, CharSequence label, Drawable icon, String key) {
super(context, shortcutType, AccessibilityFragmentType.TOGGLE,
isShortcutSwitched, id, label, icon, key);
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 6edf7a3..83cbe38 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1291,7 +1291,7 @@
private void safelyStartActivityInternal(TargetInfo cti) {
// If the target is suspended, the activity will not be successfully launched.
// Do not unregister from package manager updates in this case
- if (!cti.isSuspended()) {
+ if (!cti.isSuspended() && mRegistered) {
if (mPersonalPackageMonitor != null) {
mPersonalPackageMonitor.unregister();
}
diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java
index 3682b7b..af666d8 100644
--- a/core/java/com/android/internal/content/PackageMonitor.java
+++ b/core/java/com/android/internal/content/PackageMonitor.java
@@ -37,6 +37,7 @@
* updating, and disappearing and reappearing on the SD card.
*/
public abstract class PackageMonitor extends android.content.BroadcastReceiver {
+ static final String TAG = "PackageMonitor";
static final IntentFilter sPackageFilt = new IntentFilter();
static final IntentFilter sNonDataFilt = new IntentFilter();
static final IntentFilter sExternalFilt = new IntentFilter();
@@ -48,6 +49,9 @@
sPackageFilt.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
sPackageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED);
sPackageFilt.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
+ sPackageFilt.addAction(Intent.ACTION_PACKAGE_STARTABLE);
+ sPackageFilt.addAction(Intent.ACTION_PACKAGE_UNSTARTABLE);
+ sPackageFilt.addAction(Intent.ACTION_PACKAGE_FULLY_LOADED);
sPackageFilt.addDataScheme("package");
sNonDataFilt.addAction(Intent.ACTION_UID_REMOVED);
sNonDataFilt.addAction(Intent.ACTION_USER_STOPPED);
@@ -305,6 +309,13 @@
public void onPackageDataCleared(String packageName, int uid) {
}
+ /**
+ * Callback to indicate the package's state has changed.
+ * @param packageName Name of an installed package
+ * @param uid The UID the package runs under.
+ */
+ public void onPackageStateChanged(String packageName, int uid) {}
+
public int getChangingUserId() {
return mChangeUserId;
}
@@ -452,12 +463,21 @@
String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
mSomePackagesChanged = true;
onPackagesUnsuspended(pkgList);
+ } else if (Intent.ACTION_PACKAGE_STARTABLE.equals(action)
+ || Intent.ACTION_PACKAGE_UNSTARTABLE.equals(action)
+ || Intent.ACTION_PACKAGE_FULLY_LOADED.equals(action)) {
+ String pkg = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+ int uid = intent.getIntExtra(Intent.EXTRA_UID, 0);
+ mSomePackagesChanged = false;
+ if (pkg != null) {
+ onPackageStateChanged(pkg, uid);
+ }
}
if (mSomePackagesChanged) {
onSomePackagesChanged();
}
-
+
onFinishPackageChanges();
mChangeUserId = UserHandle.USER_NULL;
}
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index dd4409c..3624f0d 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -16,7 +16,18 @@
package com.android.internal.jank;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_PIP;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_ICON;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_RECENTS;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_QUICK_SWITCH;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__NOTIFICATION_SHADE_SWIPE;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_EXPAND_COLLAPSE_LOCK;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_QS_EXPAND_COLLAPSE;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_QS_SCROLL_SWIPE;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_ROW_EXPAND;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_ROW_SWIPE;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_SCROLL_FLING;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -63,18 +74,19 @@
// Use NO_STATSD_LOGGING in case the measurement for a given CUJ should not be logged to statsd.
@VisibleForTesting
public static final int[] CUJ_TO_STATSD_INTERACTION_TYPE = {
+ // This should be mapping to CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE.
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__NOTIFICATION_SHADE_SWIPE,
- NO_STATSD_LOGGING,
- NO_STATSD_LOGGING,
- NO_STATSD_LOGGING,
- NO_STATSD_LOGGING,
- NO_STATSD_LOGGING,
- NO_STATSD_LOGGING,
- NO_STATSD_LOGGING,
- NO_STATSD_LOGGING,
- NO_STATSD_LOGGING,
- NO_STATSD_LOGGING,
- NO_STATSD_LOGGING,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_EXPAND_COLLAPSE_LOCK,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_SCROLL_FLING,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_ROW_EXPAND,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_ROW_SWIPE,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_QS_EXPAND_COLLAPSE,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_QS_SCROLL_SWIPE,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_RECENTS,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_ICON,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_PIP,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_QUICK_SWITCH,
};
private static volatile InteractionJankMonitor sInstance;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 17323ba..4c5f988 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -65,7 +65,6 @@
import android.telephony.CellSignalStrength;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.ModemActivityInfo;
-import android.telephony.ModemActivityInfo.TransmitPower;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
@@ -7791,7 +7790,7 @@
public ControllerActivityCounterImpl getOrCreateModemControllerActivityLocked() {
if (mModemControllerActivity == null) {
mModemControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
- ModemActivityInfo.TX_POWER_LEVELS);
+ ModemActivityInfo.getNumTxPowerLevels());
}
return mModemControllerActivity;
}
@@ -9257,7 +9256,7 @@
if (in.readInt() != 0) {
mModemControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
- ModemActivityInfo.TX_POWER_LEVELS, in);
+ ModemActivityInfo.getNumTxPowerLevels(), in);
} else {
mModemControllerActivity = null;
}
@@ -10520,7 +10519,7 @@
mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
NUM_BT_TX_LEVELS);
mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
- ModemActivityInfo.TX_POWER_LEVELS);
+ ModemActivityInfo.getNumTxPowerLevels());
mMobileRadioActiveTimer = new StopwatchTimer(mClocks, null, -400, null, mOnBatteryTimeBase);
mMobileRadioActivePerAppTimer = new StopwatchTimer(mClocks, null, -401, null,
mOnBatteryTimeBase);
@@ -11710,26 +11709,7 @@
}
}
- private ModemActivityInfo mLastModemActivityInfo =
- new ModemActivityInfo(0, 0, 0, new int[0], 0);
-
- private ModemActivityInfo getDeltaModemActivityInfo(ModemActivityInfo activityInfo) {
- if (activityInfo == null) {
- return null;
- }
- int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
- for (int i = 0; i < ModemActivityInfo.TX_POWER_LEVELS; i++) {
- txTimeMs[i] = activityInfo.getTransmitPowerInfo().get(i).getTimeInMillis()
- - mLastModemActivityInfo.getTransmitPowerInfo().get(i).getTimeInMillis();
- }
- ModemActivityInfo deltaInfo = new ModemActivityInfo(activityInfo.getTimestamp(),
- activityInfo.getSleepTimeMillis() - mLastModemActivityInfo.getSleepTimeMillis(),
- activityInfo.getIdleTimeMillis() - mLastModemActivityInfo.getIdleTimeMillis(),
- txTimeMs,
- activityInfo.getReceiveTimeMillis() - mLastModemActivityInfo.getReceiveTimeMillis());
- mLastModemActivityInfo = activityInfo;
- return deltaInfo;
- }
+ private ModemActivityInfo mLastModemActivityInfo = null;
/**
* Distribute Cell radio energy info and network traffic to apps.
@@ -11746,7 +11726,9 @@
if (DEBUG_ENERGY) {
Slog.d(TAG, "Updating mobile radio stats with " + activityInfo);
}
- ModemActivityInfo deltaInfo = getDeltaModemActivityInfo(activityInfo);
+ ModemActivityInfo deltaInfo = mLastModemActivityInfo == null ? activityInfo
+ : mLastModemActivityInfo.getDelta(activityInfo);
+ mLastModemActivityInfo = activityInfo;
// Add modem tx power to history.
addModemTxPowerToHistory(deltaInfo, elapsedRealtimeMs, uptimeMs);
@@ -11778,10 +11760,9 @@
mModemActivity.getSleepTimeCounter().addCountLocked(
deltaInfo.getSleepTimeMillis());
mModemActivity.getRxTimeCounter().addCountLocked(deltaInfo.getReceiveTimeMillis());
- for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
+ for (int lvl = 0; lvl < ModemActivityInfo.getNumTxPowerLevels(); lvl++) {
mModemActivity.getTxTimeCounters()[lvl]
- .addCountLocked(deltaInfo.getTransmitPowerInfo()
- .get(lvl).getTimeInMillis());
+ .addCountLocked(deltaInfo.getTransmitDurationMillisAtPowerLevel(lvl));
}
// POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
@@ -11795,11 +11776,11 @@
mPowerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_IDLE)
+ deltaInfo.getReceiveTimeMillis() *
mPowerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX);
- List<TransmitPower> txPowerInfo = deltaInfo.getTransmitPowerInfo();
- for (int i = 0; i < Math.min(txPowerInfo.size(),
+ for (int i = 0; i < Math.min(ModemActivityInfo.getNumTxPowerLevels(),
CellSignalStrength.getNumSignalStrengthLevels()); i++) {
- energyUsed += txPowerInfo.get(i).getTimeInMillis() * mPowerProfile
- .getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX, i);
+ energyUsed += deltaInfo.getTransmitDurationMillisAtPowerLevel(i)
+ * mPowerProfile.getAveragePower(
+ PowerProfile.POWER_MODEM_CONTROLLER_TX, i);
}
// We store the power drain as mAms.
@@ -11894,10 +11875,10 @@
}
if (totalTxPackets > 0 && entry.txPackets > 0) {
- for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
- long txMs =
- entry.txPackets * deltaInfo.getTransmitPowerInfo()
- .get(lvl).getTimeInMillis();
+ for (int lvl = 0; lvl < ModemActivityInfo.getNumTxPowerLevels();
+ lvl++) {
+ long txMs = entry.txPackets
+ * deltaInfo.getTransmitDurationMillisAtPowerLevel(lvl);
txMs /= totalTxPackets;
activityCounter.getTxTimeCounters()[lvl].addCountLocked(txMs);
}
@@ -11929,18 +11910,14 @@
if (activityInfo == null) {
return;
}
- List<TransmitPower> txPowerInfo = activityInfo.getTransmitPowerInfo();
- if (txPowerInfo == null || txPowerInfo.size() != ModemActivityInfo.TX_POWER_LEVELS) {
- return;
- }
int levelMaxTimeSpent = 0;
- for (int i = 1; i < txPowerInfo.size(); i++) {
- if (txPowerInfo.get(i).getTimeInMillis() > txPowerInfo.get(levelMaxTimeSpent)
- .getTimeInMillis()) {
+ for (int i = 1; i < ModemActivityInfo.getNumTxPowerLevels(); i++) {
+ if (activityInfo.getTransmitDurationMillisAtPowerLevel(i)
+ > activityInfo.getTransmitDurationMillisAtPowerLevel(levelMaxTimeSpent)) {
levelMaxTimeSpent = i;
}
}
- if (levelMaxTimeSpent == ModemActivityInfo.TX_POWER_LEVELS - 1) {
+ if (levelMaxTimeSpent == ModemActivityInfo.getNumTxPowerLevels() - 1) {
mHistoryCur.states2 |= HistoryItem.STATE2_CELLULAR_HIGH_TX_POWER_FLAG;
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
}
@@ -13462,7 +13439,7 @@
timeInRxSignalStrengthLevelMs[i] =
getPhoneSignalStrengthTime(i, rawRealTimeUs, which) / 1000;
}
- long[] txTimeMs = new long[Math.min(ModemActivityInfo.TX_POWER_LEVELS,
+ long[] txTimeMs = new long[Math.min(ModemActivityInfo.getNumTxPowerLevels(),
counter.getTxTimeCounters().length)];
long totalTxTimeMs = 0;
for (int i = 0; i < txTimeMs.length; i++) {
@@ -15601,7 +15578,7 @@
mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
NUM_BT_TX_LEVELS, in);
mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
- ModemActivityInfo.TX_POWER_LEVELS, in);
+ ModemActivityInfo.getNumTxPowerLevels(), in);
mHasWifiReporting = in.readInt() != 0;
mHasBluetoothReporting = in.readInt() != 0;
mHasModemReporting = in.readInt() != 0;
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index caae518..77c7ce8 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -102,6 +102,13 @@
void onCameraLaunchGestureDetected(int source);
/**
+ * Notifies the status bar that the Emergency Action launch gesture has been detected.
+ *
+ * TODO(b/169175022) Update method name and docs when feature name is locked.
+ */
+ void onEmergencyActionLaunchGestureDetected();
+
+ /**
* Shows the picture-in-picture menu if an activity is in picture-in-picture mode.
*/
void showPictureInPictureMenu();
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index 555f62c..c7ac189 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -15,14 +15,22 @@
package com.android.internal.util;
import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
import android.os.Build;
import android.os.SystemClock;
import android.os.Trace;
+import android.os.UserHandle;
+import android.provider.Settings;
import android.util.EventLog;
+import android.util.KeyValueListParser;
import android.util.Log;
import android.util.SparseLongArray;
import com.android.internal.logging.EventLogTags;
+import com.android.internal.os.BackgroundThread;
+
+import java.util.concurrent.ThreadLocalRandom;
/**
* Class to track various latencies in SystemUI. It then writes the latency to statsd and also
@@ -34,6 +42,12 @@
*/
public class LatencyTracker {
private static final String TAG = "LatencyTracker";
+ private static final String SETTINGS_ENABLED_KEY = "enabled";
+ private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval";
+ /** Default to being enabled on debug builds. */
+ private static final boolean DEFAULT_ENABLED = Build.IS_DEBUGGABLE;
+ /** Default to collecting data for 1/5 of all actions (randomly sampled). */
+ private static final int DEFAULT_SAMPLING_INTERVAL = 5;
/**
* Time it takes until the first frame of the notification panel to be displayed while expanding
@@ -76,7 +90,7 @@
*/
public static final int ACTION_FACE_WAKE_AND_UNLOCK = 7;
- private static final String[] NAMES = new String[] {
+ private static final String[] NAMES = new String[]{
"expand panel",
"toggle recents",
"fingerprint wake-and-unlock",
@@ -84,9 +98,9 @@
"check credential unlocked",
"turn on screen",
"rotate the screen",
- "face wake-and-unlock" };
+ "face wake-and-unlock"};
- private static final int[] STATSD_ACTION = new int[] {
+ private static final int[] STATSD_ACTION = new int[]{
FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_EXPAND_PANEL,
FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_TOGGLE_RECENTS,
FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FINGERPRINT_WAKE_AND_UNLOCK,
@@ -100,20 +114,59 @@
private static LatencyTracker sLatencyTracker;
private final SparseLongArray mStartRtc = new SparseLongArray();
+ private final Context mContext;
+ private volatile int mSamplingInterval;
+ private volatile boolean mEnabled;
public static LatencyTracker getInstance(Context context) {
if (sLatencyTracker == null) {
- sLatencyTracker = new LatencyTracker();
+ synchronized (LatencyTracker.class) {
+ if (sLatencyTracker == null) {
+ sLatencyTracker = new LatencyTracker(context);
+ }
+ }
}
return sLatencyTracker;
}
+ public LatencyTracker(Context context) {
+ mContext = context;
+ mEnabled = DEFAULT_ENABLED;
+ mSamplingInterval = DEFAULT_SAMPLING_INTERVAL;
+
+ // Post initialization to the background in case we're running on the main thread.
+ BackgroundThread.getHandler().post(this::registerSettingsObserver);
+ BackgroundThread.getHandler().post(this::readSettings);
+ }
+
+ private void registerSettingsObserver() {
+ Uri settingsUri = Settings.Global.getUriFor(Settings.Global.LATENCY_TRACKER);
+ mContext.getContentResolver().registerContentObserver(
+ settingsUri, false, new SettingsObserver(this), UserHandle.myUserId());
+ }
+
+ private void readSettings() {
+ KeyValueListParser parser = new KeyValueListParser(',');
+ String settingsValue = Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.LATENCY_TRACKER);
+
+ try {
+ parser.setString(settingsValue);
+ mSamplingInterval = parser.getInt(SETTINGS_SAMPLING_INTERVAL_KEY,
+ DEFAULT_SAMPLING_INTERVAL);
+ mEnabled = parser.getBoolean(SETTINGS_ENABLED_KEY, DEFAULT_ENABLED);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Incorrect settings format", e);
+ mEnabled = false;
+ }
+ }
+
public static boolean isEnabled(Context ctx) {
return getInstance(ctx).isEnabled();
}
public boolean isEnabled() {
- return Build.IS_DEBUGGABLE;
+ return mEnabled;
}
/**
@@ -145,19 +198,48 @@
}
mStartRtc.delete(action);
Trace.asyncTraceEnd(Trace.TRACE_TAG_APP, NAMES[action], 0);
- logAction(action, (int)(endRtc - startRtc));
+ logAction(action, (int) (endRtc - startRtc));
}
/**
* Logs an action that has started and ended. This needs to be called from the main thread.
*
- * @param action The action to end. One of the ACTION_* values.
- * @param duration The duration of the action in ms.
+ * @param action The action to end. One of the ACTION_* values.
+ * @param duration The duration of the action in ms.
*/
- public static void logAction(int action, int duration) {
+ public void logAction(int action, int duration) {
+ boolean shouldSample = ThreadLocalRandom.current().nextInt() % mSamplingInterval == 0;
+ logActionDeprecated(action, duration, shouldSample);
+ }
+
+ /**
+ * Logs an action that has started and ended. This needs to be called from the main thread.
+ *
+ * @param action The action to end. One of the ACTION_* values.
+ * @param duration The duration of the action in ms.
+ * @param writeToStatsLog Whether to write the measured latency to FrameworkStatsLog.
+ */
+ public static void logActionDeprecated(int action, int duration, boolean writeToStatsLog) {
Log.i(TAG, "action=" + action + " latency=" + duration);
EventLog.writeEvent(EventLogTags.SYSUI_LATENCY, action, duration);
- FrameworkStatsLog.write(
- FrameworkStatsLog.UI_ACTION_LATENCY_REPORTED, STATSD_ACTION[action], duration);
+
+ if (writeToStatsLog) {
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.UI_ACTION_LATENCY_REPORTED, STATSD_ACTION[action], duration);
+ }
+ }
+
+ private static class SettingsObserver extends ContentObserver {
+ private final LatencyTracker mThisTracker;
+
+ SettingsObserver(LatencyTracker thisTracker) {
+ super(BackgroundThread.getHandler());
+ mThisTracker = thisTracker;
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri, int userId) {
+ mThisTracker.readSettings();
+ }
}
}
diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java
index a23fc4b..0bafb2f 100644
--- a/core/java/com/android/internal/util/ScreenshotHelper.java
+++ b/core/java/com/android/internal/util/ScreenshotHelper.java
@@ -279,6 +279,7 @@
final Runnable mScreenshotTimeout = () -> {
synchronized (mScreenshotLock) {
if (mScreenshotConnection != null) {
+ Log.e(TAG, "Timed out before getting screenshot capture response");
mContext.unbindService(mScreenshotConnection);
mScreenshotConnection = null;
mScreenshotService = null;
@@ -353,6 +354,7 @@
mScreenshotService = null;
// only log an error if we're still within the timeout period
if (handler.hasCallbacks(mScreenshotTimeout)) {
+ Log.e(TAG, "Screenshot service disconnected");
handler.removeCallbacks(mScreenshotTimeout);
notifyScreenshotError();
}
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 5c4c509..1ca45fe 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -338,7 +338,7 @@
return (jint)AUDIO_JAVA_BAD_VALUE;
}
const char *address = env->GetStringUTFChars((jstring)addrJobj, NULL);
- AudioDeviceTypeAddr dev = AudioDeviceTypeAddr(typesPtr[i], address);
+ AudioDeviceTypeAddr dev = AudioDeviceTypeAddr((audio_devices_t)typesPtr[i], address);
audioDeviceTypeAddrVector.push_back(dev);
env->ReleaseStringUTFChars((jstring)addrJobj, address);
}
@@ -820,7 +820,8 @@
bool useInMask)
{
nAudioGainConfig->index = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mIndex);
- nAudioGainConfig->mode = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mMode);
+ nAudioGainConfig->mode =
+ (audio_gain_mode_t)env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mMode);
ALOGV("convertAudioGainConfigToNative got gain index %d", nAudioGainConfig->index);
jint jMask = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mChannelMask);
audio_channel_mask_t nMask;
@@ -940,8 +941,8 @@
jobject jAudioDevicePort = env->GetObjectField(jAudioPortConfig,
gAudioPortConfigFields.mPort);
- nAudioPortConfig->ext.device.type = env->GetIntField(jAudioDevicePort,
- gAudioPortFields.mType);
+ nAudioPortConfig->ext.device.type =
+ (audio_devices_t)env->GetIntField(jAudioDevicePort, gAudioPortFields.mType);
jstring jDeviceAddress = (jstring)env->GetObjectField(jAudioDevicePort,
gAudioPortFields.mAddress);
const char *nDeviceAddress = env->GetStringUTFChars(jDeviceAddress, NULL);
@@ -2334,7 +2335,7 @@
static jint
android_media_AudioSystem_setAllowedCapturePolicy(JNIEnv *env, jobject thiz, jint uid, jint flags) {
- return AudioSystem::setAllowedCapturePolicy(uid, flags);
+ return AudioSystem::setAllowedCapturePolicy(uid, static_cast<audio_flags_mask_t>(flags));
}
static jint
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 3acd15a..e7e9c31 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -60,7 +60,7 @@
sp<MessageQueue> mMessageQueue;
void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
- int64_t sharedTimelineFrameCount) override;
+ VsyncEventData vsyncEventData) override;
void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
int32_t configId, nsecs_t vsyncPeriod) override;
@@ -91,14 +91,15 @@
}
void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId,
- uint32_t count, int64_t frameTimelineVsyncId) {
+ uint32_t count, VsyncEventData vsyncEventData) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
if (receiverObj.get()) {
ALOGV("receiver %p ~ Invoking vsync handler.", this);
env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync,
- timestamp, displayId.value, count, frameTimelineVsyncId);
+ timestamp, displayId.value, count, vsyncEventData.id,
+ vsyncEventData.deadlineTimestamp);
ALOGV("receiver %p ~ Returned from vsync handler.", this);
}
@@ -198,7 +199,8 @@
gDisplayEventReceiverClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
gDisplayEventReceiverClassInfo.dispatchVsync =
- GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JJIJ)V");
+ GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchVsync",
+ "(JJIJJ)V");
gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env,
gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JJZ)V");
gDisplayEventReceiverClassInfo.dispatchConfigChanged = GetMethodIDOrDie(env,
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index 9ed71ac0..1ea918a 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -343,7 +343,7 @@
jboolean(focusEvent->getHasFocus()),
jboolean(focusEvent->getInTouchMode()));
finishInputEvent(seq, true /* handled */);
- return OK;
+ continue;
}
default:
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 1419855..a61903d 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -1360,15 +1360,6 @@
transaction->detachChildren(ctrl);
}
-static void nativeSetOverrideScalingMode(JNIEnv* env, jclass clazz, jlong transactionObj,
- jlong nativeObject,
- jint scalingMode) {
- auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
-
- auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
- transaction->setOverrideScalingMode(ctrl, scalingMode);
-}
-
static jobject nativeGetHdrCapabilities(JNIEnv* env, jclass clazz, jobject tokenObject) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObject));
if (token == NULL) return NULL;
@@ -1694,8 +1685,6 @@
(void*)nativeReparent },
{"nativeSeverChildren", "(JJ)V",
(void*)nativeSeverChildren } ,
- {"nativeSetOverrideScalingMode", "(JJI)V",
- (void*)nativeSetOverrideScalingMode },
{"nativeCaptureDisplay",
"(Landroid/view/SurfaceControl$DisplayCaptureArgs;Landroid/view/SurfaceControl$ScreenCaptureListener;)I",
(void*)nativeCaptureDisplay },
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 7fac615..99fe1af 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2751,4 +2751,14 @@
// OS: R QPR2
BLUETOOTH_PAIRING_RECEIVER = 1851;
+
+ // OPEN: Settings > Display > Screen timeout
+ // CATEGORY: SETTINGS
+ // OS: S
+ SCREEN_TIMEOUT = 1852;
+
+ // OPEN: Settings > Accessibility > Reduce Bright Colors
+ // CATEGORY: SETTINGS
+ // OS: S
+ REDUCE_BRIGHT_COLORS_SETTINGS = 1853;
}
diff --git a/core/proto/android/server/vibratorservice.proto b/core/proto/android/server/vibratorservice.proto
index 281a25e..9e42e9e 100644
--- a/core/proto/android/server/vibratorservice.proto
+++ b/core/proto/android/server/vibratorservice.proto
@@ -21,6 +21,12 @@
import "frameworks/base/core/proto/android/privacy.proto";
+message OneShotProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+ repeated int32 duration = 1;
+ repeated int32 amplitude = 2;
+}
+
message WaveformProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
repeated int32 timings = 1;
@@ -35,20 +41,41 @@
optional int32 fallback = 3;
}
+message ComposedProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+ repeated int32 effect_ids = 1;
+ repeated float effect_scales = 2;
+ repeated int32 delays = 3;
+}
+
// A com.android.os.VibrationEffect object.
message VibrationEffectProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+ optional OneShotProto oneshot = 3;
optional WaveformProto waveform = 1;
optional PrebakedProto prebaked = 2;
+ optional ComposedProto composed = 4;
}
+message VibrationAttributesProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+ optional int32 usage = 1;
+ optional int32 audio_usage = 2;
+ optional int32 flags = 3;
+}
+
+// Next id: 7
message VibrationProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional int64 start_time = 1;
+ optional int64 end_time = 4;
optional VibrationEffectProto effect = 2;
- optional VibrationEffectProto origin_effect = 3;
+ optional VibrationEffectProto original_effect = 3;
+ optional VibrationAttributesProto attributes = 5;
+ optional int32 status = 6;
}
+// Next id: 17
message VibratorServiceDumpProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional VibrationProto current_vibration = 1;
@@ -57,10 +84,14 @@
optional bool vibrator_under_external_control = 4;
optional bool low_power_mode = 5;
optional int32 haptic_feedback_intensity = 6;
+ optional int32 haptic_feedback_default_intensity = 14;
optional int32 notification_intensity = 7;
+ optional int32 notification_default_intensity = 15;
optional int32 ring_intensity = 8;
+ optional int32 ring_default_intensity = 16;
repeated VibrationProto previous_ring_vibrations = 9;
repeated VibrationProto previous_notification_vibrations = 10;
repeated VibrationProto previous_alarm_vibrations = 11;
repeated VibrationProto previous_vibrations = 12;
+ repeated VibrationProto previous_external_vibrations = 13;
}
\ No newline at end of file
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e2f4f2f..f2af514 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4518,6 +4518,12 @@
<permission android:name="android.permission.MANAGE_NOTIFICATIONS"
android:protectionLevel="signature" />
+ <!-- @SystemApi @TestApi Allows adding/removing enabled notification listener components.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_NOTIFICATION_LISTENERS"
+ android:protectionLevel="signature" />
+ <uses-permission android:name="android.permission.MANAGE_NOTIFICATION_LISTENERS" />
+
<!-- Allows notifications to be colorized
<p>Not for use by third-party applications. @hide -->
<permission android:name="android.permission.USE_COLORIZED_NOTIFICATIONS"
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 7057b844..012acf5 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1206,7 +1206,7 @@
<string name="android_upgrading_apk" msgid="1339564803894466737">"<xliff:g id="NUMBER_1">%2$d</xliff:g> ичинен <xliff:g id="NUMBER_0">%1$d</xliff:g> колдонмо ыңгайлаштырылууда."</string>
<string name="android_preparing_apk" msgid="589736917792300956">"<xliff:g id="APPNAME">%1$s</xliff:g> даярдалууда."</string>
<string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Колдонмолорду иштетип баштоо"</string>
- <string name="android_upgrading_complete" msgid="409800058018374746">"Жүктөө аякталууда."</string>
+ <string name="android_upgrading_complete" msgid="409800058018374746">"Жүктөлүүдө"</string>
<string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> иштеп жатат"</string>
<string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Оюнга кайтуу үчүн таптаңыз"</string>
<string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Оюн тандоо"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 1418248..2183d010 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -957,18 +957,18 @@
<string name="autofill_parish" msgid="6847960518334530198">"Мөргөлч"</string>
<string name="autofill_area" msgid="8289022370678448983">"Хэсэг"</string>
<string name="autofill_emirate" msgid="2544082046790551168">"Эмират"</string>
- <string name="permlab_readHistoryBookmarks" msgid="9102293913842539697">"өөрийн Вэб хавчуурга болон түүхийг унших"</string>
+ <string name="permlab_readHistoryBookmarks" msgid="9102293913842539697">"өөрийн Веб хавчуурга болон түүхийг унших"</string>
<string name="permdesc_readHistoryBookmarks" msgid="2323799501008967852">"Апп нь Хөтчийн зочилж байсан бүх URL-н түүх болон Хөтчийн бүх хавчуургыг унших боломжтой. Анхаар: Энэ зөвшөөрөл нь гуравдагч талын хөтөч эсвэл вебээр хөтөчлөх чадавхтай аппликейшнүүдэд ашиглагдахгүй байх боломжтой."</string>
- <string name="permlab_writeHistoryBookmarks" msgid="6090259925187986937">"вэб хавчуурга болон түүхийг бичих"</string>
+ <string name="permlab_writeHistoryBookmarks" msgid="6090259925187986937">"веб хавчуурга болон түүхийг бичих"</string>
<string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="573341025292489065">"Апп нь таны таблет дээр хадгалагдсан Хөтчийн түүх эсвэл хавчуургыг өөрчлөх боломжтой. Энэ нь апп-д Хөтчийн датаг арилгах эсвэл өөрчлөх боломжийг олгоно. Анхаар: Энэ зөвшөөрөл нь гуравдагч талын хөтөч эсвэл вебээр хөтөчлөх чадвартай аппликейшнд ажиллахгүй байх боломжтой."</string>
- <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="88642768580408561">"Аппад таны Android TV төхөөрөмжид хадгалсан Хөтчийн түүх эсвэл хавчуургыг өөрчлөхийг зөвшөөрнө. Энэ нь аппад Хөтчийн өгөгдлийг устгах эсвэл өөрчлөхийг зөвшөөрч болзошгүй. Санамж: энэ зөвшөөрөл нь гуравдагч талын хөтөч эсвэл вэб хөтчийн чадамжтай бусад аппад хэрэгжихгүй байж болзошгүй."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="88642768580408561">"Аппад таны Android TV төхөөрөмжид хадгалсан Хөтчийн түүх эсвэл хавчуургыг өөрчлөхийг зөвшөөрнө. Энэ нь аппад Хөтчийн өгөгдлийг устгах эсвэл өөрчлөхийг зөвшөөрч болзошгүй. Санамж: энэ зөвшөөрөл нь гуравдагч талын хөтөч эсвэл веб хөтчийн чадамжтай бусад аппад хэрэгжихгүй байж болзошгүй."</string>
<string name="permdesc_writeHistoryBookmarks" product="default" msgid="2245203087160913652">"Апп нь таны утсан дээр хадгалагдсан Хөтчийн түүх эсвэл хавчуургыг өөрчлөх боломжтой. Энэ нь апп-д Хөтчийн датаг арилгах эсвэл өөрчлөх боломжийг олгоно. Анхаар: Энэ зөвшөөрөл нь гуравдагч талын хөтөч эсвэл вебээр хөтөчлөх чадвартай аппликейшнд ажиллахгүй байх боломжтой."</string>
<string name="permlab_setAlarm" msgid="1158001610254173567">"сэрүүлэг тохируулах"</string>
<string name="permdesc_setAlarm" msgid="2185033720060109640">"Апп нь суулгагдсан сэрүүлэгний апп дээр сэрүүлэг тохируулах боломжтой. Зарим сэрүүлэгний апп нь энэ функцийг дэмжихгүй байж болзошгүй."</string>
<string name="permlab_addVoicemail" msgid="4770245808840814471">"дуут шуудан нэмэх"</string>
<string name="permdesc_addVoicemail" msgid="5470312139820074324">"Таны дуут шуудангийн ирсэн мэйлд зурвас нэмэхийг апп-д зөвшөөрөх."</string>
<string name="permlab_writeGeolocationPermissions" msgid="8605631647492879449">"Хөтчийн геобайршлын зөвшөөрлийг өөрчлөх"</string>
- <string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"Апп нь Хөтчийн гео байршлын зөвшөөрлийг өөрчлөх боломжтой. Хортой апп нь энийг ашиглан дурын вэб хуудасруу байршлын мэдээллийг илгээх боломжтой."</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"Апп нь Хөтчийн гео байршлын зөвшөөрлийг өөрчлөх боломжтой. Хортой апп нь энийг ашиглан дурын веб хуудасруу байршлын мэдээллийг илгээх боломжтой."</string>
<string name="save_password_message" msgid="2146409467245462965">"Та хөтчид энэ нууц үгийг сануулах уу?"</string>
<string name="save_password_notnow" msgid="2878327088951240061">"Одоо биш"</string>
<string name="save_password_remember" msgid="6490888932657708341">"Санах"</string>
@@ -1459,7 +1459,7 @@
<string name="progress_erasing" msgid="6891435992721028004">"Хуваалцсан хадгалах санг устгаж байна…"</string>
<string name="share" msgid="4157615043345227321">"Хуваалцах"</string>
<string name="find" msgid="5015737188624767706">"Олох"</string>
- <string name="websearch" msgid="5624340204512793290">"Вэб хайлт"</string>
+ <string name="websearch" msgid="5624340204512793290">"Веб хайлт"</string>
<string name="find_next" msgid="5341217051549648153">"Дараагийнхыг хайх"</string>
<string name="find_previous" msgid="4405898398141275532">"Өмнөхөөс олох"</string>
<string name="gpsNotifTicker" msgid="3207361857637620780">"<xliff:g id="NAME">%s</xliff:g>-н байршлын хүсэлт"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 2cdf709..092686b 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1389,7 +1389,7 @@
<string name="ext_media_status_unmountable" msgid="7043574843541087748">"बिग्रेको"</string>
<string name="ext_media_status_unsupported" msgid="5460509911660539317">"असमर्थित"</string>
<string name="ext_media_status_ejecting" msgid="7532403368044013797">"निकाल्दै..."</string>
- <string name="ext_media_status_formatting" msgid="774148701503179906">"फरम्याट गर्दै…"</string>
+ <string name="ext_media_status_formatting" msgid="774148701503179906">"फर्म्याट गर्दै…"</string>
<string name="ext_media_status_missing" msgid="6520746443048867314">"सम्मिलित छैन"</string>
<string name="activity_list_empty" msgid="4219430010716034252">"कुनै मिल्ने गतिविधि पाइएन।"</string>
<string name="permlab_route_media_output" msgid="8048124531439513118">"मिडिया निकास दिशानिर्देश गराउनुहोस्"</string>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index fc489b1..645bae7 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4494,6 +4494,9 @@
shown in the warning dialog about the accessibility shortcut. -->
<string name="color_correction_feature_name">Color Correction</string>
+ <!-- Title of Reduce Bright Colors feature, shown in the warning dialog about the accessibility shortcut. [CHAR LIMIT=none] -->
+ <string name="reduce_bright_colors_feature_name">Reduce Bright Colors</string>
+
<!-- Text in toast to alert the user that the accessibility shortcut turned on an accessibility service. [CHAR LIMIT=none] -->
<string name="accessibility_shortcut_enabling_service">Held volume keys. <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g> turned on.</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1249b17..9b52f54 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3249,6 +3249,7 @@
<java-symbol type="string" name="accessibility_shortcut_disabling_service" />
<java-symbol type="string" name="color_inversion_feature_name" />
<java-symbol type="string" name="color_correction_feature_name" />
+ <java-symbol type="string" name="reduce_bright_colors_feature_name" />
<java-symbol type="string" name="config_defaultAccessibilityService" />
<java-symbol type="string" name="accessibility_shortcut_spoken_feedback" />
diff --git a/core/sysprop/Android.bp b/core/sysprop/Android.bp
index 7f20a0b..237ede2 100644
--- a/core/sysprop/Android.bp
+++ b/core/sysprop/Android.bp
@@ -19,3 +19,11 @@
api_packages: ["android.sysprop"],
vendor_available: false,
}
+
+sysprop_library {
+ name: "com.android.sysprop.watchdog",
+ srcs: ["WatchdogProperties.sysprop"],
+ property_owner: "Platform",
+ api_packages: ["android.sysprop"],
+ vendor_available: false,
+}
diff --git a/core/sysprop/WatchdogProperties.sysprop b/core/sysprop/WatchdogProperties.sysprop
new file mode 100644
index 0000000..1bcc773
--- /dev/null
+++ b/core/sysprop/WatchdogProperties.sysprop
@@ -0,0 +1,45 @@
+# Copyright (C) 2020 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.
+
+module: "android.sysprop.WatchdogProperties"
+owner: Platform
+
+# To escape the watchdog timeout loop, fatal reboot the system when
+# watchdog timed out 'fatal_count' times in 'fatal_window_second'
+# seconds, if both values are not 0. Default value of both is 0.
+prop {
+ api_name: "fatal_count"
+ type: Integer
+ prop_name: "framework_watchdog.fatal_count"
+ scope: Internal
+ access: Readonly
+}
+
+prop {
+ api_name: "fatal_window_second"
+ type: Integer
+ prop_name: "framework_watchdog.fatal_window.second"
+ scope: Internal
+ access: Readonly
+}
+
+# The fatal counting can be disabled by setting property
+# 'is_fatal_ignore' to true.
+prop {
+ api_name: "is_fatal_ignore"
+ type: Boolean
+ prop_name: "persist.debug.framework_watchdog.fatal_ignore"
+ scope: Internal
+ access: Readonly
+}
diff --git a/core/sysprop/api/com.android.sysprop.localization-current.txt b/core/sysprop/api/com.android.sysprop.localization-current.txt
index fe4f457..e69de29 100644
--- a/core/sysprop/api/com.android.sysprop.localization-current.txt
+++ b/core/sysprop/api/com.android.sysprop.localization-current.txt
@@ -1,9 +0,0 @@
-props {
- module: "android.sysprop.LocalizationProperties"
- prop {
- api_name: "locale_filter"
- type: String
- scope: Internal
- prop_name: "ro.localization.locale_filter"
- }
-}
diff --git a/core/sysprop/api/com.android.sysprop.watchdog-current.txt b/core/sysprop/api/com.android.sysprop.watchdog-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/core/sysprop/api/com.android.sysprop.watchdog-current.txt
diff --git a/core/sysprop/api/com.android.sysprop.watchdog-latest.txt b/core/sysprop/api/com.android.sysprop.watchdog-latest.txt
new file mode 100644
index 0000000..d901aef
--- /dev/null
+++ b/core/sysprop/api/com.android.sysprop.watchdog-latest.txt
@@ -0,0 +1,20 @@
+props {
+ module: "android.sysprop.WatchdogProperties"
+ prop {
+ api_name: "fatal_count"
+ type: Integer
+ scope: Internal
+ prop_name: "framework_watchdog.fatal_count"
+ }
+ prop {
+ api_name: "fatal_window_second"
+ type: Integer
+ scope: Internal
+ prop_name: "framework_watchdog.fatal_window.second"
+ }
+ prop {
+ api_name: "is_fatal_ignore"
+ scope: Internal
+ prop_name: "persist.debug.framework_watchdog.fatal_ignore"
+ }
+}
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 6f55b88..38dce15 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -164,6 +164,14 @@
<category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
</intent-filter>
</activity>
+ <activity android:name="android.view.ViewInputConnectionTestActivity"
+ android:label="View Input Connection Test"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
<activity android:name="StubTestBrowserActivity"
android:label="Stubbed Test Browser"
android:exported="true">
diff --git a/core/tests/coretests/res/layout/activity_view_ic_test.xml b/core/tests/coretests/res/layout/activity_view_ic_test.xml
new file mode 100644
index 0000000..fa26869
--- /dev/null
+++ b/core/tests/coretests/res/layout/activity_view_ic_test.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/root"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+</LinearLayout>
diff --git a/core/tests/coretests/src/android/app/NotificationHistoryTest.java b/core/tests/coretests/src/android/app/NotificationHistoryTest.java
index 7fa1613..3df0a68 100644
--- a/core/tests/coretests/src/android/app/NotificationHistoryTest.java
+++ b/core/tests/coretests/src/android/app/NotificationHistoryTest.java
@@ -117,8 +117,8 @@
history.addNotificationToWrite(n);
assertThat(history.getNotificationsToWrite().size()).isEqualTo(2);
- assertThat(history.getNotificationsToWrite().get(0)).isSameAs(n2);
- assertThat(history.getNotificationsToWrite().get(1)).isSameAs(n);
+ assertThat(history.getNotificationsToWrite().get(0)).isSameInstanceAs(n2);
+ assertThat(history.getNotificationsToWrite().get(1)).isSameInstanceAs(n);
assertThat(history.getHistoryCount()).isEqualTo(2);
}
@@ -141,11 +141,11 @@
history.addNotificationsToWrite(secondHistory);
assertThat(history.getNotificationsToWrite().size()).isEqualTo(5);
- assertThat(history.getNotificationsToWrite().get(0)).isSameAs(n3);
- assertThat(history.getNotificationsToWrite().get(1)).isSameAs(n);
- assertThat(history.getNotificationsToWrite().get(2)).isSameAs(n4);
- assertThat(history.getNotificationsToWrite().get(3)).isSameAs(n2);
- assertThat(history.getNotificationsToWrite().get(4)).isSameAs(n5);
+ assertThat(history.getNotificationsToWrite().get(0)).isSameInstanceAs(n3);
+ assertThat(history.getNotificationsToWrite().get(1)).isSameInstanceAs(n);
+ assertThat(history.getNotificationsToWrite().get(2)).isSameInstanceAs(n4);
+ assertThat(history.getNotificationsToWrite().get(3)).isSameInstanceAs(n2);
+ assertThat(history.getNotificationsToWrite().get(4)).isSameInstanceAs(n5);
assertThat(history.getHistoryCount()).isEqualTo(5);
assertThat(history.getPooledStringsToWrite()).asList().contains(n2.getChannelName());
diff --git a/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java b/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java
index ba060fa..593e70e 100644
--- a/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java
+++ b/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java
@@ -45,7 +45,8 @@
CompoundFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
assertThat(compoundFormula.getConnector()).isEqualTo(CompoundFormula.AND);
- assertThat(compoundFormula.getFormulas()).containsAllOf(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2);
+ assertThat(compoundFormula.getFormulas())
+ .containsAtLeast(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2);
}
@Test
diff --git a/core/tests/coretests/src/android/content/pm/parsing/result/ParseInputAndResultTest.kt b/core/tests/coretests/src/android/content/pm/parsing/result/ParseInputAndResultTest.kt
index d45fee9..9ad63ad 100644
--- a/core/tests/coretests/src/android/content/pm/parsing/result/ParseInputAndResultTest.kt
+++ b/core/tests/coretests/src/android/content/pm/parsing/result/ParseInputAndResultTest.kt
@@ -113,7 +113,7 @@
assertError(result)
assertThat(result.errorCode).isEqualTo(errorCode)
assertThat(result.errorMessage).isEqualTo(errorMessage)
- assertThat(result.exception).isSameAs(exception)
+ assertThat(result.exception).isSameInstanceAs(exception)
}
@Test
@@ -125,13 +125,13 @@
assertError(result)
assertThat(result.errorCode).isEqualTo(errorCode)
assertThat(result.errorMessage).isEqualTo(errorMessage)
- assertThat(result.exception).isSameAs(exception)
+ assertThat(result.exception).isSameInstanceAs(exception)
val carriedResult = input.error<Int>(result)
assertError(carriedResult)
assertThat(carriedResult.errorCode).isEqualTo(errorCode)
assertThat(carriedResult.errorMessage).isEqualTo(errorMessage)
- assertThat(carriedResult.exception).isSameAs(exception)
+ assertThat(carriedResult.exception).isSameInstanceAs(exception)
}
@Test
@@ -259,7 +259,7 @@
private fun assertSuccess(expected: Any? = null, result: ParseResult<*>) {
assertThat(result.isError).isFalse()
assertThat(result.isSuccess).isTrue()
- assertThat(result.result).isSameAs(expected)
+ assertThat(result.result).isSameInstanceAs(expected)
assertThat(result.errorCode).isEqualTo(PackageManager.INSTALL_SUCCEEDED)
assertThat(result.errorMessage).isNull()
assertThat(result.exception).isNull()
diff --git a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
index 0f6284d..01cf311 100644
--- a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
+++ b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
@@ -362,14 +362,12 @@
private final class TestPresentation extends Presentation {
private final int mColor;
- private final int mWindowType;
private final int mWindowFlags;
public TestPresentation(Context context, Display display,
int color, int windowType, int windowFlags) {
- super(context, display);
+ super(context, display, 0 /* theme */, windowType);
mColor = color;
- mWindowType = windowType;
mWindowFlags = windowFlags;
}
@@ -378,7 +376,6 @@
super.onCreate(savedInstanceState);
setTitle(TAG);
- getWindow().setType(mWindowType);
getWindow().addFlags(mWindowFlags);
// Create a solid color image to use as the content of the presentation.
diff --git a/core/tests/coretests/src/android/text/TextShaperTest.java b/core/tests/coretests/src/android/text/TextShaperTest.java
new file mode 100644
index 0000000..f92ea99
--- /dev/null
+++ b/core/tests/coretests/src/android/text/TextShaperTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 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 android.text;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.graphics.text.PositionedGlyphs;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TextShaperTest {
+
+ @Test
+ public void testFontWithPath() {
+ TextPaint p = new TextPaint();
+ p.setFontFeatureSettings("'wght' 900");
+ List<PositionedGlyphs> glyphs = StyledTextShaper.shapeText("a", 0, 1,
+ TextDirectionHeuristics.LTR, p);
+ assertThat(glyphs.size()).isEqualTo(1);
+ // This test only passes if the font of the Latin font is variable font.
+ assertThat(glyphs.get(0).getFont(0).getFile()).isNotNull();
+
+ }
+}
diff --git a/core/tests/coretests/src/android/view/ViewInputConnectionTest.java b/core/tests/coretests/src/android/view/ViewInputConnectionTest.java
new file mode 100644
index 0000000..d667af3
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewInputConnectionTest.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2020 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 android.view;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertTrue;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.os.Handler;
+import android.text.format.DateUtils;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.EditText;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.compatibility.common.util.PollingCheck;
+import com.android.frameworks.coretests.R;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for internal APIs/behaviors of {@link View} and {@link InputConnection}.
+ */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ViewInputConnectionTest {
+ @Rule
+ public ActivityTestRule<ViewInputConnectionTestActivity> mActivityRule =
+ new ActivityTestRule<>(ViewInputConnectionTestActivity.class);
+
+ private Instrumentation mInstrumentation;
+ private ViewInputConnectionTestActivity mActivity;
+ private InputMethodManager mImm;
+
+ @Before
+ public void before() {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mActivity = mActivityRule.getActivity();
+ PollingCheck.waitFor(5 * DateUtils.SECOND_IN_MILLIS, mActivity::hasWindowFocus);
+ assertTrue(mActivity.hasWindowFocus());
+ mImm = mActivity.getSystemService(InputMethodManager.class);
+ }
+
+ @Test
+ public void testInputConnectionCallbacks() throws Throwable {
+ // Add two EditText inputs to the layout view.
+ final ViewGroup viewGroup = mActivity.findViewById(R.id.root);
+ final TestEditText editText1 = new TestEditText(mActivity, false);
+ final TestEditText editText2 = new TestEditText(mActivity, false);
+ mActivityRule.runOnUiThread(() -> {
+ viewGroup.addView(editText1);
+ viewGroup.addView(editText2);
+ });
+ mInstrumentation.waitForIdleSync();
+
+ // Focus into the first EditText.
+ mActivityRule.runOnUiThread(editText1::requestFocus);
+ mInstrumentation.waitForIdleSync();
+ assertThat(editText1.isFocused()).isTrue();
+ assertThat(editText2.isFocused()).isFalse();
+
+ // Show the IME for the first EditText. Assert that the appropriate opened/closed callbacks
+ // have been invoked (InputConnection opened for the first EditText).
+ mActivityRule.runOnUiThread(() -> mImm.showSoftInput(editText1, 0));
+ mInstrumentation.waitForIdleSync();
+ mActivityRule.runOnUiThread(() -> {
+ assertThat(editText1.mCalledOnCreateInputConnection).isTrue();
+ assertThat(editText1.mCalledOnInputConnectionOpened).isTrue();
+ assertThat(editText1.mCalledOnInputConnectionClosed).isFalse();
+
+ assertThat(editText2.mCalledOnCreateInputConnection).isFalse();
+ assertThat(editText2.mCalledOnInputConnectionOpened).isFalse();
+ assertThat(editText2.mCalledOnInputConnectionClosed).isFalse();
+ });
+
+ // Focus into the second EditText.
+ mActivityRule.runOnUiThread(editText2::requestFocus);
+ mInstrumentation.waitForIdleSync();
+ assertThat(editText1.isFocused()).isFalse();
+ assertThat(editText2.isFocused()).isTrue();
+
+ // Show the IME for the second EditText. Assert that the appropriate opened/closed callbacks
+ // have been invoked (InputConnection closed for the first EditText and opened for the
+ // second EditText).
+ mActivityRule.runOnUiThread(() -> mImm.showSoftInput(editText2, 0));
+ mInstrumentation.waitForIdleSync();
+ mActivityRule.runOnUiThread(() -> {
+ assertThat(editText1.mCalledOnCreateInputConnection).isTrue();
+ assertThat(editText1.mCalledOnInputConnectionOpened).isTrue();
+ assertThat(editText1.mCalledOnInputConnectionClosed).isTrue();
+
+ assertThat(editText2.mCalledOnCreateInputConnection).isTrue();
+ assertThat(editText2.mCalledOnInputConnectionOpened).isTrue();
+ assertThat(editText2.mCalledOnInputConnectionClosed).isFalse();
+ });
+ }
+
+ @Test
+ public void testInputConnectionCallbacks_nullInputConnection() throws Throwable {
+ // Add two EditText inputs to the layout view.
+ final ViewGroup viewGroup = mActivity.findViewById(R.id.root);
+ final TestEditText editText1 = new TestEditText(mActivity, true);
+ final TestEditText editText2 = new TestEditText(mActivity, true);
+ mActivityRule.runOnUiThread(() -> {
+ viewGroup.addView(editText1);
+ viewGroup.addView(editText2);
+ });
+ mInstrumentation.waitForIdleSync();
+
+ // Focus into the first EditText.
+ mActivityRule.runOnUiThread(editText1::requestFocus);
+ mInstrumentation.waitForIdleSync();
+ assertThat(editText1.isFocused()).isTrue();
+ assertThat(editText2.isFocused()).isFalse();
+
+ // Show the IME for the first EditText. Assert that the opened/closed callbacks are not
+ // invoked since there's no input connection.
+ mActivityRule.runOnUiThread(() -> mImm.showSoftInput(editText1, 0));
+ mInstrumentation.waitForIdleSync();
+ mActivityRule.runOnUiThread(() -> {
+ assertThat(editText1.mCalledOnCreateInputConnection).isTrue();
+ assertThat(editText1.mCalledOnInputConnectionOpened).isFalse();
+ assertThat(editText1.mCalledOnInputConnectionClosed).isFalse();
+
+ assertThat(editText2.mCalledOnCreateInputConnection).isFalse();
+ assertThat(editText2.mCalledOnInputConnectionOpened).isFalse();
+ assertThat(editText2.mCalledOnInputConnectionClosed).isFalse();
+ });
+
+ // Focus into the second EditText.
+ mActivityRule.runOnUiThread(editText2::requestFocus);
+ mInstrumentation.waitForIdleSync();
+ assertThat(editText1.isFocused()).isFalse();
+ assertThat(editText2.isFocused()).isTrue();
+
+ // Show the IME for the second EditText. Assert that the opened/closed callbacks are not
+ // invoked since there's no input connection.
+ mActivityRule.runOnUiThread(() -> mImm.showSoftInput(editText2, 0));
+ mInstrumentation.waitForIdleSync();
+ mActivityRule.runOnUiThread(() -> {
+ assertThat(editText1.mCalledOnCreateInputConnection).isTrue();
+ assertThat(editText1.mCalledOnInputConnectionOpened).isFalse();
+ assertThat(editText1.mCalledOnInputConnectionClosed).isFalse();
+
+ assertThat(editText2.mCalledOnCreateInputConnection).isTrue();
+ assertThat(editText2.mCalledOnInputConnectionOpened).isFalse();
+ assertThat(editText2.mCalledOnInputConnectionClosed).isFalse();
+ });
+ }
+
+ @Test
+ public void testInputConnectionCallbacks_nonEditableInput() throws Throwable {
+ final ViewGroup viewGroup = mActivity.findViewById(R.id.root);
+ final TestButton view1 = new TestButton(mActivity);
+ final TestButton view2 = new TestButton(mActivity);
+ mActivityRule.runOnUiThread(() -> {
+ viewGroup.addView(view1);
+ viewGroup.addView(view2);
+ });
+ mInstrumentation.waitForIdleSync();
+
+ // Request focus + IME on the first view.
+ mActivityRule.runOnUiThread(view1::requestFocus);
+ mInstrumentation.waitForIdleSync();
+ assertThat(view1.isFocused()).isTrue();
+ assertThat(view2.isFocused()).isFalse();
+ mActivityRule.runOnUiThread(() -> mImm.showSoftInput(view1, 0));
+ mInstrumentation.waitForIdleSync();
+
+ // Assert that the opened/closed callbacks are not invoked since there's no InputConnection.
+ mActivityRule.runOnUiThread(() -> {
+ assertThat(view1.mCalledOnCreateInputConnection).isTrue();
+ assertThat(view1.mCalledOnInputConnectionOpened).isFalse();
+ assertThat(view1.mCalledOnInputConnectionClosed).isFalse();
+
+ assertThat(view2.mCalledOnCreateInputConnection).isFalse();
+ assertThat(view2.mCalledOnInputConnectionOpened).isFalse();
+ assertThat(view2.mCalledOnInputConnectionClosed).isFalse();
+ });
+
+ // Request focus + IME on the second view.
+ mActivityRule.runOnUiThread(view2::requestFocus);
+ mInstrumentation.waitForIdleSync();
+ assertThat(view1.isFocused()).isFalse();
+ assertThat(view2.isFocused()).isTrue();
+ mActivityRule.runOnUiThread(() -> mImm.showSoftInput(view1, 0));
+ mInstrumentation.waitForIdleSync();
+
+ // Assert that the opened/closed callbacks are not invoked since there's no InputConnection.
+ mActivityRule.runOnUiThread(() -> {
+ assertThat(view1.mCalledOnCreateInputConnection).isTrue();
+ assertThat(view1.mCalledOnInputConnectionOpened).isFalse();
+ assertThat(view1.mCalledOnInputConnectionClosed).isFalse();
+
+ assertThat(view2.mCalledOnCreateInputConnection).isTrue();
+ assertThat(view2.mCalledOnInputConnectionOpened).isFalse();
+ assertThat(view2.mCalledOnInputConnectionClosed).isFalse();
+ });
+ }
+
+ private static class TestEditText extends EditText {
+ private final boolean mReturnNullInputConnection;
+
+ public boolean mCalledOnCreateInputConnection = false;
+ public boolean mCalledOnInputConnectionOpened = false;
+ public boolean mCalledOnInputConnectionClosed = false;
+
+ TestEditText(Context context, boolean returnNullInputConnection) {
+ super(context);
+ mReturnNullInputConnection = returnNullInputConnection;
+ }
+
+ @Override
+ public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+ mCalledOnCreateInputConnection = true;
+ if (mReturnNullInputConnection) {
+ return null;
+ } else {
+ return super.onCreateInputConnection(outAttrs);
+ }
+ }
+
+ @Override
+ public void onInputConnectionOpenedInternal(@NonNull InputConnection inputConnection,
+ @NonNull EditorInfo editorInfo, @Nullable Handler handler) {
+ mCalledOnInputConnectionOpened = true;
+ super.onInputConnectionOpenedInternal(inputConnection, editorInfo, handler);
+ }
+
+ @Override
+ public void onInputConnectionClosedInternal() {
+ mCalledOnInputConnectionClosed = true;
+ super.onInputConnectionClosedInternal();
+ }
+ }
+
+ private static class TestButton extends Button {
+ public boolean mCalledOnCreateInputConnection = false;
+ public boolean mCalledOnInputConnectionOpened = false;
+ public boolean mCalledOnInputConnectionClosed = false;
+
+ TestButton(Context context) {
+ super(context);
+ }
+
+ @Override
+ public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+ mCalledOnCreateInputConnection = true;
+ return super.onCreateInputConnection(outAttrs);
+ }
+
+ @Override
+ public void onInputConnectionOpenedInternal(@NonNull InputConnection inputConnection,
+ @NonNull EditorInfo editorInfo, @Nullable Handler handler) {
+ mCalledOnInputConnectionOpened = true;
+ super.onInputConnectionOpenedInternal(inputConnection, editorInfo, handler);
+ }
+
+ @Override
+ public void onInputConnectionClosedInternal() {
+ mCalledOnInputConnectionClosed = true;
+ super.onInputConnectionClosedInternal();
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/view/ViewInputConnectionTestActivity.java b/core/tests/coretests/src/android/view/ViewInputConnectionTestActivity.java
new file mode 100644
index 0000000..55c812d
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewInputConnectionTestActivity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 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 android.view;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.frameworks.coretests.R;
+
+public class ViewInputConnectionTestActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_view_ic_test);
+ }
+}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index 628252d..402b92a 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -52,7 +52,8 @@
@Test
public void testGetLocalTextClassifier() {
- assertThat(mTcm.getTextClassifier(TextClassifier.LOCAL)).isSameAs(TextClassifier.NO_OP);
+ assertThat(mTcm.getTextClassifier(TextClassifier.LOCAL))
+ .isSameInstanceAs(TextClassifier.NO_OP);
}
@Test
diff --git a/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java b/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java
index f108eb8..a2bc77a 100644
--- a/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java
+++ b/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java
@@ -81,7 +81,7 @@
future.completeExceptionally(origException);
ExecutionException executionException =
expectThrows(ExecutionException.class, future::get);
- assertThat(executionException.getCause()).isSameAs(origException);
+ assertThat(executionException.getCause()).isSameInstanceAs(origException);
}
@Test
@@ -92,7 +92,7 @@
CountDownLatch latch = new CountDownLatch(1);
future.whenComplete((obj, err) -> {
assertThat(obj).isNull();
- assertThat(err).isSameAs(origException);
+ assertThat(err).isSameInstanceAs(origException);
latch.countDown();
});
latch.await();
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java b/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
index 5914887..942045c 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
@@ -107,7 +107,7 @@
if (!isAlive) {
return false;
}
- assertThat(mRecipient).isSameAs(recipient);
+ assertThat(mRecipient).isSameInstanceAs(recipient);
mRecipient = null;
return true;
}
diff --git a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
index 9f68ef3..7eca320 100644
--- a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
+++ b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
@@ -74,7 +74,7 @@
assertThat(copy.mImeBackDisposition).isEqualTo(original.mImeBackDisposition);
assertThat(copy.mShowImeSwitcher).isEqualTo(original.mShowImeSwitcher);
assertThat(copy.mDisabledFlags2).isEqualTo(original.mDisabledFlags2);
- assertThat(copy.mImeToken).isSameAs(original.mImeToken);
+ assertThat(copy.mImeToken).isSameInstanceAs(original.mImeToken);
assertThat(copy.mNavbarColorManagedByIme).isEqualTo(original.mNavbarColorManagedByIme);
assertThat(copy.mAppFullscreen).isEqualTo(original.mAppFullscreen);
assertThat(copy.mAppImmersive).isEqualTo(original.mAppImmersive);
diff --git a/core/tests/powertests/PowerStatsViewer/Android.bp b/core/tests/powertests/PowerStatsViewer/Android.bp
new file mode 100644
index 0000000..a3dc4fb
--- /dev/null
+++ b/core/tests/powertests/PowerStatsViewer/Android.bp
@@ -0,0 +1,13 @@
+android_test {
+ name: "PowerStatsViewer",
+ srcs: ["src/**/*.java"],
+ defaults: ["SettingsLibDefaults"],
+ static_libs: [
+ "androidx.appcompat_appcompat",
+ "androidx.cardview_cardview",
+ "androidx.recyclerview_recyclerview",
+ "com.google.android.material_material",
+ ],
+ platform_apis: true,
+ certificate: "platform",
+}
diff --git a/core/tests/powertests/PowerStatsViewer/AndroidManifest.xml b/core/tests/powertests/PowerStatsViewer/AndroidManifest.xml
new file mode 100644
index 0000000..378d035
--- /dev/null
+++ b/core/tests/powertests/PowerStatsViewer/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.core.powerstatsviewer"
+ android:sharedUserId="android.uid.system">
+
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.BATTERY_STATS"/>
+
+ <application
+ android:theme="@style/Theme"
+ android:label="Power Stats Viewer">
+ <activity android:name=".PowerStatsViewerActivity"
+ android:label="Power Stats Viewer"
+ android:launchMode="singleTop"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".AppPickerActivity"
+ android:label="Power Stats - Select an App"/>
+
+ </application>
+</manifest>
diff --git a/core/tests/powertests/PowerStatsViewer/res/layout/app_info_layout.xml b/core/tests/powertests/PowerStatsViewer/res/layout/app_info_layout.xml
new file mode 100644
index 0000000..fe6fe2d
--- /dev/null
+++ b/core/tests/powertests/PowerStatsViewer/res/layout/app_info_layout.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:background="?android:attr/selectableItemBackground"
+ android:gravity="center_vertical"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="@dimen/secondary_app_icon_size"
+ android:layout_height="@dimen/secondary_app_icon_size"
+ android:layout_marginEnd="12dp"
+ android:layout_marginTop="4dp"
+ android:layout_marginBottom="4dp"
+ android:gravity="start|center_vertical"/>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:paddingTop="16dp"
+ android:paddingBottom="16dp">
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceListItem"/>
+
+ <TextView
+ android:id="@+id/uid"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceSmall"/>
+
+ <TextView
+ android:id="@+id/packages"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textDirection="locale"
+ android:maxLines="3"
+ android:ellipsize="end"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"/>
+
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/power_mah"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|center_vertical"
+ android:layout_marginStart="16dp"
+ android:gravity="right"
+ android:textAppearance="?android:attr/textAppearanceListItem"
+ android:visibility="gone"/>
+
+</LinearLayout>
diff --git a/core/tests/powertests/PowerStatsViewer/res/layout/app_picker_layout.xml b/core/tests/powertests/PowerStatsViewer/res/layout/app_picker_layout.xml
new file mode 100644
index 0000000..6f28999
--- /dev/null
+++ b/core/tests/powertests/PowerStatsViewer/res/layout/app_picker_layout.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/app_list_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone"/>
+
+ <ProgressBar
+ style="?android:attr/progressBarStyleLarge"
+ android:id="@+id/loading_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:indeterminate="true"/>
+</FrameLayout>
\ No newline at end of file
diff --git a/core/tests/powertests/PowerStatsViewer/res/layout/power_stats_entry_layout.xml b/core/tests/powertests/PowerStatsViewer/res/layout/power_stats_entry_layout.xml
new file mode 100644
index 0000000..1ced825
--- /dev/null
+++ b/core/tests/powertests/PowerStatsViewer/res/layout/power_stats_entry_layout.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp">
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:textAppearance="@style/TextAppearanceBody"/>
+
+ <TextView
+ android:id="@+id/amount"
+ android:layout_width="0dp"
+ android:layout_weight="0.7"
+ android:layout_height="wrap_content"
+ android:gravity="right"
+ android:textAppearance="@style/TextAppearanceBody"/>
+
+ <TextView
+ android:id="@+id/percent"
+ android:layout_width="64dp"
+ android:layout_height="wrap_content"
+ android:gravity="right"
+ android:textAppearance="@style/TextAppearanceBody"/>
+</LinearLayout>
diff --git a/core/tests/powertests/PowerStatsViewer/res/layout/power_stats_viewer_layout.xml b/core/tests/powertests/PowerStatsViewer/res/layout/power_stats_viewer_layout.xml
new file mode 100644
index 0000000..9949418
--- /dev/null
+++ b/core/tests/powertests/PowerStatsViewer/res/layout/power_stats_viewer_layout.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <androidx.cardview.widget.CardView
+ style="@style/LoadTestCardView"
+ android:id="@+id/app_card"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dp"
+ android:layout_marginEnd="10dp"
+ android:layout_marginBottom="10dp"
+ android:layout_marginStart="10dp"
+ android:padding="20dp">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:minHeight="80dp"
+ android:paddingStart="10dp"
+ android:paddingEnd="10dp">
+
+ <include layout="@layout/app_info_layout"/>
+
+ </LinearLayout>
+ </androidx.cardview.widget.CardView>
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/power_stats_data_view"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+
+ <TextView
+ android:id="@+id/empty_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:visibility="gone"
+ android:text="No power stats available"/>
+ </LinearLayout>
+
+ <FrameLayout
+ android:id="@+id/loading_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#AAFFFFFF">
+ <ProgressBar
+ style="?android:attr/progressBarStyleLarge"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:indeterminate="true"/>
+ </FrameLayout>
+</FrameLayout>
diff --git a/core/tests/powertests/PowerStatsViewer/res/values/styles.xml b/core/tests/powertests/PowerStatsViewer/res/values/styles.xml
new file mode 100644
index 0000000..629d729
--- /dev/null
+++ b/core/tests/powertests/PowerStatsViewer/res/values/styles.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <style name="Theme" parent="Theme.MaterialComponents.Light">
+ <item name="colorPrimary">#34a853</item>
+ <item name="android:windowActionBar">true</item>
+ <item name="android:windowNoTitle">false</item>
+ </style>
+
+ <style name="LoadTestCardView" parent="Widget.MaterialComponents.CardView">
+ <item name="cardBackgroundColor">#ceead6</item>
+ </style>
+
+ <style name="TextAppearanceBody" parent="android:TextAppearance.DeviceDefault">
+ <item name="android:textColor">#000000</item>
+ <item name="android:textSize">18sp</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/AppInfoHelper.java b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/AppInfoHelper.java
new file mode 100644
index 0000000..8526561
--- /dev/null
+++ b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/AppInfoHelper.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2020 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.frameworks.core.powerstatsviewer;
+
+import android.annotation.Nullable;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Process;
+
+import com.android.internal.os.BatterySipper;
+
+class AppInfoHelper {
+
+ private static final String SYSTEM_SERVER_PACKAGE_NAME = "android";
+
+ public static class AppInfo {
+ public int uid;
+ public CharSequence label;
+ public double powerMah;
+ public ApplicationInfo iconInfo;
+ public CharSequence packages;
+ }
+
+ @Nullable
+ public static AppInfo makeApplicationInfo(PackageManager packageManager, int uid,
+ @Nullable BatterySipper sipper) {
+ if (sipper != null && sipper.drainType != BatterySipper.DrainType.APP) {
+ return null;
+ }
+
+ String packageWithHighestDrain = null;
+
+ AppInfo info = new AppInfo();
+ info.uid = uid;
+ if (sipper != null) {
+ sipper.sumPower();
+ info.powerMah = sipper.totalSmearedPowerMah;
+ packageWithHighestDrain = sipper.packageWithHighestDrain;
+ }
+ if (info.uid == Process.ROOT_UID) {
+ info.label = "<root>";
+ } else {
+ String[] packages = packageManager.getPackagesForUid(info.uid);
+ String primaryPackageName = null;
+ if (info.uid == Process.SYSTEM_UID) {
+ primaryPackageName = SYSTEM_SERVER_PACKAGE_NAME;
+ } else if (packages != null) {
+ for (String name : packages) {
+ primaryPackageName = name;
+ if (name.equals(packageWithHighestDrain)) {
+ break;
+ }
+ }
+ }
+
+ if (primaryPackageName != null) {
+ try {
+ ApplicationInfo applicationInfo =
+ packageManager.getApplicationInfo(primaryPackageName, 0);
+ info.label = applicationInfo.loadLabel(packageManager);
+ info.iconInfo = applicationInfo;
+ } catch (PackageManager.NameNotFoundException e) {
+ info.label = primaryPackageName;
+ }
+ } else if (packageWithHighestDrain != null) {
+ info.label = packageWithHighestDrain;
+ }
+
+ if (packages != null && packages.length > 0) {
+ StringBuilder sb = new StringBuilder();
+ if (primaryPackageName != null) {
+ sb.append(primaryPackageName);
+ }
+ for (String packageName : packages) {
+ if (packageName.equals(primaryPackageName)) {
+ continue;
+ }
+
+ if (sb.length() != 0) {
+ sb.append(", ");
+ }
+ sb.append(packageName);
+ }
+
+ info.packages = sb;
+ }
+ }
+
+ // Default the app icon to System Server. This includes root, dex2oat and other UIDs.
+ if (info.iconInfo == null) {
+ try {
+ info.iconInfo =
+ packageManager.getApplicationInfo(SYSTEM_SERVER_PACKAGE_NAME, 0);
+ } catch (PackageManager.NameNotFoundException nameNotFoundException) {
+ // Won't happen
+ }
+ }
+ return info;
+ }
+}
diff --git a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/AppPickerActivity.java b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/AppPickerActivity.java
new file mode 100644
index 0000000..b4fc73c
--- /dev/null
+++ b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/AppPickerActivity.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2008 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.frameworks.core.powerstatsviewer;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.BatteryStats;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.UserManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.activity.ComponentActivity;
+import androidx.activity.result.contract.ActivityResultContract;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.loader.app.LoaderManager;
+import androidx.loader.content.Loader;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.frameworks.core.powerstatsviewer.AppInfoHelper.AppInfo;
+import com.android.internal.os.BatterySipper;
+import com.android.internal.os.BatteryStatsHelper;
+import com.android.settingslib.utils.AsyncLoaderCompat;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Picker, showing a sorted list of applications consuming power. Returns the selected
+ * application UID or Process.INVALID_UID.
+ */
+public class AppPickerActivity extends ComponentActivity {
+ private static final String TAG = "AppPicker";
+
+ public static final ActivityResultContract<Void, Integer> CONTRACT =
+ new ActivityResultContract<Void, Integer>() {
+ @NonNull
+ @Override
+ public Intent createIntent(@NonNull Context context, Void aVoid) {
+ return new Intent(context, AppPickerActivity.class);
+ }
+
+ @Override
+ public Integer parseResult(int resultCode, @Nullable Intent intent) {
+ if (resultCode != RESULT_OK || intent == null) {
+ return Process.INVALID_UID;
+ }
+ return intent.getIntExtra(Intent.EXTRA_UID, Process.INVALID_UID);
+ }
+ };
+
+ private AppListAdapter mAppListAdapter;
+ private RecyclerView mAppList;
+ private View mLoadingView;
+
+ private interface OnAppSelectedListener {
+ void onAppSelected(int uid);
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ getActionBar().setDisplayHomeAsUpEnabled(true);
+
+ setContentView(R.layout.app_picker_layout);
+
+ mLoadingView = findViewById(R.id.loading_view);
+
+ mAppList = findViewById(R.id.app_list_view);
+ mAppList.setLayoutManager(new LinearLayoutManager(this));
+ mAppListAdapter = new AppListAdapter(AppPickerActivity.this::setSelectedUid);
+ mAppList.setAdapter(mAppListAdapter);
+
+ LoaderManager.getInstance(this).initLoader(0, null,
+ new AppListLoaderCallbacks());
+ }
+
+ protected void setSelectedUid(int uid) {
+ Intent intent = new Intent();
+ intent.putExtra(Intent.EXTRA_UID, uid);
+ setResult(RESULT_OK, intent);
+ finish();
+ }
+
+ @Override
+ public boolean onNavigateUp() {
+ onBackPressed();
+ return true;
+ }
+
+ private static class AppListLoader extends AsyncLoaderCompat<List<AppInfo>> {
+ private final BatteryStatsHelper mStatsHelper;
+ private final UserManager mUserManager;
+ private final PackageManager mPackageManager;
+
+ AppListLoader(Context context) {
+ super(context);
+ mUserManager = context.getSystemService(UserManager.class);
+ mStatsHelper = new BatteryStatsHelper(context, false /* collectBatteryBroadcast */);
+ mStatsHelper.create((Bundle) null);
+ mStatsHelper.clearStats();
+ mPackageManager = context.getPackageManager();
+ }
+
+ @Override
+ public List<AppInfo> loadInBackground() {
+ List<AppInfo> applicationList = new ArrayList<>();
+
+ mStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED,
+ mUserManager.getUserProfiles());
+
+ final List<BatterySipper> usageList = mStatsHelper.getUsageList();
+ for (BatterySipper sipper : usageList) {
+ AppInfo info =
+ AppInfoHelper.makeApplicationInfo(mPackageManager, sipper.getUid(), sipper);
+ if (info != null) {
+ applicationList.add(info);
+ }
+ }
+
+ applicationList.sort(
+ Comparator.comparing((AppInfo a) -> a.powerMah).reversed());
+ return applicationList;
+ }
+
+ @Override
+ protected void onDiscardResult(List<AppInfo> result) {
+ }
+ }
+
+ private class AppListLoaderCallbacks implements
+ LoaderManager.LoaderCallbacks<List<AppInfo>> {
+
+ @NonNull
+ @Override
+ public Loader<List<AppInfo>> onCreateLoader(int id, Bundle args) {
+ return new AppListLoader(AppPickerActivity.this);
+ }
+
+ @Override
+ public void onLoadFinished(@NonNull Loader<List<AppInfo>> loader,
+ List<AppInfo> applicationList) {
+ mAppListAdapter.setApplicationList(applicationList);
+ mAppList.setVisibility(View.VISIBLE);
+ mLoadingView.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void onLoaderReset(@NonNull Loader<List<AppInfo>> loader) {
+ }
+ }
+
+ public class AppListAdapter extends RecyclerView.Adapter<AppViewHolder> {
+ private final OnAppSelectedListener mListener;
+ private List<AppInfo> mApplicationList;
+
+ public AppListAdapter(OnAppSelectedListener listener) {
+ mListener = listener;
+ }
+
+ void setApplicationList(List<AppInfo> applicationList) {
+ mApplicationList = applicationList;
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public int getItemCount() {
+ return mApplicationList.size();
+ }
+
+ @NonNull
+ @Override
+ public AppViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) {
+ LayoutInflater layoutInflater = LayoutInflater.from(viewGroup.getContext());
+ View view = layoutInflater.inflate(R.layout.app_info_layout, viewGroup, false);
+ return new AppViewHolder(view, mListener);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull AppViewHolder appViewHolder, int position) {
+ AppInfo item = mApplicationList.get(position);
+ appViewHolder.uid = item.uid;
+ appViewHolder.titleView.setText(item.label);
+ appViewHolder.uidView.setText(
+ String.format(Locale.getDefault(), "UID: %d", item.uid));
+ appViewHolder.powerView.setText(
+ String.format(Locale.getDefault(), "%.1f mAh", item.powerMah));
+ appViewHolder.iconView.setImageDrawable(
+ item.iconInfo.loadIcon(getPackageManager()));
+ if (item.packages != null) {
+ appViewHolder.packagesView.setText(item.packages);
+ appViewHolder.packagesView.setVisibility(View.VISIBLE);
+ } else {
+ appViewHolder.packagesView.setVisibility(View.GONE);
+ }
+ }
+ }
+
+ // View Holder used when displaying apps
+ public static class AppViewHolder extends RecyclerView.ViewHolder
+ implements View.OnClickListener {
+ private final OnAppSelectedListener mListener;
+
+ public int uid;
+ public TextView titleView;
+ public TextView uidView;
+ public ImageView iconView;
+ public TextView packagesView;
+ public TextView powerView;
+
+ AppViewHolder(View view, OnAppSelectedListener listener) {
+ super(view);
+ mListener = listener;
+ view.setOnClickListener(this);
+ titleView = view.findViewById(android.R.id.title);
+ uidView = view.findViewById(R.id.uid);
+ iconView = view.findViewById(android.R.id.icon);
+ packagesView = view.findViewById(R.id.packages);
+ powerView = view.findViewById(R.id.power_mah);
+ powerView.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void onClick(View v) {
+ mListener.onAppSelected(uid);
+ }
+ }
+}
diff --git a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsData.java b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsData.java
new file mode 100644
index 0000000..09f20ba
--- /dev/null
+++ b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsData.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2020 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.frameworks.core.powerstatsviewer;
+
+import android.content.Context;
+import android.os.Process;
+
+import com.android.internal.os.BatterySipper;
+import com.android.internal.os.BatteryStatsHelper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class PowerStatsData {
+ private static final String PACKAGE_CALENDAR_PROVIDER = "com.android.providers.calendar";
+ private static final String PACKAGE_MEDIA_PROVIDER = "com.android.providers.media";
+ private static final String PACKAGE_SYSTEMUI = "com.android.systemui";
+ private static final String[] PACKAGES_SYSTEM = {PACKAGE_MEDIA_PROVIDER,
+ PACKAGE_CALENDAR_PROVIDER, PACKAGE_SYSTEMUI};
+
+ enum EntryType {
+ POWER,
+ DURATION,
+ }
+
+ public static class Entry {
+ public String title;
+ public EntryType entryType;
+ public double value;
+ public double total;
+ }
+
+ private final AppInfoHelper.AppInfo mAppInfo;
+ private final List<Entry> mEntries = new ArrayList<>();
+
+ public PowerStatsData(Context context, BatteryStatsHelper batteryStatsHelper,
+ int uid) {
+ List<BatterySipper> usageList = batteryStatsHelper.getUsageList();
+
+ double totalPowerMah = 0;
+ double totalSmearedPowerMah = 0;
+ double totalPowerExcludeSystemMah = 0;
+ double totalScreenPower = 0;
+ double totalProportionalSmearMah = 0;
+ double totalCpuPowerMah = 0;
+ double totalSystemServiceCpuPowerMah = 0;
+ double totalUsagePowerMah = 0;
+ double totalWakeLockPowerMah = 0;
+ double totalMobileRadioPowerMah = 0;
+ double totalWifiPowerMah = 0;
+ double totalBluetoothPowerMah = 0;
+ double totalGpsPowerMah = 0;
+ double totalCameraPowerMah = 0;
+ double totalFlashlightPowerMah = 0;
+ double totalSensorPowerMah = 0;
+ double totalAudioPowerMah = 0;
+ double totalVideoPowerMah = 0;
+
+ long totalCpuTimeMs = 0;
+ long totalCpuFgTimeMs = 0;
+ long totalWakeLockTimeMs = 0;
+ long totalWifiRunningTimeMs = 0;
+ long totalBluetoothRunningTimeMs = 0;
+ long totalGpsTimeMs = 0;
+ long totalCameraTimeMs = 0;
+ long totalFlashlightTimeMs = 0;
+ long totalAudioTimeMs = 0;
+ long totalVideoTimeMs = 0;
+
+ BatterySipper uidSipper = null;
+ for (BatterySipper sipper : usageList) {
+ if (sipper.drainType == BatterySipper.DrainType.SCREEN) {
+ totalScreenPower = sipper.sumPower();
+ }
+
+ if (isHiddenDrainType(sipper.drainType)) {
+ continue;
+ }
+
+ if (sipper.drainType == BatterySipper.DrainType.APP && sipper.getUid() == uid) {
+ uidSipper = sipper;
+ }
+
+ totalPowerMah += sipper.sumPower();
+ totalSmearedPowerMah += sipper.totalSmearedPowerMah;
+ totalProportionalSmearMah += sipper.proportionalSmearMah;
+
+ if (!isSystemSipper(sipper)) {
+ totalPowerExcludeSystemMah += sipper.totalSmearedPowerMah;
+ }
+
+ totalCpuPowerMah += sipper.cpuPowerMah;
+ totalSystemServiceCpuPowerMah += sipper.systemServiceCpuPowerMah;
+ totalUsagePowerMah += sipper.usagePowerMah;
+ totalWakeLockPowerMah += sipper.wakeLockPowerMah;
+ totalMobileRadioPowerMah += sipper.mobileRadioPowerMah;
+ totalWifiPowerMah += sipper.wifiPowerMah;
+ totalBluetoothPowerMah += sipper.bluetoothPowerMah;
+ totalGpsPowerMah += sipper.gpsPowerMah;
+ totalCameraPowerMah += sipper.cameraPowerMah;
+ totalFlashlightPowerMah += sipper.flashlightPowerMah;
+ totalSensorPowerMah += sipper.sensorPowerMah;
+ totalAudioPowerMah += sipper.audioPowerMah;
+ totalVideoPowerMah += sipper.videoPowerMah;
+
+ totalCpuTimeMs += sipper.cpuTimeMs;
+ totalCpuFgTimeMs += sipper.cpuFgTimeMs;
+ totalWakeLockTimeMs += sipper.wakeLockTimeMs;
+ totalWifiRunningTimeMs += sipper.wifiRunningTimeMs;
+ totalBluetoothRunningTimeMs += sipper.bluetoothRunningTimeMs;
+ totalGpsTimeMs += sipper.gpsTimeMs;
+ totalCameraTimeMs += sipper.cameraTimeMs;
+ totalFlashlightTimeMs += sipper.flashlightTimeMs;
+ totalAudioTimeMs += sipper.audioTimeMs;
+ totalVideoTimeMs += sipper.videoTimeMs;
+ }
+
+ mAppInfo = AppInfoHelper.makeApplicationInfo(context.getPackageManager(), uid, uidSipper);
+
+ if (uidSipper == null) {
+ return;
+ }
+
+ addEntry("Total power", EntryType.POWER,
+ uidSipper.totalSmearedPowerMah, totalSmearedPowerMah);
+ addEntry("... excluding system", EntryType.POWER,
+ uidSipper.totalSmearedPowerMah, totalPowerExcludeSystemMah);
+ addEntry("Screen, smeared", EntryType.POWER,
+ uidSipper.screenPowerMah, totalScreenPower);
+ addEntry("Other, smeared", EntryType.POWER,
+ uidSipper.proportionalSmearMah, totalProportionalSmearMah);
+ addEntry("Excluding smeared", EntryType.POWER,
+ uidSipper.totalPowerMah, totalPowerMah);
+ addEntry("CPU", EntryType.POWER,
+ uidSipper.cpuPowerMah, totalCpuPowerMah);
+ addEntry("System services", EntryType.POWER,
+ uidSipper.systemServiceCpuPowerMah, totalSystemServiceCpuPowerMah);
+ addEntry("RAM", EntryType.POWER,
+ uidSipper.usagePowerMah, totalUsagePowerMah);
+ addEntry("Wake lock", EntryType.POWER,
+ uidSipper.wakeLockPowerMah, totalWakeLockPowerMah);
+ addEntry("Mobile radio", EntryType.POWER,
+ uidSipper.mobileRadioPowerMah, totalMobileRadioPowerMah);
+ addEntry("WiFi", EntryType.POWER,
+ uidSipper.wifiPowerMah, totalWifiPowerMah);
+ addEntry("Bluetooth", EntryType.POWER,
+ uidSipper.bluetoothPowerMah, totalBluetoothPowerMah);
+ addEntry("GPS", EntryType.POWER,
+ uidSipper.gpsPowerMah, totalGpsPowerMah);
+ addEntry("Camera", EntryType.POWER,
+ uidSipper.cameraPowerMah, totalCameraPowerMah);
+ addEntry("Flashlight", EntryType.POWER,
+ uidSipper.flashlightPowerMah, totalFlashlightPowerMah);
+ addEntry("Sensors", EntryType.POWER,
+ uidSipper.sensorPowerMah, totalSensorPowerMah);
+ addEntry("Audio", EntryType.POWER,
+ uidSipper.audioPowerMah, totalAudioPowerMah);
+ addEntry("Video", EntryType.POWER,
+ uidSipper.videoPowerMah, totalVideoPowerMah);
+
+ addEntry("CPU time", EntryType.DURATION,
+ uidSipper.cpuTimeMs, totalCpuTimeMs);
+ addEntry("CPU foreground time", EntryType.DURATION,
+ uidSipper.cpuFgTimeMs, totalCpuFgTimeMs);
+ addEntry("Wake lock time", EntryType.DURATION,
+ uidSipper.wakeLockTimeMs, totalWakeLockTimeMs);
+ addEntry("WiFi running time", EntryType.DURATION,
+ uidSipper.wifiRunningTimeMs, totalWifiRunningTimeMs);
+ addEntry("Bluetooth time", EntryType.DURATION,
+ uidSipper.bluetoothRunningTimeMs, totalBluetoothRunningTimeMs);
+ addEntry("GPS time", EntryType.DURATION,
+ uidSipper.gpsTimeMs, totalGpsTimeMs);
+ addEntry("Camera time", EntryType.DURATION,
+ uidSipper.cameraTimeMs, totalCameraTimeMs);
+ addEntry("Flashlight time", EntryType.DURATION,
+ uidSipper.flashlightTimeMs, totalFlashlightTimeMs);
+ addEntry("Audio time", EntryType.DURATION,
+ uidSipper.audioTimeMs, totalAudioTimeMs);
+ addEntry("Video time", EntryType.DURATION,
+ uidSipper.videoTimeMs, totalVideoTimeMs);
+ }
+
+ protected boolean isHiddenDrainType(BatterySipper.DrainType drainType) {
+ return drainType == BatterySipper.DrainType.IDLE
+ || drainType == BatterySipper.DrainType.CELL
+ || drainType == BatterySipper.DrainType.SCREEN
+ || drainType == BatterySipper.DrainType.UNACCOUNTED
+ || drainType == BatterySipper.DrainType.OVERCOUNTED
+ || drainType == BatterySipper.DrainType.BLUETOOTH
+ || drainType == BatterySipper.DrainType.WIFI;
+ }
+
+ private boolean isSystemSipper(BatterySipper sipper) {
+ final int uid = sipper.uidObj == null ? -1 : sipper.getUid();
+ if (uid >= Process.ROOT_UID && uid < Process.FIRST_APPLICATION_UID) {
+ return true;
+ } else if (sipper.mPackages != null) {
+ for (final String packageName : sipper.mPackages) {
+ for (final String systemPackage : PACKAGES_SYSTEM) {
+ if (systemPackage.equals(packageName)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private void addEntry(String title, EntryType entryType, double amount, double totalAmount) {
+ Entry entry = new Entry();
+ entry.title = title;
+ entry.entryType = entryType;
+ entry.value = amount;
+ entry.total = totalAmount;
+ mEntries.add(entry);
+ }
+
+ public AppInfoHelper.AppInfo getAppInfo() {
+ return mAppInfo;
+ }
+
+ public List<Entry> getEntries() {
+ return mEntries;
+ }
+}
diff --git a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsViewerActivity.java b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsViewerActivity.java
new file mode 100644
index 0000000..1605e9c
--- /dev/null
+++ b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsViewerActivity.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2020 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.frameworks.core.powerstatsviewer;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.BatteryStats;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.UserManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.activity.ComponentActivity;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.loader.app.LoaderManager;
+import androidx.loader.app.LoaderManager.LoaderCallbacks;
+import androidx.loader.content.Loader;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.internal.os.BatteryStatsHelper;
+import com.android.settingslib.utils.AsyncLoaderCompat;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+public class PowerStatsViewerActivity extends ComponentActivity {
+ private static final int POWER_STATS_REFRESH_RATE_MILLIS = 60 * 1000;
+ public static final String PREF_SELECTED_UID = "selectedUid";
+ private static final String LOADER_ARG_UID = "uid";
+
+ private PowerStatsDataAdapter mPowerStatsDataAdapter;
+ private Runnable mPowerStatsRefresh = this::periodicPowerStatsRefresh;
+ private SharedPreferences mSharedPref;
+ private int mUid = Process.INVALID_UID;
+ private TextView mTitleView;
+ private TextView mUidView;
+ private ImageView mIconView;
+ private TextView mPackagesView;
+ private RecyclerView mPowerStatsDataView;
+ private View mLoadingView;
+ private View mEmptyView;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mSharedPref = getPreferences(Context.MODE_PRIVATE);
+
+ setContentView(R.layout.power_stats_viewer_layout);
+
+ View appCard = findViewById(R.id.app_card);
+ appCard.setOnClickListener((e) -> startAppPicker());
+
+ mTitleView = findViewById(android.R.id.title);
+ mUidView = findViewById(R.id.uid);
+ mIconView = findViewById(android.R.id.icon);
+ mPackagesView = findViewById(R.id.packages);
+
+ mPowerStatsDataView = findViewById(R.id.power_stats_data_view);
+ mPowerStatsDataView.setLayoutManager(new LinearLayoutManager(this));
+ mPowerStatsDataAdapter = new PowerStatsDataAdapter();
+ mPowerStatsDataView.setAdapter(mPowerStatsDataAdapter);
+
+ mLoadingView = findViewById(R.id.loading_view);
+ mEmptyView = findViewById(R.id.empty_view);
+
+ mUid = mSharedPref.getInt(PREF_SELECTED_UID, Process.INVALID_UID);
+ loadPowerStats();
+ if (mUid == Process.INVALID_UID) {
+ startAppPicker();
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ periodicPowerStatsRefresh();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ getMainThreadHandler().removeCallbacks(mPowerStatsRefresh);
+ }
+
+ private void startAppPicker() {
+ registerForActivityResult(AppPickerActivity.CONTRACT, this::onApplicationSelected)
+ .launch(null);
+ }
+
+ private void onApplicationSelected(int uid) {
+ if (uid == -1) {
+ if (mUid == Process.INVALID_UID) {
+ finish();
+ }
+ } else {
+ mUid = uid;
+ mSharedPref.edit().putInt(PREF_SELECTED_UID, mUid).apply();
+ mLoadingView.setVisibility(View.VISIBLE);
+ loadPowerStats();
+ }
+ }
+
+ private void periodicPowerStatsRefresh() {
+ loadPowerStats();
+ getMainThreadHandler().postDelayed(mPowerStatsRefresh, POWER_STATS_REFRESH_RATE_MILLIS);
+ }
+
+ private void loadPowerStats() {
+ Bundle args = new Bundle();
+ args.putInt(LOADER_ARG_UID, mUid);
+ LoaderManager.getInstance(this).restartLoader(0, args, new PowerStatsDataLoaderCallbacks());
+ }
+
+ private static class PowerStatsDataLoader extends AsyncLoaderCompat<PowerStatsData> {
+ private final int mUid;
+ private final BatteryStatsHelper mBatteryStatsHelper;
+ private final UserManager mUserManager;
+
+ PowerStatsDataLoader(Context context, int uid) {
+ super(context);
+ mUid = uid;
+ mUserManager = context.getSystemService(UserManager.class);
+ mBatteryStatsHelper = new BatteryStatsHelper(context,
+ false /* collectBatteryBroadcast */);
+ mBatteryStatsHelper.create((Bundle) null);
+ mBatteryStatsHelper.clearStats();
+ }
+
+ @Override
+ public PowerStatsData loadInBackground() {
+ mBatteryStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED,
+ mUserManager.getUserProfiles());
+ return new PowerStatsData(getContext(), mBatteryStatsHelper, mUid);
+ }
+
+ @Override
+ protected void onDiscardResult(PowerStatsData result) {
+ }
+ }
+
+ private class PowerStatsDataLoaderCallbacks implements LoaderCallbacks<PowerStatsData> {
+ @NonNull
+ @Override
+ public Loader<PowerStatsData> onCreateLoader(int id, Bundle args) {
+ return new PowerStatsDataLoader(PowerStatsViewerActivity.this,
+ args.getInt(LOADER_ARG_UID, Process.INVALID_UID));
+ }
+
+ @Override
+ public void onLoadFinished(@NonNull Loader<PowerStatsData> loader,
+ PowerStatsData powerStatsData) {
+
+ AppInfoHelper.AppInfo appInfo = powerStatsData.getAppInfo();
+ mTitleView.setText(appInfo.label);
+ mUidView.setText(String.format(Locale.getDefault(), "UID: %d", appInfo.uid));
+ mIconView.setImageDrawable(appInfo.iconInfo.loadIcon(getPackageManager()));
+
+ if (appInfo.packages != null) {
+ mPackagesView.setText(appInfo.packages);
+ mPackagesView.setVisibility(View.VISIBLE);
+ } else {
+ mPackagesView.setVisibility(View.GONE);
+ }
+
+ mPowerStatsDataAdapter.setEntries(powerStatsData.getEntries());
+
+ if (powerStatsData.getEntries().isEmpty()) {
+ mEmptyView.setVisibility(View.VISIBLE);
+ mPowerStatsDataView.setVisibility(View.GONE);
+ } else {
+ mEmptyView.setVisibility(View.GONE);
+ mPowerStatsDataView.setVisibility(View.VISIBLE);
+ }
+
+ mLoadingView.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void onLoaderReset(@NonNull Loader<PowerStatsData> loader) {
+ }
+ }
+
+ private static class PowerStatsDataAdapter extends
+ RecyclerView.Adapter<PowerStatsDataAdapter.ViewHolder> {
+ public static class ViewHolder extends RecyclerView.ViewHolder {
+ public TextView titleTextView;
+ public TextView amountTextView;
+ public TextView percentTextView;
+
+ ViewHolder(View itemView) {
+ super(itemView);
+
+ titleTextView = itemView.findViewById(R.id.title);
+ amountTextView = itemView.findViewById(R.id.amount);
+ percentTextView = itemView.findViewById(R.id.percent);
+ }
+ }
+
+ private List<PowerStatsData.Entry> mEntries = Collections.emptyList();
+
+ public void setEntries(List<PowerStatsData.Entry> entries) {
+ mEntries = entries;
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public int getItemCount() {
+ return mEntries.size();
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int position) {
+ LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
+ View itemView = layoutInflater.inflate(R.layout.power_stats_entry_layout, parent,
+ false);
+ return new ViewHolder(itemView);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) {
+ PowerStatsData.Entry entry = mEntries.get(position);
+ switch (entry.entryType) {
+ case POWER:
+ viewHolder.titleTextView.setText(entry.title);
+ viewHolder.amountTextView.setText(
+ String.format(Locale.getDefault(), "%.1f mAh", entry.value));
+ break;
+ case DURATION:
+ viewHolder.titleTextView.setText(entry.title);
+ viewHolder.amountTextView.setText(
+ String.format(Locale.getDefault(), "%,d ms", (long) entry.value));
+ break;
+ }
+
+ double proportion = entry.total != 0 ? entry.value * 100 / entry.total : 0;
+ viewHolder.percentTextView.setText(String.format(Locale.getDefault(), "%.1f%%",
+ proportion));
+ }
+ }
+}
diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp
index e122e00..745de84 100644
--- a/data/etc/car/Android.bp
+++ b/data/etc/car/Android.bp
@@ -149,3 +149,11 @@
src: "com.android.car.ui.paintbooth.xml",
filename_from_src: true,
}
+
+prebuilt_etc {
+ name: "allowed_privapp_com.android.car.provision",
+ system_ext_specific: true,
+ sub_dir: "permissions",
+ src: "com.android.car.provision.xml",
+ filename_from_src: true,
+}
\ No newline at end of file
diff --git a/data/etc/car/com.android.car.provision.xml b/data/etc/car/com.android.car.provision.xml
new file mode 100644
index 0000000..fa51d55e
--- /dev/null
+++ b/data/etc/car/com.android.car.provision.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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
+ -->
+<permissions>
+ <privapp-permissions package="com.android.car.provision">
+ <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+ <permission name="android.permission.WRITE_SETTINGS"/>
+ </privapp-permissions>
+</permissions>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 59727d5..31dae22 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -301,12 +301,6 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/WindowState.java"
},
- "-1741065110": {
- "message": "No app is requesting an orientation, return %d for display id=%d",
- "level": "VERBOSE",
- "group": "WM_DEBUG_ORIENTATION",
- "at": "com\/android\/server\/wm\/DisplayContent.java"
- },
"-1730156332": {
"message": "Display id=%d rotation changed to %d from %d, lastOrientation=%d",
"level": "VERBOSE",
@@ -529,6 +523,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/Task.java"
},
+ "-1480772131": {
+ "message": "No app or window is requesting an orientation, return %d for display id=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_ORIENTATION",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"-1474292612": {
"message": "Could not find task for id: %d",
"level": "DEBUG",
@@ -2515,12 +2515,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowToken.java"
},
- "845234215": {
- "message": "App is requesting an orientation, return %d for display id=%d",
- "level": "VERBOSE",
- "group": "WM_DEBUG_ORIENTATION",
- "at": "com\/android\/server\/wm\/DisplayContent.java"
- },
"849147756": {
"message": "Finish collecting in transition %d",
"level": "VERBOSE",
@@ -2923,6 +2917,12 @@
"group": "WM_DEBUG_IME",
"at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
},
+ "1381227466": {
+ "message": "App is requesting an orientation, return %d for display id=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_ORIENTATION",
+ "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
+ },
"1401295262": {
"message": "Mode default, asking user",
"level": "WARN",
@@ -3133,6 +3133,18 @@
"group": "WM_DEBUG_RESIZE",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "1640436199": {
+ "message": "No app is requesting an orientation, return %d for display id=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_ORIENTATION",
+ "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
+ },
+ "1648338379": {
+ "message": "Display id=%d is ignoring all orientation requests, return %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_ORIENTATION",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"1653210583": {
"message": "Removing app %s delayed=%b animation=%s animating=%b",
"level": "VERBOSE",
diff --git a/graphics/java/android/graphics/FrameInfo.java b/graphics/java/android/graphics/FrameInfo.java
index f768bc7..0061ea1 100644
--- a/graphics/java/android/graphics/FrameInfo.java
+++ b/graphics/java/android/graphics/FrameInfo.java
@@ -40,7 +40,7 @@
*/
public final class FrameInfo {
- public long[] frameInfo = new long[10];
+ public long[] frameInfo = new long[FRAME_INFO_SIZE];
// Various flags set to provide extra metadata about the current frame
private static final int FLAGS = 0;
@@ -87,14 +87,22 @@
// When View:draw() started
private static final int DRAW_START = 9;
+ // When the frame needs to be ready by
+ private static final int FRAME_DEADLINE = 10;
+
+ // Must be the last one
+ private static final int FRAME_INFO_SIZE = FRAME_DEADLINE + 1;
+
/** checkstyle */
- public void setVsync(long intendedVsync, long usedVsync, long frameTimelineVsyncId) {
+ public void setVsync(long intendedVsync, long usedVsync, long frameTimelineVsyncId,
+ long frameDeadline) {
frameInfo[FRAME_TIMELINE_VSYNC_ID] = frameTimelineVsyncId;
frameInfo[INTENDED_VSYNC] = intendedVsync;
frameInfo[VSYNC] = usedVsync;
frameInfo[OLDEST_INPUT_EVENT] = Long.MAX_VALUE;
frameInfo[NEWEST_INPUT_EVENT] = 0;
frameInfo[FLAGS] = 0;
+ frameInfo[FRAME_DEADLINE] = frameDeadline;
}
/** checkstyle */
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index fd5916c..a7f2739 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -355,7 +355,7 @@
*/
public @NonNull FrameRenderRequest setVsyncTime(long vsyncTime) {
// TODO(b/168552873): populate vsync Id once available to Choreographer public API
- mFrameInfo.setVsync(vsyncTime, vsyncTime, FrameInfo.INVALID_VSYNC_ID);
+ mFrameInfo.setVsync(vsyncTime, vsyncTime, FrameInfo.INVALID_VSYNC_ID, Long.MAX_VALUE);
mFrameInfo.addFlags(FrameInfo.FLAG_SURFACE_CANVAS);
return this;
}
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 28d7911..a191fe5 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -115,6 +115,21 @@
Align.LEFT, Align.CENTER, Align.RIGHT
};
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, value = {
+ ANTI_ALIAS_FLAG,
+ FILTER_BITMAP_FLAG,
+ DITHER_FLAG,
+ UNDERLINE_TEXT_FLAG,
+ STRIKE_THRU_TEXT_FLAG,
+ FAKE_BOLD_TEXT_FLAG,
+ LINEAR_TEXT_FLAG,
+ SUBPIXEL_TEXT_FLAG,
+ EMBEDDED_BITMAP_TEXT_FLAG
+ })
+ public @interface PaintFlag{}
+
/**
* Paint flag that enables antialiasing when drawing.
*
@@ -724,7 +739,7 @@
*
* @return the paint's flags (see enums ending in _Flag for bit masks)
*/
- public int getFlags() {
+ public @PaintFlag int getFlags() {
return nGetFlags(mNativePaint);
}
@@ -733,7 +748,7 @@
*
* @param flags The new flag bits for the paint
*/
- public void setFlags(int flags) {
+ public void setFlags(@PaintFlag int flags) {
nSetFlags(mNativePaint, flags);
}
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index 21b8fc6..97cd8ab 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -687,7 +687,9 @@
charBuffer[3] = (char) ((packedAxis & 0x0000_00FF_0000_0000L) >> 32);
axes[i] = new FontVariationAxis(new String(charBuffer), value);
}
- Font.Builder builder = new Font.Builder(buffer)
+ String path = nGetFontPath(ptr);
+ File file = (path == null) ? null : new File(path);
+ Font.Builder builder = new Font.Builder(buffer, file, "")
.setWeight(weight)
.setSlant(italic ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT)
.setTtcIndex(ttcIndex)
@@ -712,6 +714,9 @@
private static native long nGetAxisInfo(long ptr, int i);
@FastNative
+ private static native String nGetFontPath(long ptr);
+
+ @FastNative
private static native float nGetGlyphBounds(long font, int glyphId, long paint, RectF rect);
@FastNative
diff --git a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
index bcef154..44744bc 100644
--- a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
+++ b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
@@ -7,6 +7,12 @@
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
},
+ "-1683614271": {
+ "message": "Existing task: id=%d component=%s",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
+ },
"-1534364071": {
"message": "onTransitionReady %s: %s",
"level": "VERBOSE",
@@ -61,6 +67,12 @@
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/FullscreenTaskListener.java"
},
+ "580605218": {
+ "message": "Registering organizer",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
+ },
"980952660": {
"message": "Task root back pressed taskId=%d",
"level": "VERBOSE",
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 7ce65fd..d87de5a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -28,12 +28,14 @@
import android.app.ActivityManager.RunningTaskInfo;
import android.app.WindowConfiguration.WindowingMode;
import android.util.Log;
-import android.util.Pair;
import android.util.SparseArray;
import android.view.SurfaceControl;
import android.window.ITaskOrganizerController;
+import android.window.TaskAppearedInfo;
import android.window.TaskOrganizer;
+import androidx.annotation.NonNull;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
@@ -42,6 +44,7 @@
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.util.Arrays;
+import java.util.List;
/**
* Unified task organizer for all components in the shell.
@@ -82,7 +85,7 @@
// Keeps track of all the tasks reported to this organizer (changes in windowing mode will
// require us to report to both old and new listeners)
- private final SparseArray<Pair<RunningTaskInfo, SurfaceControl>> mTasks = new SparseArray<>();
+ private final SparseArray<TaskAppearedInfo> mTasks = new SparseArray<>();
// TODO(shell-transitions): move to a more "global" Shell location as this isn't only for Tasks
private final Transitions mTransitions;
@@ -102,6 +105,19 @@
if (Transitions.ENABLE_SHELL_TRANSITIONS) registerTransitionPlayer(mTransitions);
}
+ @Override
+ public List<TaskAppearedInfo> registerOrganizer() {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Registering organizer");
+ final List<TaskAppearedInfo> taskInfos = super.registerOrganizer();
+ for (int i = 0; i < taskInfos.size(); i++) {
+ final TaskAppearedInfo info = taskInfos.get(i);
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Existing task: id=%d component=%s",
+ info.getTaskInfo().taskId, info.getTaskInfo().baseIntent);
+ onTaskAppeared(info.getTaskInfo(), info.getLeash());
+ }
+ return taskInfos;
+ }
+
/**
* Adds a listener for tasks with given types.
*/
@@ -117,10 +133,11 @@
// Notify the listener of all existing tasks with the given type.
for (int i = mTasks.size() - 1; i >= 0; i--) {
- Pair<RunningTaskInfo, SurfaceControl> data = mTasks.valueAt(i);
- final @TaskListenerType int taskListenerType = getTaskListenerType(data.first);
+ TaskAppearedInfo data = mTasks.valueAt(i);
+ final @TaskListenerType int taskListenerType = getTaskListenerType(
+ data.getTaskInfo());
if (taskListenerType == listenerType) {
- listener.onTaskAppeared(data.first, data.second);
+ listener.onTaskAppeared(data.getTaskInfo(), data.getLeash());
}
}
}
@@ -143,7 +160,7 @@
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Task appeared taskId=%d",
taskInfo.taskId);
- mTasks.put(taskInfo.taskId, new Pair<>(taskInfo, leash));
+ mTasks.put(taskInfo.taskId, new TaskAppearedInfo(taskInfo, leash));
final TaskListener listener = mTaskListenersByType.get(getTaskListenerType(taskInfo));
if (listener != null) {
listener.onTaskAppeared(taskInfo, leash);
@@ -154,10 +171,10 @@
public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Task info changed taskId=%d",
taskInfo.taskId);
- final Pair<RunningTaskInfo, SurfaceControl> data = mTasks.get(taskInfo.taskId);
+ final TaskAppearedInfo data = mTasks.get(taskInfo.taskId);
final @TaskListenerType int listenerType = getTaskListenerType(taskInfo);
- final @TaskListenerType int prevListenerType = getTaskListenerType(data.first);
- mTasks.put(taskInfo.taskId, new Pair<>(taskInfo, data.second));
+ final @TaskListenerType int prevListenerType = getTaskListenerType(data.getTaskInfo());
+ mTasks.put(taskInfo.taskId, new TaskAppearedInfo(taskInfo, data.getLeash()));
if (prevListenerType != listenerType) {
// TODO: We currently send vanished/appeared as the task moves between types, but
// we should consider adding a different mode-changed callback
@@ -167,7 +184,7 @@
}
listener = mTaskListenersByType.get(listenerType);
if (listener != null) {
- SurfaceControl leash = data.second;
+ SurfaceControl leash = data.getLeash();
listener.onTaskAppeared(taskInfo, leash);
}
} else {
@@ -193,7 +210,7 @@
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Task vanished taskId=%d",
taskInfo.taskId);
final @TaskListenerType int prevListenerType =
- getTaskListenerType(mTasks.get(taskInfo.taskId).first);
+ getTaskListenerType(mTasks.get(taskInfo.taskId).getTaskInfo());
mTasks.remove(taskInfo.taskId);
final TaskListener listener = mTaskListenersByType.get(prevListenerType);
if (listener != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index 84b98f9..17fd16b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -276,12 +276,11 @@
long frameNumber, ClientWindowFrames outFrames,
MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
- InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
- SurfaceControl outBLASTSurfaceControl) {
+ InsetsSourceControl[] outActiveControls, Point outSurfaceSize) {
int res = super.relayout(window, attrs, requestedWidth, requestedHeight,
viewVisibility, flags, frameNumber, outFrames,
mergedConfiguration, outSurfaceControl, outInsetsState,
- outActiveControls, outSurfaceSize, outBLASTSurfaceControl);
+ outActiveControls, outSurfaceSize);
if (res != 0) {
return res;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
new file mode 100644
index 0000000..10e5c3d
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 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.wm.shell.pip;
+
+import android.annotation.NonNull;
+import android.graphics.Rect;
+
+import java.io.PrintWriter;
+
+/**
+ * Singleton source of truth for the current state of PIP bounds.
+ */
+public final class PipBoundsState {
+ private static final String TAG = PipBoundsState.class.getSimpleName();
+
+ private final @NonNull Rect mBounds = new Rect();
+
+ void setBounds(@NonNull Rect bounds) {
+ mBounds.set(bounds);
+ }
+
+ @NonNull
+ public Rect getBounds() {
+ return new Rect(mBounds);
+ }
+
+ /**
+ * Dumps internal state.
+ */
+ public void dump(PrintWriter pw, String prefix) {
+ final String innerPrefix = prefix + " ";
+ pw.println(prefix + TAG);
+ pw.println(innerPrefix + "mBounds=" + mBounds);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 846da0a..15fd424 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -67,7 +67,6 @@
import com.android.wm.shell.pip.phone.PipMenuActivityController;
import com.android.wm.shell.pip.phone.PipMotionHelper;
import com.android.wm.shell.pip.phone.PipUpdateThread;
-import com.android.wm.shell.pip.phone.PipUtils;
import com.android.wm.shell.splitscreen.SplitScreen;
import java.io.PrintWriter;
@@ -134,11 +133,11 @@
private final Handler mMainHandler;
private final Handler mUpdateHandler;
+ private final PipBoundsState mPipBoundsState;
private final PipBoundsHandler mPipBoundsHandler;
private final PipAnimationController mPipAnimationController;
private final PipUiEventLogger mPipUiEventLoggerLogger;
private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>();
- private final Rect mLastReportedBounds = new Rect();
private final int mEnterExitAnimationDuration;
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
private final Map<IBinder, Configuration> mInitialState = new HashMap<>();
@@ -262,7 +261,8 @@
*/
private boolean mShouldIgnoreEnteringPipTransition;
- public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler,
+ public PipTaskOrganizer(Context context, @NonNull PipBoundsState pipBoundsState,
+ @NonNull PipBoundsHandler boundsHandler,
@NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
Optional<SplitScreen> splitScreenOptional,
@NonNull DisplayController displayController,
@@ -270,6 +270,7 @@
@NonNull ShellTaskOrganizer shellTaskOrganizer) {
mMainHandler = new Handler(Looper.getMainLooper());
mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks);
+ mPipBoundsState = pipBoundsState;
mPipBoundsHandler = boundsHandler;
mEnterExitAnimationDuration = context.getResources()
.getInteger(R.integer.config_pipResizeAnimationDuration);
@@ -279,30 +280,21 @@
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
mSplitScreenOptional = splitScreenOptional;
mTaskOrganizer = shellTaskOrganizer;
-
- if (!PipUtils.hasSystemFeature(context)) {
- Log.w(TAG, "Device not support PIP feature");
- } else {
- mTaskOrganizer.addListener(this, TASK_LISTENER_TYPE_PIP);
- displayController.addDisplayWindowListener(this);
- }
+ mTaskOrganizer.addListener(this, TASK_LISTENER_TYPE_PIP);
+ displayController.addDisplayWindowListener(this);
}
public Handler getUpdateHandler() {
return mUpdateHandler;
}
- public Rect getLastReportedBounds() {
- return new Rect(mLastReportedBounds);
- }
-
public Rect getCurrentOrAnimatingBounds() {
PipAnimationController.PipTransitionAnimator animator =
mPipAnimationController.getCurrentAnimator();
if (animator != null && animator.isRunning()) {
return new Rect(animator.getDestinationBounds());
}
- return getLastReportedBounds();
+ return mPipBoundsState.getBounds();
}
public boolean isInPip() {
@@ -347,7 +339,7 @@
* Expect {@link #onTaskAppeared(ActivityManager.RunningTaskInfo, SurfaceControl)} afterwards.
*/
public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
- mLastReportedBounds.set(destinationBounds);
+ mPipBoundsState.setBounds(destinationBounds);
}
/**
@@ -394,7 +386,7 @@
final SurfaceControl.Transaction tx =
mSurfaceControlTransactionFactory.getTransaction();
mSurfaceTransactionHelper.scale(tx, mLeash, destinationBounds,
- mLastReportedBounds);
+ mPipBoundsState.getBounds());
tx.setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height());
// We set to fullscreen here for now, but later it will be set to UNDEFINED for
// the proper windowing mode to take place. See #applyWindowingModeChangeOnExit.
@@ -408,9 +400,9 @@
@Override
public void onTransactionReady(int id, SurfaceControl.Transaction t) {
t.apply();
- scheduleAnimateResizePip(mLastReportedBounds, destinationBounds,
- getValidSourceHintRect(mTaskInfo, destinationBounds), direction,
- animationDurationMs, null /* updateBoundsCallback */);
+ scheduleAnimateResizePip(mPipBoundsState.getBounds(),
+ destinationBounds, getValidSourceHintRect(mTaskInfo, destinationBounds),
+ direction, animationDurationMs, null /* updateBoundsCallback */);
mState = State.EXITING_PIP;
}
});
@@ -441,7 +433,7 @@
// removePipImmediately is expected when the following animation finishes.
mUpdateHandler.post(() -> mPipAnimationController
- .getAnimator(mLeash, mLastReportedBounds, 1f, 0f)
+ .getAnimator(mLeash, mPipBoundsState.getBounds(), 1f, 0f)
.setTransitionDirection(TRANSITION_DIRECTION_REMOVE_STACK)
.setPipAnimationCallback(mPipAnimationCallback)
.setDuration(mEnterExitAnimationDuration)
@@ -480,7 +472,7 @@
if (mShouldIgnoreEnteringPipTransition) {
// Animation has been finished together with Recents, directly apply the sync
// transaction to PiP here.
- applyEnterPipSyncTransaction(mLastReportedBounds, () -> {
+ applyEnterPipSyncTransaction(mPipBoundsState.getBounds(), () -> {
mState = State.ENTERED_PIP;
});
mShouldIgnoreEnteringPipTransition = false;
@@ -572,7 +564,7 @@
private void sendOnPipTransitionStarted(
@PipAnimationController.TransitionDirection int direction) {
- final Rect pipBounds = new Rect(mLastReportedBounds);
+ final Rect pipBounds = mPipBoundsState.getBounds();
runOnMainHandler(() -> {
for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
@@ -701,7 +693,7 @@
}
final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
info.topActivity, getAspectRatioOrDefault(newParams),
- mLastReportedBounds, getMinimalSize(info.topActivityInfo),
+ mPipBoundsState.getBounds(), getMinimalSize(info.topActivityInfo),
true /* userCurrentMinEdgeSize */);
Objects.requireNonNull(destinationBounds, "Missing destination bounds");
scheduleAnimateResizePip(destinationBounds, mEnterExitAnimationDuration,
@@ -759,7 +751,7 @@
sendOnPipTransitionCancelled(direction);
sendOnPipTransitionFinished(direction);
}
- mLastReportedBounds.set(destinationBoundsOut);
+ mPipBoundsState.setBounds(destinationBoundsOut);
// Create a reset surface transaction for the new bounds and update the window
// container transaction
@@ -774,8 +766,8 @@
destinationBoundsOut.set(animator.getDestinationBounds());
}
} else {
- if (!mLastReportedBounds.isEmpty()) {
- destinationBoundsOut.set(mLastReportedBounds);
+ if (!mPipBoundsState.getBounds().isEmpty()) {
+ destinationBoundsOut.set(mPipBoundsState.getBounds());
}
}
}
@@ -827,7 +819,7 @@
Log.d(TAG, "skip scheduleAnimateResizePip, entering pip deferred");
return;
}
- scheduleAnimateResizePip(mLastReportedBounds, toBounds, null /* sourceHintRect */,
+ scheduleAnimateResizePip(mPipBoundsState.getBounds(), toBounds, null /* sourceHintRect */,
TRANSITION_DIRECTION_NONE, duration, updateBoundsCallback);
}
@@ -963,7 +955,7 @@
Log.w(TAG, "Abort animation, invalid leash");
return;
}
- mLastReportedBounds.set(destinationBounds);
+ mPipBoundsState.setBounds(destinationBounds);
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
mSurfaceTransactionHelper
.crop(tx, mLeash, destinationBounds)
@@ -999,7 +991,7 @@
throw new RuntimeException("Callers should call scheduleResizePip() instead of this "
+ "directly");
}
- mLastReportedBounds.set(destinationBounds);
+ mPipBoundsState.setBounds(destinationBounds);
if (direction == TRANSITION_DIRECTION_REMOVE_STACK) {
removePipImmediately();
return;
@@ -1141,7 +1133,6 @@
pw.println(innerPrefix + "mState=" + mState);
pw.println(innerPrefix + "mOneShotAnimationType=" + mOneShotAnimationType);
pw.println(innerPrefix + "mPictureInPictureParams=" + mPictureInPictureParams);
- pw.println(innerPrefix + "mLastReportedBounds=" + mLastReportedBounds);
pw.println(innerPrefix + "mInitialState:");
for (Map.Entry<IBinder, Configuration> e : mInitialState.entrySet()) {
pw.println(innerPrefix + " binder=" + e.getKey()
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
index fddd547..18b6922 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
@@ -15,6 +15,7 @@
*/
package com.android.wm.shell.pip.phone;
+import android.annotation.NonNull;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.Region;
@@ -28,6 +29,7 @@
import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
import com.android.wm.shell.R;
+import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipSnapAlgorithm;
import com.android.wm.shell.pip.PipTaskOrganizer;
@@ -50,6 +52,7 @@
private Context mContext;
private Handler mHandler;
+ private final @NonNull PipBoundsState mPipBoundsState;
private PipMotionHelper mMotionHelper;
private PipTaskOrganizer mTaskOrganizer;
private PipSnapAlgorithm mSnapAlgorithm;
@@ -62,12 +65,14 @@
private final Rect mExpandedMovementBounds = new Rect();
private Rect mTmpBounds = new Rect();
- public PipAccessibilityInteractionConnection(Context context, PipMotionHelper motionHelper,
+ public PipAccessibilityInteractionConnection(Context context,
+ @NonNull PipBoundsState pipBoundsState, PipMotionHelper motionHelper,
PipTaskOrganizer taskOrganizer, PipSnapAlgorithm snapAlgorithm,
AccessibilityCallbacks callbacks, Runnable updateMovementBoundCallback,
Handler handler) {
mContext = context;
mHandler = handler;
+ mPipBoundsState = pipBoundsState;
mMotionHelper = motionHelper;
mTaskOrganizer = taskOrganizer;
mSnapAlgorithm = snapAlgorithm;
@@ -148,7 +153,7 @@
private void setToExpandedBounds() {
float savedSnapFraction = mSnapAlgorithm.getSnapFraction(
- new Rect(mTaskOrganizer.getLastReportedBounds()), mNormalMovementBounds);
+ mPipBoundsState.getBounds(), mNormalMovementBounds);
mSnapAlgorithm.applySnapFraction(mExpandedBounds, mExpandedMovementBounds,
savedSnapFraction);
mTaskOrganizer.scheduleFinishResizePip(mExpandedBounds, (Rect bounds) -> {
@@ -159,7 +164,7 @@
private void setToNormalBounds() {
float savedSnapFraction = mSnapAlgorithm.getSnapFraction(
- new Rect(mTaskOrganizer.getLastReportedBounds()), mExpandedMovementBounds);
+ mPipBoundsState.getBounds(), mExpandedMovementBounds);
mSnapAlgorithm.applySnapFraction(mNormalBounds, mNormalMovementBounds, savedSnapFraction);
mTaskOrganizer.scheduleFinishResizePip(mNormalBounds, (Rect bounds) -> {
mMotionHelper.synchronizePinnedStackBounds();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index ea9c960..13f5ac3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -17,10 +17,10 @@
package com.android.wm.shell.pip.phone;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
-import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.PictureInPictureParams;
import android.app.RemoteAction;
@@ -33,17 +33,21 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
-import android.util.Log;
+import android.util.Slog;
import android.view.DisplayInfo;
import android.view.IPinnedStackController;
import android.window.WindowContainerTransaction;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.pip.PinnedStackListenerForwarder;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipTaskOrganizer;
import java.io.PrintWriter;
@@ -61,10 +65,12 @@
private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
private final Rect mTmpInsetBounds = new Rect();
private final Rect mTmpNormalBounds = new Rect();
+ protected final Rect mReentryBounds = new Rect();
private DisplayController mDisplayController;
private PipAppOpsListener mAppOpsListener;
private PipBoundsHandler mPipBoundsHandler;
+ private @NonNull PipBoundsState mPipBoundsState;
private PipMediaController mMediaController;
private PipTouchHandler mTouchHandler;
private Consumer<Boolean> mPinnedStackAnimationRecentsCallback;
@@ -97,7 +103,7 @@
// If the pip was in the offset zone earlier, adjust the new bounds to the bottom of the
// movement bounds
mTouchHandler.adjustBoundsForRotation(mTmpNormalBounds,
- mPipTaskOrganizer.getLastReportedBounds(), mTmpInsetBounds);
+ mPipBoundsState.getBounds(), mTmpInsetBounds);
// The bounds are being applied to a specific snap fraction, so reset any known offsets
// for the previous orientation before updating the movement bounds.
@@ -192,46 +198,28 @@
}
}
- public PipController(Context context,
+ protected PipController(Context context,
DisplayController displayController,
PipAppOpsListener pipAppOpsListener,
PipBoundsHandler pipBoundsHandler,
+ @NonNull PipBoundsState pipBoundsState,
PipMediaController pipMediaController,
PipMenuActivityController pipMenuActivityController,
PipTaskOrganizer pipTaskOrganizer,
PipTouchHandler pipTouchHandler,
WindowManagerShellWrapper windowManagerShellWrapper
) {
- mContext = context;
-
- if (PipUtils.hasSystemFeature(mContext)) {
- initController(context, displayController, pipAppOpsListener, pipBoundsHandler,
- pipMediaController, pipMenuActivityController, pipTaskOrganizer,
- pipTouchHandler, windowManagerShellWrapper);
- } else {
- Log.w(TAG, "Device not support PIP feature");
- }
- }
-
- private void initController(Context context,
- DisplayController displayController,
- PipAppOpsListener pipAppOpsListener,
- PipBoundsHandler pipBoundsHandler,
- PipMediaController pipMediaController,
- PipMenuActivityController pipMenuActivityController,
- PipTaskOrganizer pipTaskOrganizer,
- PipTouchHandler pipTouchHandler,
- WindowManagerShellWrapper windowManagerShellWrapper) {
-
// Ensure that we are the primary user's SystemUI.
final int processUser = UserManager.get(context).getUserHandle();
if (processUser != UserHandle.USER_SYSTEM) {
throw new IllegalStateException("Non-primary Pip component not currently supported.");
}
+ mContext = context;
mWindowManagerShellWrapper = windowManagerShellWrapper;
mDisplayController = displayController;
mPipBoundsHandler = pipBoundsHandler;
+ mPipBoundsState = pipBoundsState;
mPipTaskOrganizer = pipTaskOrganizer;
mPipTaskOrganizer.registerPipTransitionCallback(this);
mMediaController = pipMediaController;
@@ -251,7 +239,7 @@
mWindowManagerShellWrapper.addPinnedStackListener(
new PipControllerPinnedStackListener());
} catch (RemoteException e) {
- Log.e(TAG, "Failed to register pinned stack listener", e);
+ Slog.e(TAG, "Failed to register pinned stack listener", e);
}
}
@@ -360,7 +348,7 @@
final boolean changed = mPipBoundsHandler.setShelfHeight(visible, shelfHeight);
if (changed) {
mTouchHandler.onShelfVisibilityChanged(visible, shelfHeight);
- updateMovementBounds(mPipTaskOrganizer.getLastReportedBounds(),
+ updateMovementBounds(mPipBoundsState.getBounds(),
false /* fromRotation */, false /* fromImeAdjustment */,
true /* fromShelfAdjustment */, null /* windowContainerTransaction */);
}
@@ -395,7 +383,8 @@
public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) {
if (isOutPipDirection(direction)) {
// Exiting PIP, save the reentry bounds to restore to when re-entering.
- mPipBoundsHandler.onSaveReentryBounds(activity, pipBounds);
+ updateReentryBounds(pipBounds);
+ mPipBoundsHandler.onSaveReentryBounds(activity, mReentryBounds);
}
// Disable touches while the animation is running
mTouchHandler.setTouchEnabled(false);
@@ -404,6 +393,16 @@
}
}
+ /**
+ * Update the bounds used to save the re-entry size and snap fraction when exiting PIP.
+ */
+ public void updateReentryBounds(Rect bounds) {
+ final Rect reentryBounds = mTouchHandler.getUserResizeBounds();
+ float snapFraction = mPipBoundsHandler.getSnapFraction(bounds);
+ mPipBoundsHandler.applySnapFraction(reentryBounds, snapFraction);
+ mReentryBounds.set(reentryBounds);
+ }
+
@Override
public void onPipTransitionFinished(ComponentName activity, int direction) {
onPipTransitionFinishedOrCanceled(direction);
@@ -445,5 +444,26 @@
mTouchHandler.dump(pw, innerPrefix);
mPipBoundsHandler.dump(pw, innerPrefix);
mPipTaskOrganizer.dump(pw, innerPrefix);
+ mPipBoundsState.dump(pw, innerPrefix);
+ }
+
+ /**
+ * Instantiates {@link PipController}, returns {@code null} if the feature not supported.
+ */
+ @Nullable
+ public static PipController create(Context context, DisplayController displayController,
+ PipAppOpsListener pipAppOpsListener, PipBoundsHandler pipBoundsHandler,
+ PipBoundsState pipBoundsState, PipMediaController pipMediaController,
+ PipMenuActivityController pipMenuActivityController,
+ PipTaskOrganizer pipTaskOrganizer, PipTouchHandler pipTouchHandler,
+ WindowManagerShellWrapper windowManagerShellWrapper) {
+ if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
+ Slog.w(TAG, "Device doesn't support Pip feature");
+ return null;
+ }
+
+ return new PipController(context, displayController, pipAppOpsListener, pipBoundsHandler,
+ pipBoundsState, pipMediaController, pipMenuActivityController,
+ pipTaskOrganizer, pipTouchHandler, windowManagerShellWrapper);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index fe1d44c7..b5fa030 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -37,6 +37,7 @@
import com.android.wm.shell.animation.PhysicsAnimator;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
+import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipSnapAlgorithm;
import com.android.wm.shell.pip.PipTaskOrganizer;
@@ -66,6 +67,7 @@
private final Context mContext;
private final PipTaskOrganizer mPipTaskOrganizer;
+ private final @NonNull PipBoundsState mPipBoundsState;
private PipMenuActivityController mMenuController;
private PipSnapAlgorithm mSnapAlgorithm;
@@ -178,11 +180,12 @@
public void onPipTransitionCanceled(ComponentName activity, int direction) {}
};
- public PipMotionHelper(Context context, PipTaskOrganizer pipTaskOrganizer,
- PipMenuActivityController menuController, PipSnapAlgorithm snapAlgorithm,
- FloatingContentCoordinator floatingContentCoordinator) {
+ public PipMotionHelper(Context context, @NonNull PipBoundsState pipBoundsState,
+ PipTaskOrganizer pipTaskOrganizer, PipMenuActivityController menuController,
+ PipSnapAlgorithm snapAlgorithm, FloatingContentCoordinator floatingContentCoordinator) {
mContext = context;
mPipTaskOrganizer = pipTaskOrganizer;
+ mPipBoundsState = pipBoundsState;
mMenuController = menuController;
mSnapAlgorithm = snapAlgorithm;
mFloatingContentCoordinator = floatingContentCoordinator;
@@ -220,7 +223,7 @@
*/
void synchronizePinnedStackBounds() {
cancelAnimations();
- mBounds.set(mPipTaskOrganizer.getLastReportedBounds());
+ mBounds.set(mPipBoundsState.getBounds());
mTemporaryBounds.setEmpty();
if (mPipTaskOrganizer.isInPip()) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 07beb43..a2233e5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -22,6 +22,7 @@
import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_FULL;
import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_NONE;
+import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Context;
@@ -48,6 +49,7 @@
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipUiEventLogger;
@@ -70,6 +72,7 @@
private final boolean mEnableResize;
private final Context mContext;
private final PipBoundsHandler mPipBoundsHandler;
+ private final @NonNull PipBoundsState mPipBoundsState;
private final PipUiEventLogger mPipUiEventLogger;
private final PipDismissTargetHandler mPipDismissTargetHandler;
@@ -161,6 +164,7 @@
public PipTouchHandler(Context context,
PipMenuActivityController menuController,
PipBoundsHandler pipBoundsHandler,
+ @NonNull PipBoundsState pipBoundsState,
PipTaskOrganizer pipTaskOrganizer,
FloatingContentCoordinator floatingContentCoordinator,
PipUiEventLogger pipUiEventLogger) {
@@ -168,11 +172,12 @@
mContext = context;
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
mPipBoundsHandler = pipBoundsHandler;
+ mPipBoundsState = pipBoundsState;
mMenuController = menuController;
mMenuController.addListener(new PipMenuListener());
mGesture = new DefaultPipTouchGesture();
- mMotionHelper = new PipMotionHelper(mContext, pipTaskOrganizer, mMenuController,
- mPipBoundsHandler.getSnapAlgorithm(), floatingContentCoordinator);
+ mMotionHelper = new PipMotionHelper(mContext, pipBoundsState, pipTaskOrganizer,
+ mMenuController, mPipBoundsHandler.getSnapAlgorithm(), floatingContentCoordinator);
mPipResizeGestureHandler =
new PipResizeGestureHandler(context, pipBoundsHandler, mMotionHelper,
pipTaskOrganizer, this::getMovementBounds,
@@ -189,8 +194,8 @@
reloadResources();
mFloatingContentCoordinator = floatingContentCoordinator;
- mConnection = new PipAccessibilityInteractionConnection(mContext, mMotionHelper,
- pipTaskOrganizer, mPipBoundsHandler.getSnapAlgorithm(),
+ mConnection = new PipAccessibilityInteractionConnection(mContext, pipBoundsState,
+ mMotionHelper, pipTaskOrganizer, mPipBoundsHandler.getSnapAlgorithm(),
this::onAccessibilityShowMenu, this::updateMovementBounds, mHandler);
mPipUiEventLogger = pipUiEventLogger;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipUtils.java
index 6a58ce0..bd2ba32 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipUtils.java
@@ -18,7 +18,6 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import android.app.ActivityTaskManager;
import android.app.ActivityTaskManager.RootTaskInfo;
@@ -30,7 +29,6 @@
import android.util.Pair;
public class PipUtils {
-
private static final String TAG = "PipUtils";
/**
@@ -58,14 +56,4 @@
}
return new Pair<>(null, 0);
}
-
- /**
- * The util to check if device has PIP feature
- *
- * @param context application context
- * @return true if device has PIP feature, false otherwise.
- */
- public static boolean hasSystemFeature(Context context) {
- return context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
index a0ce9da..f3dadfc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -26,7 +26,7 @@
public enum ShellProtoLogGroup implements IProtoLogGroup {
// NOTE: Since we enable these from the same WM ShellCommand, these names should not conflict
// with those in the framework ProtoLogGroup
- WM_SHELL_TASK_ORG(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ WM_SHELL_TASK_ORG(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
Consts.TAG_WM_SHELL),
WM_SHELL_TRANSITIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
Consts.TAG_WM_SHELL),
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
index f01fc51..5418a5b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
@@ -22,6 +22,10 @@
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_MULTI_WINDOW;
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_PIP;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
@@ -29,10 +33,12 @@
import static org.mockito.Mockito.verify;
import android.app.ActivityManager.RunningTaskInfo;
+import android.content.pm.ParceledListSlice;
import android.os.RemoteException;
import android.view.SurfaceControl;
import android.window.ITaskOrganizer;
import android.window.ITaskOrganizerController;
+import android.window.TaskAppearedInfo;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -93,8 +99,12 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mOrganizer = new ShellTaskOrganizer(mTaskOrganizerController, mSyncTransactionQueue,
- mTransactionPool, mTestExecutor, mTestExecutor);
+ try {
+ doReturn(ParceledListSlice.<TaskAppearedInfo>emptyList())
+ .when(mTaskOrganizerController).registerTaskOrganizer(any());
+ } catch (RemoteException e) {}
+ mOrganizer = spy(new ShellTaskOrganizer(mTaskOrganizerController, mSyncTransactionQueue,
+ mTransactionPool, mTestExecutor, mTestExecutor));
}
@Test
@@ -116,8 +126,29 @@
}
@Test
+ public void testRegisterWithExistingTasks() throws RemoteException {
+ // Setup some tasks
+ RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW);
+ RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_MULTI_WINDOW);
+ ArrayList<TaskAppearedInfo> taskInfos = new ArrayList<>();
+ taskInfos.add(new TaskAppearedInfo(task1, new SurfaceControl()));
+ taskInfos.add(new TaskAppearedInfo(task2, new SurfaceControl()));
+ doReturn(new ParceledListSlice(taskInfos))
+ .when(mTaskOrganizerController).registerTaskOrganizer(any());
+
+ // Register and expect the tasks to be stored
+ mOrganizer.registerOrganizer();
+
+ // Check that the tasks are next reported when the listener is added
+ TrackingTaskListener listener = new TrackingTaskListener();
+ mOrganizer.addListener(listener, TASK_LISTENER_TYPE_MULTI_WINDOW);
+ assertTrue(listener.appeared.contains(task1));
+ assertTrue(listener.appeared.contains(task2));
+ }
+
+ @Test
public void testAppearedVanished() {
- RunningTaskInfo taskInfo = createTaskInfo(WINDOWING_MODE_MULTI_WINDOW);
+ RunningTaskInfo taskInfo = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW);
TrackingTaskListener listener = new TrackingTaskListener();
mOrganizer.addListener(listener, TASK_LISTENER_TYPE_MULTI_WINDOW);
mOrganizer.onTaskAppeared(taskInfo, null);
@@ -129,7 +160,7 @@
@Test
public void testAddListenerExistingTasks() {
- RunningTaskInfo taskInfo = createTaskInfo(WINDOWING_MODE_MULTI_WINDOW);
+ RunningTaskInfo taskInfo = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW);
mOrganizer.onTaskAppeared(taskInfo, null);
TrackingTaskListener listener = new TrackingTaskListener();
@@ -139,7 +170,7 @@
@Test
public void testWindowingModeChange() {
- RunningTaskInfo taskInfo = createTaskInfo(WINDOWING_MODE_MULTI_WINDOW);
+ RunningTaskInfo taskInfo = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW);
TrackingTaskListener mwListener = new TrackingTaskListener();
TrackingTaskListener pipListener = new TrackingTaskListener();
mOrganizer.addListener(mwListener, TASK_LISTENER_TYPE_MULTI_WINDOW);
@@ -148,14 +179,15 @@
assertTrue(mwListener.appeared.contains(taskInfo));
assertTrue(pipListener.appeared.isEmpty());
- taskInfo = createTaskInfo(WINDOWING_MODE_PINNED);
+ taskInfo = createTaskInfo(1, WINDOWING_MODE_PINNED);
mOrganizer.onTaskInfoChanged(taskInfo);
assertTrue(mwListener.vanished.contains(taskInfo));
assertTrue(pipListener.appeared.contains(taskInfo));
}
- private RunningTaskInfo createTaskInfo(int windowingMode) {
+ private RunningTaskInfo createTaskInfo(int taskId, int windowingMode) {
RunningTaskInfo taskInfo = new RunningTaskInfo();
+ taskInfo.taskId = taskId;
taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
return taskInfo;
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 92f03e1..a282a48 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -18,28 +18,26 @@
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
+import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.Context;
import android.content.pm.PackageManager;
import android.os.RemoteException;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableContext;
import android.testing.TestableLooper;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTestCase;
-import com.android.wm.shell.pip.phone.PipAppOpsListener;
-import com.android.wm.shell.pip.phone.PipController;
-import com.android.wm.shell.pip.phone.PipMediaController;
-import com.android.wm.shell.pip.phone.PipTouchHandler;
import org.junit.Before;
import org.junit.Test;
@@ -54,47 +52,52 @@
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class PipControllerTest extends PipTestCase {
- private com.android.wm.shell.pip.phone.PipController mPipController;
- private TestableContext mSpiedContext;
+ private PipController mPipController;
- @Mock private DisplayController mMockdDisplayController;
- @Mock private PackageManager mPackageManager;
- @Mock private com.android.wm.shell.pip.phone.PipMenuActivityController
- mMockPipMenuActivityController;
+ @Mock private DisplayController mMockDisplayController;
+ @Mock private PipMenuActivityController mMockPipMenuActivityController;
@Mock private PipAppOpsListener mMockPipAppOpsListener;
@Mock private PipBoundsHandler mMockPipBoundsHandler;
@Mock private PipMediaController mMockPipMediaController;
@Mock private PipTaskOrganizer mMockPipTaskOrganizer;
@Mock private PipTouchHandler mMockPipTouchHandler;
@Mock private WindowManagerShellWrapper mMockWindowManagerShellWrapper;
+ @Mock private PipBoundsState mMockPipBoundsState;
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
-
- mSpiedContext = spy(mContext);
-
- when(mPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)).thenReturn(false);
- when(mSpiedContext.getPackageManager()).thenReturn(mPackageManager);
-
- mPipController = new PipController(mSpiedContext, mMockdDisplayController,
- mMockPipAppOpsListener, mMockPipBoundsHandler, mMockPipMediaController,
- mMockPipMenuActivityController, mMockPipTaskOrganizer, mMockPipTouchHandler,
- mMockWindowManagerShellWrapper);
+ mPipController = new PipController(mContext, mMockDisplayController,
+ mMockPipAppOpsListener, mMockPipBoundsHandler, mMockPipBoundsState,
+ mMockPipMediaController, mMockPipMenuActivityController, mMockPipTaskOrganizer,
+ mMockPipTouchHandler, mMockWindowManagerShellWrapper);
}
@Test
- public void testNonPipDevice_shouldNotRegisterPipTransitionCallback() {
- verify(mMockPipTaskOrganizer, never()).registerPipTransitionCallback(any());
+ public void instantiatePipController_registersPipTransitionCallback() {
+ verify(mMockPipTaskOrganizer).registerPipTransitionCallback(any());
}
@Test
- public void testNonPipDevice_shouldNotAddDisplayChangingController() {
- verify(mMockdDisplayController, never()).addDisplayChangingController(any());
+ public void instantiatePipController_addsDisplayChangingController() {
+ verify(mMockDisplayController).addDisplayChangingController(any());
}
@Test
- public void testNonPipDevice_shouldNotAddDisplayWindowListener() {
- verify(mMockdDisplayController, never()).addDisplayWindowListener(any());
+ public void instantiatePipController_addsDisplayWindowListener() {
+ verify(mMockDisplayController).addDisplayWindowListener(any());
+ }
+
+ @Test
+ public void createPip_notSupported_returnsNull() {
+ Context spyContext = spy(mContext);
+ PackageManager mockPackageManager = mock(PackageManager.class);
+ when(mockPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)).thenReturn(false);
+ when(spyContext.getPackageManager()).thenReturn(mockPackageManager);
+
+ assertNull(PipController.create(spyContext, mMockDisplayController,
+ mMockPipAppOpsListener, mMockPipBoundsHandler, mMockPipBoundsState,
+ mMockPipMediaController, mMockPipMenuActivityController, mMockPipTaskOrganizer,
+ mMockPipTouchHandler, mMockWindowManagerShellWrapper));
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTaskOrganizerTest.java
index c66ba13..46ebbf3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTaskOrganizerTest.java
@@ -16,25 +16,19 @@
package com.android.wm.shell.pip.phone;
-import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
-
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import android.content.pm.PackageManager;
import android.os.RemoteException;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableContext;
import android.testing.TestableLooper;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTestCase;
@@ -57,37 +51,30 @@
@TestableLooper.RunWithLooper
public class PipTaskOrganizerTest extends PipTestCase {
private PipTaskOrganizer mSpiedPipTaskOrganizer;
- private TestableContext mSpiedContext;
@Mock private DisplayController mMockdDisplayController;
- @Mock private PackageManager mPackageManager;
@Mock private PipBoundsHandler mMockPipBoundsHandler;
@Mock private PipSurfaceTransactionHelper mMockPipSurfaceTransactionHelper;
@Mock private PipUiEventLogger mMockPipUiEventLogger;
@Mock private Optional<SplitScreen> mMockOptionalSplitScreen;
@Mock private ShellTaskOrganizer mMockShellTaskOrganizer;
+ @Mock private PipBoundsState mMockPipBoundsState;
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
-
- mSpiedContext = spy(mContext);
-
- when(mPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)).thenReturn(false);
- when(mSpiedContext.getPackageManager()).thenReturn(mPackageManager);
-
- mSpiedPipTaskOrganizer = spy(new PipTaskOrganizer(mSpiedContext, mMockPipBoundsHandler,
- mMockPipSurfaceTransactionHelper, mMockOptionalSplitScreen, mMockdDisplayController,
- mMockPipUiEventLogger, mMockShellTaskOrganizer));
+ mSpiedPipTaskOrganizer = new PipTaskOrganizer(mContext, mMockPipBoundsState,
+ mMockPipBoundsHandler, mMockPipSurfaceTransactionHelper, mMockOptionalSplitScreen,
+ mMockdDisplayController, mMockPipUiEventLogger, mMockShellTaskOrganizer);
}
@Test
- public void testNonPipDevice_shellTaskOrganizer_shouldNotAddListener() {
- verify(mMockShellTaskOrganizer, never()).addListener(any(), anyInt());
+ public void instantiatePipTaskOrganizer_addsTaskListener() {
+ verify(mMockShellTaskOrganizer).addListener(any(), anyInt());
}
@Test
- public void testNonPipDevice_displayController_shouldNotAddDisplayWindowListener() {
- verify(mMockdDisplayController, never()).addDisplayWindowListener(any());
+ public void instantiatePipTaskOrganizer_addsDisplayWindowListener() {
+ verify(mMockdDisplayController).addDisplayWindowListener(any());
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
index 93a45c4..4713142 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
@@ -33,6 +33,7 @@
import com.android.wm.shell.R;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipSnapAlgorithm;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTestCase;
@@ -74,6 +75,7 @@
@Mock
private PipUiEventLogger mPipUiEventLogger;
+ private PipBoundsState mPipBoundsState;
private PipBoundsHandler mPipBoundsHandler;
private PipSnapAlgorithm mPipSnapAlgorithm;
private PipMotionHelper mMotionHelper;
@@ -90,11 +92,12 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mPipBoundsState = new PipBoundsState();
mPipBoundsHandler = new PipBoundsHandler(mContext);
mPipSnapAlgorithm = mPipBoundsHandler.getSnapAlgorithm();
mPipSnapAlgorithm = new PipSnapAlgorithm(mContext);
mPipTouchHandler = new PipTouchHandler(mContext, mPipMenuActivityController,
- mPipBoundsHandler, mPipTaskOrganizer, mFloatingContentCoordinator,
+ mPipBoundsHandler, mPipBoundsState, mPipTaskOrganizer, mFloatingContentCoordinator,
mPipUiEventLogger);
mMotionHelper = Mockito.spy(mPipTouchHandler.getMotionHelper());
mPipResizeGestureHandler = Mockito.spy(mPipTouchHandler.getPipResizeGestureHandler());
diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp
index 30ce537..fd18d2f 100644
--- a/libs/hwui/FrameInfo.cpp
+++ b/libs/hwui/FrameInfo.cpp
@@ -31,6 +31,7 @@
"AnimationStart",
"PerformTraversalsStart",
"DrawStart",
+ "FrameDeadline",
"SyncQueued",
"SyncStart",
"IssueDrawCommandsStart",
@@ -45,7 +46,7 @@
static_cast<int>(FrameInfoIndex::NumIndexes),
"size mismatch: FrameInfoNames doesn't match the enum!");
-static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 18,
+static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 19,
"Must update value in FrameMetrics.java#FRAME_STATS_COUNT (and here)");
void FrameInfo::importUiThreadInfo(int64_t* info) {
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
index f5bfedd..d24eca7 100644
--- a/libs/hwui/FrameInfo.h
+++ b/libs/hwui/FrameInfo.h
@@ -27,7 +27,7 @@
namespace android {
namespace uirenderer {
-#define UI_THREAD_FRAME_INFO_SIZE 10
+#define UI_THREAD_FRAME_INFO_SIZE 11
enum class FrameInfoIndex {
Flags = 0,
@@ -40,6 +40,7 @@
AnimationStart,
PerformTraversalsStart,
DrawStart,
+ FrameDeadline,
// End of UI frame info
SyncQueued,
@@ -77,9 +78,11 @@
explicit UiFrameInfoBuilder(int64_t* buffer) : mBuffer(buffer) {
memset(mBuffer, 0, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
set(FrameInfoIndex::FrameTimelineVsyncId) = INVALID_VSYNC_ID;
+ set(FrameInfoIndex::FrameDeadline) = std::numeric_limits<int64_t>::max();
}
- UiFrameInfoBuilder& setVsync(nsecs_t vsyncTime, nsecs_t intendedVsync, int64_t vsyncId) {
+ UiFrameInfoBuilder& setVsync(nsecs_t vsyncTime, nsecs_t intendedVsync,
+ int64_t vsyncId, int64_t frameDeadline) {
set(FrameInfoIndex::FrameTimelineVsyncId) = vsyncId;
set(FrameInfoIndex::Vsync) = vsyncTime;
set(FrameInfoIndex::IntendedVsync) = intendedVsync;
@@ -89,6 +92,7 @@
set(FrameInfoIndex::AnimationStart) = vsyncTime;
set(FrameInfoIndex::PerformTraversalsStart) = vsyncTime;
set(FrameInfoIndex::DrawStart) = vsyncTime;
+ set(FrameInfoIndex::FrameDeadline) = frameDeadline;
return *this;
}
diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp
index b802908..5f6b53a 100644
--- a/libs/hwui/hwui/MinikinUtils.cpp
+++ b/libs/hwui/hwui/MinikinUtils.cpp
@@ -21,7 +21,6 @@
#include <log/log.h>
#include <minikin/MeasuredText.h>
-#include <minikin/Measurement.h>
#include "Paint.h"
#include "SkPathMeasure.h"
#include "Typeface.h"
@@ -70,18 +69,6 @@
}
}
-void MinikinUtils::getBounds(const Paint* paint, minikin::Bidi bidiFlags, const Typeface* typeface,
- const uint16_t* buf, size_t bufSize, minikin::MinikinRect* out) {
- minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
-
- const minikin::U16StringPiece textBuf(buf, bufSize);
- const minikin::StartHyphenEdit startHyphen = paint->getStartHyphenEdit();
- const minikin::EndHyphenEdit endHyphen = paint->getEndHyphenEdit();
-
- minikin::getBounds(textBuf, minikin::Range(0, textBuf.size()), bidiFlags, minikinPaint,
- startHyphen, endHyphen, out);
-}
-
float MinikinUtils::measureText(const Paint* paint, minikin::Bidi bidiFlags,
const Typeface* typeface, const uint16_t* buf, size_t start,
size_t count, size_t bufSize, float* advances) {
diff --git a/libs/hwui/hwui/MinikinUtils.h b/libs/hwui/hwui/MinikinUtils.h
index a15803a..7c3f0d8 100644
--- a/libs/hwui/hwui/MinikinUtils.h
+++ b/libs/hwui/hwui/MinikinUtils.h
@@ -48,9 +48,6 @@
size_t contextStart, size_t contextCount,
minikin::MeasuredText* mt);
- static void getBounds(const Paint* paint, minikin::Bidi bidiFlags, const Typeface* typeface,
- const uint16_t* buf, size_t bufSize, minikin::MinikinRect* out);
-
static float measureText(const Paint* paint, minikin::Bidi bidiFlags,
const Typeface* typeface, const uint16_t* buf,
size_t start, size_t count, size_t bufSize,
diff --git a/libs/hwui/jni/Paint.cpp b/libs/hwui/jni/Paint.cpp
index 3c86b28..89ff9b2 100644
--- a/libs/hwui/jni/Paint.cpp
+++ b/libs/hwui/jni/Paint.cpp
@@ -339,13 +339,18 @@
}
static void doTextBounds(JNIEnv* env, const jchar* text, int count, jobject bounds,
- const Paint& paint, const Typeface* typeface, jint bidiFlagsInt) {
+ const Paint& paint, const Typeface* typeface, jint bidiFlags) {
SkRect r;
SkIRect ir;
+ minikin::Layout layout = MinikinUtils::doLayout(&paint,
+ static_cast<minikin::Bidi>(bidiFlags), typeface,
+ text, count, // text buffer
+ 0, count, // draw range
+ 0, count, // context range
+ nullptr);
minikin::MinikinRect rect;
- minikin::Bidi bidiFlags = static_cast<minikin::Bidi>(bidiFlagsInt);
- MinikinUtils::getBounds(&paint, bidiFlags, typeface, text, count, &rect);
+ layout.getBounds(&rect);
r.fLeft = rect.mLeft;
r.fTop = rect.mTop;
r.fRight = rect.mRight;
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index c89463b..a146b64 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -514,7 +514,8 @@
proxy.setLightGeometry((Vector3){0, 0, 0}, 0);
nsecs_t vsync = systemTime(SYSTEM_TIME_MONOTONIC);
UiFrameInfoBuilder(proxy.frameInfo())
- .setVsync(vsync, vsync, UiFrameInfoBuilder::INVALID_VSYNC_ID)
+ .setVsync(vsync, vsync, UiFrameInfoBuilder::INVALID_VSYNC_ID,
+ std::numeric_limits<int64_t>::max())
.addFlag(FrameInfoFlags::SurfaceCanvas);
proxy.syncAndDrawFrame();
}
diff --git a/libs/hwui/jni/fonts/Font.cpp b/libs/hwui/jni/fonts/Font.cpp
index 6bc318d..aeb096d 100644
--- a/libs/hwui/jni/fonts/Font.cpp
+++ b/libs/hwui/jni/fonts/Font.cpp
@@ -221,6 +221,17 @@
return (static_cast<uint64_t>(var.axisTag) << 32) | static_cast<uint64_t>(floatBinary);
}
+// FastNative
+static jstring Font_getFontPath(JNIEnv* env, jobject, jlong fontHandle) {
+ const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
+ MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->typeface().get());
+ const std::string& filePath = minikinSkia->getFilePath();
+ if (filePath.empty()) {
+ return nullptr;
+ }
+ return env->NewStringUTF(filePath.c_str());
+}
+
// Critical Native
static jlong Font_getNativeFontPtr(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
@@ -274,6 +285,7 @@
{ "nGetFontMetrics", "(JJLandroid/graphics/Paint$FontMetrics;)F", (void*) Font_getFontMetrics },
{ "nGetFontInfo", "(J)J", (void*) Font_getFontInfo },
{ "nGetAxisInfo", "(JI)J", (void*) Font_getAxisInfo },
+ { "nGetFontPath", "(J)Ljava/lang/String;", (void*) Font_getFontPath },
{ "nGetNativeFontPtr", "(J)J", (void*) Font_getNativeFontPtr },
};
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 212a428..ad6363b 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -29,7 +29,7 @@
#include <SkSurface.h>
#include <SkTypes.h>
-#include <GrContext.h>
+#include <GrDirectContext.h>
#include <GrTypes.h>
#include <vk/GrVkTypes.h>
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 0435981..1ac9922 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -629,10 +629,11 @@
nsecs_t vsync = mRenderThread.timeLord().computeFrameTimeNanos();
int64_t vsyncId = mRenderThread.timeLord().lastVsyncId();
+ int64_t frameDeadline = mRenderThread.timeLord().lastFrameDeadline();
int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE];
UiFrameInfoBuilder(frameInfo)
.addFlag(FrameInfoFlags::RTAnimation)
- .setVsync(vsync, vsync, vsyncId);
+ .setVsync(vsync, vsync, vsyncId, frameDeadline);
TreeInfo info(TreeInfo::MODE_RT_ONLY, *this);
prepareTree(info, frameInfo, systemTime(SYSTEM_TIME_MONOTONIC), node);
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 1ea595d..c9146b2 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -130,7 +130,8 @@
int64_t vsync = mFrameInfo[static_cast<int>(FrameInfoIndex::Vsync)];
int64_t intendedVsync = mFrameInfo[static_cast<int>(FrameInfoIndex::IntendedVsync)];
int64_t vsyncId = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameTimelineVsyncId)];
- mRenderThread->timeLord().vsyncReceived(vsync, intendedVsync, vsyncId);
+ int64_t frameDeadline = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameDeadline)];
+ mRenderThread->timeLord().vsyncReceived(vsync, intendedVsync, vsyncId, frameDeadline);
bool canDraw = mContext->makeCurrent();
mContext->unpinImages();
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 9371656..a101d46 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -52,8 +52,9 @@
void RenderThread::frameCallback(int64_t frameTimeNanos, void* data) {
RenderThread* rt = reinterpret_cast<RenderThread*>(data);
int64_t vsyncId = AChoreographer_getVsyncId(rt->mChoreographer);
+ int64_t frameDeadline = AChoreographer_getFrameDeadline(rt->mChoreographer);
rt->mVsyncRequested = false;
- if (rt->timeLord().vsyncReceived(frameTimeNanos, frameTimeNanos, vsyncId) &&
+ if (rt->timeLord().vsyncReceived(frameTimeNanos, frameTimeNanos, vsyncId, frameDeadline) &&
!rt->mFrameCallbackTaskPending) {
ATRACE_NAME("queue mFrameCallbackTask");
rt->mFrameCallbackTaskPending = true;
diff --git a/libs/hwui/renderthread/TimeLord.cpp b/libs/hwui/renderthread/TimeLord.cpp
index 7dc36c4..abb6330 100644
--- a/libs/hwui/renderthread/TimeLord.cpp
+++ b/libs/hwui/renderthread/TimeLord.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
#include "TimeLord.h"
+#include <limits>
namespace android {
namespace uirenderer {
@@ -22,12 +23,15 @@
TimeLord::TimeLord() : mFrameIntervalNanos(milliseconds_to_nanoseconds(16)),
mFrameTimeNanos(0),
mFrameIntendedTimeNanos(0),
- mFrameVsyncId(-1) {}
+ mFrameVsyncId(-1),
+ mFrameDeadline(std::numeric_limits<int64_t>::max()){}
-bool TimeLord::vsyncReceived(nsecs_t vsync, nsecs_t intendedVsync, int64_t vsyncId) {
+bool TimeLord::vsyncReceived(nsecs_t vsync, nsecs_t intendedVsync, int64_t vsyncId,
+ int64_t frameDeadline) {
if (intendedVsync > mFrameIntendedTimeNanos) {
mFrameIntendedTimeNanos = intendedVsync;
mFrameVsyncId = vsyncId;
+ mFrameDeadline = frameDeadline;
}
if (vsync > mFrameTimeNanos) {
diff --git a/libs/hwui/renderthread/TimeLord.h b/libs/hwui/renderthread/TimeLord.h
index 23c1e51..fa05c030 100644
--- a/libs/hwui/renderthread/TimeLord.h
+++ b/libs/hwui/renderthread/TimeLord.h
@@ -32,10 +32,12 @@
nsecs_t frameIntervalNanos() const { return mFrameIntervalNanos; }
// returns true if the vsync is newer, false if it was rejected for staleness
- bool vsyncReceived(nsecs_t vsync, nsecs_t indendedVsync, int64_t vsyncId);
+ bool vsyncReceived(nsecs_t vsync, nsecs_t indendedVsync, int64_t vsyncId,
+ int64_t frameDeadline);
nsecs_t latestVsync() { return mFrameTimeNanos; }
nsecs_t computeFrameTimeNanos();
int64_t lastVsyncId() const { return mFrameVsyncId; }
+ int64_t lastFrameDeadline() const { return mFrameDeadline; }
private:
friend class RenderThread;
@@ -47,6 +49,7 @@
nsecs_t mFrameTimeNanos;
nsecs_t mFrameIntendedTimeNanos;
int64_t mFrameVsyncId;
+ int64_t mFrameDeadline;
};
} /* namespace renderthread */
diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index ed89c59..eda5d22 100644
--- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp
+++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
@@ -146,7 +146,7 @@
testContext.waitForVsync();
nsecs_t vsync = systemTime(SYSTEM_TIME_MONOTONIC);
UiFrameInfoBuilder(proxy->frameInfo())
- .setVsync(vsync, vsync, UiFrameInfoBuilder::INVALID_VSYNC_ID);
+ .setVsync(vsync, vsync, UiFrameInfoBuilder::INVALID_VSYNC_ID, std::numeric_limits<int64_t>::max());
proxy->syncAndDrawFrame();
}
@@ -167,7 +167,7 @@
{
ATRACE_NAME("UI-Draw Frame");
UiFrameInfoBuilder(proxy->frameInfo())
- .setVsync(vsync, vsync, UiFrameInfoBuilder::INVALID_VSYNC_ID);
+ .setVsync(vsync, vsync, UiFrameInfoBuilder::INVALID_VSYNC_ID, std::numeric_limits<int64_t>::max());
scene->doFrame(i);
proxy->syncAndDrawFrame();
}
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index e03643c..4977c21 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -21,6 +21,7 @@
import android.Manifest;
import android.annotation.FloatRange;
+import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -38,6 +39,8 @@
import com.android.internal.util.Preconditions;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
@@ -65,16 +68,41 @@
*/
public static final long PASSIVE_INTERVAL = Long.MAX_VALUE;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({QUALITY_LOW_POWER, QUALITY_BALANCED_POWER_ACCURACY, QUALITY_HIGH_ACCURACY})
+ public @interface Quality {}
+
+ /**
+ * A quality constant indicating a location provider may choose to satisfy this request by
+ * providing very accurate locations at the expense of potentially increased power usage.
+ */
+ public static final int QUALITY_HIGH_ACCURACY = 100;
+
+ /**
+ * A quality constant indicating a location provider may choose to satisfy this request by
+ * equally balancing power and accuracy constraints.
+ */
+ public static final int QUALITY_BALANCED_POWER_ACCURACY = 102;
+
+ /**
+ * A quality constant indicating a location provider may choose to satisfy this request by
+ * providing less accurate locations in order to save power.
+ */
+ public static final int QUALITY_LOW_POWER = 104;
+
/**
* Used with {@link #setQuality} to request the most accurate locations available.
*
* <p>This may be up to 1 meter accuracy, although this is implementation dependent.
*
* @hide
+ * @deprecated Use {@link #QUALITY_HIGH_ACCURACY} instead.
*/
+ @Deprecated
@SystemApi
@TestApi
- public static final int ACCURACY_FINE = 100;
+ public static final int ACCURACY_FINE = QUALITY_HIGH_ACCURACY;
/**
* Used with {@link #setQuality} to request "block" level accuracy.
@@ -84,10 +112,12 @@
* such as this often consumes less power.
*
* @hide
+ * @deprecated Use {@link #QUALITY_BALANCED_POWER_ACCURACY} instead.
*/
+ @Deprecated
@SystemApi
@TestApi
- public static final int ACCURACY_BLOCK = 102;
+ public static final int ACCURACY_BLOCK = QUALITY_BALANCED_POWER_ACCURACY;
/**
* Used with {@link #setQuality} to request "city" level accuracy.
@@ -97,10 +127,12 @@
* such as this often consumes less power.
*
* @hide
+ * @deprecated Use {@link #QUALITY_LOW_POWER} instead.
*/
+ @Deprecated
@SystemApi
@TestApi
- public static final int ACCURACY_CITY = 104;
+ public static final int ACCURACY_CITY = QUALITY_LOW_POWER;
/**
* Used with {@link #setQuality} to require no direct power impact (passive locations).
@@ -123,7 +155,9 @@
* possible.
*
* @hide
+ * @deprecated Use {@link #QUALITY_LOW_POWER} instead.
*/
+ @Deprecated
@SystemApi
@TestApi
public static final int POWER_LOW = 201;
@@ -134,7 +168,9 @@
* <p>This location request will allow high power location work.
*
* @hide
+ * @deprecated Use {@link #QUALITY_HIGH_ACCURACY} instead.
*/
+ @Deprecated
@SystemApi
@TestApi
public static final int POWER_HIGH = 203;
@@ -144,7 +180,7 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "Use {@link "
+ "LocationManager} methods to provide the provider explicitly.")
@Nullable private String mProvider;
- private int mQuality;
+ private @Quality int mQuality;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "Use {@link "
+ "LocationRequest} instead.")
private long mInterval;
@@ -168,7 +204,7 @@
public static LocationRequest create() {
// 60 minutes is the default legacy interval
return new LocationRequest.Builder(60 * 60 * 1000)
- .setQuality(POWER_LOW)
+ .setQuality(QUALITY_LOW_POWER)
.build();
}
@@ -241,7 +277,7 @@
private LocationRequest(
@Nullable String provider,
long intervalMillis,
- int quality,
+ @Quality int quality,
long expireAtRealtimeMillis,
long durationMillis,
int maxUpdates,
@@ -251,9 +287,6 @@
boolean locationSettingsIgnored,
boolean lowPower,
WorkSource workSource) {
- Preconditions.checkArgument(intervalMillis != PASSIVE_INTERVAL || quality == POWER_NONE);
- Preconditions.checkArgument(minUpdateIntervalMillis <= intervalMillis);
-
mProvider = provider;
mInterval = intervalMillis;
mQuality = quality;
@@ -297,24 +330,39 @@
@SystemApi
@Deprecated
public @NonNull LocationRequest setQuality(int quality) {
- mQuality = Builder.checkQuality(quality, true);
+ switch (quality) {
+ case POWER_HIGH:
+ // fall through
+ case ACCURACY_FINE:
+ mQuality = QUALITY_HIGH_ACCURACY;
+ break;
+ case ACCURACY_BLOCK:
+ mQuality = QUALITY_BALANCED_POWER_ACCURACY;
+ break;
+ case POWER_LOW:
+ // fall through
+ case ACCURACY_CITY:
+ mQuality = QUALITY_LOW_POWER;
+ break;
+ case POWER_NONE:
+ mInterval = PASSIVE_INTERVAL;
+ break;
+ default:
+ throw new IllegalArgumentException("invalid quality: " + quality);
+ }
+
return this;
}
/**
- * Returns the quality of the location request.
+ * Returns the quality hint for this location request. The quality hint informs the provider how
+ * it should attempt to manage any accuracy vs power tradeoffs while attempting to satisfy this
+ * location request.
*
- * @return the quality of the location request
- *
- * @hide
+ * @return the desired quality tradeoffs between accuracy and power
*/
- @SystemApi
- public int getQuality() {
- if (mInterval == PASSIVE_INTERVAL) {
- return POWER_NONE;
- } else {
- return mQuality;
- }
+ public @Quality int getQuality() {
+ return mQuality;
}
/**
@@ -749,97 +797,65 @@
if (mProvider != null) {
s.append(mProvider).append(" ");
}
- if (mQuality != POWER_NONE && mQuality != ACCURACY_BLOCK) {
- s.append(qualityToString(mQuality)).append(" ");
- }
if (mInterval != PASSIVE_INTERVAL) {
s.append("@");
TimeUtils.formatDuration(mInterval, s);
+
+ switch (mQuality) {
+ case QUALITY_HIGH_ACCURACY:
+ s.append(" HIGH_ACCURACY");
+ break;
+ case QUALITY_BALANCED_POWER_ACCURACY:
+ s.append(" BALANCED");
+ break;
+ case QUALITY_LOW_POWER:
+ s.append(" LOW_POWER");
+ break;
+ }
} else {
s.append("PASSIVE");
}
if (mExpireAtRealtimeMillis != Long.MAX_VALUE) {
- s.append(" expireAt=").append(TimeUtils.formatRealtime(mExpireAtRealtimeMillis));
+ s.append(", expireAt=").append(TimeUtils.formatRealtime(mExpireAtRealtimeMillis));
}
if (mDurationMillis != Long.MAX_VALUE) {
- s.append(" duration=");
+ s.append(", duration=");
TimeUtils.formatDuration(mDurationMillis, s);
}
if (mMaxUpdates != Integer.MAX_VALUE) {
- s.append(" maxUpdates=").append(mMaxUpdates);
+ s.append(", maxUpdates=").append(mMaxUpdates);
}
if (mMinUpdateIntervalMillis != IMPLICIT_MIN_UPDATE_INTERVAL
&& mMinUpdateIntervalMillis < mInterval) {
- s.append(" minUpdateInterval=");
+ s.append(", minUpdateInterval=");
TimeUtils.formatDuration(mMinUpdateIntervalMillis, s);
}
if (mMinUpdateDistanceMeters > 0.0) {
- s.append(" minUpdateDistance=").append(mMinUpdateDistanceMeters);
+ s.append(", minUpdateDistance=").append(mMinUpdateDistanceMeters);
}
if (mLowPower) {
- s.append(" lowPower");
+ s.append(", lowPower");
}
if (mHideFromAppOps) {
- s.append(" hiddenFromAppOps");
+ s.append(", hiddenFromAppOps");
}
if (mLocationSettingsIgnored) {
- s.append(" locationSettingsIgnored");
+ s.append(", locationSettingsIgnored");
}
- if (mWorkSource != null) {
- s.append(" ").append(mWorkSource);
+ if (mWorkSource != null && !mWorkSource.isEmpty()) {
+ s.append(", ").append(mWorkSource);
}
s.append(']');
return s.toString();
}
- private static String qualityToString(int quality) {
- switch (quality) {
- case ACCURACY_FINE:
- return "ACCURACY_FINE";
- case ACCURACY_BLOCK:
- return "ACCURACY_BLOCK";
- case ACCURACY_CITY:
- return "ACCURACY_CITY";
- case POWER_NONE:
- return "POWER_NONE";
- case POWER_LOW:
- return "POWER_LOW";
- case POWER_HIGH:
- return "POWER_HIGH";
- default:
- return "???";
- }
- }
-
/**
* A builder class for {@link LocationRequest}.
*/
public static final class Builder {
- private static int checkQuality(int quality, boolean allowDeprecated) {
- switch (quality) {
- case ACCURACY_FINE:
- // fall through
- case ACCURACY_BLOCK:
- // fall through
- case ACCURACY_CITY:
- // fall through
- case POWER_LOW:
- // fall through
- case POWER_HIGH:
- return quality;
- case POWER_NONE:
- if (allowDeprecated) {
- return quality;
- }
- // fall through
- default:
- throw new IllegalArgumentException("invalid quality: " + quality);
- }
- }
-
private long mIntervalMillis;
- private int mQuality;
+ private @Quality int mQuality;
private long mDurationMillis;
private int mMaxUpdates;
private long mMinUpdateIntervalMillis;
@@ -857,7 +873,7 @@
// gives us a range check
setIntervalMillis(intervalMillis);
- mQuality = ACCURACY_BLOCK;
+ mQuality = QUALITY_BALANCED_POWER_ACCURACY;
mDurationMillis = Long.MAX_VALUE;
mMaxUpdates = Integer.MAX_VALUE;
mMinUpdateIntervalMillis = IMPLICIT_MIN_UPDATE_INTERVAL;
@@ -885,9 +901,6 @@
// handle edge cases that can only happen with location request that has been modified
// by deprecated SystemApi methods
- if (mQuality == POWER_NONE) {
- mIntervalMillis = PASSIVE_INTERVAL;
- }
if (mIntervalMillis == PASSIVE_INTERVAL
&& mMinUpdateIntervalMillis == IMPLICIT_MIN_UPDATE_INTERVAL) {
// this is the legacy default minimum update interval, so if we're forced to
@@ -914,11 +927,17 @@
}
/**
- * @hide
+ * Sets the request quality. The quality is a hint to providers on how they should weigh
+ * power vs accuracy tradeoffs. High accuracy locations may cost more power to produce, and
+ * lower accuracy locations may cost less power to produce. Defaults to
+ * {@link #QUALITY_BALANCED_POWER_ACCURACY}.
*/
- @SystemApi
- public @NonNull Builder setQuality(int quality) {
- mQuality = checkQuality(quality, false);
+ public @NonNull Builder setQuality(@Quality int quality) {
+ Preconditions.checkArgument(
+ quality == QUALITY_LOW_POWER || quality == QUALITY_BALANCED_POWER_ACCURACY
+ || quality == QUALITY_HIGH_ACCURACY,
+ "quality must be a defined QUALITY constant, not " + quality);
+ mQuality = quality;
return this;
}
@@ -1102,7 +1121,7 @@
return new LocationRequest(
null,
mIntervalMillis,
- mIntervalMillis != PASSIVE_INTERVAL ? mQuality : POWER_NONE,
+ mQuality,
Long.MAX_VALUE,
mDurationMillis,
mMaxUpdates,
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index eb2e23e..4a095c9 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -28,7 +28,6 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
-import android.telephony.PhoneNumberUtils;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
@@ -161,7 +160,7 @@
be set to true when the phone is having emergency call, and then will
be set to false by mPhoneStateListener when the emergency call ends.
*/
- mIsInEmergencyCall = PhoneNumberUtils.isEmergencyNumber(phoneNumber);
+ mIsInEmergencyCall = mTelephonyManager.isEmergencyNumber(phoneNumber);
if (DEBUG) Log.v(TAG, "ACTION_NEW_OUTGOING_CALL - " + getInEmergency());
} else if (action.equals(LocationManager.MODE_CHANGED_ACTION)) {
updateLocationMode();
diff --git a/location/java/com/android/internal/location/ProviderRequest.java b/location/java/com/android/internal/location/ProviderRequest.java
index fee86ce..00ba552 100644
--- a/location/java/com/android/internal/location/ProviderRequest.java
+++ b/location/java/com/android/internal/location/ProviderRequest.java
@@ -16,10 +16,15 @@
package com.android.internal.location;
+import static android.location.LocationRequest.QUALITY_BALANCED_POWER_ACCURACY;
+import static android.location.LocationRequest.QUALITY_HIGH_ACCURACY;
+import static android.location.LocationRequest.QUALITY_LOW_POWER;
+
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
import android.location.LocationRequest;
+import android.location.LocationRequest.Quality;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -41,7 +46,7 @@
public static final long INTERVAL_DISABLED = Long.MAX_VALUE;
public static final ProviderRequest EMPTY_REQUEST = new ProviderRequest(
- INTERVAL_DISABLED, false, false, Collections.emptyList(), new WorkSource());
+ INTERVAL_DISABLED, QUALITY_BALANCED_POWER_ACCURACY, false, false, new WorkSource());
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "{@link "
+ "ProviderRequest}")
@@ -49,6 +54,7 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "{@link "
+ "ProviderRequest}")
public final long interval;
+ private final @Quality int mQuality;
private final boolean mLowPower;
private final boolean mLocationSettingsIgnored;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "{@link "
@@ -56,15 +62,24 @@
public final List<LocationRequest> locationRequests;
private final WorkSource mWorkSource;
- private ProviderRequest(long intervalMillis, boolean lowPower,
- boolean locationSettingsIgnored, @NonNull List<LocationRequest> locationRequests,
- @NonNull WorkSource workSource) {
+ private ProviderRequest(long intervalMillis, @Quality int quality, boolean lowPower,
+ boolean locationSettingsIgnored, @NonNull WorkSource workSource) {
reportLocation = intervalMillis != INTERVAL_DISABLED;
interval = intervalMillis;
+ mQuality = quality;
mLowPower = lowPower;
mLocationSettingsIgnored = locationSettingsIgnored;
- this.locationRequests = locationRequests;
- mWorkSource = workSource;
+ if (intervalMillis != INTERVAL_DISABLED) {
+ locationRequests = Collections.singletonList(new LocationRequest.Builder(intervalMillis)
+ .setQuality(quality)
+ .setLowPower(lowPower)
+ .setLocationSettingsIgnored(locationSettingsIgnored)
+ .setWorkSource(workSource)
+ .build());
+ } else {
+ locationRequests = Collections.emptyList();
+ }
+ mWorkSource = Objects.requireNonNull(workSource);
}
/**
@@ -84,6 +99,15 @@
}
/**
+ * The quality hint for this location request. The quality hint informs the provider how it
+ * should attempt to manage any accuracy vs power tradeoffs while attempting to satisfy this
+ * provider request.
+ */
+ public @Quality int getQuality() {
+ return mQuality;
+ }
+
+ /**
* Whether any applicable hardware low power modes should be used to satisfy this request.
*/
public boolean isLowPower() {
@@ -100,13 +124,6 @@
}
/**
- * The full list of location requests contributing to this provider request.
- */
- public @NonNull List<LocationRequest> getLocationRequests() {
- return locationRequests;
- }
-
- /**
* The power blame for this provider request.
*/
public @NonNull WorkSource getWorkSource() {
@@ -117,13 +134,17 @@
new Parcelable.Creator<ProviderRequest>() {
@Override
public ProviderRequest createFromParcel(Parcel in) {
- return new ProviderRequest(
- /* intervalMillis= */ in.readLong(),
- /* lowPower= */ in.readBoolean(),
- /* locationSettingsIgnored= */ in.readBoolean(),
- /* locationRequests= */
- in.createTypedArrayList(LocationRequest.CREATOR),
- /* workSource= */ in.readTypedObject(WorkSource.CREATOR));
+ long intervalMillis = in.readLong();
+ if (intervalMillis == INTERVAL_DISABLED) {
+ return EMPTY_REQUEST;
+ } else {
+ return new ProviderRequest(
+ intervalMillis,
+ /* quality= */ in.readInt(),
+ /* lowPower= */ in.readBoolean(),
+ /* locationSettingsIgnored= */ in.readBoolean(),
+ /* workSource= */ in.readTypedObject(WorkSource.CREATOR));
+ }
}
@Override
@@ -140,10 +161,12 @@
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeLong(interval);
- parcel.writeBoolean(mLowPower);
- parcel.writeBoolean(mLocationSettingsIgnored);
- parcel.writeTypedList(locationRequests);
- parcel.writeTypedObject(mWorkSource, flags);
+ if (interval != INTERVAL_DISABLED) {
+ parcel.writeInt(mQuality);
+ parcel.writeBoolean(mLowPower);
+ parcel.writeBoolean(mLocationSettingsIgnored);
+ parcel.writeTypedObject(mWorkSource, flags);
+ }
}
@Override
@@ -160,16 +183,16 @@
return that.interval == INTERVAL_DISABLED;
} else {
return interval == that.interval
+ && mQuality == that.mQuality
&& mLowPower == that.mLowPower
&& mLocationSettingsIgnored == that.mLocationSettingsIgnored
- && locationRequests.equals(that.locationRequests)
&& mWorkSource.equals(that.mWorkSource);
}
}
@Override
public int hashCode() {
- return Objects.hash(interval, mWorkSource);
+ return Objects.hash(interval, mQuality, mWorkSource);
}
@Override
@@ -179,6 +202,13 @@
if (interval != INTERVAL_DISABLED) {
s.append("@");
TimeUtils.formatDuration(interval, s);
+ if (mQuality != QUALITY_BALANCED_POWER_ACCURACY) {
+ if (mQuality == QUALITY_HIGH_ACCURACY) {
+ s.append(", HIGH_ACCURACY");
+ } else if (mQuality == QUALITY_LOW_POWER) {
+ s.append(", LOW_POWER");
+ }
+ }
if (mLowPower) {
s.append(", lowPower");
}
@@ -200,9 +230,9 @@
*/
public static class Builder {
private long mIntervalMillis = INTERVAL_DISABLED;
+ private int mQuality = QUALITY_BALANCED_POWER_ACCURACY;
private boolean mLowPower;
private boolean mLocationSettingsIgnored;
- private List<LocationRequest> mLocationRequests = Collections.emptyList();
private WorkSource mWorkSource = new WorkSource();
/**
@@ -216,6 +246,20 @@
}
/**
+ * Sets the request quality. The quality is a hint to providers on how they should weigh
+ * power vs accuracy tradeoffs. High accuracy locations may cost more power to produce, and
+ * lower accuracy locations may cost less power to produce. Defaults to
+ * {@link LocationRequest#QUALITY_BALANCED_POWER_ACCURACY}.
+ */
+ public @NonNull Builder setQuality(@Quality int quality) {
+ Preconditions.checkArgument(
+ quality == QUALITY_LOW_POWER || quality == QUALITY_BALANCED_POWER_ACCURACY
+ || quality == QUALITY_HIGH_ACCURACY);
+ mQuality = quality;
+ return this;
+ }
+
+ /**
* Sets whether hardware low power mode should be used. False by default.
*/
public @NonNull Builder setLowPower(boolean lowPower) {
@@ -232,15 +276,6 @@
}
/**
- * Sets the {@link LocationRequest}s associated with this request. Empty by default.
- */
- public @NonNull Builder setLocationRequests(
- @NonNull List<LocationRequest> locationRequests) {
- this.mLocationRequests = Objects.requireNonNull(locationRequests);
- return this;
- }
-
- /**
* Sets the work source for power blame. Empty by default.
*/
public @NonNull Builder setWorkSource(@NonNull WorkSource workSource) {
@@ -255,8 +290,8 @@
if (mIntervalMillis == INTERVAL_DISABLED) {
return EMPTY_REQUEST;
} else {
- return new ProviderRequest(mIntervalMillis, mLowPower, mLocationSettingsIgnored,
- mLocationRequests, mWorkSource);
+ return new ProviderRequest(mIntervalMillis, mQuality, mLowPower,
+ mLocationSettingsIgnored, mWorkSource);
}
}
}
diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt
index f43eb63..80636c6 100644
--- a/location/lib/api/current.txt
+++ b/location/lib/api/current.txt
@@ -29,18 +29,18 @@
field public static final String FUSED_PROVIDER = "fused";
}
- public final class LocationRequestUnbundled {
- method public long getFastestInterval();
- method public long getInterval();
- method public int getQuality();
- method public float getSmallestDisplacement();
- method public boolean isLocationSettingsIgnored();
- field public static final int ACCURACY_BLOCK = 102; // 0x66
- field public static final int ACCURACY_CITY = 104; // 0x68
- field public static final int ACCURACY_FINE = 100; // 0x64
- field public static final int POWER_HIGH = 203; // 0xcb
- field public static final int POWER_LOW = 201; // 0xc9
- field public static final int POWER_NONE = 200; // 0xc8
+ @Deprecated public final class LocationRequestUnbundled {
+ method @Deprecated public long getFastestInterval();
+ method @Deprecated public long getInterval();
+ method @Deprecated @android.location.LocationRequest.Quality public int getQuality();
+ method @Deprecated public float getSmallestDisplacement();
+ method @Deprecated public boolean isLocationSettingsIgnored();
+ field @Deprecated public static final int ACCURACY_BLOCK = 102; // 0x66
+ field @Deprecated public static final int ACCURACY_CITY = 104; // 0x68
+ field @Deprecated public static final int ACCURACY_FINE = 100; // 0x64
+ field @Deprecated public static final int POWER_HIGH = 203; // 0xcb
+ field @Deprecated public static final int POWER_LOW = 201; // 0xc9
+ field @Deprecated public static final int POWER_NONE = 200; // 0xc8
}
public final class ProviderPropertiesUnbundled {
@@ -49,7 +49,8 @@
public final class ProviderRequestUnbundled {
method public long getInterval();
- method @NonNull public java.util.List<com.android.location.provider.LocationRequestUnbundled> getLocationRequests();
+ method @Deprecated @NonNull public java.util.List<com.android.location.provider.LocationRequestUnbundled> getLocationRequests();
+ method @android.location.LocationRequest.Quality @RequiresApi(android.os.Build.VERSION_CODES.S) public int getQuality();
method public boolean getReportLocation();
method @NonNull @RequiresApi(android.os.Build.VERSION_CODES.S) public android.os.WorkSource getWorkSource();
method @RequiresApi(android.os.Build.VERSION_CODES.Q) public boolean isLocationSettingsIgnored();
diff --git a/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java b/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java
index 92e05ef..0e7c633 100644
--- a/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java
+++ b/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java
@@ -17,6 +17,7 @@
package com.android.location.provider;
import android.location.LocationRequest;
+import android.location.LocationRequest.Quality;
/**
* This class is an interface to LocationRequests for unbundled applications.
@@ -24,55 +25,50 @@
* <p>IMPORTANT: This class is effectively a public API for unbundled
* applications, and must remain API stable. See README.txt in the root
* of this package for more information.
+ *
+ * @deprecated Do not use.
*/
+@Deprecated
public final class LocationRequestUnbundled {
+
/**
- * Returned by {@link #getQuality} when requesting the most accurate locations available.
- *
- * <p>This may be up to 1 meter accuracy, although this is implementation dependent.
+ * @deprecated Use {@link LocationRequest#QUALITY_HIGH_ACCURACY} instead.
*/
+ @Deprecated
public static final int ACCURACY_FINE = LocationRequest.ACCURACY_FINE;
/**
- * Returned by {@link #getQuality} when requesting "block" level accuracy.
- *
- * <p>Block level accuracy is considered to be about 100 meter accuracy,
- * although this is implementation dependent. Using a coarse accuracy
- * such as this often consumes less power.
+ * @deprecated Use {@link LocationRequest#QUALITY_BALANCED_POWER_ACCURACY} instead.
*/
+ @Deprecated
public static final int ACCURACY_BLOCK = LocationRequest.ACCURACY_BLOCK;
+
/**
- * Returned by {@link #getQuality} when requesting "city" level accuracy.
- *
- * <p>City level accuracy is considered to be about 10km accuracy,
- * although this is implementation dependent. Using a coarse accuracy
- * such as this often consumes less power.
+ * @deprecated Use {@link LocationRequest#QUALITY_LOW_POWER} instead.
*/
+ @Deprecated
public static final int ACCURACY_CITY = LocationRequest.ACCURACY_CITY;
+
/**
- * Returned by {@link #getQuality} when requiring no direct power impact (passive locations).
- *
- * <p>This location request will not trigger any active location requests,
- * but will receive locations triggered by other applications. Your application
- * will not receive any direct power blame for location work.
+ * @deprecated Do not use.
*/
+ @Deprecated
public static final int POWER_NONE = LocationRequest.POWER_NONE;
- /**
- * Returned by {@link #getQuality} when requesting low power impact.
- *
- * <p>This location request will avoid high power location work where
- * possible.
- */
- public static final int POWER_LOW = LocationRequest.POWER_LOW;
/**
- * Returned by {@link #getQuality} when allowing high power consumption for location.
- *
- * <p>This location request will allow high power location work.
+ * @deprecated Use {@link LocationRequest#QUALITY_LOW_POWER} instead.
*/
+ @Deprecated
+ public static final int POWER_LOW = LocationRequest.POWER_LOW;
+
+
+ /**
+ * @deprecated Use {@link LocationRequest#QUALITY_BALANCED_POWER_ACCURACY} instead.
+ */
+ @Deprecated
public static final int POWER_HIGH = LocationRequest.POWER_HIGH;
private final LocationRequest delegate;
@@ -102,9 +98,9 @@
/**
* Get the quality of the request.
*
- * @return an accuracy or power constant
+ * @return a {@link LocationRequest} QUALITY_* constant
*/
- public int getQuality() {
+ public @Quality int getQuality() {
return delegate.getQuality();
}
diff --git a/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java b/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
index 6f5fcc7..f7bac74 100644
--- a/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
+++ b/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
@@ -25,7 +25,7 @@
import com.android.internal.location.ProviderRequest;
-import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
@@ -57,6 +57,16 @@
}
/**
+ * The quality hint for this location request. The quality hint informs the provider how it
+ * should attempt to manage any accuracy vs power tradeoffs while attempting to satisfy this
+ * provider request.
+ */
+ @RequiresApi(Build.VERSION_CODES.S)
+ public @LocationRequest.Quality int getQuality() {
+ return mRequest.getQuality();
+ }
+
+ /**
* The interval at which a provider should report location. Will return
* {@link #INTERVAL_DISABLED} for an inactive request.
*/
@@ -84,14 +94,22 @@
/**
* The full list of location requests contributing to this provider request.
+ *
+ * @deprecated Do not use.
*/
+ @Deprecated
public @NonNull List<LocationRequestUnbundled> getLocationRequests() {
- List<LocationRequestUnbundled> result = new ArrayList<>(
- mRequest.getLocationRequests().size());
- for (LocationRequest r : mRequest.getLocationRequests()) {
- result.add(new LocationRequestUnbundled(r));
+ if (!mRequest.isActive()) {
+ return Collections.emptyList();
}
- return result;
+
+ return Collections.singletonList(new LocationRequestUnbundled(
+ new LocationRequest.Builder(mRequest.getIntervalMillis())
+ .setQuality(mRequest.getQuality())
+ .setLowPower(mRequest.isLowPower())
+ .setLocationSettingsIgnored(mRequest.isLocationSettingsIgnored())
+ .setWorkSource(mRequest.getWorkSource())
+ .build()));
}
/**
diff --git a/media/OWNERS b/media/OWNERS
index 36df3a0..0fc781c 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -15,6 +15,8 @@
klhyun@google.com
lajos@google.com
marcone@google.com
+nchalko@google.com
philburk@google.com
+quxiangfang@google.com
sungsoo@google.com
wonsik@google.com
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 0747ab13..ae97a71 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -2711,12 +2711,12 @@
}
};
- private final Pattern zeroPattern = new Pattern(0, 0);
+ private static final Pattern ZERO_PATTERN = new Pattern(0, 0);
/**
* The pattern applicable to the protected data in each subsample.
*/
- private Pattern pattern;
+ private Pattern mPattern = ZERO_PATTERN;
/**
* Set the subsample count, clear/encrypted sizes, key, IV and mode fields of
@@ -2735,22 +2735,30 @@
key = newKey;
iv = newIV;
mode = newMode;
- pattern = zeroPattern;
+ mPattern = ZERO_PATTERN;
+ }
+
+ /**
+ * Returns the {@link Pattern encryption pattern}.
+ */
+ public @NonNull Pattern getPattern() {
+ return new Pattern(mPattern.getEncryptBlocks(), mPattern.getSkipBlocks());
}
/**
* Set the encryption pattern on a {@link MediaCodec.CryptoInfo} instance.
- * See {@link MediaCodec.CryptoInfo.Pattern}.
+ * See {@link Pattern}.
*/
public void setPattern(Pattern newPattern) {
if (newPattern == null) {
- newPattern = zeroPattern;
+ newPattern = ZERO_PATTERN;
}
- pattern = newPattern;
+ setPattern(newPattern.getEncryptBlocks(), newPattern.getSkipBlocks());
}
+ // Accessed from android_media_MediaExtractor.cpp.
private void setPattern(int blocksToEncrypt, int blocksToSkip) {
- pattern = new Pattern(blocksToEncrypt, blocksToSkip);
+ mPattern = new Pattern(blocksToEncrypt, blocksToSkip);
}
@Override
@@ -2772,9 +2780,9 @@
builder.append(", encrypted ");
builder.append(Arrays.toString(numBytesOfEncryptedData));
builder.append(", pattern (encrypt: ");
- builder.append(pattern.mEncryptBlocks);
+ builder.append(mPattern.mEncryptBlocks);
builder.append(", skip: ");
- builder.append(pattern.mSkipBlocks);
+ builder.append(mPattern.mSkipBlocks);
builder.append(")");
return builder.toString();
}
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 2b3f420c..4d87fb3 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -45,6 +45,9 @@
import android.text.TextUtils;
import android.util.Log;
import android.view.Display;
+import android.view.DisplayAddress;
+
+import com.android.internal.annotations.VisibleForTesting;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -1737,7 +1740,9 @@
*/
private static final int DEFAULT_PLAYBACK_VOLUME = DEFAULT_PLAYBACK_MAX_VOLUME;
- RouteInfo(RouteCategory category) {
+ /** @hide */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public RouteInfo(RouteCategory category) {
mCategory = category;
mDeviceType = DEVICE_TYPE_UNKNOWN;
}
@@ -2078,7 +2083,9 @@
return mPresentationDisplay;
}
- boolean updatePresentationDisplay() {
+ /** @hide */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public boolean updatePresentationDisplay() {
Display display = choosePresentationDisplay();
if (mPresentationDisplay != display) {
mPresentationDisplay = display;
@@ -2088,41 +2095,81 @@
}
private Display choosePresentationDisplay() {
- if ((mSupportedTypes & ROUTE_TYPE_LIVE_VIDEO) != 0) {
- Display[] displays = sStatic.getAllPresentationDisplays();
+ if ((getSupportedTypes() & ROUTE_TYPE_LIVE_VIDEO) == 0) {
+ return null;
+ }
+ final Display[] displays = getAllPresentationDisplays();
+ if (displays == null || displays.length == 0) {
+ return null;
+ }
- // Ensure that the specified display is valid for presentations.
- // This check will normally disallow the default display unless it was
- // configured as a presentation display for some reason.
- if (mPresentationDisplayId >= 0) {
- for (Display display : displays) {
- if (display.getDisplayId() == mPresentationDisplayId) {
- return display;
- }
+ // Ensure that the specified display is valid for presentations.
+ // This check will normally disallow the default display unless it was
+ // configured as a presentation display for some reason.
+ if (mPresentationDisplayId >= 0) {
+ for (Display display : displays) {
+ if (display.getDisplayId() == mPresentationDisplayId) {
+ return display;
}
- return null;
}
+ return null;
+ }
- // Find the indicated Wifi display by its address.
- if (mDeviceAddress != null) {
- for (Display display : displays) {
- if (display.getType() == Display.TYPE_WIFI
- && mDeviceAddress.equals(display.getAddress())) {
- return display;
- }
+ // Find the indicated Wifi display by its address.
+ if (getDeviceAddress() != null) {
+ for (Display display : displays) {
+ if (display.getType() == Display.TYPE_WIFI
+ && displayAddressEquals(display)) {
+ return display;
}
- return null;
- }
-
- // For the default route, choose the first presentation display from the list.
- if (this == sStatic.mDefaultAudioVideo && displays.length > 0) {
- return displays[0];
}
}
+
+ // Returns the first hard-wired display.
+ for (Display display : displays) {
+ if (display.getType() == Display.TYPE_EXTERNAL) {
+ return display;
+ }
+ }
+
+ // Returns the first non-default built-in display.
+ for (Display display : displays) {
+ if (display.getType() == Display.TYPE_INTERNAL) {
+ return display;
+ }
+ }
+
+ // For the default route, choose the first presentation display from the list.
+ if (this == getDefaultAudioVideo()) {
+ return displays[0];
+ }
return null;
}
/** @hide */
+ @VisibleForTesting
+ public Display[] getAllPresentationDisplays() {
+ return sStatic.getAllPresentationDisplays();
+ }
+
+ /** @hide */
+ @VisibleForTesting
+ public RouteInfo getDefaultAudioVideo() {
+ return sStatic.mDefaultAudioVideo;
+ }
+
+ private boolean displayAddressEquals(Display display) {
+ final DisplayAddress displayAddress = display.getAddress();
+ // mDeviceAddress recorded mac address. If displayAddress is not a kind of Network,
+ // return false early.
+ if (!(displayAddress instanceof DisplayAddress.Network)) {
+ return false;
+ }
+ final DisplayAddress.Network networkAddress = (DisplayAddress.Network) displayAddress;
+ return getDeviceAddress().equals(networkAddress.toString());
+ }
+
+ /** @hide */
@UnsupportedAppUsage
public String getDeviceAddress() {
return mDeviceAddress;
diff --git a/media/java/android/media/MediaTranscodeManager.java b/media/java/android/media/MediaTranscodeManager.java
index 8cbe52f..8676462 100644
--- a/media/java/android/media/MediaTranscodeManager.java
+++ b/media/java/android/media/MediaTranscodeManager.java
@@ -443,7 +443,7 @@
}
@Override
- public void onAwaitNumberOfJobsChanged(int jobId, int oldAwaitNumber,
+ public void onAwaitNumberOfSessionsChanged(int jobId, int oldAwaitNumber,
int newAwaitNumber) throws RemoteException {
//TODO(hkuang): Implement this.
}
@@ -1081,7 +1081,7 @@
private final MediaTranscodeManager mManager;
private Executor mListenerExecutor;
private OnTranscodingFinishedListener mListener;
- private int mJobId = -1;
+ private int mSessionId = -1;
// Lock for internal state.
private final Object mLock = new Object();
@GuardedBy("mLock")
@@ -1104,7 +1104,7 @@
private TranscodingJob(
@NonNull MediaTranscodeManager manager,
@NonNull TranscodingRequest request,
- @NonNull TranscodingJobParcel parcel,
+ @NonNull TranscodingSessionParcel parcel,
@NonNull @CallbackExecutor Executor executor,
@NonNull OnTranscodingFinishedListener listener) {
Objects.requireNonNull(manager, "manager must not be null");
@@ -1112,7 +1112,7 @@
Objects.requireNonNull(executor, "listenerExecutor must not be null");
Objects.requireNonNull(listener, "listener must not be null");
mManager = manager;
- mJobId = parcel.jobId;
+ mSessionId = parcel.sessionId;
mListenerExecutor = executor;
mListener = listener;
mRequest = request;
@@ -1196,16 +1196,16 @@
synchronized (mManager.mPendingTranscodingJobs) {
try {
// Submits the request to MediaTranscoding service.
- TranscodingJobParcel jobParcel = new TranscodingJobParcel();
- if (!client.submitRequest(mRequest.writeToParcel(), jobParcel)) {
+ TranscodingSessionParcel sessionParcel = new TranscodingSessionParcel();
+ if (!client.submitRequest(mRequest.writeToParcel(), sessionParcel)) {
mHasRetried = true;
throw new UnsupportedOperationException("Failed to enqueue request");
}
// Replace the old job id wit the new one.
- mJobId = jobParcel.jobId;
+ mSessionId = sessionParcel.sessionId;
// Adds the new job back into pending jobs.
- mManager.mPendingTranscodingJobs.put(mJobId, this);
+ mManager.mPendingTranscodingJobs.put(mSessionId, this);
} catch (RemoteException re) {
throw new MediaTranscodingException.ServiceNotAvailableException(
"Failed to resubmit request to Transcoding service");
@@ -1229,7 +1229,7 @@
ITranscodingClient client = mManager.getTranscodingClient();
// The client may be gone.
if (client != null) {
- client.cancelJob(mJobId);
+ client.cancelSession(mSessionId);
}
} catch (RemoteException re) {
//TODO(hkuang): Find out what to do if failing to cancel the job.
@@ -1272,7 +1272,7 @@
* @return job id.
*/
public int getJobId() {
- return mJobId;
+ return mSessionId;
}
/**
@@ -1326,7 +1326,7 @@
break;
}
return String.format(" Job: {id: %d, status: %s, result: %s, progress: %d}",
- mJobId, status, result, mProgress);
+ mSessionId, status, result, mProgress);
}
private void updateProgress(int newProgress) {
@@ -1383,7 +1383,7 @@
// Submits the request to MediaTranscoding service.
try {
- TranscodingJobParcel jobParcel = new TranscodingJobParcel();
+ TranscodingSessionParcel sessionParcel = new TranscodingSessionParcel();
// Synchronizes the access to mPendingTranscodingJobs to make sure the job Id is
// inserted in the mPendingTranscodingJobs in the callback handler.
synchronized (mPendingTranscodingJobs) {
@@ -1399,15 +1399,15 @@
}
}
- if (!mTranscodingClient.submitRequest(requestParcel, jobParcel)) {
+ if (!mTranscodingClient.submitRequest(requestParcel, sessionParcel)) {
throw new UnsupportedOperationException("Failed to enqueue request");
}
}
- // Wraps the TranscodingJobParcel into a TranscodingJob and returns it to client for
+ // Wraps the TranscodingSessionParcel into a TranscodingJob and returns it to client for
// tracking.
TranscodingJob job = new TranscodingJob(this, transcodingRequest,
- jobParcel,
+ sessionParcel,
listenerExecutor,
listener);
diff --git a/media/java/android/media/tv/TunedInfo.java b/media/java/android/media/tv/TunedInfo.java
index 6fc5784..6199c89 100644
--- a/media/java/android/media/tv/TunedInfo.java
+++ b/media/java/android/media/tv/TunedInfo.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
@@ -35,6 +36,7 @@
* or pass-through input.
* @hide
*/
+@SystemApi
public final class TunedInfo implements Parcelable {
static final String TAG = "TunedInfo";
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 73539fb..e9959be 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -906,8 +906,8 @@
* @param tunedInfos a list of {@link TunedInfo} objects of new tuned information.
* @hide
*/
- public void onCurrentTunedInfosUpdated(
- @NonNull List<TunedInfo> tunedInfos) {
+ @SystemApi
+ public void onCurrentTunedInfosUpdated(@NonNull List<TunedInfo> tunedInfos) {
}
}
@@ -969,7 +969,7 @@
});
}
- public void onCurrentTunedInfosUpdated(final List<TunedInfo> currentTunedInfos) {
+ public void postCurrentTunedInfosUpdated(final List<TunedInfo> currentTunedInfos) {
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -1286,7 +1286,7 @@
public void onCurrentTunedInfosUpdated(List<TunedInfo> currentTunedInfos) {
synchronized (mLock) {
for (TvInputCallbackRecord record : mCallbackRecords) {
- record.onCurrentTunedInfosUpdated(currentTunedInfos);
+ record.postCurrentTunedInfosUpdated(currentTunedInfos);
}
}
}
@@ -1988,6 +1988,7 @@
* {@link TunedInfo#getChannelUri()} returns {@code null}.
* @hide
*/
+ @SystemApi
@RequiresPermission("com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS")
@NonNull
public List<TunedInfo> getCurrentTunedInfos() {
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index e148d0e..56499e2 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -98,15 +98,49 @@
* Invalid timestamp.
*
* <p>Returned by {@link android.media.tv.tuner.filter.TimeFilter#getSourceTime()},
- * {@link android.media.tv.tuner.filter.TimeFilter#getTimeStamp()}, or
- * {@link Tuner#getAvSyncTime(int)} when the requested timestamp is not available.
+ * {@link android.media.tv.tuner.filter.TimeFilter#getTimeStamp()},
+ * {@link Tuner#getAvSyncTime(int)} or {@link TsRecordEvent#getPts()} and
+ * {@link MmtpRecordEvent#getPts()} when the requested timestamp is not available.
*
* @see android.media.tv.tuner.filter.TimeFilter#getSourceTime()
* @see android.media.tv.tuner.filter.TimeFilter#getTimeStamp()
* @see Tuner#getAvSyncTime(int)
+ * @see android.media.tv.tuner.filter.TsRecordEvent#getPts()
+ * @see android.media.tv.tuner.filter.MmtpRecordEvent#getPts()
*/
- public static final long INVALID_TIMESTAMP = -1L;
-
+ public static final long INVALID_TIMESTAMP =
+ android.hardware.tv.tuner.V1_1.Constants.Constant64Bit.INVALID_PRESENTATION_TIME_STAMP;
+ /**
+ * Invalid mpu sequence number in MmtpRecordEvent.
+ *
+ * <p>Returned by {@link MmtpRecordEvent#getMpuSequenceNumber()} when the requested sequence
+ * number is not available.
+ *
+ * @see android.media.tv.tuner.filter.MmtpRecordEvent#getMpuSequenceNumber()
+ */
+ public static final int INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM =
+ android.hardware.tv.tuner.V1_1.Constants.Constant
+ .INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM;
+ /**
+ * Invalid local transport stream id.
+ *
+ * <p>Returned by {@link #linkFrontendToCiCam(int)} when the requested failed
+ * or the hal implementation does not support the operation.
+ *
+ * @see #linkFrontendToCiCam(int)
+ */
+ public static final int INVALID_LTS_ID =
+ android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_LTS_ID;
+ /**
+ * Invalid 64-bit filter ID.
+ */
+ public static final long INVALID_FILTER_ID_64BIT =
+ android.hardware.tv.tuner.V1_1.Constants.Constant64Bit.INVALID_FILTER_ID_64BIT;
+ /**
+ * Invalid frequency that is used as the default frontend frequency setting.
+ */
+ public static final int INVALID_FRONTEND_SETTING_FREQUENCY =
+ android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_FRONTEND_SETTING_FREQUENCY;
/** @hide */
@IntDef(prefix = "SCAN_TYPE_", value = {SCAN_TYPE_UNDEFINED, SCAN_TYPE_AUTO, SCAN_TYPE_BLIND})
@@ -204,6 +238,7 @@
private final Context mContext;
private final TunerResourceManager mTunerResourceManager;
private final int mClientId;
+ private static int sTunerVersion = TunerVersionChecker.TUNER_VERSION_UNKNOWN;
private Frontend mFrontend;
private EventHandler mHandler;
@@ -255,6 +290,14 @@
public Tuner(@NonNull Context context, @Nullable String tvInputSessionId,
@TvInputService.PriorityHintUseCaseType int useCase) {
nativeSetup();
+ sTunerVersion = nativeGetTunerVersion();
+ if (sTunerVersion == TunerVersionChecker.TUNER_VERSION_UNKNOWN) {
+ Log.e(TAG, "Unknown Tuner version!");
+ } else {
+ Log.d(TAG, "Current Tuner version is "
+ + TunerVersionChecker.getMajorVersion(sTunerVersion) + "."
+ + TunerVersionChecker.getMinorVersion(sTunerVersion) + ".");
+ }
mContext = context;
mTunerResourceManager = (TunerResourceManager)
context.getSystemService(Context.TV_TUNER_RESOURCE_MGR_SERVICE);
@@ -295,6 +338,11 @@
}
/** @hide */
+ public static int getTunerVersion() {
+ return sTunerVersion;
+ }
+
+ /** @hide */
public List<Integer> getFrontendIds() {
return nativeGetFrontendIds();
}
@@ -419,6 +467,11 @@
/**
* Native method to get all frontend IDs.
*/
+ private native int nativeGetTunerVersion();
+
+ /**
+ * Native method to get all frontend IDs.
+ */
private native List<Integer> nativeGetFrontendIds();
/**
@@ -437,7 +490,9 @@
private native Integer nativeGetAvSyncHwId(Filter filter);
private native Long nativeGetAvSyncTime(int avSyncId);
private native int nativeConnectCiCam(int ciCamId);
+ private native int nativeLinkCiCam(int ciCamId);
private native int nativeDisconnectCiCam();
+ private native int nativeUnlinkCiCam(int ciCamId);
private native FrontendInfo nativeGetFrontendInfo(int id);
private native Filter nativeOpenFilter(int type, int subType, long bufferSize);
private native TimeFilter nativeOpenTimeFilter();
@@ -568,6 +623,10 @@
* OnTuneEventListener#SIGNAL_NO_SIGNAL} events sent to the {@link OnTuneEventListener}
* specified in {@link #setOnTuneEventListener(Executor, OnTuneEventListener)}.
*
+ * <p>Tuning with {@link android.media.tv.tuner.frontend.DtmbFrontendSettings} is only
+ * supported in Tuner 1.1 or higher version. Unsupported version will cause no-op. Use {@link
+ * TunerVersionChecker.getTunerVersion()} to get the version information.
+ *
* @param settings Signal delivery information the frontend uses to
* search and lock the signal.
* @return result status of tune operation.
@@ -578,6 +637,12 @@
public int tune(@NonNull FrontendSettings settings) {
Log.d(TAG, "Tune to " + settings.getFrequency());
mFrontendType = settings.getType();
+ if (mFrontendType == FrontendSettings.TYPE_DTMB) {
+ if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "Tuner with DTMB Frontend")) {
+ return RESULT_UNAVAILABLE;
+ }
+ }
if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND)) {
mFrontendInfo = null;
Log.d(TAG, "Write Stats Log for tuning.");
@@ -607,6 +672,10 @@
*
* <p>Details for channels found are returned via {@link ScanCallback}.
*
+ * <p>Scanning with {@link android.media.tv.tuner.frontend.DtmbFrontendSettings} is only
+ * supported in Tuner 1.1 or higher version. Unsupported version will cause no-op. Use {@link
+ * TunerVersionChecker.getTunerVersion()} to get the version information.
+ *
* @param settings A {@link FrontendSettings} to configure the frontend.
* @param scanType The scan type.
* @throws SecurityException if the caller does not have appropriate permissions.
@@ -622,6 +691,12 @@
+ "started.");
}
mFrontendType = settings.getType();
+ if (mFrontendType == FrontendSettings.TYPE_DTMB) {
+ if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "Scan with DTMB Frontend")) {
+ return RESULT_UNAVAILABLE;
+ }
+ }
if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND)) {
mScanCallback = scanCallback;
mScanCallbackExecutor = executor;
@@ -760,6 +835,33 @@
}
/**
+ * Link Conditional Access Modules (CAM) Frontend to support Common Interface (CI) by-pass mode.
+ *
+ * <p>It is used by the client to link CI-CAM to a Frontend. CI by-pass mode requires that
+ * the CICAM also receives the TS concurrently from the frontend when the Demux is receiving
+ * the TS directly from the frontend.
+ *
+ * <p>Use {@link #unlinkFrontendToCicam(int)} to disconnect.
+ *
+ * <p>This API is only supported by Tuner HAL 1.1 or higher. Unsupported version would cause
+ * no-op and return {@link INVALID_LTS_ID}. Use {@link TunerVersionChecker.getTunerVersion()} to
+ * check the version.
+ *
+ * @param ciCamId specify CI-CAM Id to link.
+ * @return Local transport stream id when connection is successfully established. Failed
+ * operation returns {@link INVALID_LTS_ID}.
+ */
+ public int linkFrontendToCiCam(int ciCamId) {
+ if (TunerVersionChecker.checkHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1,
+ "linkFrontendToCiCam")) {
+ if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND)) {
+ return nativeLinkCiCam(ciCamId);
+ }
+ }
+ return INVALID_LTS_ID;
+ }
+
+ /**
* Disconnects Conditional Access Modules (CAM)
*
* <p>The demux will use the output from the frontend as the input after this call.
@@ -775,6 +877,28 @@
}
/**
+ * Unlink Conditional Access Modules (CAM) Frontend.
+ *
+ * <p>It is used by the client to unlink CI-CAM to a Frontend.
+ *
+ * <p>This API is only supported by Tuner HAL 1.1 or higher. Unsupported version would cause
+ * no-op. Use {@link TunerVersionChecker.getTunerVersion()} to check the version.
+ *
+ * @param ciCamId specify CI-CAM Id to unlink.
+ * @return result status of the operation.
+ */
+ @Result
+ public int unlinkFrontendToCiCam(int ciCamId) {
+ if (TunerVersionChecker.checkHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1,
+ "unlinkFrontendToCiCam")) {
+ if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND)) {
+ return nativeUnlinkCiCam(ciCamId);
+ }
+ }
+ return RESULT_UNAVAILABLE;
+ }
+
+ /**
* Gets the frontend information.
*
* @return The frontend information. {@code null} if the operation failed.
diff --git a/media/java/android/media/tv/tuner/TunerVersionChecker.java b/media/java/android/media/tv/tuner/TunerVersionChecker.java
new file mode 100644
index 0000000..739f87d
--- /dev/null
+++ b/media/java/android/media/tv/tuner/TunerVersionChecker.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2020 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 android.media.tv.tuner;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Utility class to check the currently running Tuner Hal implementation version.
+ *
+ * APIs that are not supported by the HAL implementation version would be no-op.
+ *
+ * @hide
+ */
+@TestApi
+@SystemApi
+public final class TunerVersionChecker {
+ private static final String TAG = "TunerVersionChecker";
+
+ private TunerVersionChecker() {}
+
+ /** @hide */
+ @IntDef(prefix = "TUNER_VERSION_", value = {TUNER_VERSION_UNKNOWN, TUNER_VERSION_1_0,
+ TUNER_VERSION_1_1})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TunerVersion {}
+ /**
+ * Unknown Tuner version.
+ */
+ public static final int TUNER_VERSION_UNKNOWN = 0;
+ /**
+ * Tuner version 1.0.
+ */
+ public static final int TUNER_VERSION_1_0 = (1 << 16);
+ /**
+ * Tuner version 1.1.
+ */
+ public static final int TUNER_VERSION_1_1 = ((1 << 16) | 1);
+
+ /**
+ * Get the current running Tuner version.
+ *
+ * @return Tuner version.
+ */
+ @TunerVersion
+ public static int getTunerVersion() {
+ return Tuner.getTunerVersion();
+ }
+
+ /**
+ * Check if the current running Tuner version supports the given version.
+ *
+ * <p>Note that we treat different major versions as unsupported among each other. If any
+ * feature could be supported across major versions, please use
+ * {@link #isHigherOrEqualVersionTo(int)} to check.
+ *
+ * @param version the version to support.
+ *
+ * @return true if the current version is under the same major version as the given version
+ * and has higher or the same minor version as the given version.
+ * @hide
+ */
+ @TestApi
+ public static boolean supportTunerVersion(@TunerVersion int version) {
+ int currentVersion = Tuner.getTunerVersion();
+ return isHigherOrEqualVersionTo(version)
+ && (getMajorVersion(version) == getMajorVersion(currentVersion));
+ }
+
+ /**
+ * Check if the current running Tuner version is higher than or equal to a given version.
+ *
+ * @param version the version to compare.
+ *
+ * @return true if the current version is higher or equal to the support version.
+ * @hide
+ */
+ @TestApi
+ public static boolean isHigherOrEqualVersionTo(@TunerVersion int version) {
+ int currentVersion = Tuner.getTunerVersion();
+ return currentVersion >= version;
+ }
+
+ /**
+ * Get the major version from a version number.
+ *
+ * @param version the version to be checked.
+ *
+ * @return the major version number.
+ * @hide
+ */
+ @TestApi
+ public static int getMajorVersion(@TunerVersion int version) {
+ return ((version & 0xFFFF0000) >>> 16);
+ }
+
+ /**
+ * Get the major version from a version number.
+ *
+ * @param version the version to be checked.
+ *
+ * @return the minor version number.
+ * @hide
+ */
+ @TestApi
+ public static int getMinorVersion(@TunerVersion int version) {
+ return (version & 0xFFFF);
+ }
+
+ /** @hide */
+ public static boolean checkHigherOrEqualVersionTo(
+ @TunerVersion int version, String methodName) {
+ if (!TunerVersionChecker.isHigherOrEqualVersionTo(version)) {
+ Log.e(TAG, "Current Tuner version "
+ + TunerVersionChecker.getMajorVersion(Tuner.getTunerVersion()) + "."
+ + TunerVersionChecker.getMinorVersion(Tuner.getTunerVersion())
+ + " does not support " + methodName + ".");
+ return false;
+ }
+ return true;
+ }
+
+ /** @hide */
+ public static boolean checkSupportVersion(@TunerVersion int version, String methodName) {
+ if (!TunerVersionChecker.supportTunerVersion(version)) {
+ Log.e(TAG, "Current Tuner version "
+ + TunerVersionChecker.getMajorVersion(Tuner.getTunerVersion()) + "."
+ + TunerVersionChecker.getMinorVersion(Tuner.getTunerVersion())
+ + " does not support " + methodName + ".");
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
index bb00bb3..597278b 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
@@ -123,13 +123,14 @@
/**
* Attaches a filter to DVR interface for playback.
*
- * <p>This method will be deprecated. Now it's a no-op.
- * <p>Filters opened by {@link Tuner#openFilter} are used for DVR playback.
+ * @deprecated attaching filters is not valid in Dvr Playback use case. This API is a no-op.
+ * Filters opened by {@link Tuner#openFilter} are used for DVR playback.
*
* @param filter the filter to be attached.
* @return result status of the operation.
*/
@Result
+ @Deprecated
public int attachFilter(@NonNull Filter filter) {
// no-op
return Tuner.RESULT_UNAVAILABLE;
@@ -138,13 +139,14 @@
/**
* Detaches a filter from DVR interface.
*
- * <p>This method will be deprecated. Now it's a no-op.
- * <p>Filters opened by {@link Tuner#openFilter} are used for DVR playback.
+ * @deprecated detaching filters is not valid in Dvr Playback use case. This API is a no-op.
+ * Filters opened by {@link Tuner#openFilter} are used for DVR playback.
*
* @param filter the filter to be detached.
* @return result status of the operation.
*/
@Result
+ @Deprecated
public int detachFilter(@NonNull Filter filter) {
// no-op
return Tuner.RESULT_UNAVAILABLE;
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index f0015b7..2f2d8f7 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -185,7 +185,7 @@
private long mNativeContext;
private FilterCallback mCallback;
private Executor mExecutor;
- private final int mId;
+ private final long mId;
private int mMainType;
private int mSubtype;
private Filter mSource;
@@ -196,6 +196,7 @@
private native int nativeConfigureFilter(
int type, int subType, FilterConfiguration settings);
private native int nativeGetId();
+ private native long nativeGetId64Bit();
private native int nativeSetDataSource(Filter source);
private native int nativeStartFilter();
private native int nativeStopFilter();
@@ -204,7 +205,7 @@
private native int nativeClose();
// Called by JNI
- private Filter(int id) {
+ private Filter(long id) {
mId = id;
}
@@ -269,6 +270,16 @@
}
/**
+ * Gets the 64-bit filter Id.
+ */
+ public long getId64Bit() {
+ synchronized (mLock) {
+ TunerUtils.checkResourceState(TAG, mIsClosed);
+ return nativeGetId64Bit();
+ }
+ }
+
+ /**
* Sets the filter's data source.
*
* A filter uses demux as data source by default. If the data was packetized
diff --git a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
index f54b686..2649fcf 100644
--- a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.annotation.Size;
import android.annotation.SystemApi;
+import android.media.tv.tuner.TunerVersionChecker;
/**
* Filter configuration for a IP filter.
@@ -28,20 +29,28 @@
*/
@SystemApi
public final class IpFilterConfiguration extends FilterConfiguration {
+ /**
+ * Undefined filter type.
+ */
+ public static final int INVALID_IP_FILTER_CONTEXT_ID =
+ android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_IP_FILTER_CONTEXT_ID;
+
private final byte[] mSrcIpAddress;
private final byte[] mDstIpAddress;
private final int mSrcPort;
private final int mDstPort;
private final boolean mPassthrough;
+ private final int mIpFilterContextId;
private IpFilterConfiguration(Settings settings, byte[] srcAddr, byte[] dstAddr, int srcPort,
- int dstPort, boolean passthrough) {
+ int dstPort, boolean passthrough, int ipCid) {
super(settings);
mSrcIpAddress = srcAddr;
mDstIpAddress = dstAddr;
mSrcPort = srcPort;
mDstPort = dstPort;
mPassthrough = passthrough;
+ mIpFilterContextId = ipCid;
}
@Override
@@ -86,6 +95,15 @@
public boolean isPassthrough() {
return mPassthrough;
}
+ /**
+ * Gets the ip filter context id. Default value is {@link #INVALID_IP_FILTER_CONTEXT_ID}.
+ *
+ * <p>This API is only supported by Tuner HAL 1.1 or higher. Unsupported version would return
+ * default value. Use {@link TunerVersionChecker.getTunerVersion()} to check the version.
+ */
+ public int getIpFilterContextId() {
+ return mIpFilterContextId;
+ }
/**
* Creates a builder for {@link IpFilterConfiguration}.
@@ -105,6 +123,7 @@
private int mDstPort = 0;
private boolean mPassthrough = false;
private Settings mSettings;
+ private int mIpCid = INVALID_IP_FILTER_CONTEXT_ID;
private Builder() {
}
@@ -170,6 +189,21 @@
}
/**
+ * Sets the ip filter context id. Default value is {@link #INVALID_IP_FILTER_CONTEXT_ID}.
+ *
+ * <p>This API is only supported by Tuner HAL 1.1 or higher. Unsupported version would cause
+ * no-op. Use {@link TunerVersionChecker.getTunerVersion()} to check the version.
+ */
+ @NonNull
+ public Builder setIpFilterContextId(int ipContextId) {
+ if (TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "setIpFilterContextId")) {
+ mIpCid = ipContextId;
+ }
+ return this;
+ }
+
+ /**
* Builds a {@link IpFilterConfiguration} object.
*/
@NonNull
@@ -180,8 +214,8 @@
"The lengths of src and dst IP address must be 4 or 16 and must be the same."
+ "srcLength=" + ipAddrLength + ", dstLength=" + mDstIpAddress.length);
}
- return new IpFilterConfiguration(
- mSettings, mSrcIpAddress, mDstIpAddress, mSrcPort, mDstPort, mPassthrough);
+ return new IpFilterConfiguration(mSettings, mSrcIpAddress, mDstIpAddress, mSrcPort,
+ mDstPort, mPassthrough, mIpCid);
}
}
}
diff --git a/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java b/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java
index 466fa3e..7060bd72 100644
--- a/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java
+++ b/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java
@@ -29,11 +29,15 @@
public class MmtpRecordEvent extends FilterEvent {
private final int mScHevcIndexMask;
private final long mDataLength;
+ private final int mMpuSequenceNumber;
+ private final long mPts;
// This constructor is used by JNI code only
- private MmtpRecordEvent(int scHevcIndexMask, long dataLength) {
+ private MmtpRecordEvent(int scHevcIndexMask, long dataLength, int mpuSequenceNumber, long pts) {
mScHevcIndexMask = scHevcIndexMask;
mDataLength = dataLength;
+ mMpuSequenceNumber = mpuSequenceNumber;
+ mPts = pts;
}
/**
@@ -51,4 +55,20 @@
public long getDataLength() {
return mDataLength;
}
+
+ /**
+ * Get the MPU sequence number of the filtered data.
+ */
+ public int getMpuSequenceNumber() {
+ return mMpuSequenceNumber;
+ }
+
+ /**
+ * Get the Presentation Time Stamp(PTS) for the audio or video frame. It is based on 90KHz
+ * and has the same format as the PTS in ISO/IEC 13818-1. It is used only for the SC and
+ * the SC_HEVC.
+ */
+ public long getPts() {
+ return mPts;
+ }
}
diff --git a/media/java/android/media/tv/tuner/filter/TsRecordEvent.java b/media/java/android/media/tv/tuner/filter/TsRecordEvent.java
index 7a14bb8..258e2f2 100644
--- a/media/java/android/media/tv/tuner/filter/TsRecordEvent.java
+++ b/media/java/android/media/tv/tuner/filter/TsRecordEvent.java
@@ -32,13 +32,15 @@
private final int mTsIndexMask;
private final int mScIndexMask;
private final long mDataLength;
+ private final long mPts;
// This constructor is used by JNI code only
- private TsRecordEvent(int pid, int tsIndexMask, int scIndexMask, long dataLength) {
+ private TsRecordEvent(int pid, int tsIndexMask, int scIndexMask, long dataLength, long pts) {
mPid = pid;
mTsIndexMask = tsIndexMask;
mScIndexMask = scIndexMask;
mDataLength = dataLength;
+ mPts = pts;
}
/**
@@ -72,4 +74,13 @@
public long getDataLength() {
return mDataLength;
}
+
+ /**
+ * Gets the Presentation Time Stamp(PTS) for the audio or video frame. It is based on 90KHz
+ * and has the same format as the PTS in ISO/IEC 13818-1. It is used only for the SC and
+ * the SC_HEVC.
+ */
+ public long getPts() {
+ return mPts;
+ }
}
diff --git a/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java
index 1d36da3..c6a5bb0 100644
--- a/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java
@@ -21,6 +21,7 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.hardware.tv.tuner.V1_0.Constants;
+import android.media.tv.tuner.TunerVersionChecker;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -164,9 +165,32 @@
*/
public static final int SIF_L_PRIME = Constants.FrontendAnalogSifStandard.L_PRIME;
+ /** @hide */
+ @IntDef(prefix = "AFT_FLAG_",
+ value = {AFT_FLAG_UNDEFINED, AFT_FLAG_TRUE, AFT_FLAG_FALSE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AftFlag {}
+
+ /**
+ * Aft flag is not defined.
+ */
+ public static final int AFT_FLAG_UNDEFINED =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendAnalogAftFlag.UNDEFINED;
+ /**
+ * Aft flag is set true.
+ */
+ public static final int AFT_FLAG_TRUE =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendAnalogAftFlag.AFT_TRUE;
+ /**
+ * Aft flag is not set.
+ */
+ public static final int AFT_FLAG_FALSE =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendAnalogAftFlag.AFT_FALSE;
+
private final int mSignalType;
private final int mSifStandard;
+ private final int mAftFlag;
@Override
public int getType() {
@@ -191,6 +215,14 @@
}
/**
+ * Gets AFT flag.
+ */
+ @AftFlag
+ public int getAftFlag() {
+ return mAftFlag;
+ }
+
+ /**
* Creates a builder for {@link AnalogFrontendSettings}.
*/
@NonNull
@@ -198,10 +230,11 @@
return new Builder();
}
- private AnalogFrontendSettings(int frequency, int signalType, int sifStandard) {
+ private AnalogFrontendSettings(int frequency, int signalType, int sifStandard, int aftFlag) {
super(frequency);
mSignalType = signalType;
mSifStandard = sifStandard;
+ mAftFlag = aftFlag;
}
/**
@@ -211,6 +244,7 @@
private int mFrequency = 0;
private int mSignalType = SIGNAL_TYPE_UNDEFINED;
private int mSifStandard = SIF_UNDEFINED;
+ private int mAftFlag = AFT_FLAG_UNDEFINED;
private Builder() {}
@@ -227,6 +261,24 @@
}
/**
+ * Set Aft flag.
+ *
+ * <p>This API is only supported by Tuner HAL 1.1 or higher. Unsupported version would cause
+ * no-op. Use {@link TunerVersionChecker.getTunerVersion()} to check the version.
+ *
+ * @param aftFlag the value to set the aft flag. The default value is
+ * {@link #AFT_FLAG_UNDEFINED}.
+ */
+ @NonNull
+ public Builder setAftFlag(@AftFlag int aftFlag) {
+ if (TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "setAftFlag")) {
+ mAftFlag = aftFlag;
+ }
+ return this;
+ }
+
+ /**
* Sets analog signal type.
*
* <p>Default value is {@link #SIGNAL_TYPE_UNDEFINED}.
@@ -253,7 +305,7 @@
*/
@NonNull
public AnalogFrontendSettings build() {
- return new AnalogFrontendSettings(mFrequency, mSignalType, mSifStandard);
+ return new AnalogFrontendSettings(mFrequency, mSignalType, mSifStandard, mAftFlag);
}
}
}
diff --git a/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java
index f9eabc5..ed1ce2d 100644
--- a/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java
@@ -377,8 +377,8 @@
*/
@NonNull
public Atsc3FrontendSettings build() {
- return new Atsc3FrontendSettings(
- mFrequency, mBandwidth, mDemodOutputFormat, mPlpSettings);
+ return new Atsc3FrontendSettings(mFrequency, mBandwidth, mDemodOutputFormat,
+ mPlpSettings);
}
}
diff --git a/media/java/android/media/tv/tuner/frontend/DtmbFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/DtmbFrontendCapabilities.java
new file mode 100644
index 0000000..9fc3a23
--- /dev/null
+++ b/media/java/android/media/tv/tuner/frontend/DtmbFrontendCapabilities.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2020 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 android.media.tv.tuner.frontend;
+
+import android.annotation.SystemApi;
+
+/**
+ * DTMB Capabilities.
+ *
+ * <p>DTMB Frontend is only supported in Tuner HAL 1.1 or higher.
+ * @hide
+ */
+@SystemApi
+public class DtmbFrontendCapabilities extends FrontendCapabilities {
+ private final int mModulationCap;
+ private final int mTransmissionModeCap;
+ private final int mGuardIntervalCap;
+ private final int mTimeInterleaveModeCap;
+ private final int mCodeRateCap;
+ private final int mBandwidthCap;
+
+ private DtmbFrontendCapabilities(int modulationCap, int transmissionModeCap,
+ int guardIntervalCap, int timeInterleaveModeCap, int codeRateCap, int bandwidthCap) {
+ mModulationCap = modulationCap;
+ mTransmissionModeCap = transmissionModeCap;
+ mGuardIntervalCap = guardIntervalCap;
+ mTimeInterleaveModeCap = timeInterleaveModeCap;
+ mCodeRateCap = codeRateCap;
+ mBandwidthCap = bandwidthCap;
+ }
+
+ /**
+ * Gets modulation capability.
+ *
+ * @return full modulation capabilies. If the caps bitwise AND with any value from
+ * bit masks {@link DtmbFrontendSettings.Modulation} is true, then that modulation is supported.
+ */
+ @DtmbFrontendSettings.Modulation
+ public int getModulationCapability() {
+ return mModulationCap;
+ }
+
+ /**
+ * Gets Transmission Mode capability.
+ *
+ * @return full Transmission Mode capabilies. If the caps bitwise AND with any value from
+ * bit masks {@link DtmbFrontendSettings.TransmissionMode} is true, then that transmission mode
+ * is supported.
+ */
+ @DtmbFrontendSettings.TransmissionMode
+ public int getTransmissionModeCapability() {
+ return mTransmissionModeCap;
+ }
+
+ /**
+ * Gets Guard Interval capability.
+ *
+ * @return full Guard Interval capabilies. If the caps bitwise AND with any value from
+ * bit masks {@link DtmbFrontendSettings.GuardInterval} is true, then that Guard Interval is
+ * supported.
+ */
+ @DtmbFrontendSettings.GuardInterval
+ public int getGuardIntervalCapability() {
+ return mGuardIntervalCap;
+ }
+
+ /**
+ * Gets Time Interleave Mode capability.
+ *
+ * @return full Time Interleave Mode capabilies. If the caps bitwise AND with any value from
+ * bit masks {@link DtmbFrontendSettings.TimeInterleaveMode} is true, then that Time Interleave
+ * Mode is supported.
+ */
+ @DtmbFrontendSettings.TimeInterleaveMode
+ public int getTimeInterleaveModeCapability() {
+ return mTimeInterleaveModeCap;
+ }
+
+ /**
+ * Gets Code Rate capability.
+ *
+ * @return full Code Rate capabilies. If the caps bitwise AND with any value from
+ * bit masks {@link DtmbFrontendSettings.CodeRate} is true, then that Code Rate is supported.
+ */
+ @DtmbFrontendSettings.CodeRate
+ public int getCodeRateCapability() {
+ return mCodeRateCap;
+ }
+
+ /**
+ * Gets Bandwidth capability.
+ *
+ * @return full Bandwidth capabilies. If the caps bitwise AND with any value from
+ * bit masks {@link DtmbFrontendSettings.Bandwidth} is true, then that Bandwidth is supported.
+ */
+ @DtmbFrontendSettings.Bandwidth
+ public int getBandwidthCapability() {
+ return mBandwidthCap;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/frontend/DtmbFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DtmbFrontendSettings.java
new file mode 100644
index 0000000..2c3fe6a
--- /dev/null
+++ b/media/java/android/media/tv/tuner/frontend/DtmbFrontendSettings.java
@@ -0,0 +1,441 @@
+/*
+ * Copyright 2020 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 android.media.tv.tuner.frontend;
+
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Frontend settings for DTMB.
+ *
+ * <p>DTMB Frontend is only supported in Tuner HAL 1.1 or higher. Use {@link
+ * android.media.tv.tuner.TunerVersionChecker.getTunerVersion()} to get the version information.
+ *
+ * @hide
+ */
+@SystemApi
+public class DtmbFrontendSettings extends FrontendSettings {
+
+ /** @hide */
+ @IntDef(flag = true,
+ prefix = "BANDWIDTH_",
+ value = {BANDWIDTH_UNDEFINED, BANDWIDTH_AUTO, BANDWIDTH_6MHZ, BANDWIDTH_8MHZ})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Bandwidth {}
+
+ /**
+ * Bandwidth not defined.
+ */
+ public static final int BANDWIDTH_UNDEFINED =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbBandwidth.UNDEFINED;
+ /**
+ * Hardware is able to detect and set bandwidth automatically
+ */
+ public static final int BANDWIDTH_AUTO =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbBandwidth.AUTO;
+ /**
+ * 6 MHz bandwidth.
+ */
+ public static final int BANDWIDTH_6MHZ =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbBandwidth.BANDWIDTH_6MHZ;
+ /**
+ * 8 MHz bandwidth.
+ */
+ public static final int BANDWIDTH_8MHZ =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbBandwidth.BANDWIDTH_8MHZ;
+
+
+ /** @hide */
+ @IntDef(flag = true,
+ prefix = "TIME_INTERLEAVE_MODE_",
+ value = {TIME_INTERLEAVE_MODE_UNDEFINED, TIME_INTERLEAVE_MODE_AUTO,
+ TIME_INTERLEAVE_MODE_TIMER_INT_240, TIME_INTERLEAVE_MODE_TIMER_INT_720})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TimeInterleaveMode {}
+
+ /**
+ * Time Interleave Mode undefined.
+ */
+ public static final int TIME_INTERLEAVE_MODE_UNDEFINED =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbTimeInterleaveMode.UNDEFINED;
+ /**
+ * Hardware is able to detect and set time interleave mode automatically
+ */
+ public static final int TIME_INTERLEAVE_MODE_AUTO =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbTimeInterleaveMode.AUTO;
+ /**
+ * Time Interleave Mode timer int 240.
+ */
+ public static final int TIME_INTERLEAVE_MODE_TIMER_INT_240 =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbTimeInterleaveMode.TIMER_INT_240;
+ /**
+ * Time Interleave Mode timer int 720.
+ */
+ public static final int TIME_INTERLEAVE_MODE_TIMER_INT_720 =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbTimeInterleaveMode.TIMER_INT_720;
+
+
+ /** @hide */
+ @IntDef(flag = true,
+ prefix = "GUARD_INTERVAL_",
+ value = {GUARD_INTERVAL_UNDEFINED, GUARD_INTERVAL_AUTO,
+ GUARD_INTERVAL_PN_420_VARIOUS, GUARD_INTERVAL_PN_595_CONST,
+ GUARD_INTERVAL_PN_945_VARIOUS, GUARD_INTERVAL_PN_420_CONST,
+ GUARD_INTERVAL_PN_945_CONST, GUARD_INTERVAL_PN_RESERVED})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface GuardInterval {}
+
+ /**
+ * Guard Interval undefined.
+ */
+ public static final int GUARD_INTERVAL_UNDEFINED =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbGuardInterval.UNDEFINED;
+ /**
+ * Hardware is able to detect and set Guard Interval automatically.
+ */
+ public static final int GUARD_INTERVAL_AUTO =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbGuardInterval.AUTO;
+ /**
+ * PN_420_VARIOUS Guard Interval.
+ */
+ public static final int GUARD_INTERVAL_PN_420_VARIOUS =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbGuardInterval.PN_420_VARIOUS;
+ /**
+ * PN_595_CONST Guard Interval.
+ */
+ public static final int GUARD_INTERVAL_PN_595_CONST =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbGuardInterval.PN_595_CONST;
+ /**
+ * PN_945_VARIOUS Guard Interval.
+ */
+ public static final int GUARD_INTERVAL_PN_945_VARIOUS =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbGuardInterval.PN_945_VARIOUS;
+ /**
+ * PN_420_CONST Guard Interval.
+ */
+ public static final int GUARD_INTERVAL_PN_420_CONST =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbGuardInterval.PN_420_CONST;
+ /**
+ * PN_945_CONST Guard Interval.
+ */
+ public static final int GUARD_INTERVAL_PN_945_CONST =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbGuardInterval.PN_945_CONST;
+ /**
+ * PN_RESERVED Guard Interval.
+ */
+ public static final int GUARD_INTERVAL_PN_RESERVED =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbGuardInterval.PN_RESERVED;
+
+
+ /** @hide */
+ @IntDef(flag = true,
+ prefix = "MODULATION_",
+ value = {MODULATION_CONSTELLATION_UNDEFINED, MODULATION_CONSTELLATION_AUTO,
+ MODULATION_CONSTELLATION_4QAM, MODULATION_CONSTELLATION_4QAM_NR,
+ MODULATION_CONSTELLATION_16QAM, MODULATION_CONSTELLATION_32QAM,
+ MODULATION_CONSTELLATION_64QAM})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Modulation {}
+
+ /**
+ * Constellation not defined.
+ */
+ public static final int MODULATION_CONSTELLATION_UNDEFINED =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbModulation.UNDEFINED;
+ /**
+ * Hardware is able to detect and set Constellation automatically.
+ */
+ public static final int MODULATION_CONSTELLATION_AUTO =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbModulation.AUTO;
+ /**
+ * 4QAM Constellation.
+ */
+ public static final int MODULATION_CONSTELLATION_4QAM =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbModulation.CONSTELLATION_4QAM;
+ /**
+ * 4QAM_NR Constellation.
+ */
+ public static final int MODULATION_CONSTELLATION_4QAM_NR =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbModulation.CONSTELLATION_4QAM_NR;
+ /**
+ * 16QAM Constellation.
+ */
+ public static final int MODULATION_CONSTELLATION_16QAM =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbModulation.CONSTELLATION_16QAM;
+ /**
+ * 32QAM Constellation.
+ */
+ public static final int MODULATION_CONSTELLATION_32QAM =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbModulation.CONSTELLATION_32QAM;
+ /**
+ * 64QAM Constellation.
+ */
+ public static final int MODULATION_CONSTELLATION_64QAM =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbModulation.CONSTELLATION_64QAM;
+
+ /** @hide */
+ @IntDef(flag = true,
+ prefix = "CODERATE_",
+ value = {CODERATE_UNDEFINED, CODERATE_AUTO, CODERATE_2_5, CODERATE_3_5, CODERATE_4_5})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CodeRate {}
+
+ /**
+ * Code rate undefined.
+ */
+ public static final int CODERATE_UNDEFINED =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbCodeRate.UNDEFINED;
+ /**
+ * Hardware is able to detect and set code rate automatically.
+ */
+ public static final int CODERATE_AUTO =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbCodeRate.AUTO;
+ /**
+ * 2/5 code rate.
+ */
+ public static final int CODERATE_2_5 =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbCodeRate.CODERATE_2_5;
+ /**
+ * 3/5 code rate.
+ */
+ public static final int CODERATE_3_5 =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbCodeRate.CODERATE_3_5;
+ /**
+ * 4/5 code rate.
+ */
+ public static final int CODERATE_4_5 =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbCodeRate.CODERATE_4_5;
+
+ /** @hide */
+ @IntDef(flag = true,
+ prefix = "TRANSMISSION_MODE_",
+ value = {TRANSMISSION_MODE_UNDEFINED, TRANSMISSION_MODE_AUTO,
+ TRANSMISSION_MODE_C1, TRANSMISSION_MODE_C3780})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TransmissionMode {}
+
+ /**
+ * Transmission Mode undefined.
+ */
+ public static final int TRANSMISSION_MODE_UNDEFINED =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbTransmissionMode.UNDEFINED;
+ /**
+ * Hardware is able to detect and set Transmission Mode automatically
+ */
+ public static final int TRANSMISSION_MODE_AUTO =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbTransmissionMode.AUTO;
+ /**
+ * C1 Transmission Mode.
+ */
+ public static final int TRANSMISSION_MODE_C1 =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbTransmissionMode.C1;
+ /**
+ * C3780 Transmission Mode.
+ */
+ public static final int TRANSMISSION_MODE_C3780 =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbTransmissionMode.C3780;
+
+
+ private final int mModulation;
+ private final int mCodeRate;
+ private final int mTransmissionMode;
+ private final int mBandwidth;
+ private final int mGuardInterval;
+ private final int mTimeInterleaveMode;
+
+ private DtmbFrontendSettings(int frequency, int modulation, int codeRate, int transmissionMode,
+ int guardInterval, int timeInterleaveMode, int bandwidth) {
+ super(frequency);
+ mModulation = modulation;
+ mCodeRate = codeRate;
+ mTransmissionMode = transmissionMode;
+ mGuardInterval = guardInterval;
+ mTimeInterleaveMode = timeInterleaveMode;
+ mBandwidth = bandwidth;
+ }
+
+ /**
+ * Gets Modulation.
+ */
+ @Modulation
+ public int getModulation() {
+ return mModulation;
+ }
+
+ /**
+ * Gets Code Rate.
+ */
+ @Modulation
+ public int getCodeRate() {
+ return mCodeRate;
+ }
+
+ /**
+ * Gets Transmission Mode.
+ */
+ @Modulation
+ public int getTransmissionMode() {
+ return mTransmissionMode;
+ }
+
+ /**
+ * Gets Bandwidth.
+ */
+ @Modulation
+ public int getBandwidth() {
+ return mBandwidth;
+ }
+
+ /**
+ * Gets Time Interleave Mode.
+ */
+ @Modulation
+ public int getTimeInterleaveMode() {
+ return mTimeInterleaveMode;
+ }
+
+
+ /**
+ * Gets Guard Interval.
+ */
+ @Modulation
+ public int getGuardInterval() {
+ return mGuardInterval;
+ }
+
+ /**
+ * Creates a builder for {@link AtscFrontendSettings}.
+ */
+ @NonNull
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder for {@link AtscFrontendSettings}.
+ */
+ public static final class Builder {
+ private int mFrequency = 0;
+ private int mModulation = MODULATION_CONSTELLATION_UNDEFINED;
+ private int mCodeRate = CODERATE_UNDEFINED;
+ private int mTransmissionMode = TRANSMISSION_MODE_UNDEFINED;
+ private int mBandwidth = BANDWIDTH_UNDEFINED;
+ private int mTimeInterleaveMode = TIME_INTERLEAVE_MODE_UNDEFINED;
+ private int mGuardInterval = GUARD_INTERVAL_UNDEFINED;
+
+ private Builder() {
+ }
+
+ /**
+ * Sets frequency in Hz.
+ *
+ * <p>Default value is 0.
+ */
+ @NonNull
+ @IntRange(from = 1)
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public Builder setFrequency(int frequency) {
+ mFrequency = frequency;
+ return this;
+ }
+
+ /**
+ * Sets Modulation.
+ *
+ * <p>Default value is {@link #MODULATION_CONSTELLATION_UNDEFINED}.
+ */
+ @NonNull
+ public Builder setModulation(@Modulation int modulation) {
+ mModulation = modulation;
+ return this;
+ }
+
+ /**
+ * Sets Code Rate.
+ *
+ * <p>Default value is {@link #CODERATE_UNDEFINED}.
+ */
+ @NonNull
+ public Builder setCodeRate(@CodeRate int codeRate) {
+ mCodeRate = codeRate;
+ return this;
+ }
+
+ /**
+ * Sets Bandwidth.
+ *
+ * <p>Default value is {@link #BANDWIDTH_UNDEFINED}.
+ */
+ @NonNull
+ public Builder setBandwidth(@Bandwidth int bandwidth) {
+ mBandwidth = bandwidth;
+ return this;
+ }
+
+ /**
+ * Sets Time Interleave Mode.
+ *
+ * <p>Default value is {@link #TIME_INTERLEAVE_MODE_UNDEFINED}.
+ */
+ @NonNull
+ public Builder setTimeInterleaveMode(@TimeInterleaveMode int timeInterleaveMode) {
+ mTimeInterleaveMode = timeInterleaveMode;
+ return this;
+ }
+
+ /**
+ * Sets Guard Interval.
+ *
+ * <p>Default value is {@link #GUARD_INTERVAL_UNDEFINED}.
+ */
+ @NonNull
+ public Builder setGuardInterval(@GuardInterval int guardInterval) {
+ mGuardInterval = guardInterval;
+ return this;
+ }
+ /**
+ * Sets Transmission Mode.
+ *
+ * <p>Default value is {@link #TRANSMISSION_MODE_UNDEFINED}.
+ */
+ @NonNull
+ public Builder setTransmissionMode(@TransmissionMode int transmissionMode) {
+ mTransmissionMode = transmissionMode;
+ return this;
+ }
+
+ /**
+ * Builds a {@link DtmbFrontendSettings} object.
+ */
+ @NonNull
+ public DtmbFrontendSettings build() {
+ return new DtmbFrontendSettings(mFrequency, mModulation, mCodeRate,
+ mTransmissionMode, mGuardInterval, mTimeInterleaveMode, mBandwidth);
+ }
+ }
+
+ @Override
+ public int getType() {
+ return FrontendSettings.TYPE_DTMB;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
index 271e91e..e6968bb 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
@@ -21,6 +21,8 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.hardware.tv.tuner.V1_0.Constants;
+import android.media.tv.tuner.TunerVersionChecker;
+import android.media.tv.tuner.frontend.FrontendSettings.FrontendSpectralInversion;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -117,7 +119,11 @@
public static final int ANNEX_C = Constants.FrontendDvbcAnnex.C;
- /** @hide */
+ /**
+ * @deprecated Use the {@link FrontendSettings#FrontendSpectralInversion} instead.
+ * @hide
+ */
+ @Deprecated
@IntDef(prefix = "SPECTRAL_INVERSION_",
value = {SPECTRAL_INVERSION_UNDEFINED, SPECTRAL_INVERSION_NORMAL,
SPECTRAL_INVERSION_INVERTED})
@@ -126,20 +132,97 @@
/**
* Spectral Inversion Type undefined.
+ *
+ * @deprecated Use the {@link FrontendSettings#FRONTEND_SPECTRAL_INVERSION_UNDEFINED} instead.
*/
+ @Deprecated
public static final int SPECTRAL_INVERSION_UNDEFINED =
Constants.FrontendDvbcSpectralInversion.UNDEFINED;
/**
* Normal Spectral Inversion.
+ *
+ * @deprecated Use the {@link FrontendSettings#FRONTEND_SPECTRAL_INVERSION_NORMAL} instead.
*/
+ @Deprecated
public static final int SPECTRAL_INVERSION_NORMAL =
Constants.FrontendDvbcSpectralInversion.NORMAL;
/**
* Inverted Spectral Inversion.
+ *
+ * @deprecated Use the {@link FrontendSettings#FRONTEND_SPECTRAL_INVERSION_INVERTED} instead.
*/
+ @Deprecated
public static final int SPECTRAL_INVERSION_INVERTED =
Constants.FrontendDvbcSpectralInversion.INVERTED;
+ /** @hide */
+ @IntDef(flag = true,
+ prefix = "TIME_INTERLEAVE_MODE_",
+ value = {TIME_INTERLEAVE_MODE_UNDEFINED, TIME_INTERLEAVE_MODE_AUTO,
+ TIME_INTERLEAVE_MODE_128_1_0, TIME_INTERLEAVE_MODE_128_1_1,
+ TIME_INTERLEAVE_MODE_64_2, TIME_INTERLEAVE_MODE_32_4,
+ TIME_INTERLEAVE_MODE_16_8, TIME_INTERLEAVE_MODE_8_16,
+ TIME_INTERLEAVE_MODE_128_2, TIME_INTERLEAVE_MODE_128_3,
+ TIME_INTERLEAVE_MODE_128_4})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TimeInterleaveMode {}
+
+ /**
+ * Time interleave mode undefined.
+ */
+ public static final int TIME_INTERLEAVE_MODE_UNDEFINED =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendCableTimeInterleaveMode.UNDEFINED;
+ /**
+ * Hardware is able to detect and set Time Interleave Mode automatically.
+ */
+ public static final int TIME_INTERLEAVE_MODE_AUTO =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendCableTimeInterleaveMode.AUTO;
+ /**
+ * 128/1/0 Time Interleave Mode.
+ */
+ public static final int TIME_INTERLEAVE_MODE_128_1_0 = android.hardware.tv.tuner.V1_1.Constants
+ .FrontendCableTimeInterleaveMode.INTERLEAVING_128_1_0;
+ /**
+ * 128/1/1 Time Interleave Mode.
+ */
+ public static final int TIME_INTERLEAVE_MODE_128_1_1 = android.hardware.tv.tuner.V1_1.Constants
+ .FrontendCableTimeInterleaveMode.INTERLEAVING_128_1_1;
+ /**
+ * 64/2 Time Interleave Mode.
+ */
+ public static final int TIME_INTERLEAVE_MODE_64_2 = android.hardware.tv.tuner.V1_1.Constants
+ .FrontendCableTimeInterleaveMode.INTERLEAVING_64_2;
+ /**
+ * 32/4 Time Interleave Mode.
+ */
+ public static final int TIME_INTERLEAVE_MODE_32_4 = android.hardware.tv.tuner.V1_1.Constants
+ .FrontendCableTimeInterleaveMode.INTERLEAVING_32_4;
+ /**
+ * 16/8 Time Interleave Mode.
+ */
+ public static final int TIME_INTERLEAVE_MODE_16_8 = android.hardware.tv.tuner.V1_1.Constants
+ .FrontendCableTimeInterleaveMode.INTERLEAVING_16_8;
+ /**
+ * 8/16 Time Interleave Mode.
+ */
+ public static final int TIME_INTERLEAVE_MODE_8_16 = android.hardware.tv.tuner.V1_1.Constants
+ .FrontendCableTimeInterleaveMode.INTERLEAVING_8_16;
+ /**
+ * 128/2 Time Interleave Mode.
+ */
+ public static final int TIME_INTERLEAVE_MODE_128_2 = android.hardware.tv.tuner.V1_1.Constants
+ .FrontendCableTimeInterleaveMode.INTERLEAVING_128_2;
+ /**
+ * 128/3 Time Interleave Mode.
+ */
+ public static final int TIME_INTERLEAVE_MODE_128_3 = android.hardware.tv.tuner.V1_1.Constants
+ .FrontendCableTimeInterleaveMode.INTERLEAVING_128_3;
+ /**
+ * 128/4 Time Interleave Mode.
+ */
+ public static final int TIME_INTERLEAVE_MODE_128_4 = android.hardware.tv.tuner.V1_1.Constants
+ .FrontendCableTimeInterleaveMode.INTERLEAVING_128_4;
+
private final int mModulation;
private final long mInnerFec;
@@ -147,9 +230,11 @@
private final int mOuterFec;
private final int mAnnex;
private final int mSpectralInversion;
+ // Dvbc time interleave mode is only supported in Tuner 1.1 or higher.
+ private final int mInterleaveMode;
private DvbcFrontendSettings(int frequency, int modulation, long innerFec, int symbolRate,
- int outerFec, int annex, int spectralInversion) {
+ int outerFec, int annex, int spectralInversion, int interleaveMode) {
super(frequency);
mModulation = modulation;
mInnerFec = innerFec;
@@ -157,6 +242,7 @@
mOuterFec = outerFec;
mAnnex = annex;
mSpectralInversion = spectralInversion;
+ mInterleaveMode = interleaveMode;
}
/**
@@ -196,10 +282,17 @@
/**
* Gets Spectral Inversion.
*/
- @SpectralInversion
+ @FrontendSpectralInversion
public int getSpectralInversion() {
return mSpectralInversion;
}
+ /**
+ * Gets Time Interleave Mode.
+ */
+ @TimeInterleaveMode
+ public int getTimeInterleaveMode() {
+ return mInterleaveMode;
+ }
/**
* Creates a builder for {@link DvbcFrontendSettings}.
@@ -219,7 +312,8 @@
private int mSymbolRate = 0;
private int mOuterFec = OUTER_FEC_UNDEFINED;
private int mAnnex = ANNEX_UNDEFINED;
- private int mSpectralInversion = SPECTRAL_INVERSION_UNDEFINED;
+ private int mSpectralInversion = FrontendSettings.FRONTEND_SPECTRAL_INVERSION_UNDEFINED;
+ private int mInterleaveMode = TIME_INTERLEAVE_MODE_UNDEFINED;
private Builder() {
}
@@ -289,13 +383,30 @@
/**
* Sets Spectral Inversion.
*
- * <p>Default value is {@link #SPECTRAL_INVERSION_UNDEFINED}.
+ * <p>Default value is {@link FrontendSettings#FRONTEND_SPECTRAL_INVERSION_UNDEFINED}.
*/
@NonNull
- public Builder setSpectralInversion(@SpectralInversion int spectralInversion) {
+ public Builder setSpectralInversion(@FrontendSpectralInversion int spectralInversion) {
mSpectralInversion = spectralInversion;
return this;
}
+ /**
+ * Set the time interleave mode.
+ *
+ * <p>This API is only supported by Tuner HAL 1.1 or higher. Unsupported version would cause
+ * no-op. Use {@link TunerVersionChecker.getTunerVersion()} to check the version.
+ *
+ * @param interleaveMode the value to set as the time interleave mode. Default value is
+ * {@link #TIME_INTERLEAVE_MODE_UNDEFINED}.
+ */
+ @NonNull
+ public Builder setTimeInterleaveMode(@TimeInterleaveMode int interleaveMode) {
+ if (TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "setTimeInterleaveMode")) {
+ mInterleaveMode = interleaveMode;
+ }
+ return this;
+ }
/**
* Builds a {@link DvbcFrontendSettings} object.
@@ -303,7 +414,7 @@
@NonNull
public DvbcFrontendSettings build() {
return new DvbcFrontendSettings(mFrequency, mModulation, mInnerFec, mSymbolRate,
- mOuterFec, mAnnex, mSpectralInversion);
+ mOuterFec, mAnnex, mSpectralInversion, mInterleaveMode);
}
}
diff --git a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
index 60b070f..343dbb1 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
@@ -23,6 +23,8 @@
import android.annotation.SystemApi;
import android.hardware.tv.tuner.V1_0.Constants;
import android.media.tv.tuner.Tuner;
+import android.media.tv.tuner.TunerVersionChecker;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -36,6 +38,44 @@
public class DvbsFrontendSettings extends FrontendSettings {
/** @hide */
@IntDef(flag = true,
+ prefix = "SCAN_TYPE_",
+ value = {SCAN_TYPE_UNDEFINED, SCAN_TYPE_DIRECT, SCAN_TYPE_DISEQC,
+ SCAN_TYPE_UNICABLE, SCAN_TYPE_JESS})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ScanType {}
+
+ /**
+ * Dvbs scan type undefined.
+ */
+ public static final int SCAN_TYPE_UNDEFINED =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbsScanType.UNDEFINED;
+
+ /**
+ * Dvbs scan type DIRECT.
+ */
+ public static final int SCAN_TYPE_DIRECT =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbsScanType.DIRECT;
+
+ /**
+ * Dvbs scan type DISEQC.
+ */
+ public static final int SCAN_TYPE_DISEQC =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbsScanType.DISEQC;
+
+ /**
+ * Dvbs scan type UNICABLE.
+ */
+ public static final int SCAN_TYPE_UNICABLE =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbsScanType.UNICABLE;
+
+ /**
+ * Dvbs scan type JESS.
+ */
+ public static final int SCAN_TYPE_JESS =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbsScanType.JESS;
+
+ /** @hide */
+ @IntDef(flag = true,
prefix = "MODULATION_",
value = {MODULATION_UNDEFINED, MODULATION_AUTO, MODULATION_MOD_QPSK,
MODULATION_MOD_8PSK, MODULATION_MOD_16QAM, MODULATION_MOD_16PSK,
@@ -218,9 +258,12 @@
private final int mInputStreamId;
private final int mStandard;
private final int mVcmMode;
+ // Dvbs scan type is only supported in Tuner 1.1 or higher.
+ private final int mScanType;
private DvbsFrontendSettings(int frequency, int modulation, DvbsCodeRate codeRate,
- int symbolRate, int rolloff, int pilot, int inputStreamId, int standard, int vcm) {
+ int symbolRate, int rolloff, int pilot, int inputStreamId, int standard, int vcm,
+ int scanType) {
super(frequency);
mModulation = modulation;
mCodeRate = codeRate;
@@ -230,6 +273,7 @@
mInputStreamId = inputStreamId;
mStandard = standard;
mVcmMode = vcm;
+ mScanType = scanType;
}
/**
@@ -286,6 +330,13 @@
public int getVcmMode() {
return mVcmMode;
}
+ /**
+ * Get scan type.
+ */
+ @ScanType
+ public int getScanType() {
+ return mScanType;
+ }
/**
* Creates a builder for {@link DvbsFrontendSettings}.
@@ -308,6 +359,7 @@
private int mInputStreamId = Tuner.INVALID_STREAM_ID;
private int mStandard = STANDARD_AUTO;
private int mVcmMode = VCM_MODE_UNDEFINED;
+ private int mScanType = SCAN_TYPE_UNDEFINED;
private Builder() {
}
@@ -325,6 +377,24 @@
}
/**
+ * Set the scan type.
+ *
+ * <p>This API is only supported by Tuner HAL 1.1 or higher. Unsupported version would cause
+ * no-op. Use {@link TunerVersionChecker.getTunerVersion()} to check the version.
+ *
+ * @param scanType the value to set as the scan type. Default value is
+ * {@link android.media.tv.tuner.frontend.DvbsFrontendSettings#DVBS_SCAN_TYPE_UNDEFINED}.
+ */
+ @NonNull
+ public Builder setScanType(@ScanType int scanType) {
+ if (TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "setScanType")) {
+ mScanType = scanType;
+ }
+ return this;
+ }
+
+ /**
* Sets Modulation.
*
* <p>Default value is {@link #MODULATION_UNDEFINED}.
@@ -411,7 +481,7 @@
@NonNull
public DvbsFrontendSettings build() {
return new DvbsFrontendSettings(mFrequency, mModulation, mCodeRate, mSymbolRate,
- mRolloff, mPilot, mInputStreamId, mStandard, mVcmMode);
+ mRolloff, mPilot, mInputStreamId, mStandard, mVcmMode, mScanType);
}
}
diff --git a/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
index 5c057de..07d1797 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
@@ -21,6 +21,7 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.hardware.tv.tuner.V1_0.Constants;
+import android.media.tv.tuner.TunerVersionChecker;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -75,8 +76,21 @@
* 32K Transmission Mode.
*/
public static final int TRANSMISSION_MODE_32K = Constants.FrontendDvbtTransmissionMode.MODE_32K;
-
-
+ /**
+ * 8K Transmission Extended Mode.
+ */
+ public static final int TRANSMISSION_MODE_EXTENDED_8K =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbtTransmissionMode.MODE_8K_E;
+ /**
+ * 16K Transmission Extended Mode.
+ */
+ public static final int TRANSMISSION_MODE_EXTENDED_16K =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbtTransmissionMode.MODE_16K_E;
+ /**
+ * 32K Transmission Extended Mode.
+ */
+ public static final int TRANSMISSION_MODE_EXTENDED_32K =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbtTransmissionMode.MODE_32K_E;
/** @hide */
@IntDef(flag = true,
@@ -124,8 +138,9 @@
@IntDef(flag = true,
prefix = "CONSTELLATION_",
value = {CONSTELLATION_UNDEFINED, CONSTELLATION_AUTO, CONSTELLATION_QPSK,
- CONSTELLATION_16QAM, CONSTELLATION_64QAM,
- CONSTELLATION_256QAM})
+ CONSTELLATION_16QAM, CONSTELLATION_64QAM, CONSTELLATION_256QAM,
+ CONSTELLATION_QPSK_R, CONSTELLATION_16QAM_R, CONSTELLATION_64QAM_R,
+ CONSTELLATION_256QAM_R})
@Retention(RetentionPolicy.SOURCE)
public @interface Constellation {}
@@ -157,7 +172,30 @@
*/
public static final int CONSTELLATION_256QAM =
Constants.FrontendDvbtConstellation.CONSTELLATION_256QAM;
-
+ /**
+ * QPSK Rotated Constellation.
+ */
+ public static final int CONSTELLATION_QPSK_R =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbtConstellation
+ .CONSTELLATION_QPSK_R;
+ /**
+ * 16QAM Rotated Constellation.
+ */
+ public static final int CONSTELLATION_16QAM_R =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbtConstellation
+ .CONSTELLATION_16QAM_R;
+ /**
+ * 64QAM Rotated Constellation.
+ */
+ public static final int CONSTELLATION_64QAM_R =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbtConstellation
+ .CONSTELLATION_64QAM_R;
+ /**
+ * 256QAM Rotated Constellation.
+ */
+ public static final int CONSTELLATION_256QAM_R =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbtConstellation
+ .CONSTELLATION_256QAM_R;
/** @hide */
@IntDef(flag = true,
@@ -366,8 +404,7 @@
*/
public static final int PLP_MODE_MANUAL = Constants.FrontendDvbtPlpMode.MANUAL;
-
- private final int mTransmissionMode;
+ private int mTransmissionMode;
private final int mBandwidth;
private final int mConstellation;
private final int mHierarchy;
@@ -489,6 +526,19 @@
return mPlpGroupId;
}
+ private static boolean isExtendedTransmissionMode(@TransmissionMode int transmissionMode) {
+ return transmissionMode == TRANSMISSION_MODE_EXTENDED_8K
+ || transmissionMode == TRANSMISSION_MODE_EXTENDED_16K
+ || transmissionMode == TRANSMISSION_MODE_EXTENDED_32K;
+ }
+
+ private static boolean isExtendedConstellation(@Constellation int constellation) {
+ return constellation == CONSTELLATION_QPSK_R
+ || constellation == CONSTELLATION_16QAM_R
+ || constellation == CONSTELLATION_64QAM_R
+ || constellation == CONSTELLATION_256QAM_R;
+ }
+
/**
* Creates a builder for {@link DvbtFrontendSettings}.
*/
@@ -534,13 +584,23 @@
/**
* Sets Transmission Mode.
*
+ * <p>{@link #TRANSMISSION_MODE_EXTENDED_8K}, {@link #TRANSMISSION_MODE_EXTENDED_16K} and
+ * {@link #TRANSMISSION_MODE_EXTENDED_32K} are only supported by Tuner HAL 1.1 or higher.
+ * Unsupported version would cause no-op. Use {@link TunerVersionChecker.getTunerVersion()}
+ * to check the version.
+ *
* <p>Default value is {@link #TRANSMISSION_MODE_UNDEFINED}.
*/
@NonNull
public Builder setTransmissionMode(@TransmissionMode int transmissionMode) {
- mTransmissionMode = transmissionMode;
+ if (!isExtendedTransmissionMode(transmissionMode)
+ || TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "set TransmissionMode Ext")) {
+ mTransmissionMode = transmissionMode;
+ }
return this;
}
+
/**
* Sets Bandwidth.
*
@@ -554,11 +614,20 @@
/**
* Sets Constellation.
*
+ * <p>{@link #CONSTELLATION_QPSK_R}, {@link #CONSTELLATION_16QAM_R},
+ * {@link #CONSTELLATION_64QAM_R} and {@link #CONSTELLATION_256QAM_Rare} are only supported
+ * by Tuner HAL 1.1 or higher. Unsupported version would cause no-op. Use
+ * {@link TunerVersionChecker.getTunerVersion()} to check the version.
+ *
* <p>Default value is {@link #CONSTELLATION_UNDEFINED}.
*/
@NonNull
public Builder setConstellation(@Constellation int constellation) {
- mConstellation = constellation;
+ if (!isExtendedConstellation(constellation)
+ || TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "set Constellation Ext")) {
+ mConstellation = constellation;
+ }
return this;
}
/**
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
index 2f2fa97..2147622 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
@@ -17,9 +17,12 @@
package android.media.tv.tuner.frontend;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.LongDef;
import android.annotation.SystemApi;
import android.hardware.tv.tuner.V1_0.Constants;
+import android.media.tv.tuner.Tuner;
+import android.media.tv.tuner.TunerVersionChecker;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -34,7 +37,7 @@
/** @hide */
@IntDef(prefix = "TYPE_",
value = {TYPE_UNDEFINED, TYPE_ANALOG, TYPE_ATSC, TYPE_ATSC3, TYPE_DVBC, TYPE_DVBS,
- TYPE_DVBT, TYPE_ISDBS, TYPE_ISDBS3, TYPE_ISDBT})
+ TYPE_DVBT, TYPE_ISDBS, TYPE_ISDBS3, TYPE_ISDBT, TYPE_DTMB})
@Retention(RetentionPolicy.SOURCE)
public @interface Type {}
@@ -78,7 +81,10 @@
* Integrated Services Digital Broadcasting-Terrestrial (ISDB-T) frontend type.
*/
public static final int TYPE_ISDBT = Constants.FrontendType.ISDBT;
-
+ /**
+ * Digital Terrestrial Multimedia Broadcast standard (DTMB) frontend type.
+ */
+ public static final int TYPE_DTMB = android.hardware.tv.tuner.V1_1.Constants.FrontendType.DTMB;
/** @hide */
@@ -241,9 +247,36 @@
*/
public static final long FEC_77_90 = Constants.FrontendInnerFec.FEC_77_90;
+ /** @hide */
+ @IntDef(prefix = "FRONTEND_SPECTRAL_INVERSION_",
+ value = {FRONTEND_SPECTRAL_INVERSION_UNDEFINED, FRONTEND_SPECTRAL_INVERSION_NORMAL,
+ FRONTEND_SPECTRAL_INVERSION_INVERTED})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface FrontendSpectralInversion {}
+
+ /**
+ * Spectral Inversion Type undefined.
+ */
+ public static final int FRONTEND_SPECTRAL_INVERSION_UNDEFINED =
+ Constants.FrontendDvbcSpectralInversion.UNDEFINED;
+ /**
+ * Normal Spectral Inversion.
+ */
+ public static final int FRONTEND_SPECTRAL_INVERSION_NORMAL =
+ Constants.FrontendDvbcSpectralInversion.NORMAL;
+ /**
+ * Inverted Spectral Inversion.
+ */
+ public static final int FRONTEND_SPECTRAL_INVERSION_INVERTED =
+ Constants.FrontendDvbcSpectralInversion.INVERTED;
+
private final int mFrequency;
+ // End frequency is only supported in Tuner 1.1 or higher.
+ private int mEndFrequency = Tuner.INVALID_FRONTEND_SETTING_FREQUENCY;
+ // General spectral inversion is only supported in Tuner 1.1 or higher.
+ private int mSpectralInversion = FRONTEND_SPECTRAL_INVERSION_UNDEFINED;
FrontendSettings(int frequency) {
mFrequency = frequency;
@@ -263,4 +296,57 @@
public int getFrequency() {
return mFrequency;
}
+
+ /**
+ * Get the end frequency.
+ *
+ * @return the end frequency in Hz.
+ */
+ public int getEndFrequency() {
+ return mEndFrequency;
+ }
+
+ /**
+ * Get the spectral inversion.
+ *
+ * @return the value of the spectral inversion.
+ */
+ @FrontendSpectralInversion
+ public int getFrontendSpectralInversion() {
+ return mSpectralInversion;
+ }
+
+ /**
+ * Set Spectral Inversion.
+ *
+ * <p>This API is only supported by Tuner HAL 1.1 or higher. Unsupported version would cause
+ * no-op. Use {@link TunerVersionChecker.getTunerVersion()} to check the version.
+ *
+ * @param inversion the value to set as the spectral inversion. Default value is {@link
+ * #FRONTEND_SPECTRAL_INVERSION_UNDEFINED}.
+ */
+ public void setSpectralInversion(@FrontendSpectralInversion int inversion) {
+ if (TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "setSpectralInversion")) {
+ mSpectralInversion = inversion;
+ }
+ }
+
+ /**
+ * Set End Frequency. This API is only supported with Tuner HAL 1.1 or higher. Otherwise it
+ * would be no-op.
+ *
+ * <p>This API is only supported by Tuner HAL 1.1 or higher. Unsupported version would cause
+ * no-op. Use {@link TunerVersionChecker.getTunerVersion()} to check the version.
+ *
+ * @param endFrequency the end frequency used during blind scan. The default value is
+ * {@link android.media.tv.tuner.Tuner#INVALID_FRONTEND_SETTING_FREQUENCY}.
+ */
+ @IntRange(from = 1)
+ public void setEndFrequency(int endFrequency) {
+ if (TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "setEndFrequency")) {
+ mEndFrequency = endFrequency;
+ }
+ }
}
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 4e27c8e..724965d 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -142,6 +142,7 @@
shared_libs: [
"android.hardware.graphics.bufferqueue@2.0",
"android.hardware.tv.tuner@1.0",
+ "android.hardware.tv.tuner@1.1",
"libandroid_runtime",
"libcutils",
"libfmq",
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 0b0e162..71c86cc 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -2662,7 +2662,7 @@
gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
CHECK(gFields.cryptoInfoModeID != NULL);
- gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "pattern",
+ gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "mPattern",
"Landroid/media/MediaCodec$CryptoInfo$Pattern;");
CHECK(gFields.cryptoInfoPatternID != NULL);
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index 2ef7b9e..b6c47fca 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -140,6 +140,27 @@
fmt = applyFormatOverrides(fmt, containerFormat);
switch (fmt) {
case HAL_PIXEL_FORMAT_YCbCr_420_888:
+ // Width and height should be multiple of 2. Wrong dataSize would be returned otherwise.
+ if (buffer->width % 2 != 0) {
+ ALOGE("YCbCr_420_888: width (%d) should be a multiple of 2", buffer->width);
+ return BAD_VALUE;
+ }
+
+ if (buffer->height % 2 != 0) {
+ ALOGE("YCbCr_420_888: height (%d) should be a multiple of 2", buffer->height);
+ return BAD_VALUE;
+ }
+
+ if (buffer->width <= 0) {
+ ALOGE("YCbCr_420_888: width (%d) should be a > 0", buffer->width);
+ return BAD_VALUE;
+ }
+
+ if (buffer->height <= 0) {
+ ALOGE("YCbCr_420_888: height (%d) should be a > 0", buffer->height);
+ return BAD_VALUE;
+ }
+
pData =
(idx == 0) ?
buffer->data :
@@ -160,6 +181,27 @@
break;
// NV21
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ // Width and height should be multiple of 2. Wrong dataSize would be returned otherwise.
+ if (buffer->width % 2 != 0) {
+ ALOGE("YCrCb_420_SP: width (%d) should be a multiple of 2", buffer->width);
+ return BAD_VALUE;
+ }
+
+ if (buffer->height % 2 != 0) {
+ ALOGE("YCrCb_420_SP: height (%d) should be a multiple of 2", buffer->height);
+ return BAD_VALUE;
+ }
+
+ if (buffer->width <= 0) {
+ ALOGE("YCrCb_420_SP: width (%d) should be a > 0", buffer->width);
+ return BAD_VALUE;
+ }
+
+ if (buffer->height <= 0) {
+ ALOGE("YCrCb_420_SP: height (%d) should be a > 0", buffer->height);
+ return BAD_VALUE;
+ }
+
cr = buffer->data + (buffer->stride * buffer->height);
cb = cr + 1;
// only map until last pixel
@@ -178,6 +220,27 @@
rStride = buffer->width;
break;
case HAL_PIXEL_FORMAT_YV12:
+ // Width and height should be multiple of 2. Wrong dataSize would be returned otherwise.
+ if (buffer->width % 2 != 0) {
+ ALOGE("YV12: width (%d) should be a multiple of 2", buffer->width);
+ return BAD_VALUE;
+ }
+
+ if (buffer->height % 2 != 0) {
+ ALOGE("YV12: height (%d) should be a multiple of 2", buffer->height);
+ return BAD_VALUE;
+ }
+
+ if (buffer->width <= 0) {
+ ALOGE("YV12: width (%d) should be a > 0", buffer->width);
+ return BAD_VALUE;
+ }
+
+ if (buffer->height <= 0) {
+ ALOGE("YV12: height (%d) should be a > 0", buffer->height);
+ return BAD_VALUE;
+ }
+
// Y and C stride need to be 16 pixel aligned.
LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
"Stride is not 16 pixel aligned %d", buffer->stride);
@@ -344,6 +407,11 @@
int flexFormat = format;
if (isPossiblyYUV(format)) {
res = buffer->lockAsyncYCbCr(inUsage, rect, &ycbcr, fenceFd);
+
+ if (res != OK) {
+ ALOGW("lockAsyncYCbCr failed with error %d", res);
+ }
+
pData = ycbcr.y;
flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888;
}
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 5daf8b0..979dc06 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -22,7 +22,6 @@
#include "android_runtime/AndroidRuntime.h"
#include <android-base/logging.h>
-#include <android/hardware/tv/tuner/1.0/ITuner.h>
#include <media/stagefright/foundation/ADebug.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedLocalRef.h>
@@ -34,7 +33,6 @@
using ::android::hardware::hidl_bitfield;
using ::android::hardware::hidl_vec;
using ::android::hardware::tv::tuner::V1_0::AudioExtraMetaData;
-using ::android::hardware::tv::tuner::V1_0::Constant;
using ::android::hardware::tv::tuner::V1_0::DataFormat;
using ::android::hardware::tv::tuner::V1_0::DemuxAlpFilterSettings;
using ::android::hardware::tv::tuner::V1_0::DemuxAlpFilterType;
@@ -129,12 +127,21 @@
using ::android::hardware::tv::tuner::V1_0::FrontendStatusAtsc3PlpInfo;
using ::android::hardware::tv::tuner::V1_0::FrontendStatusType;
using ::android::hardware::tv::tuner::V1_0::FrontendType;
-using ::android::hardware::tv::tuner::V1_0::ITuner;
using ::android::hardware::tv::tuner::V1_0::LnbPosition;
using ::android::hardware::tv::tuner::V1_0::LnbTone;
using ::android::hardware::tv::tuner::V1_0::LnbVoltage;
using ::android::hardware::tv::tuner::V1_0::PlaybackSettings;
using ::android::hardware::tv::tuner::V1_0::RecordSettings;
+using ::android::hardware::tv::tuner::V1_1::Constant;
+using ::android::hardware::tv::tuner::V1_1::Constant64Bit;
+using ::android::hardware::tv::tuner::V1_1::FrontendAnalogAftFlag;
+using ::android::hardware::tv::tuner::V1_1::FrontendAnalogSettingsExt1_1;
+using ::android::hardware::tv::tuner::V1_1::FrontendCableTimeInterleaveMode;
+using ::android::hardware::tv::tuner::V1_1::FrontendDvbsScanType;
+using ::android::hardware::tv::tuner::V1_1::FrontendDvbcSettingsExt1_1;
+using ::android::hardware::tv::tuner::V1_1::FrontendDvbsSettingsExt1_1;
+using ::android::hardware::tv::tuner::V1_1::FrontendDvbtSettingsExt1_1;
+using ::android::hardware::tv::tuner::V1_1::FrontendSpectralInversion;
struct fields_t {
jfieldID tunerContext;
@@ -310,9 +317,9 @@
/////////////// MediaEvent ///////////////////////
-MediaEvent::MediaEvent(sp<IFilter> iFilter, hidl_handle avHandle,
- uint64_t dataId, uint64_t dataLength, jobject obj) : mIFilter(iFilter),
- mDataId(dataId), mDataLength(dataLength), mBuffer(nullptr),
+MediaEvent::MediaEvent(sp<Filter> filter, hidl_handle avHandle,
+ uint64_t dataId, uint64_t dataSize, jobject obj) : mFilter(filter),
+ mDataId(dataId), mDataSize(dataSize), mBuffer(nullptr),
mDataIdRefCnt(0), mAvHandleRefCnt(0), mIonHandle(nullptr) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
mMediaEventObj = env->NewWeakGlobalRef(obj);
@@ -336,7 +343,8 @@
void MediaEvent::finalize() {
if (mAvHandleRefCnt == 0) {
- mIFilter->releaseAvHandle(hidl_handle(mAvHandle), mDataIdRefCnt == 0 ? mDataId : 0);
+ mFilter->mFilterSp->releaseAvHandle(
+ hidl_handle(mAvHandle), mDataIdRefCnt == 0 ? mDataId : 0);
native_handle_close(mAvHandle);
}
}
@@ -349,7 +357,47 @@
if (mLinearBlockObj != NULL) {
return mLinearBlockObj;
}
- mIonHandle = new C2HandleIon(dup(mAvHandle->data[0]), mDataLength);
+
+ int fd;
+ int numInts = 0;
+ int memIndex;
+ int dataSize;
+ if (mAvHandle->numFds == 0) {
+ if (mFilter->mAvSharedHandle == NULL) {
+ ALOGE("Shared AV memory handle is not initialized.");
+ return NULL;
+ }
+ if (mFilter->mAvSharedHandle->numFds == 0) {
+ ALOGE("Shared AV memory handle is empty.");
+ return NULL;
+ }
+ fd = mFilter->mAvSharedHandle->data[0];
+ dataSize = mFilter->mAvSharedMemSize;
+ numInts = mFilter->mAvSharedHandle->numInts;
+ if (numInts > 0) {
+ // If the first int in the shared native handle has value, use it as the index
+ memIndex = mFilter->mAvSharedHandle->data[mFilter->mAvSharedHandle->numFds];
+ }
+ } else {
+ fd = mAvHandle->data[0];
+ dataSize = mDataSize;
+ numInts = mAvHandle->numInts;
+ if (numInts > 0) {
+ // Otherwise if the first int in the av native handle returned from the filter
+ // event has value, use it as the index
+ memIndex = mAvHandle->data[mAvHandle->numFds];
+ } else {
+ if (mFilter->mAvSharedHandle != NULL) {
+ numInts = mFilter->mAvSharedHandle->numInts;
+ if (numInts > 0) {
+ // If the first int in the shared native handle has value, use it as the index
+ memIndex = mFilter->mAvSharedHandle->data[mFilter->mAvSharedHandle->numFds];
+ }
+ }
+ }
+ }
+
+ mIonHandle = new C2HandleIon(dup(fd), dataSize);
std::shared_ptr<C2LinearBlock> block = _C2BlockFactory::CreateLinearBlock(mIonHandle);
if (block != nullptr) {
// CreateLinearBlock delete mIonHandle after it create block successfully.
@@ -358,13 +406,11 @@
JNIEnv *env = AndroidRuntime::getJNIEnv();
std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
context->mBlock = block;
- std::shared_ptr<C2Buffer> pC2Buffer = context->toC2Buffer(0, mDataLength);
+ std::shared_ptr<C2Buffer> pC2Buffer = context->toC2Buffer(0, dataSize);
context->mBuffer = pC2Buffer;
mC2Buffer = pC2Buffer;
- if (mAvHandle->numInts > 0) {
- // use first int in the native_handle as the index
- int index = mAvHandle->data[mAvHandle->numFds];
- std::shared_ptr<C2Param> c2param = std::make_shared<C2DataIdInfo>(index, mDataId);
+ if (numInts > 0) {
+ std::shared_ptr<C2Param> c2param = std::make_shared<C2DataIdInfo>(memIndex, mDataId);
std::shared_ptr<C2Info> info(std::static_pointer_cast<C2Info>(c2param));
pC2Buffer->setInfo(info);
}
@@ -471,7 +517,7 @@
if (mediaEvent.avMemory.getNativeHandle() != NULL || mediaEvent.avDataId != 0) {
sp<MediaEvent> mediaEventSp =
- new MediaEvent(mIFilter, mediaEvent.avMemory,
+ new MediaEvent(mFilter, mediaEvent.avMemory,
mediaEvent.avDataId, dataLength + offset, obj);
mediaEventSp->mAvHandleRefCnt++;
env->SetLongField(obj, eventContext, (jlong) mediaEventSp.get());
@@ -505,10 +551,11 @@
}
jobjectArray FilterCallback::getTsRecordEvent(
- jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events,
+ const std::vector<DemuxFilterEventExt::Event>& eventsExt) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/TsRecordEvent");
- jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IIIJ)V");
+ jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IIIJJ)V");
for (int i = 0; i < events.size(); i++) {
auto event = events[i];
@@ -537,28 +584,39 @@
jlong byteNumber = static_cast<jlong>(tsRecordEvent.byteNumber);
+ jlong pts = (eventsExt.size() > i) ? static_cast<jlong>(eventsExt[i].tsRecord().pts)
+ : static_cast<jlong>(Constant64Bit::INVALID_PRESENTATION_TIME_STAMP);
+
jobject obj =
- env->NewObject(eventClazz, eventInit, jpid, ts, sc, byteNumber);
+ env->NewObject(eventClazz, eventInit, jpid, ts, sc, byteNumber, pts);
env->SetObjectArrayElement(arr, i, obj);
}
return arr;
}
jobjectArray FilterCallback::getMmtpRecordEvent(
- jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events,
+ const std::vector<DemuxFilterEventExt::Event>& eventsExt) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/MmtpRecordEvent");
- jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IJ)V");
+ jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IJIJ)V");
for (int i = 0; i < events.size(); i++) {
auto event = events[i];
+
DemuxFilterMmtpRecordEvent mmtpRecordEvent = event.mmtpRecord();
jint scHevcIndexMask = static_cast<jint>(mmtpRecordEvent.scHevcIndexMask);
jlong byteNumber = static_cast<jlong>(mmtpRecordEvent.byteNumber);
+ jint mpuSequenceNumber = (eventsExt.size() > i)
+ ? static_cast<jint>(eventsExt[i].mmtpRecord().mpuSequenceNumber)
+ : static_cast<jint>(Constant::INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM);
+ jlong pts = (eventsExt.size() > i) ? static_cast<jlong>(eventsExt[i].mmtpRecord().pts)
+ : static_cast<jlong>(Constant64Bit::INVALID_PRESENTATION_TIME_STAMP);
jobject obj =
- env->NewObject(eventClazz, eventInit, scHevcIndexMask, byteNumber);
+ env->NewObject(eventClazz, eventInit, scHevcIndexMask, byteNumber,
+ mpuSequenceNumber, pts);
env->SetObjectArrayElement(arr, i, obj);
}
return arr;
@@ -627,12 +685,14 @@
return arr;
}
-Return<void> FilterCallback::onFilterEvent(const DemuxFilterEvent& filterEvent) {
- ALOGD("FilterCallback::onFilterEvent");
+Return<void> FilterCallback::onFilterEvent_1_1(const DemuxFilterEvent& filterEvent,
+ const DemuxFilterEventExt& filterEventExt) {
+ ALOGD("FilterCallback::onFilterEvent_1_1");
JNIEnv *env = AndroidRuntime::getJNIEnv();
std::vector<DemuxFilterEvent::Event> events = filterEvent.events;
+ std::vector<DemuxFilterEventExt::Event> eventsExt = filterEventExt.events;
jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/FilterEvent");
jobjectArray array = env->NewObjectArray(events.size(), eventClazz, NULL);
@@ -652,11 +712,11 @@
break;
}
case DemuxFilterEvent::Event::hidl_discriminator::tsRecord: {
- array = getTsRecordEvent(array, events);
+ array = getTsRecordEvent(array, events, eventsExt);
break;
}
case DemuxFilterEvent::Event::hidl_discriminator::mmtpRecord: {
- array = getMmtpRecordEvent(array, events);
+ array = getMmtpRecordEvent(array, events, eventsExt);
break;
}
case DemuxFilterEvent::Event::hidl_discriminator::download: {
@@ -677,18 +737,26 @@
}
}
env->CallVoidMethod(
- mFilter,
+ mFilter->mFilterObj,
gFields.onFilterEventID,
array);
return Void();
}
+Return<void> FilterCallback::onFilterEvent(const DemuxFilterEvent& filterEvent) {
+ ALOGD("FilterCallback::onFilterEvent");
+ std::vector<DemuxFilterEventExt::Event> emptyEventsExt;
+ DemuxFilterEventExt emptyFilterEventExt {
+ .events = emptyEventsExt,
+ };
+ return onFilterEvent_1_1(filterEvent, emptyFilterEventExt);
+}
Return<void> FilterCallback::onFilterStatus(const DemuxFilterStatus status) {
ALOGD("FilterCallback::onFilterStatus");
JNIEnv *env = AndroidRuntime::getJNIEnv();
env->CallVoidMethod(
- mFilter,
+ mFilter->mFilterObj,
gFields.onFilterStatusID,
(jint)status);
return Void();
@@ -696,17 +764,11 @@
void FilterCallback::setFilter(const sp<Filter> filter) {
ALOGD("FilterCallback::setFilter");
- mFilter = filter->mFilterObj;
- mIFilter = filter->mFilterSp;
+ // JNI Object
+ mFilter = filter;
}
-FilterCallback::~FilterCallback() {
- JNIEnv *env = AndroidRuntime::getJNIEnv();
- if (mFilter != NULL) {
- env->DeleteWeakGlobalRef(mFilter);
- mFilter = NULL;
- }
-}
+FilterCallback::~FilterCallback() {}
/////////////// Filter ///////////////////////
@@ -919,6 +981,8 @@
/////////////// Tuner ///////////////////////
sp<ITuner> JTuner::mTuner;
+sp<::android::hardware::tv::tuner::V1_1::ITuner> JTuner::mTuner_1_1;
+int JTuner::mTunerVersion = 0;
JTuner::JTuner(JNIEnv *env, jobject thiz)
: mClass(NULL) {
@@ -950,13 +1014,28 @@
sp<ITuner> JTuner::getTunerService() {
if (mTuner == nullptr) {
- mTuner = ITuner::getService();
+ mTunerVersion = 0;
+ mTuner_1_1 = ::android::hardware::tv::tuner::V1_1::ITuner::getService();
- if (mTuner == nullptr) {
- ALOGW("Failed to get tuner service.");
- }
- }
- return mTuner;
+ if (mTuner_1_1 == nullptr) {
+ ALOGW("Failed to get tuner 1.1 service.");
+ mTuner = ITuner::getService();
+ if (mTuner == nullptr) {
+ ALOGW("Failed to get tuner 1.0 service.");
+ } else {
+ mTunerVersion = 1 << 16;
+ }
+ } else {
+ mTuner = static_cast<sp<ITuner>>(mTuner_1_1);
+ mTunerVersion = ((1 << 16) | 1);
+ }
+ }
+ return mTuner;
+}
+
+jint JTuner::getTunerVersion() {
+ ALOGD("JTuner::getTunerVersion()");
+ return (jint) mTunerVersion;
}
jobject JTuner::getFrontendIds() {
@@ -996,6 +1075,7 @@
return NULL;
}
mFe = fe;
+ mFe_1_1 = ::android::hardware::tv::tuner::V1_1::IFrontend::castFrom(mFe);
mFeId = id;
if (mDemux != NULL) {
mDemux->setFrontendDataSource(mFeId);
@@ -1305,12 +1385,21 @@
return lnbObj;
}
-int JTuner::tune(const FrontendSettings& settings) {
+int JTuner::tune(const FrontendSettings& settings, const FrontendSettingsExt1_1& settingsExt1_1) {
if (mFe == NULL) {
ALOGE("frontend is not initialized");
return (int)Result::INVALID_STATE;
}
- Result result = mFe->tune(settings);
+ Result result;
+ sp<::android::hardware::tv::tuner::V1_1::IFrontend> fe_1_1 =
+ ::android::hardware::tv::tuner::V1_1::IFrontend::castFrom(mFe);
+ if (fe_1_1 == NULL) {
+ ALOGD("1.1 frontend is not found. Using 1.0 instead.");
+ result = mFe->tune(settings);
+ return (int)result;
+ }
+
+ result = fe_1_1->tune_1_1(settings, settingsExt1_1);
return (int)result;
}
@@ -1323,12 +1412,22 @@
return (int)result;
}
-int JTuner::scan(const FrontendSettings& settings, FrontendScanType scanType) {
+int JTuner::scan(const FrontendSettings& settings, FrontendScanType scanType,
+ const FrontendSettingsExt1_1& settingsExt1_1) {
if (mFe == NULL) {
ALOGE("frontend is not initialized");
return (int)Result::INVALID_STATE;
}
- Result result = mFe->scan(settings, scanType);
+ Result result;
+ sp<::android::hardware::tv::tuner::V1_1::IFrontend> fe_1_1 =
+ ::android::hardware::tv::tuner::V1_1::IFrontend::castFrom(mFe);
+ if (fe_1_1 == NULL) {
+ ALOGD("1.1 frontend is not found. Using 1.0 instead.");
+ result = mFe->scan(settings, scanType);
+ return (int)result;
+ }
+
+ result = fe_1_1->scan_1_1(settings, scanType, settingsExt1_1);
return (int)result;
}
@@ -1455,6 +1554,27 @@
return (int) r;
}
+int JTuner::linkCiCam(int id) {
+ if (mFe_1_1 == NULL) {
+ ALOGE("frontend 1.1 is not initialized");
+ return (int)Constant::INVALID_LTS_ID;
+ }
+
+ Result res;
+ uint32_t ltsId;
+ mFe_1_1->linkCiCam(static_cast<uint32_t>(id),
+ [&](Result r, uint32_t id) {
+ res = r;
+ ltsId = id;
+ });
+
+ if (res != Result::SUCCESS) {
+ return (int)Constant::INVALID_LTS_ID;
+ }
+
+ return (int) ltsId;
+}
+
int JTuner::disconnectCiCam() {
if (mDemux == NULL) {
Result r = openDemux();
@@ -1466,6 +1586,18 @@
return (int) r;
}
+
+int JTuner::unlinkCiCam(int id) {
+ if (mFe_1_1 == NULL) {
+ ALOGE("frontend 1.1 is not initialized");
+ return (int)Result::INVALID_STATE;
+ }
+
+ Result r = mFe_1_1->unlinkCiCam(static_cast<uint32_t>(id));
+
+ return (int) r;
+}
+
jobject JTuner::openDescrambler() {
ALOGD("JTuner::openDescrambler");
if (mTuner == nullptr || mDemux == nullptr) {
@@ -1504,6 +1636,7 @@
}
sp<IFilter> iFilterSp;
+ sp<::android::hardware::tv::tuner::V1_1::IFilter> iFilterSp_1_1;
sp<FilterCallback> callback = new FilterCallback();
Result res;
mDemux->openFilter(type, bufferSize, callback,
@@ -1515,24 +1648,54 @@
ALOGD("Failed to open filter, type = %d", type.mainType);
return NULL;
}
- int fId;
+ uint64_t fId;
iFilterSp->getId([&](Result, uint32_t filterId) {
fId = filterId;
});
+ iFilterSp_1_1 = ::android::hardware::tv::tuner::V1_1::IFilter::castFrom(iFilterSp);
+ if (iFilterSp_1_1 != NULL) {
+ iFilterSp_1_1->getId64Bit([&](Result, uint64_t filterId64Bit) {
+ fId = filterId64Bit;
+ });
+ }
JNIEnv *env = AndroidRuntime::getJNIEnv();
jobject filterObj =
env->NewObject(
env->FindClass("android/media/tv/tuner/filter/Filter"),
gFields.filterInitID,
- (jint) fId);
+ (jlong) fId);
sp<Filter> filterSp = new Filter(iFilterSp, filterObj);
filterSp->incStrong(filterObj);
env->SetLongField(filterObj, gFields.filterContext, (jlong)filterSp.get());
-
+ filterSp->mIsMediaFilter = false;
+ filterSp->mAvSharedHandle = NULL;
callback->setFilter(filterSp);
+ if (type.mainType == DemuxFilterMainType::MMTP) {
+ if (type.subType.mmtpFilterType() == DemuxMmtpFilterType::AUDIO ||
+ type.subType.mmtpFilterType() == DemuxMmtpFilterType::VIDEO) {
+ filterSp->mIsMediaFilter = true;
+ }
+ }
+
+ if (type.mainType == DemuxFilterMainType::TS) {
+ if (type.subType.tsFilterType() == DemuxTsFilterType::AUDIO ||
+ type.subType.tsFilterType() == DemuxTsFilterType::VIDEO) {
+ filterSp->mIsMediaFilter = true;
+ }
+ }
+
+ if (iFilterSp_1_1 != NULL && filterSp->mIsMediaFilter) {
+ iFilterSp_1_1->getAvSharedHandle([&](Result r, hidl_handle avMemory, uint64_t avMemSize) {
+ if (r == Result::SUCCESS) {
+ filterSp->mAvSharedHandle = native_handle_clone(avMemory.getNativeHandle());
+ filterSp->mAvSharedMemSize = avMemSize;
+ }
+ });
+ }
+
return filterObj;
}
@@ -1902,6 +2065,10 @@
if (mFe != NULL) {
r = mFe->close();
}
+ if (r == Result::SUCCESS) {
+ mFe = NULL;
+ mFe_1_1 = NULL;
+ }
return (jint) r;
}
@@ -1910,6 +2077,9 @@
if (mDemux != NULL) {
r = mDemux->close();
}
+ if (r == Result::SUCCESS) {
+ mDemux = NULL;
+ }
return (jint) r;
}
@@ -1962,6 +2132,22 @@
return freq;
}
+static uint32_t getFrontendSettingsEndFreq(JNIEnv *env, const jobject& settings) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/frontend/FrontendSettings");
+ jfieldID endFreqField = env->GetFieldID(clazz, "mEndFrequency", "I");
+ uint32_t endFreq = static_cast<uint32_t>(env->GetIntField(settings, endFreqField));
+ return endFreq;
+}
+
+static FrontendSpectralInversion getFrontendSettingsSpectralInversion(
+ JNIEnv *env, const jobject& settings) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/frontend/FrontendSettings");
+ jfieldID inversionField = env->GetFieldID(clazz, "mSpectralInversion", "I");
+ FrontendSpectralInversion inversion =
+ static_cast<FrontendSpectralInversion>(env->GetIntField(settings, inversionField));
+ return inversion;
+}
+
static FrontendSettings getAnalogFrontendSettings(JNIEnv *env, const jobject& settings) {
FrontendSettings frontendSettings;
uint32_t freq = getFrontendSettingsFreq(env, settings);
@@ -1981,6 +2167,18 @@
return frontendSettings;
}
+static void getAnalogFrontendSettingsExt1_1(JNIEnv *env, const jobject& settings,
+ FrontendSettingsExt1_1& settingsExt1_1) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/frontend/AnalogFrontendSettings");
+ FrontendAnalogAftFlag aftFlag =
+ static_cast<FrontendAnalogAftFlag>(
+ env->GetIntField(settings, env->GetFieldID(clazz, "mAftFlag", "I")));
+ FrontendAnalogSettingsExt1_1 analogExt1_1 {
+ .aftFlag = aftFlag,
+ };
+ settingsExt1_1.settingExt.analog(analogExt1_1);
+}
+
static hidl_vec<FrontendAtsc3PlpSettings> getAtsc3PlpSettings(
JNIEnv *env, const jobject& settings) {
jclass clazz = env->FindClass("android/media/tv/tuner/frontend/Atsc3FrontendSettings");
@@ -2100,6 +2298,19 @@
return frontendSettings;
}
+static void getDvbcFrontendSettingsExt1_1(JNIEnv *env, const jobject& settings,
+ FrontendSettingsExt1_1& settingsExt1_1) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbcFrontendSettings");
+ FrontendCableTimeInterleaveMode interleaveMode =
+ static_cast<FrontendCableTimeInterleaveMode>(
+ env->GetIntField(settings, env->GetFieldID(clazz, "mInterleaveMode", "I")));
+
+ FrontendDvbcSettingsExt1_1 dvbcExt1_1 {
+ .interleaveMode = interleaveMode,
+ };
+ settingsExt1_1.settingExt.dvbc(dvbcExt1_1);
+}
+
static FrontendDvbsCodeRate getDvbsCodeRate(JNIEnv *env, const jobject& settings) {
jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbsFrontendSettings");
jobject jcodeRate =
@@ -2141,7 +2352,6 @@
uint32_t freq = getFrontendSettingsFreq(env, settings);
jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbsFrontendSettings");
-
FrontendDvbsModulation modulation =
static_cast<FrontendDvbsModulation>(
env->GetIntField(settings, env->GetFieldID(clazz, "mModulation", "I")));
@@ -2180,6 +2390,22 @@
return frontendSettings;
}
+static void getDvbsFrontendSettingsExt1_1(JNIEnv *env, const jobject& settings,
+ FrontendSettingsExt1_1& settingsExt1_1) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbsFrontendSettings");
+ FrontendDvbsScanType scanType =
+ static_cast<FrontendDvbsScanType>(
+ env->GetIntField(settings, env->GetFieldID(clazz, "mScanType", "I")));
+ bool isDiseqcRxMessage = static_cast<bool>(env->GetBooleanField(
+ settings, env->GetFieldID(clazz, "mIsDiseqcRxMessage", "B")));
+
+ FrontendDvbsSettingsExt1_1 dvbsExt1_1 {
+ .scanType = scanType,
+ .isDiseqcRxMessage = isDiseqcRxMessage,
+ };
+ settingsExt1_1.settingExt.dvbs(dvbsExt1_1);
+}
+
static FrontendSettings getDvbtFrontendSettings(JNIEnv *env, const jobject& settings) {
FrontendSettings frontendSettings;
uint32_t freq = getFrontendSettingsFreq(env, settings);
@@ -2246,6 +2472,25 @@
return frontendSettings;
}
+static void getDvbtFrontendSettingsExt1_1(JNIEnv *env, const jobject& settings,
+ FrontendSettingsExt1_1& settingsExt1_1) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbtFrontendSettings");
+
+ FrontendDvbtSettingsExt1_1 dvbtExt1_1;
+ int transmissionMode =
+ env->GetIntField(settings, env->GetFieldID(clazz, "mTransmissionMode", "I"));
+ dvbtExt1_1.transmissionMode = static_cast<
+ ::android::hardware::tv::tuner::V1_1::FrontendDvbtTransmissionMode>(
+ transmissionMode);
+
+ int constellation =
+ env->GetIntField(settings, env->GetFieldID(clazz, "mConstellation", "I"));
+ dvbtExt1_1.constellation = static_cast<
+ ::android::hardware::tv::tuner::V1_1::FrontendDvbtConstellation>(constellation);
+
+ settingsExt1_1.settingExt.dvbt(dvbtExt1_1);
+}
+
static FrontendSettings getIsdbsFrontendSettings(JNIEnv *env, const jobject& settings) {
FrontendSettings frontendSettings;
uint32_t freq = getFrontendSettingsFreq(env, settings);
@@ -2386,6 +2631,54 @@
}
}
+static FrontendSettingsExt1_1 getFrontendSettingsExt1_1(JNIEnv *env, int type, jobject settings) {
+ ALOGD("getFrontendSettingsExt1_1 %d", type);
+
+ FrontendSettingsExt1_1 settingsExt1_1 {
+ .endFrequency = static_cast<uint32_t>(Constant::INVALID_FRONTEND_SETTING_FREQUENCY),
+ .inversion = FrontendSpectralInversion::UNDEFINED,
+ };
+ settingsExt1_1.settingExt.noinit();
+ FrontendType feType = static_cast<FrontendType>(type);
+ switch(feType) {
+ case FrontendType::DVBS:
+ getDvbsFrontendSettingsExt1_1(env, settings, settingsExt1_1);
+ break;
+ case FrontendType::DVBT:
+ getDvbtFrontendSettingsExt1_1(env, settings, settingsExt1_1);
+ break;
+ case FrontendType::ANALOG:
+ getAnalogFrontendSettingsExt1_1(env, settings, settingsExt1_1);
+ break;
+ case FrontendType::ATSC3:
+ break;
+ case FrontendType::ATSC:
+ break;
+ case FrontendType::DVBC:
+ getDvbcFrontendSettingsExt1_1(env, settings, settingsExt1_1);
+ break;
+ case FrontendType::ISDBS:
+ break;
+ case FrontendType::ISDBS3:
+ break;
+ case FrontendType::ISDBT:
+ break;
+ default:
+ // should never happen because a type is associated with a subclass of
+ // FrontendSettings and not set by users
+ jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "Unsupported frontend type %d", type);
+ return FrontendSettingsExt1_1();
+ }
+
+ uint32_t endFreq = getFrontendSettingsEndFreq(env, settings);
+ FrontendSpectralInversion inversion = getFrontendSettingsSpectralInversion(env, settings);
+ settingsExt1_1.endFrequency = endFreq;
+ settingsExt1_1.inversion = inversion;
+
+ return settingsExt1_1;
+}
+
static sp<Filter> getFilter(JNIEnv *env, jobject filter) {
return (Filter *)env->GetLongField(filter, gFields.filterContext);
}
@@ -2460,7 +2753,7 @@
jclass filterClazz = env->FindClass("android/media/tv/tuner/filter/Filter");
gFields.filterContext = env->GetFieldID(filterClazz, "mNativeContext", "J");
gFields.filterInitID =
- env->GetMethodID(filterClazz, "<init>", "(I)V");
+ env->GetMethodID(filterClazz, "<init>", "(J)V");
gFields.onFilterStatusID =
env->GetMethodID(filterClazz, "onFilterStatus", "(I)V");
gFields.onFilterEventID =
@@ -2501,6 +2794,11 @@
setTuner(env,thiz, tuner);
}
+static jint android_media_tv_Tuner_native_get_tuner_version(JNIEnv *env, jobject thiz) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ return tuner->getTunerVersion();
+}
+
static jobject android_media_tv_Tuner_get_frontend_ids(JNIEnv *env, jobject thiz) {
sp<JTuner> tuner = getTuner(env, thiz);
return tuner->getFrontendIds();
@@ -2522,7 +2820,9 @@
static int android_media_tv_Tuner_tune(JNIEnv *env, jobject thiz, jint type, jobject settings) {
sp<JTuner> tuner = getTuner(env, thiz);
- return tuner->tune(getFrontendSettings(env, type, settings));
+ FrontendSettings setting = getFrontendSettings(env, type, settings);
+ FrontendSettingsExt1_1 settingExt = getFrontendSettingsExt1_1(env, type, settings);
+ return tuner->tune(setting, settingExt);
}
static int android_media_tv_Tuner_stop_tune(JNIEnv *env, jobject thiz) {
@@ -2533,8 +2833,9 @@
static int android_media_tv_Tuner_scan(
JNIEnv *env, jobject thiz, jint settingsType, jobject settings, jint scanType) {
sp<JTuner> tuner = getTuner(env, thiz);
- return tuner->scan(getFrontendSettings(
- env, settingsType, settings), static_cast<FrontendScanType>(scanType));
+ FrontendSettings setting = getFrontendSettings(env, settingsType, settings);
+ FrontendSettingsExt1_1 settingExt = getFrontendSettingsExt1_1(env, settingsType, settings);
+ return tuner->scan(setting, static_cast<FrontendScanType>(scanType), settingExt);
}
static int android_media_tv_Tuner_stop_scan(JNIEnv *env, jobject thiz) {
@@ -2579,11 +2880,21 @@
return tuner->connectCiCam(id);
}
+static int android_media_tv_Tuner_link_cicam(JNIEnv *env, jobject thiz, jint id) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ return tuner->linkCiCam(id);
+}
+
static int android_media_tv_Tuner_disconnect_cicam(JNIEnv *env, jobject thiz) {
sp<JTuner> tuner = getTuner(env, thiz);
return tuner->disconnectCiCam();
}
+static int android_media_tv_Tuner_unlink_cicam(JNIEnv *env, jobject thiz, jint id) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ return tuner->unlinkCiCam(id);
+}
+
static jobject android_media_tv_Tuner_get_frontend_info(JNIEnv *env, jobject thiz, jint id) {
sp<JTuner> tuner = getTuner(env, thiz);
return tuner->getFrontendInfo(id);
@@ -2991,6 +3302,29 @@
return filterSettings;
}
+static Result configureIpFilterContextId(
+ JNIEnv *env, sp<IFilter> iFilterSp, jobject ipFilterConfigObj) {
+ jclass clazz = env->FindClass(
+ "android/media/tv/tuner/filter/IpFilterConfiguration");
+ uint32_t cid = env->GetIntField(ipFilterConfigObj, env->GetFieldID(
+ clazz, "mIpFilterContextId", "I"));
+ Result res = Result::SUCCESS;
+ if (cid != static_cast<uint32_t>(Constant::INVALID_IP_FILTER_CONTEXT_ID)) {
+ sp<::android::hardware::tv::tuner::V1_1::IFilter> iFilterSp_1_1;
+ iFilterSp_1_1 = ::android::hardware::tv::tuner::V1_1::IFilter::castFrom(iFilterSp);
+
+ if (iFilterSp_1_1 != NULL) {
+ res = iFilterSp_1_1->configureIpCid(cid);
+ if (res != Result::SUCCESS) {
+ return res;
+ }
+ } else {
+ ALOGW("configureIpCid is not supported with the current HAL implementation.");
+ }
+ }
+ return res;
+}
+
static jint copyData(JNIEnv *env, std::unique_ptr<MQ>& mq, EventFlag* flag, jbyteArray buffer,
jlong offset, jlong size) {
ALOGD("copyData, size=%ld, offset=%ld", (long) size, (long) offset);
@@ -3034,6 +3368,13 @@
return (jint) res;
}
+ if (static_cast<DemuxFilterMainType>(type) == DemuxFilterMainType::IP) {
+ res = configureIpFilterContextId(env, iFilterSp, settings);
+ if (res != Result::SUCCESS) {
+ return (jint) res;
+ }
+ }
+
MQDescriptorSync<uint8_t> filterMQDesc;
Result getQueueDescResult = Result::UNKNOWN_ERROR;
if (filterSp->mFilterMQ == NULL) {
@@ -3071,6 +3412,36 @@
return (jint) id;
}
+static jlong android_media_tv_Tuner_get_filter_64bit_id(JNIEnv* env, jobject filter) {
+ sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
+ if (iFilterSp == NULL) {
+ ALOGD("Failed to get filter ID: filter not found");
+ return static_cast<jlong>(
+ ::android::hardware::tv::tuner::V1_1::Constant64Bit::INVALID_FILTER_ID_64BIT);
+ }
+
+ sp<::android::hardware::tv::tuner::V1_1::IFilter> iFilterSp_1_1;
+ iFilterSp_1_1 = ::android::hardware::tv::tuner::V1_1::IFilter::castFrom(iFilterSp);
+ Result res;
+ uint64_t id;
+
+ if (iFilterSp_1_1 != NULL) {
+ iFilterSp_1_1->getId64Bit(
+ [&](Result r, uint64_t filterId64Bit) {
+ res = r;
+ id = filterId64Bit;
+ });
+ } else {
+ ALOGW("getId64Bit is not supported with the current HAL implementation.");
+ return static_cast<jlong>(
+ ::android::hardware::tv::tuner::V1_1::Constant64Bit::INVALID_FILTER_ID_64BIT);
+ }
+
+ return (res == Result::SUCCESS) ?
+ static_cast<jlong>(id) : static_cast<jlong>(
+ ::android::hardware::tv::tuner::V1_1::Constant64Bit::INVALID_FILTER_ID_64BIT);
+}
+
static jint android_media_tv_Tuner_set_filter_data_source(
JNIEnv* env, jobject filter, jobject srcFilter) {
sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
@@ -3684,6 +4055,7 @@
static const JNINativeMethod gTunerMethods[] = {
{ "nativeInit", "()V", (void *)android_media_tv_Tuner_native_init },
{ "nativeSetup", "()V", (void *)android_media_tv_Tuner_native_setup },
+ { "nativeGetTunerVersion", "()I", (void *)android_media_tv_Tuner_native_get_tuner_version },
{ "nativeGetFrontendIds", "()Ljava/util/List;",
(void *)android_media_tv_Tuner_get_frontend_ids },
{ "nativeOpenFrontendByHandle", "(I)Landroid/media/tv/tuner/Tuner$Frontend;",
@@ -3705,6 +4077,10 @@
{ "nativeGetAvSyncTime", "(I)Ljava/lang/Long;",
(void *)android_media_tv_Tuner_get_av_sync_time },
{ "nativeConnectCiCam", "(I)I", (void *)android_media_tv_Tuner_connect_cicam },
+ { "nativeLinkCiCam", "(I)I",
+ (void *)android_media_tv_Tuner_link_cicam },
+ { "nativeUnlinkCiCam", "(I)I",
+ (void *)android_media_tv_Tuner_unlink_cicam },
{ "nativeDisconnectCiCam", "()I", (void *)android_media_tv_Tuner_disconnect_cicam },
{ "nativeGetFrontendInfo", "(I)Landroid/media/tv/tuner/frontend/FrontendInfo;",
(void *)android_media_tv_Tuner_get_frontend_info },
@@ -3735,6 +4111,8 @@
{ "nativeConfigureFilter", "(IILandroid/media/tv/tuner/filter/FilterConfiguration;)I",
(void *)android_media_tv_Tuner_configure_filter },
{ "nativeGetId", "()I", (void *)android_media_tv_Tuner_get_filter_id },
+ { "nativeGetId64Bit", "()J",
+ (void *)android_media_tv_Tuner_get_filter_64bit_id },
{ "nativeSetDataSource", "(Landroid/media/tv/tuner/filter/Filter;)I",
(void *)android_media_tv_Tuner_set_filter_data_source },
{ "nativeStartFilter", "()I", (void *)android_media_tv_Tuner_start_filter },
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index c4deeaf..d70a5ff 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -17,7 +17,12 @@
#ifndef _ANDROID_MEDIA_TV_TUNER_H_
#define _ANDROID_MEDIA_TV_TUNER_H_
-#include <android/hardware/tv/tuner/1.0/ITuner.h>
+#include <android/hardware/tv/tuner/1.1/IFilter.h>
+#include <android/hardware/tv/tuner/1.1/IFilterCallback.h>
+#include <android/hardware/tv/tuner/1.1/IFrontend.h>
+#include <android/hardware/tv/tuner/1.1/ITuner.h>
+#include <android/hardware/tv/tuner/1.1/types.h>
+
#include <C2BlockInternal.h>
#include <C2HandleIonInternal.h>
#include <C2ParamDef.h>
@@ -38,6 +43,7 @@
using ::android::hardware::hidl_vec;
using ::android::hardware::kSynchronizedReadWrite;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
+using ::android::hardware::tv::tuner::V1_1::DemuxFilterEventExt;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterType;
using ::android::hardware::tv::tuner::V1_0::DemuxPid;
@@ -49,12 +55,13 @@
using ::android::hardware::tv::tuner::V1_0::FrontendScanMessageType;
using ::android::hardware::tv::tuner::V1_0::FrontendScanType;
using ::android::hardware::tv::tuner::V1_0::FrontendSettings;
+using ::android::hardware::tv::tuner::V1_1::FrontendSettingsExt1_1;
using ::android::hardware::tv::tuner::V1_0::IDemux;
using ::android::hardware::tv::tuner::V1_0::IDescrambler;
using ::android::hardware::tv::tuner::V1_0::IDvr;
using ::android::hardware::tv::tuner::V1_0::IDvrCallback;
using ::android::hardware::tv::tuner::V1_0::IFilter;
-using ::android::hardware::tv::tuner::V1_0::IFilterCallback;
+using ::android::hardware::tv::tuner::V1_1::IFilterCallback;
using ::android::hardware::tv::tuner::V1_0::IFrontend;
using ::android::hardware::tv::tuner::V1_0::IFrontendCallback;
using ::android::hardware::tv::tuner::V1_0::ILnb;
@@ -112,18 +119,32 @@
int mFd;
};
+struct Filter : public RefBase {
+ Filter(sp<IFilter> sp, jobject obj);
+ ~Filter();
+ int close();
+ sp<IFilter> getIFilter();
+ sp<IFilter> mFilterSp;
+ std::unique_ptr<MQ> mFilterMQ;
+ EventFlag* mFilterMQEventFlag;
+ jweak mFilterObj;
+ native_handle_t* mAvSharedHandle;
+ uint64_t mAvSharedMemSize;
+ bool mIsMediaFilter;
+};
+
struct MediaEvent : public RefBase {
- MediaEvent(sp<IFilter> iFilter, hidl_handle avHandle, uint64_t dataId,
- uint64_t dataLength, jobject obj);
+ MediaEvent(sp<Filter> filter, hidl_handle avHandle, uint64_t dataId,
+ uint64_t dataSize, jobject obj);
~MediaEvent();
jobject getLinearBlock();
uint64_t getAudioHandle();
void finalize();
- sp<IFilter> mIFilter;
+ sp<Filter> mFilter;
native_handle_t* mAvHandle;
uint64_t mDataId;
- uint64_t mDataLength;
+ uint64_t mDataSize;
uint8_t* mBuffer;
android::Mutex mLock;
int mDataIdRefCnt;
@@ -134,26 +155,16 @@
std::weak_ptr<C2Buffer> mC2Buffer;
};
-struct Filter : public RefBase {
- Filter(sp<IFilter> sp, jobject obj);
- ~Filter();
- int close();
- sp<IFilter> getIFilter();
- sp<IFilter> mFilterSp;
- std::unique_ptr<MQ> mFilterMQ;
- EventFlag* mFilterMQEventFlag;
- jweak mFilterObj;
-};
-
struct FilterCallback : public IFilterCallback {
~FilterCallback();
+ virtual Return<void> onFilterEvent_1_1(const DemuxFilterEvent& filterEvent,
+ const DemuxFilterEventExt& filterEventExt);
virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent);
virtual Return<void> onFilterStatus(const DemuxFilterStatus status);
void setFilter(const sp<Filter> filter);
private:
- jweak mFilter;
- sp<IFilter> mIFilter;
+ sp<Filter> mFilter;
jobjectArray getSectionEvent(
jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
jobjectArray getMediaEvent(
@@ -161,9 +172,11 @@
jobjectArray getPesEvent(
jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
jobjectArray getTsRecordEvent(
- jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>&events,
+ const std::vector<DemuxFilterEventExt::Event>& eventsExt);
jobjectArray getMmtpRecordEvent(
- jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>&events,
+ const std::vector<DemuxFilterEventExt::Event>& eventsExt);
jobjectArray getDownloadEvent(
jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
jobjectArray getIpPayloadEvent(
@@ -194,17 +207,21 @@
struct JTuner : public RefBase {
JTuner(JNIEnv *env, jobject thiz);
sp<ITuner> getTunerService();
+ int getTunerVersion();
jobject getAvSyncHwId(sp<Filter> filter);
jobject getAvSyncTime(jint id);
int connectCiCam(jint id);
+ int linkCiCam(jint id);
int disconnectCiCam();
+ int unlinkCiCam(jint id);
jobject getFrontendIds();
jobject openFrontendById(int id);
jint closeFrontendById(int id);
jobject getFrontendInfo(int id);
- int tune(const FrontendSettings& settings);
+ int tune(const FrontendSettings& settings, const FrontendSettingsExt1_1& settingsExt1_1);
int stopTune();
- int scan(const FrontendSettings& settings, FrontendScanType scanType);
+ int scan(const FrontendSettings& settings, FrontendScanType scanType,
+ const FrontendSettingsExt1_1& settingsExt1_1);
int stopScan();
int setLnb(int id);
int setLna(bool enable);
@@ -229,8 +246,13 @@
jclass mClass;
jweak mObject;
static sp<ITuner> mTuner;
+ static sp<::android::hardware::tv::tuner::V1_1::ITuner> mTuner_1_1;
+ // An integer that carries the Tuner version. The high 16 bits are the major version number
+ // while the low 16 bits are the minor version. Default value is unknown version 0.
+ static int mTunerVersion;
hidl_vec<FrontendId> mFeIds;
sp<IFrontend> mFe;
+ sp<::android::hardware::tv::tuner::V1_1::IFrontend> mFe_1_1;
int mFeId;
hidl_vec<LnbId> mLnbIds;
sp<ILnb> mLnb;
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index 45c49e5..0d53ab1 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -331,7 +331,7 @@
}
if (deviceType != AUDIO_DEVICE_NONE) {
- device.mType = deviceType;
+ device.mType = (audio_devices_t)deviceType;
ScopedUtfChars address(env, deviceAddress);
device.setAddress(address.c_str());
}
diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp
index ca3cc855..26725f8 100644
--- a/media/jni/soundpool/android_media_SoundPool.cpp
+++ b/media/jni/soundpool/android_media_SoundPool.cpp
@@ -200,7 +200,7 @@
paa->usage = (audio_usage_t) env->GetIntField(jaa, javaAudioAttrFields.fieldUsage);
paa->content_type =
(audio_content_type_t) env->GetIntField(jaa, javaAudioAttrFields.fieldContentType);
- paa->flags = env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
+ paa->flags = (audio_flags_mask_t) env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
ALOGV("android_media_SoundPool_native_setup");
auto *ap = new SoundPool(maxChannels, paa);
diff --git a/media/tests/MediaRouter/Android.bp b/media/tests/MediaRouter/Android.bp
index 5a0a50c..4d0c258 100644
--- a/media/tests/MediaRouter/Android.bp
+++ b/media/tests/MediaRouter/Android.bp
@@ -11,7 +11,8 @@
static_libs: [
"android-support-test",
"mockito-target-minus-junit4",
- "testng"
+ "testng",
+ "truth-prebuilt",
],
platform_apis: true,
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouteInfoTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouteInfoTest.java
new file mode 100644
index 0000000..92e4c95
--- /dev/null
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouteInfoTest.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2020 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.mediaroutertest;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.hardware.display.DisplayManagerGlobal;
+import android.media.MediaRouter;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.Display;
+import android.view.DisplayAddress;
+import android.view.DisplayAdjustments;
+import android.view.DisplayInfo;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class MediaRouteInfoTest {
+ private TestableRouteInfo mRouteInfo;
+ private static Display sWifiDisplay;
+ private static Display sExternalDisplay;
+ private static Display sInternalDisplay;
+ private static final String FAKE_MAC_ADDRESS = "fake MAC address";
+
+ @BeforeClass
+ public static void setUpOnce() {
+ final DisplayManagerGlobal global = DisplayManagerGlobal.getInstance();
+ final DisplayInfo wifiInfo = new DisplayInfo();
+ wifiInfo.flags = Display.FLAG_PRESENTATION;
+ wifiInfo.type = Display.TYPE_WIFI;
+ wifiInfo.address = DisplayAddress.fromMacAddress(FAKE_MAC_ADDRESS);
+ sWifiDisplay = new Display(global, 2, wifiInfo, new DisplayAdjustments());
+
+ final DisplayInfo externalInfo = new DisplayInfo();
+ externalInfo.flags = Display.FLAG_PRESENTATION;
+ externalInfo.type = Display.TYPE_EXTERNAL;
+ sExternalDisplay = new Display(global, 3, externalInfo, new DisplayAdjustments());
+
+ final DisplayInfo internalInfo = new DisplayInfo();
+ internalInfo.flags = Display.FLAG_PRESENTATION;
+ internalInfo.type = Display.TYPE_INTERNAL;
+ sInternalDisplay = new Display(global, 4, internalInfo, new DisplayAdjustments());
+ }
+
+ @Before
+ public void setUp() {
+ mRouteInfo = new TestableRouteInfo();
+ }
+
+ @Test
+ public void testGetPresentationDisplay_notLiveVideo() {
+ mRouteInfo.setPresentationDisplays(sWifiDisplay);
+ mRouteInfo.mSupportedType = MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
+
+ mRouteInfo.updatePresentationDisplay();
+
+ assertThat(mRouteInfo.getPresentationDisplay()).isNull();
+ }
+
+ @Test
+ public void testGetPresentationDisplay_includesLiveVideo() {
+ mRouteInfo.setPresentationDisplays(sWifiDisplay);
+ mRouteInfo.mSupportedType |= MediaRouter.ROUTE_TYPE_LIVE_AUDIO;
+
+ mRouteInfo.updatePresentationDisplay();
+
+ assertThat(mRouteInfo.getPresentationDisplay()).isEqualTo(sWifiDisplay);
+ }
+
+ @Test
+ public void testGetPresentationDisplay_noPresentationDisplay() {
+ mRouteInfo.updatePresentationDisplay();
+
+ assertThat(mRouteInfo.getPresentationDisplay()).isNull();
+ }
+
+ @Test
+ public void testGetPresentationDisplay_wifiDisplayOnly() {
+ mRouteInfo.setPresentationDisplays(sWifiDisplay);
+
+ mRouteInfo.updatePresentationDisplay();
+
+ assertThat(mRouteInfo.getPresentationDisplay()).isEqualTo(sWifiDisplay);
+ }
+
+ @Test
+ public void testGetPresentationDisplay_externalDisplayOnly() {
+ mRouteInfo.setPresentationDisplays(sExternalDisplay);
+
+ mRouteInfo.updatePresentationDisplay();
+
+ assertThat(mRouteInfo.getPresentationDisplay()).isEqualTo(sExternalDisplay);
+ }
+
+ @Test
+ public void testGetPresentationDisplay_internalDisplayOnly() {
+ mRouteInfo.setPresentationDisplays(sInternalDisplay);
+
+ mRouteInfo.updatePresentationDisplay();
+
+ assertThat(mRouteInfo.getPresentationDisplay()).isEqualTo(sInternalDisplay);
+ }
+
+ @Test
+ public void testGetPresentationDisplay_addressNotMatch() {
+ mRouteInfo.setPresentationDisplays(sWifiDisplay);
+ mRouteInfo.mDeviceAddress = "Not match";
+
+ mRouteInfo.updatePresentationDisplay();
+
+ assertThat(mRouteInfo.getPresentationDisplay()).isNull();
+ }
+
+ @Test
+ public void testGetPresentationDisplay_containsWifiAndExternalDisplays_returnWifiDisplay() {
+ mRouteInfo.setPresentationDisplays(sExternalDisplay, sWifiDisplay);
+
+ mRouteInfo.updatePresentationDisplay();
+
+ assertThat(mRouteInfo.getPresentationDisplay()).isEqualTo(sWifiDisplay);
+ }
+
+ @Test
+ public void testGetPresentationDisplay_containsExternalAndInternalDisplays_returnExternal() {
+ mRouteInfo.setPresentationDisplays(sExternalDisplay, sInternalDisplay);
+
+ mRouteInfo.updatePresentationDisplay();
+
+ assertThat(mRouteInfo.getPresentationDisplay()).isEqualTo(sExternalDisplay);
+ }
+
+ @Test
+ public void testGetPresentationDisplay_containsAllDisplays_returnWifiDisplay() {
+ mRouteInfo.setPresentationDisplays(sExternalDisplay, sInternalDisplay, sWifiDisplay);
+
+ mRouteInfo.updatePresentationDisplay();
+
+ assertThat(mRouteInfo.getPresentationDisplay()).isEqualTo(sWifiDisplay);
+ }
+
+ private static class TestableRouteInfo extends MediaRouter.RouteInfo {
+ private Display[] mDisplays = new Display[0];
+ private int mSupportedType = MediaRouter.ROUTE_TYPE_LIVE_VIDEO;
+ private String mDeviceAddress = FAKE_MAC_ADDRESS;
+ private MediaRouter.RouteInfo mDefaultRouteInfo = null;
+
+ private TestableRouteInfo() {
+ super(null);
+ }
+
+ private void setPresentationDisplays(Display ...displays) {
+ mDisplays = new Display[displays.length];
+ System.arraycopy(displays, 0, mDisplays, 0, displays.length);
+ }
+
+ @Override
+ public Display[] getAllPresentationDisplays() {
+ return mDisplays;
+ }
+
+ @Override
+ public int getSupportedTypes() {
+ return mSupportedType;
+ }
+
+ @Override
+ public String getDeviceAddress() {
+ return mDeviceAddress;
+ }
+
+ @Override
+ public MediaRouter.RouteInfo getDefaultAudioVideo() {
+ return mDefaultRouteInfo;
+ }
+ }
+}
diff --git a/native/graphics/jni/imagedecoder.cpp b/native/graphics/jni/imagedecoder.cpp
index 56f3906..ac4c16a 100644
--- a/native/graphics/jni/imagedecoder.cpp
+++ b/native/graphics/jni/imagedecoder.cpp
@@ -346,3 +346,25 @@
void AImageDecoder_delete(AImageDecoder* decoder) {
delete toDecoder(decoder);
}
+
+bool AImageDecoder_isAnimated(AImageDecoder* decoder) {
+ if (!decoder) return false;
+
+ ImageDecoder* imageDecoder = toDecoder(decoder);
+ return imageDecoder->mCodec->codec()->getFrameCount() > 1;
+}
+
+int32_t AImageDecoder_getRepeatCount(AImageDecoder* decoder) {
+ if (!decoder) return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+
+ ImageDecoder* imageDecoder = toDecoder(decoder);
+ const int count = imageDecoder->mCodec->codec()->getRepetitionCount();
+
+ // Skia should not report anything out of range, but defensively treat
+ // negative and too big as INFINITE.
+ if (count == SkCodec::kRepetitionCountInfinite || count < 0
+ || count > std::numeric_limits<int32_t>::max()) {
+ return ANDROID_IMAGE_DECODER_INFINITE;
+ }
+ return count;
+}
diff --git a/native/graphics/jni/libjnigraphics.map.txt b/native/graphics/jni/libjnigraphics.map.txt
index 01c1477..a184ab9 100644
--- a/native/graphics/jni/libjnigraphics.map.txt
+++ b/native/graphics/jni/libjnigraphics.map.txt
@@ -13,6 +13,8 @@
AImageDecoder_setTargetSize; # introduced=30
AImageDecoder_computeSampledSize; # introduced=30
AImageDecoder_setCrop; # introduced=30
+ AImageDecoder_isAnimated; # introduced=31
+ AImageDecoder_getRepeatCount; # introduced=31
AImageDecoderHeaderInfo_getWidth; # introduced=30
AImageDecoderHeaderInfo_getHeight; # introduced=30
AImageDecoderHeaderInfo_getMimeType; # introduced=30
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index 36207c9..aed080e 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -2889,6 +2889,7 @@
field public static final int GESTURE_2_FINGER_DOUBLE_TAP = 20; // 0x14
field public static final int GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD = 40; // 0x28
field public static final int GESTURE_2_FINGER_SINGLE_TAP = 19; // 0x13
+ field public static final int GESTURE_2_FINGER_SINGLE_TAP_AND_HOLD = 43; // 0x2b
field public static final int GESTURE_2_FINGER_SWIPE_DOWN = 26; // 0x1a
field public static final int GESTURE_2_FINGER_SWIPE_LEFT = 27; // 0x1b
field public static final int GESTURE_2_FINGER_SWIPE_RIGHT = 28; // 0x1c
@@ -2897,11 +2898,13 @@
field public static final int GESTURE_3_FINGER_DOUBLE_TAP = 23; // 0x17
field public static final int GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD = 41; // 0x29
field public static final int GESTURE_3_FINGER_SINGLE_TAP = 22; // 0x16
+ field public static final int GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD = 44; // 0x2c
field public static final int GESTURE_3_FINGER_SWIPE_DOWN = 30; // 0x1e
field public static final int GESTURE_3_FINGER_SWIPE_LEFT = 31; // 0x1f
field public static final int GESTURE_3_FINGER_SWIPE_RIGHT = 32; // 0x20
field public static final int GESTURE_3_FINGER_SWIPE_UP = 29; // 0x1d
field public static final int GESTURE_3_FINGER_TRIPLE_TAP = 24; // 0x18
+ field public static final int GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD = 45; // 0x2d
field public static final int GESTURE_4_FINGER_DOUBLE_TAP = 38; // 0x26
field public static final int GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD = 42; // 0x2a
field public static final int GESTURE_4_FINGER_SINGLE_TAP = 37; // 0x25
@@ -10664,12 +10667,15 @@
field public static final String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
field public static final String ACTION_PACKAGE_DATA_CLEARED = "android.intent.action.PACKAGE_DATA_CLEARED";
field public static final String ACTION_PACKAGE_FIRST_LAUNCH = "android.intent.action.PACKAGE_FIRST_LAUNCH";
+ field public static final String ACTION_PACKAGE_FULLY_LOADED = "android.intent.action.PACKAGE_FULLY_LOADED";
field public static final String ACTION_PACKAGE_FULLY_REMOVED = "android.intent.action.PACKAGE_FULLY_REMOVED";
field @Deprecated public static final String ACTION_PACKAGE_INSTALL = "android.intent.action.PACKAGE_INSTALL";
field public static final String ACTION_PACKAGE_NEEDS_VERIFICATION = "android.intent.action.PACKAGE_NEEDS_VERIFICATION";
field public static final String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED";
field public static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED";
field public static final String ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED";
+ field public static final String ACTION_PACKAGE_STARTABLE = "android.intent.action.PACKAGE_STARTABLE";
+ field public static final String ACTION_PACKAGE_UNSTARTABLE = "android.intent.action.PACKAGE_UNSTARTABLE";
field public static final String ACTION_PACKAGE_VERIFIED = "android.intent.action.PACKAGE_VERIFIED";
field public static final String ACTION_PASTE = "android.intent.action.PASTE";
field public static final String ACTION_PICK = "android.intent.action.PICK";
@@ -10834,6 +10840,7 @@
field public static final String EXTRA_TIMEZONE = "time-zone";
field public static final String EXTRA_TITLE = "android.intent.extra.TITLE";
field public static final String EXTRA_UID = "android.intent.extra.UID";
+ field public static final String EXTRA_UNSTARTABLE_REASON = "android.intent.extra.UNSTARTABLE_REASON";
field public static final String EXTRA_USER = "android.intent.extra.USER";
field public static final int FILL_IN_ACTION = 1; // 0x1
field public static final int FILL_IN_CATEGORIES = 4; // 0x4
@@ -11707,7 +11714,10 @@
method public android.graphics.drawable.Drawable getIcon(int);
method public CharSequence getLabel();
method public String getName();
+ method public float getProgress();
method public android.os.UserHandle getUser();
+ method public boolean isLoading();
+ method public boolean isStartable();
}
public class LauncherApps {
@@ -11747,6 +11757,7 @@
ctor public LauncherApps.Callback();
method public abstract void onPackageAdded(String, android.os.UserHandle);
method public abstract void onPackageChanged(String, android.os.UserHandle);
+ method public void onPackageProgressChanged(@NonNull String, @NonNull android.os.UserHandle, float);
method public abstract void onPackageRemoved(String, android.os.UserHandle);
method public abstract void onPackagesAvailable(String[], android.os.UserHandle, boolean);
method public void onPackagesSuspended(String[], android.os.UserHandle);
@@ -12293,6 +12304,9 @@
field public static final int SYNCHRONOUS = 2; // 0x2
field @Nullable public static final java.util.List<java.security.cert.Certificate> TRUST_ALL;
field @NonNull public static final java.util.List<java.security.cert.Certificate> TRUST_NONE;
+ field public static final int UNSTARTABLE_REASON_CONNECTION_ERROR = 1; // 0x1
+ field public static final int UNSTARTABLE_REASON_INSUFFICIENT_STORAGE = 2; // 0x2
+ field public static final int UNSTARTABLE_REASON_UNKNOWN = 0; // 0x0
field public static final int VERIFICATION_ALLOW = 1; // 0x1
field public static final int VERIFICATION_REJECT = -1; // 0xffffffff
field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff
@@ -24071,9 +24085,13 @@
method @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMaxUpdates();
method @FloatRange(from=0, to=java.lang.Float.MAX_VALUE) public float getMinUpdateDistanceMeters();
method @IntRange(from=0) public long getMinUpdateIntervalMillis();
+ method public int getQuality();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationRequest> CREATOR;
field public static final long PASSIVE_INTERVAL = 9223372036854775807L; // 0x7fffffffffffffffL
+ field public static final int QUALITY_BALANCED_POWER_ACCURACY = 102; // 0x66
+ field public static final int QUALITY_HIGH_ACCURACY = 100; // 0x64
+ field public static final int QUALITY_LOW_POWER = 104; // 0x68
}
public static final class LocationRequest.Builder {
@@ -24086,6 +24104,7 @@
method @NonNull public android.location.LocationRequest.Builder setMaxUpdates(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
method @NonNull public android.location.LocationRequest.Builder setMinUpdateDistanceMeters(@FloatRange(from=0, to=java.lang.Float.MAX_VALUE) float);
method @NonNull public android.location.LocationRequest.Builder setMinUpdateIntervalMillis(@IntRange(from=0) long);
+ method @NonNull public android.location.LocationRequest.Builder setQuality(int);
}
public interface OnNmeaMessageListener {
@@ -25438,6 +25457,7 @@
public static final class MediaCodec.CryptoInfo {
ctor public MediaCodec.CryptoInfo();
+ method @NonNull public android.media.MediaCodec.CryptoInfo.Pattern getPattern();
method public void set(int, @NonNull int[], @NonNull int[], @NonNull byte[], @NonNull byte[], int);
method public void setPattern(android.media.MediaCodec.CryptoInfo.Pattern);
field public byte[] iv;
@@ -42234,11 +42254,13 @@
method public long getLastAudiblyAlertedMillis();
method public String getOverrideGroupKey();
method public int getRank();
+ method @Nullable public android.content.pm.ShortcutInfo getShortcutInfo();
method @NonNull public java.util.List<android.app.Notification.Action> getSmartActions();
method @NonNull public java.util.List<java.lang.CharSequence> getSmartReplies();
method public int getSuppressedVisualEffects();
method public int getUserSentiment();
method public boolean isAmbient();
+ method public boolean isConversation();
method public boolean isSuspended();
method public boolean matchesInterruptionFilter();
field public static final int USER_SENTIMENT_NEGATIVE = -1; // 0xffffffff
@@ -46574,6 +46596,7 @@
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getDeviceSoftwareVersion();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<java.lang.String> getEquivalentHomePlmns();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String[] getForbiddenPlmns();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getGroupIdLevel1();
method public String getIccAuthentication(int, int, String);
@@ -46598,7 +46621,7 @@
method @Deprecated public int getPhoneCount();
method public int getPhoneType();
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE}) public int getPreferredOpportunisticDataSubscription();
- method @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public android.telephony.ServiceState getServiceState();
+ method @Nullable @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public android.telephony.ServiceState getServiceState();
method @Nullable public android.telephony.SignalStrength getSignalStrength();
method public int getSimCarrierId();
method @Nullable public CharSequence getSimCarrierIdName();
@@ -46621,7 +46644,7 @@
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailAlphaTag();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getVoiceNetworkType();
- method public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle);
+ method @Nullable public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle);
method public boolean hasCarrierPrivileges();
method public boolean hasIccCard();
method @Deprecated public boolean iccCloseLogicalChannel(int);
@@ -51848,11 +51871,12 @@
method @Nullable public android.net.Uri getLinkUri();
method public int getSource();
field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
- field public static final int SOURCE_AUTOFILL = 3; // 0x3
- field public static final int SOURCE_CLIPBOARD = 0; // 0x0
- field public static final int SOURCE_DRAG_AND_DROP = 2; // 0x2
- field public static final int SOURCE_INPUT_METHOD = 1; // 0x1
- field public static final int SOURCE_PROCESS_TEXT = 4; // 0x4
+ field public static final int SOURCE_APP = 0; // 0x0
+ field public static final int SOURCE_AUTOFILL = 4; // 0x4
+ field public static final int SOURCE_CLIPBOARD = 1; // 0x1
+ field public static final int SOURCE_DRAG_AND_DROP = 3; // 0x3
+ field public static final int SOURCE_INPUT_METHOD = 2; // 0x2
+ field public static final int SOURCE_PROCESS_TEXT = 5; // 0x5
}
public static final class OnReceiveContentCallback.Payload.Builder {
diff --git a/non-updatable-api/module-lib-current.txt b/non-updatable-api/module-lib-current.txt
index b19ce48..3c1d19f 100644
--- a/non-updatable-api/module-lib-current.txt
+++ b/non-updatable-api/module-lib-current.txt
@@ -1,10 +1,20 @@
// Signature format: 2.0
package android.app {
+ public class ActivityManager {
+ method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void addHomeVisibilityListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.HomeVisibilityListener);
+ method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void removeHomeVisibilityListener(@NonNull android.app.HomeVisibilityListener);
+ }
+
public class AppOpsManager {
field public static final String OPSTR_NO_ISOLATED_STORAGE = "android:no_isolated_storage";
}
+ public abstract class HomeVisibilityListener {
+ ctor public HomeVisibilityListener();
+ method public abstract void onHomeVisibilityChanged(boolean);
+ }
+
public class NotificationManager {
method public boolean hasEnabledNotificationListener(@NonNull String, @NonNull android.os.UserHandle);
field public static final String ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED = "android.app.action.NOTIFICATION_LISTENER_ENABLED_CHANGED";
@@ -123,6 +133,18 @@
}
+package android.telephony {
+
+ public abstract class CellSignalStrength {
+ method public static int getNumSignalStrengthLevels();
+ }
+
+ public class TelephonyManager {
+ method @NonNull public static int[] getAllNetworkTypes();
+ }
+
+}
+
package android.util {
public class AtomicFile {
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index 515c273..842d613 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -122,6 +122,7 @@
field public static final String MANAGE_FACTORY_RESET_PROTECTION = "android.permission.MANAGE_FACTORY_RESET_PROTECTION";
field public static final String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
field public static final String MANAGE_MUSIC_RECOGNITION = "android.permission.MANAGE_MUSIC_RECOGNITION";
+ field public static final String MANAGE_NOTIFICATION_LISTENERS = "android.permission.MANAGE_NOTIFICATION_LISTENERS";
field public static final String MANAGE_ONE_TIME_PERMISSION_SESSIONS = "android.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS";
field public static final String MANAGE_ROLE_HOLDERS = "android.permission.MANAGE_ROLE_HOLDERS";
field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
@@ -674,8 +675,10 @@
public class NotificationManager {
method @NonNull public java.util.List<java.lang.String> getAllowedAssistantAdjustments();
method @Nullable public android.content.ComponentName getAllowedNotificationAssistant();
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public java.util.List<android.content.ComponentName> getEnabledNotificationListeners();
method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName);
method public void setNotificationAssistantAccessGranted(@Nullable android.content.ComponentName, boolean);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public void setNotificationListenerAccessGranted(@NonNull android.content.ComponentName, boolean);
field @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) public static final String ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL = "android.app.action.CLOSE_NOTIFICATION_HANDLER_PANEL";
field @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) public static final String ACTION_OPEN_NOTIFICATION_HANDLER_PANEL = "android.app.action.OPEN_NOTIFICATION_HANDLER_PANEL";
field @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) public static final String ACTION_TOGGLE_NOTIFICATION_HANDLER_PANEL = "android.app.action.TOGGLE_NOTIFICATION_HANDLER_PANEL";
@@ -4111,7 +4114,6 @@
method @Deprecated public long getInterval();
method @Deprecated public int getNumUpdates();
method @Deprecated @NonNull public String getProvider();
- method public int getQuality();
method @Deprecated public float getSmallestDisplacement();
method @NonNull public android.os.WorkSource getWorkSource();
method public boolean isHiddenFromAppOps();
@@ -4130,11 +4132,11 @@
method @Deprecated @NonNull public android.location.LocationRequest setQuality(int);
method @Deprecated @NonNull public android.location.LocationRequest setSmallestDisplacement(float);
method @Deprecated public void setWorkSource(@Nullable android.os.WorkSource);
- field public static final int ACCURACY_BLOCK = 102; // 0x66
- field public static final int ACCURACY_CITY = 104; // 0x68
- field public static final int ACCURACY_FINE = 100; // 0x64
- field public static final int POWER_HIGH = 203; // 0xcb
- field public static final int POWER_LOW = 201; // 0xc9
+ field @Deprecated public static final int ACCURACY_BLOCK = 102; // 0x66
+ field @Deprecated public static final int ACCURACY_CITY = 104; // 0x68
+ field @Deprecated public static final int ACCURACY_FINE = 100; // 0x64
+ field @Deprecated public static final int POWER_HIGH = 203; // 0xcb
+ field @Deprecated public static final int POWER_LOW = 201; // 0xc9
field @Deprecated public static final int POWER_NONE = 200; // 0xc8
}
@@ -4142,7 +4144,6 @@
method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LocationRequest.Builder setHiddenFromAppOps(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest.Builder setLocationSettingsIgnored(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.location.LocationRequest.Builder setLowPower(boolean);
- method @NonNull public android.location.LocationRequest.Builder setQuality(int);
method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
}
@@ -4709,6 +4710,22 @@
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.DvbDeviceInfo> CREATOR;
}
+ public final class TunedInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getAppTag();
+ method public int getAppType();
+ method @Nullable public android.net.Uri getChannelUri();
+ method @NonNull public String getInputId();
+ method public boolean isForeground();
+ method public boolean isRecordingSession();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int APP_TAG_SELF = 0; // 0x0
+ field public static final int APP_TYPE_NON_SYSTEM = 3; // 0x3
+ field public static final int APP_TYPE_SELF = 1; // 0x1
+ field public static final int APP_TYPE_SYSTEM = 2; // 0x2
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.TunedInfo> CREATOR;
+ }
+
public final class TvContentRatingSystemInfo implements android.os.Parcelable {
method public static android.media.tv.TvContentRatingSystemInfo createTvContentRatingSystemInfo(int, android.content.pm.ApplicationInfo);
method public int describeContents();
@@ -4824,6 +4841,7 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void addBlockedRating(@NonNull android.media.tv.TvContentRating);
method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public boolean captureFrame(String, android.view.Surface, android.media.tv.TvStreamConfig);
method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public java.util.List<android.media.tv.TvStreamConfig> getAvailableTvStreamConfigList(String);
+ method @NonNull @RequiresPermission("com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS") public java.util.List<android.media.tv.TunedInfo> getCurrentTunedInfos();
method @NonNull @RequiresPermission("android.permission.DVB_DEVICE") public java.util.List<android.media.tv.DvbDeviceInfo> getDvbDeviceList();
method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public java.util.List<android.media.tv.TvInputHardwareInfo> getHardwareList();
method @RequiresPermission(android.Manifest.permission.READ_CONTENT_RATING_SYSTEMS) public java.util.List<android.media.tv.TvContentRatingSystemInfo> getTvContentRatingSystemList();
@@ -4849,6 +4867,10 @@
method public abstract void onStreamConfigChanged(android.media.tv.TvStreamConfig[]);
}
+ public abstract static class TvInputManager.TvInputCallback {
+ method public void onCurrentTunedInfosUpdated(@NonNull java.util.List<android.media.tv.TunedInfo>);
+ }
+
public abstract class TvInputService extends android.app.Service {
method @Nullable public android.media.tv.TvInputInfo onHardwareAdded(android.media.tv.TvInputHardwareInfo);
method @Nullable public String onHardwareRemoved(android.media.tv.TvInputHardwareInfo);
@@ -4976,6 +4998,7 @@
method @Nullable public android.media.tv.tuner.DemuxCapabilities getDemuxCapabilities();
method @Nullable public android.media.tv.tuner.frontend.FrontendInfo getFrontendInfo();
method @Nullable public android.media.tv.tuner.frontend.FrontendStatus getFrontendStatus(@NonNull int[]);
+ method public int linkFrontendToCiCam(int);
method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_DESCRAMBLER) public android.media.tv.tuner.Descrambler openDescrambler();
method @Nullable public android.media.tv.tuner.dvr.DvrPlayback openDvrPlayback(long, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.dvr.OnPlaybackStatusChangedListener);
method @Nullable public android.media.tv.tuner.dvr.DvrRecorder openDvrRecorder(long, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.dvr.OnRecordStatusChangedListener);
@@ -4989,9 +5012,14 @@
method public void setResourceLostListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.Tuner.OnResourceLostListener);
method public void shareFrontendFromTuner(@NonNull android.media.tv.tuner.Tuner);
method public int tune(@NonNull android.media.tv.tuner.frontend.FrontendSettings);
+ method public int unlinkFrontendToCiCam(int);
method public void updateResourcePriority(int, int);
field public static final int INVALID_AV_SYNC_ID = -1; // 0xffffffff
field public static final int INVALID_FILTER_ID = -1; // 0xffffffff
+ field public static final long INVALID_FILTER_ID_64BIT = -1L; // 0xffffffffffffffffL
+ field public static final int INVALID_FRONTEND_SETTING_FREQUENCY = -1; // 0xffffffff
+ field public static final int INVALID_LTS_ID = -1; // 0xffffffff
+ field public static final int INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM = -1; // 0xffffffff
field public static final int INVALID_STREAM_ID = 65535; // 0xffff
field public static final long INVALID_TIMESTAMP = -1L; // 0xffffffffffffffffL
field public static final int INVALID_TS_PID = 65535; // 0xffff
@@ -5011,15 +5039,22 @@
method public void onResourceLost(@NonNull android.media.tv.tuner.Tuner);
}
+ public final class TunerVersionChecker {
+ method public static int getTunerVersion();
+ field public static final int TUNER_VERSION_1_0 = 65536; // 0x10000
+ field public static final int TUNER_VERSION_1_1 = 65537; // 0x10001
+ field public static final int TUNER_VERSION_UNKNOWN = 0; // 0x0
+ }
+
}
package android.media.tv.tuner.dvr {
public class DvrPlayback implements java.lang.AutoCloseable {
- method public int attachFilter(@NonNull android.media.tv.tuner.filter.Filter);
+ method @Deprecated public int attachFilter(@NonNull android.media.tv.tuner.filter.Filter);
method public void close();
method public int configure(@NonNull android.media.tv.tuner.dvr.DvrSettings);
- method public int detachFilter(@NonNull android.media.tv.tuner.filter.Filter);
+ method @Deprecated public int detachFilter(@NonNull android.media.tv.tuner.filter.Filter);
method public int flush();
method public long read(long);
method public long read(@NonNull byte[], long, long);
@@ -5144,6 +5179,7 @@
method public int configure(@NonNull android.media.tv.tuner.filter.FilterConfiguration);
method public int flush();
method public int getId();
+ method public long getId64Bit();
method public int read(@NonNull byte[], long, long);
method public int setDataSource(@Nullable android.media.tv.tuner.filter.Filter);
method public int start();
@@ -5195,16 +5231,19 @@
method @NonNull public static android.media.tv.tuner.filter.IpFilterConfiguration.Builder builder();
method @NonNull @Size(min=4, max=16) public byte[] getDstIpAddress();
method public int getDstPort();
+ method public int getIpFilterContextId();
method @NonNull @Size(min=4, max=16) public byte[] getSrcIpAddress();
method public int getSrcPort();
method public int getType();
method public boolean isPassthrough();
+ field public static final int INVALID_IP_FILTER_CONTEXT_ID = -1; // 0xffffffff
}
public static final class IpFilterConfiguration.Builder {
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration build();
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setDstIpAddress(@NonNull byte[]);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setDstPort(int);
+ method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setIpFilterContextId(int);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setPassthrough(boolean);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setSrcIpAddress(@NonNull byte[]);
@@ -5244,6 +5283,8 @@
public class MmtpRecordEvent extends android.media.tv.tuner.filter.FilterEvent {
method public long getDataLength();
+ method public int getMpuSequenceNumber();
+ method public long getPts();
method public int getScHevcIndexMask();
}
@@ -5406,6 +5447,7 @@
public class TsRecordEvent extends android.media.tv.tuner.filter.FilterEvent {
method public long getDataLength();
method public int getPacketId();
+ method public long getPts();
method public int getScIndexMask();
method public int getTsIndexMask();
}
@@ -5421,9 +5463,13 @@
public class AnalogFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
method @NonNull public static android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder builder();
+ method public int getAftFlag();
method public int getSifStandard();
method public int getSignalType();
method public int getType();
+ field public static final int AFT_FLAG_FALSE = 2; // 0x2
+ field public static final int AFT_FLAG_TRUE = 1; // 0x1
+ field public static final int AFT_FLAG_UNDEFINED = 0; // 0x0
field public static final int SIF_AUTO = 1; // 0x1
field public static final int SIF_BG = 2; // 0x2
field public static final int SIF_BG_A2 = 4; // 0x4
@@ -5456,6 +5502,7 @@
public static class AnalogFrontendSettings.Builder {
method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings build();
+ method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setAftFlag(int);
method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setFrequency(int);
method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setSifStandard(int);
method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setSignalType(int);
@@ -5571,6 +5618,69 @@
method @NonNull public android.media.tv.tuner.frontend.AtscFrontendSettings.Builder setModulation(int);
}
+ public class DtmbFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
+ method public int getBandwidthCapability();
+ method public int getCodeRateCapability();
+ method public int getGuardIntervalCapability();
+ method public int getModulationCapability();
+ method public int getTimeInterleaveModeCapability();
+ method public int getTransmissionModeCapability();
+ }
+
+ public class DtmbFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
+ method @NonNull public static android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder builder();
+ method public int getBandwidth();
+ method public int getCodeRate();
+ method public int getGuardInterval();
+ method public int getModulation();
+ method public int getTimeInterleaveMode();
+ method public int getTransmissionMode();
+ method public int getType();
+ field public static final int BANDWIDTH_6MHZ = 4; // 0x4
+ field public static final int BANDWIDTH_8MHZ = 2; // 0x2
+ field public static final int BANDWIDTH_AUTO = 1; // 0x1
+ field public static final int BANDWIDTH_UNDEFINED = 0; // 0x0
+ field public static final int CODERATE_2_5 = 2; // 0x2
+ field public static final int CODERATE_3_5 = 4; // 0x4
+ field public static final int CODERATE_4_5 = 8; // 0x8
+ field public static final int CODERATE_AUTO = 1; // 0x1
+ field public static final int CODERATE_UNDEFINED = 0; // 0x0
+ field public static final int GUARD_INTERVAL_AUTO = 1; // 0x1
+ field public static final int GUARD_INTERVAL_PN_420_CONST = 16; // 0x10
+ field public static final int GUARD_INTERVAL_PN_420_VARIOUS = 2; // 0x2
+ field public static final int GUARD_INTERVAL_PN_595_CONST = 4; // 0x4
+ field public static final int GUARD_INTERVAL_PN_945_CONST = 32; // 0x20
+ field public static final int GUARD_INTERVAL_PN_945_VARIOUS = 8; // 0x8
+ field public static final int GUARD_INTERVAL_PN_RESERVED = 64; // 0x40
+ field public static final int GUARD_INTERVAL_UNDEFINED = 0; // 0x0
+ field public static final int MODULATION_CONSTELLATION_16QAM = 8; // 0x8
+ field public static final int MODULATION_CONSTELLATION_32QAM = 16; // 0x10
+ field public static final int MODULATION_CONSTELLATION_4QAM = 2; // 0x2
+ field public static final int MODULATION_CONSTELLATION_4QAM_NR = 4; // 0x4
+ field public static final int MODULATION_CONSTELLATION_64QAM = 32; // 0x20
+ field public static final int MODULATION_CONSTELLATION_AUTO = 1; // 0x1
+ field public static final int MODULATION_CONSTELLATION_UNDEFINED = 0; // 0x0
+ field public static final int TIME_INTERLEAVE_MODE_AUTO = 1; // 0x1
+ field public static final int TIME_INTERLEAVE_MODE_TIMER_INT_240 = 2; // 0x2
+ field public static final int TIME_INTERLEAVE_MODE_TIMER_INT_720 = 4; // 0x4
+ field public static final int TIME_INTERLEAVE_MODE_UNDEFINED = 0; // 0x0
+ field public static final int TRANSMISSION_MODE_AUTO = 1; // 0x1
+ field public static final int TRANSMISSION_MODE_C1 = 2; // 0x2
+ field public static final int TRANSMISSION_MODE_C3780 = 4; // 0x4
+ field public static final int TRANSMISSION_MODE_UNDEFINED = 0; // 0x0
+ }
+
+ public static final class DtmbFrontendSettings.Builder {
+ method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings build();
+ method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setBandwidth(int);
+ method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setCodeRate(int);
+ method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setFrequency(int);
+ method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setGuardInterval(int);
+ method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setModulation(int);
+ method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setTimeInterleaveMode(int);
+ method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setTransmissionMode(int);
+ }
+
public class DvbcFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
method public int getAnnexCapability();
method public int getFecCapability();
@@ -5585,6 +5695,7 @@
method public int getOuterFec();
method public int getSpectralInversion();
method public int getSymbolRate();
+ method public int getTimeInterleaveMode();
method public int getType();
field public static final int ANNEX_A = 1; // 0x1
field public static final int ANNEX_B = 2; // 0x2
@@ -5600,9 +5711,20 @@
field public static final int OUTER_FEC_OUTER_FEC_NONE = 1; // 0x1
field public static final int OUTER_FEC_OUTER_FEC_RS = 2; // 0x2
field public static final int OUTER_FEC_UNDEFINED = 0; // 0x0
- field public static final int SPECTRAL_INVERSION_INVERTED = 2; // 0x2
- field public static final int SPECTRAL_INVERSION_NORMAL = 1; // 0x1
- field public static final int SPECTRAL_INVERSION_UNDEFINED = 0; // 0x0
+ field @Deprecated public static final int SPECTRAL_INVERSION_INVERTED = 2; // 0x2
+ field @Deprecated public static final int SPECTRAL_INVERSION_NORMAL = 1; // 0x1
+ field @Deprecated public static final int SPECTRAL_INVERSION_UNDEFINED = 0; // 0x0
+ field public static final int TIME_INTERLEAVE_MODE_128_1_0 = 2; // 0x2
+ field public static final int TIME_INTERLEAVE_MODE_128_1_1 = 4; // 0x4
+ field public static final int TIME_INTERLEAVE_MODE_128_2 = 128; // 0x80
+ field public static final int TIME_INTERLEAVE_MODE_128_3 = 256; // 0x100
+ field public static final int TIME_INTERLEAVE_MODE_128_4 = 512; // 0x200
+ field public static final int TIME_INTERLEAVE_MODE_16_8 = 32; // 0x20
+ field public static final int TIME_INTERLEAVE_MODE_32_4 = 16; // 0x10
+ field public static final int TIME_INTERLEAVE_MODE_64_2 = 8; // 0x8
+ field public static final int TIME_INTERLEAVE_MODE_8_16 = 64; // 0x40
+ field public static final int TIME_INTERLEAVE_MODE_AUTO = 1; // 0x1
+ field public static final int TIME_INTERLEAVE_MODE_UNDEFINED = 0; // 0x0
}
public static class DvbcFrontendSettings.Builder {
@@ -5614,6 +5736,7 @@
method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setOuterFec(int);
method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setSpectralInversion(int);
method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setSymbolRate(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setTimeInterleaveMode(int);
}
public class DvbsCodeRate {
@@ -5645,6 +5768,7 @@
method public int getModulation();
method public int getPilot();
method public int getRolloff();
+ method public int getScanType();
method public int getStandard();
method public int getSymbolRate();
method public int getType();
@@ -5675,6 +5799,11 @@
field public static final int ROLLOFF_0_35 = 1; // 0x1
field public static final int ROLLOFF_0_5 = 6; // 0x6
field public static final int ROLLOFF_UNDEFINED = 0; // 0x0
+ field public static final int SCAN_TYPE_DIRECT = 1; // 0x1
+ field public static final int SCAN_TYPE_DISEQC = 2; // 0x2
+ field public static final int SCAN_TYPE_JESS = 4; // 0x4
+ field public static final int SCAN_TYPE_UNDEFINED = 0; // 0x0
+ field public static final int SCAN_TYPE_UNICABLE = 3; // 0x3
field public static final int STANDARD_AUTO = 1; // 0x1
field public static final int STANDARD_S = 2; // 0x2
field public static final int STANDARD_S2 = 4; // 0x4
@@ -5692,6 +5821,7 @@
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setModulation(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setPilot(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setRolloff(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setScanType(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setStandard(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setSymbolRate(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setVcmMode(int);
@@ -5744,10 +5874,14 @@
field public static final int CODERATE_AUTO = 1; // 0x1
field public static final int CODERATE_UNDEFINED = 0; // 0x0
field public static final int CONSTELLATION_16QAM = 4; // 0x4
+ field public static final int CONSTELLATION_16QAM_R = 64; // 0x40
field public static final int CONSTELLATION_256QAM = 16; // 0x10
+ field public static final int CONSTELLATION_256QAM_R = 256; // 0x100
field public static final int CONSTELLATION_64QAM = 8; // 0x8
+ field public static final int CONSTELLATION_64QAM_R = 128; // 0x80
field public static final int CONSTELLATION_AUTO = 1; // 0x1
field public static final int CONSTELLATION_QPSK = 2; // 0x2
+ field public static final int CONSTELLATION_QPSK_R = 32; // 0x20
field public static final int CONSTELLATION_UNDEFINED = 0; // 0x0
field public static final int GUARD_INTERVAL_19_128 = 64; // 0x40
field public static final int GUARD_INTERVAL_19_256 = 128; // 0x80
@@ -5781,6 +5915,9 @@
field public static final int TRANSMISSION_MODE_4K = 8; // 0x8
field public static final int TRANSMISSION_MODE_8K = 4; // 0x4
field public static final int TRANSMISSION_MODE_AUTO = 1; // 0x1
+ field public static final int TRANSMISSION_MODE_EXTENDED_16K = 256; // 0x100
+ field public static final int TRANSMISSION_MODE_EXTENDED_32K = 512; // 0x200
+ field public static final int TRANSMISSION_MODE_EXTENDED_8K = 128; // 0x80
field public static final int TRANSMISSION_MODE_UNDEFINED = 0; // 0x0
}
@@ -5818,8 +5955,12 @@
}
public abstract class FrontendSettings {
+ method public int getEndFrequency();
method public int getFrequency();
+ method public int getFrontendSpectralInversion();
method public abstract int getType();
+ method @IntRange(from=1) public void setEndFrequency(int);
+ method public void setSpectralInversion(int);
field public static final long FEC_11_15 = 4194304L; // 0x400000L
field public static final long FEC_11_20 = 8388608L; // 0x800000L
field public static final long FEC_11_45 = 16777216L; // 0x1000000L
@@ -5857,9 +5998,13 @@
field public static final long FEC_9_20 = 2097152L; // 0x200000L
field public static final long FEC_AUTO = 1L; // 0x1L
field public static final long FEC_UNDEFINED = 0L; // 0x0L
+ field public static final int FRONTEND_SPECTRAL_INVERSION_INVERTED = 2; // 0x2
+ field public static final int FRONTEND_SPECTRAL_INVERSION_NORMAL = 1; // 0x1
+ field public static final int FRONTEND_SPECTRAL_INVERSION_UNDEFINED = 0; // 0x0
field public static final int TYPE_ANALOG = 1; // 0x1
field public static final int TYPE_ATSC = 2; // 0x2
field public static final int TYPE_ATSC3 = 3; // 0x3
+ field public static final int TYPE_DTMB = 10; // 0xa
field public static final int TYPE_DVBC = 4; // 0x4
field public static final int TYPE_DVBS = 5; // 0x5
field public static final int TYPE_DVBT = 6; // 0x6
@@ -9886,6 +10031,25 @@
field public static final String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming";
}
+ public final class ModemActivityInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.telephony.ModemActivityInfo getDelta(@NonNull android.telephony.ModemActivityInfo);
+ method public long getIdleTimeMillis();
+ method public static int getNumTxPowerLevels();
+ method public long getReceiveTimeMillis();
+ method public long getSleepTimeMillis();
+ method public long getTimestampMillis();
+ method public long getTransmitDurationMillisAtPowerLevel(int);
+ method @NonNull public android.util.Range<java.lang.Integer> getTransmitPowerRange(int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ModemActivityInfo> CREATOR;
+ field public static final int TX_POWER_LEVEL_0 = 0; // 0x0
+ field public static final int TX_POWER_LEVEL_1 = 1; // 0x1
+ field public static final int TX_POWER_LEVEL_2 = 2; // 0x2
+ field public static final int TX_POWER_LEVEL_3 = 3; // 0x3
+ field public static final int TX_POWER_LEVEL_4 = 4; // 0x4
+ }
+
public final class NetworkRegistrationInfo implements android.os.Parcelable {
method @Nullable public android.telephony.DataSpecificRegistrationInfo getDataSpecificInfo();
method public int getRegistrationState();
@@ -10379,7 +10543,6 @@
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDeviceSoftwareVersion(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEmergencyNumberDbVersion();
- method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<java.lang.String> getEquivalentHomePlmns();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Map<java.lang.Integer,java.lang.Integer> getLogicalToPhysicalSlotMapping();
diff --git a/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java b/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java
index 6d31a8d..3bfe410 100644
--- a/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java
@@ -26,19 +26,24 @@
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.pip.Pip;
+import dagger.BindsOptionalOf;
import dagger.Module;
import dagger.Provides;
/** Provides dependencies from {@link com.android.wm.shell} for CarSystemUI. */
@Module(includes = WMShellBaseModule.class)
-public class CarWMShellModule {
+public abstract class CarWMShellModule {
@SysUISingleton
@Provides
- DisplayImeController provideDisplayImeController(Context context,
+ static DisplayImeController provideDisplayImeController(Context context,
IWindowManager wmService, DisplayController displayController,
@Main Handler mainHandler, TransactionPool transactionPool) {
return new DisplaySystemBarsController(context, wmService, displayController,
mainHandler, transactionPool);
}
+
+ @BindsOptionalOf
+ abstract Pip optionalPip();
}
diff --git a/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java b/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java
index 900e68d..6827d6e 100644
--- a/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java
+++ b/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java
@@ -19,6 +19,9 @@
import static android.content.Intent.ACTION_USER_SWITCHED;
import static android.location.LocationManager.GPS_PROVIDER;
import static android.location.LocationManager.NETWORK_PROVIDER;
+import static android.location.LocationRequest.QUALITY_LOW_POWER;
+
+import static com.android.location.provider.ProviderRequestUnbundled.INTERVAL_DISABLED;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
@@ -35,7 +38,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.location.ProviderRequest;
import com.android.location.provider.LocationProviderBase;
-import com.android.location.provider.LocationRequestUnbundled;
import com.android.location.provider.ProviderPropertiesUnbundled;
import com.android.location.provider.ProviderRequestUnbundled;
@@ -147,8 +149,8 @@
mRequest = new ProviderRequestUnbundled(ProviderRequest.EMPTY_REQUEST);
mWorkSource = new WorkSource();
- mGpsInterval = Long.MAX_VALUE;
- mNetworkInterval = Long.MAX_VALUE;
+ mGpsInterval = INTERVAL_DISABLED;
+ mNetworkInterval = INTERVAL_DISABLED;
}
void start() {
@@ -175,30 +177,9 @@
@GuardedBy("mLock")
private void updateRequirementsLocked() {
- long gpsInterval = Long.MAX_VALUE;
- long networkInterval = Long.MAX_VALUE;
- if (mRequest.getReportLocation()) {
- for (LocationRequestUnbundled request : mRequest.getLocationRequests()) {
- switch (request.getQuality()) {
- case LocationRequestUnbundled.ACCURACY_FINE:
- case LocationRequestUnbundled.ACCURACY_BLOCK:
- case LocationRequestUnbundled.POWER_HIGH:
- if (request.getInterval() < gpsInterval) {
- gpsInterval = request.getInterval();
- }
- if (request.getInterval() < networkInterval) {
- networkInterval = request.getInterval();
- }
- break;
- case LocationRequestUnbundled.ACCURACY_CITY:
- case LocationRequestUnbundled.POWER_LOW:
- if (request.getInterval() < networkInterval) {
- networkInterval = request.getInterval();
- }
- break;
- }
- }
- }
+ long gpsInterval = mRequest.getQuality() < QUALITY_LOW_POWER ? mRequest.getInterval()
+ : INTERVAL_DISABLED;
+ long networkInterval = mRequest.getInterval();
if (gpsInterval != mGpsInterval) {
resetProviderRequestLocked(GPS_PROVIDER, mGpsInterval, gpsInterval, mGpsListener);
@@ -214,11 +195,12 @@
@GuardedBy("mLock")
private void resetProviderRequestLocked(String provider, long oldInterval, long newInterval,
LocationListener listener) {
- if (oldInterval != Long.MAX_VALUE) {
+ if (oldInterval != INTERVAL_DISABLED && newInterval == INTERVAL_DISABLED) {
mLocationManager.removeUpdates(listener);
}
- if (newInterval != Long.MAX_VALUE) {
+ if (newInterval != INTERVAL_DISABLED) {
LocationRequest request = new LocationRequest.Builder(newInterval)
+ .setQuality(mRequest.getQuality())
.setLocationSettingsIgnored(mRequest.isLocationSettingsIgnored())
.setWorkSource(mWorkSource)
.build();
@@ -254,10 +236,10 @@
void dump(PrintWriter writer) {
synchronized (mLock) {
writer.println("request: " + mRequest);
- if (mGpsInterval != Long.MAX_VALUE) {
+ if (mGpsInterval != INTERVAL_DISABLED) {
writer.println(" gps interval: " + mGpsInterval);
}
- if (mNetworkInterval != Long.MAX_VALUE) {
+ if (mNetworkInterval != INTERVAL_DISABLED) {
writer.println(" network interval: " + mNetworkInterval);
}
if (mGpsLocation != null) {
diff --git a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
index d3aa977..61349d9 100644
--- a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
+++ b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
@@ -48,7 +48,6 @@
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
-import java.util.Collections;
import java.util.Random;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -60,7 +59,6 @@
private static final long TIMEOUT_MS = 5000;
- private Context mContext;
private Random mRandom;
private LocationManager mLocationManager;
@@ -72,15 +70,15 @@
long seed = System.currentTimeMillis();
Log.i(TAG, "location seed: " + seed);
- mContext = InstrumentationRegistry.getTargetContext();
+ Context context = InstrumentationRegistry.getTargetContext();
mRandom = new Random(seed);
- mLocationManager = mContext.getSystemService(LocationManager.class);
+ mLocationManager = context.getSystemService(LocationManager.class);
setMockLocation(true);
mManager = new LocationProviderManagerCapture();
mProvider = ILocationProvider.Stub.asInterface(
- new FusedLocationProvider(mContext).getBinder());
+ new FusedLocationProvider(context).getBinder());
mProvider.setLocationProviderManager(mManager);
mLocationManager.addTestProvider(NETWORK_PROVIDER,
@@ -118,12 +116,9 @@
@Test
public void testNetworkRequest() throws Exception {
- LocationRequest request = new LocationRequest.Builder(1000).build();
-
mProvider.setRequest(
new ProviderRequest.Builder()
.setIntervalMillis(1000)
- .setLocationRequests(Collections.singletonList(request))
.build(),
new WorkSource());
@@ -135,14 +130,10 @@
@Test
public void testGpsRequest() throws Exception {
- LocationRequest request = new LocationRequest.Builder(1000)
- .setQuality(LocationRequest.POWER_HIGH)
- .build();
-
mProvider.setRequest(
new ProviderRequest.Builder()
+ .setQuality(LocationRequest.QUALITY_HIGH_ACCURACY)
.setIntervalMillis(1000)
- .setLocationRequests(Collections.singletonList(request))
.build(),
new WorkSource());
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
index 8e140ca..83974af 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
@@ -254,7 +254,7 @@
mLocationManager.requestLocationUpdates(
LocationManager.FUSED_PROVIDER,
new LocationRequest.Builder(LOCATION_UPDATE_MS)
- .setQuality(LocationRequest.POWER_LOW)
+ .setQuality(LocationRequest.QUALITY_LOW_POWER)
.build(),
new HandlerExecutor(new Handler(Looper.getMainLooper())),
this);
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 2f97f27..e2b04d4 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Voordat jy \'n beperkte profiel kan skep, moet jy \'n skermslot opstel om jou programme en persoonlike data te beskerm."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Stel slot op"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Skakel oor na <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Skep tans nuwe gebruiker …"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Bynaam"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Voeg gas by"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Verwyder gas"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gas"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Neem \'n foto"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Kies \'n prent"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Kies foto"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Toestelverstek"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Gedeaktiveer"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Geaktiveer"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index f0d8a40..0e3684e 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"የተገደበ መገለጫ መፍጠር ከመቻልዎ በፊት መተግበሪያዎችዎን እና የግል ውሂብዎን ለመጠበቅ ቁልፍ ማያ ገጽ ማዋቀር አለብዎት።"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"ቁልፍ አዘጋጅ"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"ወደ <xliff:g id="USER_NAME">%s</xliff:g> ቀይር"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"አዲስ ተጠቃሚ በመፍጠር ላይ…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"ቅጽል ስም"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"እንግዳን አክል"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"እንግዳን አስወግድ"</string>
<string name="guest_nickname" msgid="6332276931583337261">"እንግዳ"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"ፎቶ አንሳ"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"ምስል ይምረጡ"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"ፎቶ ይምረጡ"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"የመሣሪያ ነባሪ"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ተሰናክሏል"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ነቅቷል"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 323ba44..7ec46d2 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -549,19 +549,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"قبل أن تتمكن من إنشاء ملف شخصي مقيد، يلزمك إعداد تأمين للشاشة لحماية تطبيقاتك وبياناتك الشخصية."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"تعيين التأمين"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"التبديل إلى <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"جارٍ إنشاء مستخدم جديد…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"اللقب"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"إضافة ضيف"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"إزالة جلسة الضيف"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ضيف"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"التقاط صورة"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"اختيار صورة"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"اختيار صورة"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"الإعداد التلقائي للجهاز"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"غير مفعّل"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"مفعّل"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 7679c64..fe04094 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"আপুনি সীমিত প্ৰ\'ফাইল এটা সৃষ্টি কৰাৰ আগেয়ে, আপোনাৰ ব্যক্তিগত ডেটা আৰু এপবিলাকক সুৰক্ষিত কৰিবলৈ স্ক্ৰীণ লক এটা নিৰ্ধাৰণ কৰিব লাগিব।"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"লক ছেট কৰক"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>লৈ সলনি কৰক"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"নতুন ব্যৱহাৰকাৰী সৃষ্টি কৰি থকা হৈছে…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"উপনাম"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"অতিথি যোগ কৰক"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"অতিথি আঁতৰাওক"</string>
<string name="guest_nickname" msgid="6332276931583337261">"অতিথি"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"এখন ফট’ তোলক"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"এখন প্ৰতিচ্ছবি বাছনি কৰক"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"ফট’ বাছনি কৰক"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"ডিভাইচ ডিফ’ল্ট"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"অক্ষম কৰা আছে"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"সক্ষম কৰা আছে"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index d0bf0ed..bd10cfb 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Məhdudlaşdırılmış profil yaratmadan öncə, Siz tətbiqlərinizi və şəxsi datanızı qorumaq üçün ekran kilidi quraşdırmalısınız."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Kilid ayarlayın"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> adlı istifadəçiyə keçin"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Yeni istifadəçi yaradılır…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Ləqəb"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Qonaq əlavə edin"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Qonağı silin"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Qonaq"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Foto çəkin"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Şəkil seçin"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Foto seçin"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Cihaz defoltu"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Deaktiv"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiv"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 3beb9b8..0deb927 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -546,19 +546,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Da biste mogli da napravite ograničeni profil, treba da podesite zaključavanje ekrana da biste zaštitili aplikacije i lične podatke."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Podesi zaključavanje"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Pređi na korisnika <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Pravi se novi korisnik…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Nadimak"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Slikaj"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberi sliku"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Izaberite sliku"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Podrazumevano za uređaj"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Onemogućeno"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index af6da4e..9aad825 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -547,19 +547,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Перш чым вы зможаце стварыць профіль з абмежаваннямi, вам трэба наладзіць блакiроўку экрана для абароны сваiх дадаткаў і асабістай інфармацыі."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Усталёўка блакiроўкi"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Пераключыцца на карыстальніка <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Ствараецца новы карыстальнік…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Псеўданім"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Дадаць госця"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Выдаліць госця"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Госць"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Зрабіць фота"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Выбраць відарыс"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Выбраць фота"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Стандартная прылада"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Выключана"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Уключана"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 0097c9c..8bf13fe 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Преди да можете да създадете потребителски профил с ограничена функционалност, трябва да настроите заключения екран, за да защитите приложенията и личните си данни."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Задаване на заключване"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Превключване към <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Създава се нов потребител…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Псевдоним"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Добавяне на гост"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Премахване на госта"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гост"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Правене на снимка"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Избиране на изображение"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Избиране на снимката"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Стандартна настройка за у-вото"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Деактивирано"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Активирано"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index c351542..8bcf9a6 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"আপনি একটি সীমাবদ্ধযুক্ত প্রোফাইল তৈরি করার আগে, আপনাকে আপনার অ্যাপ্লিকেশন এবং ব্যক্তিগত ডেটা সুরক্ষিত করার জন্য একটি স্ক্রিন লক সেট-আপ করতে হবে।"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"লক সেট করুন"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>-এ পাল্টান"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"নতুন ব্যবহারকারী তৈরি করা হচ্ছে…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"বিশেষ নাম"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"অতিথি যোগ করুন"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"অতিথি সরান"</string>
<string name="guest_nickname" msgid="6332276931583337261">"অতিথি"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"ফটো তুলুন"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"একটি ইমেজ বেছে নিন"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"ফটো বেছে নিন"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"ডিভাইসের ডিফল্ট"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"বন্ধ করা আছে"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"চালু করা আছে"</string>
diff --git a/packages/SettingsLib/res/values-bs/arrays.xml b/packages/SettingsLib/res/values-bs/arrays.xml
index 775cd15..6d2f1f3 100644
--- a/packages/SettingsLib/res/values-bs/arrays.xml
+++ b/packages/SettingsLib/res/values-bs/arrays.xml
@@ -27,7 +27,7 @@
<item msgid="8356618438494652335">"Autentifikacija…"</item>
<item msgid="2837871868181677206">"Dobivanje IP adrese…"</item>
<item msgid="4613015005934755724">"Povezano"</item>
- <item msgid="3763530049995655072">"Suspendirano"</item>
+ <item msgid="3763530049995655072">"Obustavljeno"</item>
<item msgid="7852381437933824454">"Prekidanje veze…"</item>
<item msgid="5046795712175415059">"Isključen"</item>
<item msgid="2473654476624070462">"Neuspješno"</item>
@@ -41,7 +41,7 @@
<item msgid="3028983857109369308">"Autentifikacija s mrežom <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
<item msgid="4287401332778341890">"Dobivanje IP adrese iz mreže <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
<item msgid="1043944043827424501">"Povezano s mrežom <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
- <item msgid="7445993821842009653">"Suspendirano"</item>
+ <item msgid="7445993821842009653">"Obustavljeno"</item>
<item msgid="1175040558087735707">"Prekidanje veze s mrežom <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
<item msgid="699832486578171722">"Isključen"</item>
<item msgid="522383512264986901">"Neuspješno"</item>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 3d358730..32f6aa7 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -546,19 +546,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Prije nego vam se omogući kreiranje ograničenog profila, morate postaviti zaključavanje ekrana da biste zaštitili svoje aplikacije i lične podatke."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Postaviti zaključavanje"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Prebaci na korisnika <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Kreiranje novog korisnika…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Nadimak"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Snimite fotografiju"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberite sliku"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Odabir fotografije"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Zadana postavka uređaja"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Onemogućeno"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index b1edd78..525a187 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Per crear un perfil restringit, has de configurar una pantalla de bloqueig per protegir les aplicacions i les dades personals."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Defineix un bloqueig"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Canvia a <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"S\'està creant l\'usuari…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Àlies"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Afegeix un convidat"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Suprimeix el convidat"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidat"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Fes una foto"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Tria una imatge"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Selecciona una foto"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Opció predeter. del dispositiu"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desactivat"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activat"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index bdce444c..64ad700 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -547,19 +547,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Před vytvořením omezeného profilu je nutné nejprve nastavit zámek obrazovky k ochraně aplikací a dat."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Nastavit zámek"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Přepnout na uživatele <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Vytváření nového uživatele…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Přezdívka"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Přidat hosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Odstranit hosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Host"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Pořídit fotku"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Vybrat obrázek"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Vybrat fotku"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Výchozí nastavení zařízení"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Vypnuto"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Zapnuto"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 1dc0e4e..433368b 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Før du kan oprette en begrænset profil, skal du oprette en skærmlås for at beskytte dine apps og personlige data."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Konfigurer låseskærmen"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Skift til <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Opretter ny bruger…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Kaldenavn"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Tilføj gæsten"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Fjern gæsten"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gæst"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Tag et billede"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Vælg et billede"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Vælg billede"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Enhedens standardindstilling"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Deaktiveret"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiveret"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index a9cdf1f..9946eed 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Vor dem Erstellen eines eingeschränkten Profils musst du eine Displaysperre einrichten, um deine Apps und personenbezogenen Daten zu schützen."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Sperre einrichten"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Zu <xliff:g id="USER_NAME">%s</xliff:g> wechseln"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Neuer Nutzer wird erstellt…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Alias"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Gast hinzufügen"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Gast entfernen"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gast"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Foto machen"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Bild auswählen"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Foto auswählen"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Gerätestandard"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Deaktiviert"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiviert"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 00b8434..c265dbc 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Προκειμένου να μπορέσετε να δημιουργήσετε ένα περιορισμένο προφίλ, θα πρέπει να δημιουργήσετε ένα κλείδωμα οθόνης για την προστασία των εφαρμογών και των προσωπικών δεδομένων σας."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Ορισμός κλειδώματος"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Εναλλαγή σε <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Δημιουργία νέου χρήστη…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Ψευδώνυμο"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Προσθήκη επισκέπτη"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Κατάργηση επισκέπτη"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Επισκέπτης"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Λήψη φωτογραφίας"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Επιλογή εικόνας"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Επιλογή φωτογραφίας"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Προεπιλογή συσκευής"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Ανενεργή"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ενεργή"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 4bb2d8a..285c615 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Before you can create a restricted profile, you\'ll need to set up a screen lock to protect your apps and personal data."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Set lock"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Switch to <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creating new user…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Take a photo"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Choose an image"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Select photo"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Device default"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 05c12d6..bbd5c76 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Before you can create a restricted profile, you\'ll need to set up a screen lock to protect your apps and personal data."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Set lock"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Switch to <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creating new user…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Take a photo"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Choose an image"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Select photo"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Device default"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 4bb2d8a..285c615 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Before you can create a restricted profile, you\'ll need to set up a screen lock to protect your apps and personal data."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Set lock"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Switch to <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creating new user…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Take a photo"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Choose an image"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Select photo"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Device default"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 4bb2d8a..285c615 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Before you can create a restricted profile, you\'ll need to set up a screen lock to protect your apps and personal data."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Set lock"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Switch to <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creating new user…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Take a photo"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Choose an image"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Select photo"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Device default"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 1dc5f5b..ab421f6 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Para poder crear un perfil restringido, debes configurar un bloqueo de pantalla que proteja tus aplicaciones y datos personales."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Configurar bloqueo"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Cambiar a <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creando usuario nuevo…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Sobrenombre"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Agregar invitado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Quitar invitado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invitado"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Tomar una foto"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Elegir una imagen"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Seleccionar foto"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Predeterminado del dispositivo"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Inhabilitado"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Habilitado"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 977b469..f6157b4 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Para poder crear un perfil restringido, debes configurar una pantalla de bloqueo que proteja tus aplicaciones y datos personales."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Establecer bloqueo"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Cambiar a <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creando usuario…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Apodo"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Añadir invitado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Quitar invitado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invitado"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Hacer foto"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Seleccionar una imagen"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Seleccionar foto"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Predeterminado por el dispositivo"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Inhabilitado"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Habilitado"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 3c2593a..72766c0 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Enne piiratud profiili loomist peate seadistama lukustusekraani, et oma rakendusi ja isiklikke andmeid kaitsta."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Määra lukk"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Lülita kasutajale <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Uue kasutaja loomine …"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Hüüdnimi"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Lisa külaline"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Eemalda külaline"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Külaline"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Pildistage"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Valige pilt"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Valige foto"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Seadme vaikeseade"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Keelatud"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Lubatud"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 33ce3c7..c7462ce 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Profil murriztua sortu aurretik, aplikazioak eta datu pertsonalak babesteko, pantaila blokeatzeko metodo bat konfiguratu beharko duzu."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Ezarri blokeoa"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Aldatu <xliff:g id="USER_NAME">%s</xliff:g> erabiltzailera"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Beste erabiltzaile bat sortzen…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Goitizena"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Gehitu gonbidatua"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Kendu gonbidatua"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gonbidatua"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Atera argazki bat"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Aukeratu irudi bat"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Hautatu argazki bat"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Gailuaren balio lehenetsia"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desgaituta"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Gaituta"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 0453788..c5a4f2f 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"قبل از ایجاد یک نمایه محدود، باید یک قفل صفحه را برای محافظت از برنامهها و دادههای شخصی خود تنظیم کنید."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"تنظیم قفل"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"رفتن به <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"درحال ایجاد کاربر جدید…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"نام مستعار"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"افزودن مهمان"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"حذف مهمان"</string>
<string name="guest_nickname" msgid="6332276931583337261">"مهمان"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"عکس گرفتن"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"انتخاب تصویر"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"انتخاب عکس"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"پیشفرض دستگاه"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"غیرفعال"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"فعال"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 7f85572..dd1c12a 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Ennen kuin voit luoda rajoitetun profiilin, määritä näytön lukitus, joka suojelee sovelluksiasi ja henkilökohtaisia tietojasi."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Aseta lukitus"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Vaihda tähän käyttäjään: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Luodaan uutta käyttäjää…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Lempinimi"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Lisää vieras"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Poista vieras"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Vieras"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Ota valokuva"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Valitse kuva"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Valitse valokuva"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Laitteen oletusasetus"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Ei käytössä"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Käytössä"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 1745e02..f0364c6 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Avant de créer un profil limité, vous devez définir un écran de verrouillage pour protéger vos applications et vos données personnelles."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Définir verrouillage écran"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Passer à <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Créer un utilisateur…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Pseudo"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Ajouter un invité"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Supprimer l\'invité"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invité"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Prendre une photo"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Sélectionner une image"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Sélectionnez une photo"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Valeur par défaut de l\'appareil"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Désactivé"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activé"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 8c753ae..17d13c1 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Avant de créer un profil limité, vous devez définir un écran de verrouillage pour protéger vos applications et vos données personnelles."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Définir verrouillage écran"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Passer à <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Création d\'un nouvel utilisateur…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Pseudo"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Ajouter un invité"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Supprimer l\'invité"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invité"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Prendre une photo"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Choisir une image"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Sélectionner une photo"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Paramètre par défaut"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Désactivé"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activé"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 414564b..e0b21c3 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Para poder crear un perfil restrinxido, precisarás configurar un bloqueo da pantalla para protexer as túas aplicacións e datos persoais."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Establecer bloqueo"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Cambiar a <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creando usuario novo…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Alcume"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Engadir convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Quitar convidado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Tirar foto"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Escoller imaxe"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Seleccionar foto"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Funcionamento predeterminado"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desactivado"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activado"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 634870c..08a2b99 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"તમે પ્રતિબંધિત પ્રોફાઇલ બનાવી શકો તે પહેલાં, તમારે તમારી ઍપ્લિકેશનો અને વ્યક્તિગત ડેટાની સુરક્ષા માટે એક લૉક સ્ક્રીન સેટ કરવાની જરૂર પડશે."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"લૉક સેટ કરો"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> પર સ્વિચ કરો"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"નવા વપરાશકર્તા બનાવી રહ્યાં છીએ…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"ઉપનામ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"અતિથિ ઉમેરો"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"અતિથિને કાઢી નાખો"</string>
<string name="guest_nickname" msgid="6332276931583337261">"અતિથિ"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"ફોટો લો"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"છબી પસંદ કરો"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"ફોટો પસંદ કરો"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"ડિવાઇસ ડિફૉલ્ટ"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"બંધ છે"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ચાલુ છે"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index bd052c0..8486e34 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"इससे पहले कि आप कोई प्रतिबंधित प्रोफ़ाइल बनाएं, आपको अपने ऐप्लिकेशन और व्यक्तिगत डेटा की सुरक्षा करने के लिए एक स्क्रीन लॉक सेट करना होगा."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"लॉक सेट करें"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> पर जाएं"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"नया उपयोगकर्ता बनाया जा रहा है…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"प्रचलित नाम"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"मेहमान जोड़ें"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"मेहमान हटाएं"</string>
<string name="guest_nickname" msgid="6332276931583337261">"मेहमान"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"फ़ोटो खींचें"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"कोई इमेज चुनें"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"फ़ोटो चुनें"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"डिवाइस की डिफ़ॉल्ट सेटिंग"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"बंद है"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"चालू है"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 3cff480..a4ef323 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -546,19 +546,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Prije izrade ograničenog profila trebate postaviti zaključavanje zaslona radi zaštite svojih aplikacija i osobnih podataka."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Postavi zaključavanje"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Prelazak na korisnika <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Izrada novog korisnika…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Nadimak"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodavanje gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Uklanjanje gosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Fotografiraj"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberi sliku"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Odabir slike"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Zadana postavka uređaja"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Onemogućeno"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 854265c..480552b 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Mielőtt létrehozhatna egy korlátozott profilt, be kell állítania egy képernyőzárat, hogy megvédje alkalmazásait és személyes adatait."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Képernyőzár beállítása"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Váltás erre: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Új felhasználó létrehozása…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Becenév"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Vendég hozzáadása"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Vendég munkamenet eltávolítása"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Vendég"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Fotó készítése"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Kép kiválasztása"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Fotó kiválasztása"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Alapértelmezett"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Letiltva"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Engedélyezve"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 35b218e..9fbf998 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Նախքան դուք կկարողանաք ստեղծել սահմանափակ պրոֆիլ, դուք պետք է կարգավորեք էկրանի կողպումը` ձեր ծրագրերը և անձնական տվյալները պաշտպանելու համար:"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Կարգավորել կողպումը"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Անցնել <xliff:g id="USER_NAME">%s</xliff:g> պրոֆիլին"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Ստեղծվում է օգտատիրոջ նոր պրոֆիլ…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Կեղծանուն"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Ավելացնել հյուր"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Հեռացնել հյուրին"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Հյուր"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Լուսանկարել"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Ընտրել պատկեր"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Ընտրեք լուսանկար"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Կանխադրված տարբերակ"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Անջատված է"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Միացված է"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index cf6455f..b1391ec 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Sebelum dapat membuat profil yang dibatasi, Anda perlu menyiapkan kunci layar untuk melindungi aplikasi dan data pribadi Anda."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Setel kunci"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Beralih ke <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Membuat pengguna baru …"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Nama panggilan"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Tambahkan tamu"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Hapus tamu"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Tamu"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Ambil foto"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Pilih gambar"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Pilih foto"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Default perangkat"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Nonaktif"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktif"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index b4be963..1636c55 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Áður en þú getur búið til takmarkað snið þarftu að setja upp skjálás til að vernda forritin þín og persónuleg gögn."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Velja lás"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Skipta yfir í <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Stofnar nýjan notanda…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Gælunafn"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Bæta gesti við"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Fjarlægja gest"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gestur"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Taka mynd"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Velja mynd"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Velja mynd"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Sjálfgefin stilling tækis"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Slökkt"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Virkt"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 69b1b5e..b358d65 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Prima di poter creare un profilo con limitazioni, devi impostare un blocco schermo per proteggere le tue app e i tuoi dati personali."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Imposta blocco"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Passa a <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creazione nuovo utente…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Aggiungi ospite"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Rimuovi ospite"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Ospite"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Scatta una foto"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Scegli un\'immagine"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Seleziona la foto"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Parametro predefinito"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Non attivo"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Attivo"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 158872d..0f2eb4b 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -547,19 +547,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"לפני שתוכל ליצור פרופיל מוגבל, תצטרך להגדיר נעילת מסך כדי להגן על האפליקציות ועל הנתונים האישיים שלך."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"הגדרת נעילה"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"מעבר אל <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"בתהליך יצירה של משתמש חדש…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"כינוי"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"הוספת אורח"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"הסרת אורח"</string>
<string name="guest_nickname" msgid="6332276931583337261">"אורח"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"צילום תמונה"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"לבחירת תמונה"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"בחירת תמונה"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"ברירת המחדל של המכשיר"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"מושבת"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"מופעל"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 13fd53f..dba1c95 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"制限付きプロファイルを作成する場合は、アプリや個人データを保護するように画面ロックを設定しておく必要があります。"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"ロックを設定"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> に切り替え"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"新しいユーザーを作成しています…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"ニックネーム"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ゲストを追加"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ゲストを削除"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ゲスト"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"写真を撮る"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"画像を選択"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"写真を選択"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"デバイスのデフォルト"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"無効"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"有効"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index f411d00..ffb5c9a 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Шектелген профайл жасақтауға дейін қолданбалар мен жеке деректерді қорғау үшін экран бекітпесін тағайындау қажет."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Бекітпе тағайындау"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> пайдаланушысына ауысу"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Жаңа пайдаланушы профилі жасалуда…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Лақап ат"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Қонақты енгізу"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Қонақты өшіру"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Қонақ"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Фотосуретке түсіру"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Сурет таңдау"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Фотосурет таңдау"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Құрылғыны әдепкісінше реттеу"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Өшірулі"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Қосулы"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 9b7cc4c..6fbd2d1 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"មុនពេលអ្នកអាចបង្កើតប្រវត្តិរូបបានដាក់កម្រិត អ្នកត្រូវរៀបចំការចាក់សោអេក្រង់ ដើម្បីការពារកម្មវិធី និងទិន្នន័យផ្ទាល់ខ្លួនរបស់អ្នក។"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"កំណត់ការចាក់សោ"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"ប្ដូរទៅ <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"កំពុងបង្កើតអ្នកប្រើប្រាស់ថ្មី…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"ឈ្មោះហៅក្រៅ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"បញ្ចូលភ្ញៀវ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"លុបភ្ញៀវ"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ភ្ញៀវ"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"ថតរូប"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"ជ្រើសរើសរូបភាព"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"ជ្រើសរើសរូបថត"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"លំនាំដើមរបស់ឧបករណ៍"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"បានបិទ"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"បានបើក"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 1f74d9b6..653d8ba 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"ನೀವು ನಿರ್ಬಂಧಿತ ಪ್ರೊಫೈಲ್ ಅನ್ನು ರಚಿಸಬಹುದಾದರ ಮೊದಲು, ನಿಮ್ಮ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ವೈಯಕ್ತಿಕ ಡೇಟಾವನ್ನು ರಕ್ಷಿಸಲು ನೀವು ಪರದೆಯ ಲಾಕ್ ಹೊಂದಿಸುವ ಅಗತ್ಯವಿದೆ."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"ಲಾಕ್ ಹೊಂದಿಸಿ"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> ಗೆ ಬದಲಿಸಿ"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲಾಗುತ್ತಿದೆ…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"ಅಡ್ಡ ಹೆಸರು"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ಅತಿಥಿಯನ್ನು ಸೇರಿಸಿ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ಅತಿಥಿಯನ್ನು ತೆಗೆದುಹಾಕಿ"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ಅತಿಥಿ"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"ಫೋಟೋ ತೆಗೆದುಕೊಳ್ಳಿ"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"ಚಿತ್ರವನ್ನು ಆರಿಸಿ"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"ಫೋಟೋ ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"ಸಾಧನದ ಡೀಫಾಲ್ಟ್"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index d130834..761f813 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"제한된 프로필을 만들기 전에 화면 잠금을 설정하여 앱과 개인 데이터를 보호해야 합니다."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"잠금 설정"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>(으)로 전환"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"새로운 사용자를 만드는 중…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"닉네임"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"게스트 추가"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"게스트 삭제"</string>
<string name="guest_nickname" msgid="6332276931583337261">"게스트"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"사진 찍기"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"이미지 선택"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"사진 선택"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"기기 기본값"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"사용 중지됨"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"사용 설정됨"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 5672913..c72b93f 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Чектелген профайл түзөөрдөн мурун, сиз өзүңүздүн колдонмолоруңузду жана жеке маалыматтарыңызды коргош үчүн, бөгөттөө көшөгөсүн орнотушуңуз керек болот."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Бөгөт коюу"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> аккаунтуна которулуу"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Жаңы колдонуучу түзүлүүдө…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Ылакап аты"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Конок кошуу"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Конокту өчүрүү"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Конок"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Сүрөткө тартуу"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Сүрөт тандаңыз"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Сүрөт тандаңыз"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Түзмөктүн демейки параметри"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Өчүк"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Күйүк"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index b3b3c81..7883308 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"ກ່ອນທ່ານຈະສ້າງໂປຣໄຟລ໌ທີ່ຖືກຈຳກັດນັ້ນ, ທ່ານຈະຕ້ອງຕັ້ງຄ່າການລັອກໜ້າຈໍ ເພື່ອປ້ອງກັນແອັບຯ ແລະຂໍ້ມູນສ່ວນໂຕຂອງທ່ານກ່ອນ."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"ຕັ້ງການລັອກ"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"ສະຫຼັບໄປ <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"ກຳລັງສ້າງຜູ້ໃຊ້ໃໝ່…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"ຊື່ຫຼິ້ນ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ເພີ່ມແຂກ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ລຶບແຂກອອກ"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ແຂກ"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"ຖ່າຍຮູບ"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"ເລືອກຮູບ"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"ເລືອກຮູບ"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"ຄ່າເລີ່ມຕົ້ນອຸປະກອນ"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ປິດການນຳໃຊ້ແລ້ວ"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ເປີດການນຳໃຊ້ແລ້ວ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 2e5385e..e3aa368 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -547,19 +547,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Prieš kuriant apribotą profilį reikės nustatyti ekrano užraktą, kad apsaugotumėte programas ir asmeninius duomenis."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Nustatyti užraktą"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Perjungti į <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Kuriamas naujas naudotojas…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Slapyvardis"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Pridėti svečią"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Pašalinti svečią"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Svečias"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Fotografuoti"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Pasirinkti vaizdą"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Pasirinkti nuotrauką"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Numatyt. įrenginio nustatymas"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Išjungta"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Įgalinta"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index f4fe8e3..e994974 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -546,19 +546,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Lai varētu izveidot ierobežotu profilu, jums jāiestata ekrāna bloķēšana, kas aizsargās jūsu lietotni un personas datus."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Iestatīt bloķēšanu"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Pārslēgties uz: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Notiek jauna lietotāja izveide…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Segvārds"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Pievienot viesi"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Noņemt viesi"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Viesis"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Uzņemt fotoattēlu"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Izvēlēties attēlu"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Atlasīt fotoattēlu"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Ierīces noklusējums"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Atspējots"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Iespējots"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 1e933fb..e711747 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Пред да може да создадете ограничен профил, треба да поставите заклучување на екранот за да ги заштити вашите апликации и лични податоци."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Постави заклучување"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Префрли на <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Се создава нов корисник…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Прекар"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Додај гостин"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Отстрани гостин"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гостин"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Фотографирајте"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Одберете слика"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Изберете фотографија"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Стандардно за уредот"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Оневозможено"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Овозможено"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 970f778..cebd552 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"ഒരു നിയന്ത്രിത പ്രൊഫൈൽ സൃഷ്ടിക്കുന്നതിനുമുമ്പ്, നിങ്ങളുടെ അപ്ലിക്കേഷനുകളും വ്യക്തിഗത ഡാറ്റയും പരിരക്ഷിക്കുന്നതിന് ഒരു സ്ക്രീൻ ലോക്ക് സജ്ജീകരിക്കേണ്ടതുണ്ട്."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"ലോക്ക് സജ്ജീകരിക്കുക"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> എന്നതിലേക്ക് മാറുക"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"പുതിയ ഉപയോക്താവിനെ സൃഷ്ടിക്കുന്നു…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"വിളിപ്പേര്"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"അതിഥിയെ ചേർക്കുക"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"അതിഥിയെ നീക്കം ചെയ്യുക"</string>
<string name="guest_nickname" msgid="6332276931583337261">"അതിഥി"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"ഒരു ഫോട്ടോ എടുക്കുക"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"ഒരു ചിത്രം തിരഞ്ഞെടുക്കുക"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"ഫോട്ടോ തിരഞ്ഞെടുക്കുക"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"ഉപകരണത്തിന്റെ ഡിഫോൾട്ട് പ്രവർത്തനം"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"പ്രവർത്തനരഹിതമാക്കി"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"പ്രവർത്തനക്ഷമമാക്കി"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 3dc4989..8074366 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Та хязгаарлагдсан профайл үүсгэхийн өмнө өөрийн апп-ууд болон хувийн өгөгдлийг хамгаалахын тулд дэлгэцийн түгжээг тохируулах шаардлагатай."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Түгжээг тохируулах"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> руу сэлгэх"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Шинэ хэрэглэгч үүсгэж байна…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Хоч"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Зочин нэмэх"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Зочин хасах"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Зочин"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Зураг авах"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Зураг сонгох"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Зураг сонгох"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Төхөөрөмжийн өгөгдмөл"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Идэвхгүй болгосон"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Идэвхжүүлсэн"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 7e418a4..fbfe84c 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"तुम्ही एक प्रतिबंधित प्रोफाईल तयार करु शकण्यापूर्वी तुम्हाला तुमचे अॅप्स आणि वैयक्तिक डेटा संरक्षित करण्यासाठी एक स्क्रीन लॉक सेट करण्याची आवश्यकता राहील."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"लॉक सेट करा"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> वर स्विच करा"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"नवीन वापरकर्ता तयार करत आहे…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"टोपणनाव"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"अतिथी जोडा"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"अतिथी काढून टाका"</string>
<string name="guest_nickname" msgid="6332276931583337261">"अतिथी"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"फोटो काढा"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"इमेज निवडा"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"फोटो निवडा"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"डिव्हाइस डीफॉल्ट"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"बंद केले आहे"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"सुरू केले आहे"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 4c23a84..d988dd0 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Sebelum anda boleh membuat profil yang terhad, anda perlu menyediakan kunci skrin untuk melindungi apl dan data peribadi anda."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Tetapkan kunci"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Tukar kepada <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Mencipta pengguna baharu…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Nama panggilan"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Tambah tetamu"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Alih keluar tetamu"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Tetamu"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Ambil foto"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Pilih imej"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Pilih foto"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Lalai peranti"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Dilumpuhkan"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Didayakan"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index aa3cf08..5a16743 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"ကန့်သတ်ကိုယ်ရေးအချက်အလက်တစ်ခုကို မပြုလုပ်မီ သင်၏ အပလီကေးရှင်းများနှင့် ကိုယ်ပိုင်အချက်အလက်များကို ကာကွယ်ရန် မျက်နှာပြင်သော့ချခြင်းကို စီမံရန် လိုအပ်လိမ့်မည်"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"သော့ချရန် သတ်မှတ်ပါ"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> သို့ ပြောင်းရန်"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"အသုံးပြုသူအသစ် ပြုလုပ်နေသည်…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"နာမည်ပြောင်"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ဧည့်သည့် ထည့်ရန်"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ဧည့်သည်ကို ဖယ်ထုတ်ရန်"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ဧည့်သည်"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"ဓာတ်ပုံရိုက်ရန်"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"ပုံရွေးရန်"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"ဓာတ်ပုံရွေးရန်"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"စက်ပစ္စည်းမူရင်း"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ပိတ်ထားသည်"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ဖွင့်ထားသည်"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 0c5431b..df96ea6 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Før du kan opprette en begrenset profil, må du konfigurere skjermlåsen for å beskytte appene og de personlige dataene dine."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Angi lås"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Bytt til <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Oppretter en ny bruker …"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Kallenavn"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Legg til en gjest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Fjern gjesten"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gjest"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Ta et bilde"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Velg et bilde"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Velg et bilde"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Standard for enheten"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Slått av"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Slått på"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 4c230d3..54adb3a 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"निषेधयुक्त प्रोफाइल बनाउनु अघि तपाईँको एप र व्यक्तिगत डेटा सुरक्षा गर्नाका लागि तपाईँले स्क्रिन लक सेटअप गर्नु पर्दछ ।"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"लक सेट गर्नुहोस्"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"प्रयोगकर्ता बदलेर <xliff:g id="USER_NAME">%s</xliff:g> पार्नुहोस्"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"नयाँ प्रयोगकर्ता बनाउँदै…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"उपनाम"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"अतिथि थप्नुहोस्"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"अतिथि हटाउनुहोस्"</string>
<string name="guest_nickname" msgid="6332276931583337261">"अतिथि"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"फोटो खिच्नुहोस्"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"कुनै फोटो छनौट गर्नुहोस्"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"फोटो चयन गर्नुहोस्"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"पूर्वनिर्धारित यन्त्र"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"असक्षम पारिएको छ"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"सक्षम पारिएको छ"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index ae734a5..729d57b 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Voordat je een beperkt profiel kunt maken, moet je een schermvergrendeling instellen om je apps en persoonsgegevens te beschermen."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Vergrendeling instellen"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Overschakelen naar <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Nieuwe gebruiker maken…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Bijnaam"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Gast toevoegen"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Gast verwijderen"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gast"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Foto maken"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Afbeelding kiezen"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Foto selecteren"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Apparaatstandaard"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Uitgeschakeld"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ingeschakeld"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 18a88fa..1ce7d56e 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"ପ୍ରତିବନ୍ଧିତ ପ୍ରୋଫାଇଲ୍ ତିଆରି କରିବାବେଳେ, ନିଜ ଆପ୍ ଓ ବ୍ୟକ୍ତିଗତ ତଥ୍ୟର ସୁରକ୍ଷା ପାଇଁ ଏକ ସ୍କ୍ରୀନ୍ ଲକ୍ ସେଟ୍ କରନ୍ତୁ।"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"ଲକ୍ ସେଟ୍ କରନ୍ତୁ"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>କୁ ସ୍ୱିଚ୍ କରନ୍ତୁ"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"ନୂଆ ଉପଯୋଗକର୍ତ୍ତା ତିଆରି କରାଯାଉଛି…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"ଡାକନାମ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ଅତିଥି ଯୋଗ କରନ୍ତୁ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ଅତିଥିଙ୍କୁ କାଢ଼ି ଦିଅନ୍ତୁ"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ଅତିଥି"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"ଗୋଟିଏ ଫଟୋ ଉଠାନ୍ତୁ"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"ଏକ ଛବି ବାଛନ୍ତୁ"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"ଫଟୋ ବାଛନ୍ତୁ"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"ଡିଭାଇସ୍ ଡିଫଲ୍ଟ"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ଅକ୍ଷମ କରାଯାଇଛି"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ସକ୍ଷମ କରାଯାଇଛି"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index b1bde27..c122a28 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"ਇਸਤੋਂ ਪਹਿਲਾਂ ਕਿ ਤੁਸੀਂ ਇੱਕ ਪ੍ਰਤਿਬੰਧਿਤ ਪ੍ਰੋਫਾਈਲ ਬਣਾ ਸਕੋ, ਤੁਹਾਨੂੰ ਆਪਣੀਆਂ ਐਪਾਂ ਅਤੇ ਨਿੱਜੀ ਡਾਟਾ ਸੁਰੱਖਿਅਤ ਕਰਨ ਲਈ ਇੱਕ ਸਕ੍ਰੀਨ ਲਾਕ ਸੈੱਟ ਅੱਪ ਕਰਨ ਦੀ ਲੋੜ ਹੈ।"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">" ਲਾਕ ਸੈੱਟ ਕਰੋ"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> \'ਤੇ ਜਾਓ"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਬਣਾਇਆ ਜਾ ਰਿਹਾ ਹੈ…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"ਉਪਨਾਮ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ਮਹਿਮਾਨ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ਮਹਿਮਾਨ ਹਟਾਓ"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ਮਹਿਮਾਨ"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"ਇੱਕ ਫ਼ੋਟੋ ਖਿੱਚੋ"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"ਕੋਈ ਚਿੱਤਰ ਚੁਣੋ"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"ਫ਼ੋਟੋ ਚੁਣੋ"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"ਡੀਵਾਈਸ ਪੂਰਵ-ਨਿਰਧਾਰਤ"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ਬੰਦ ਕੀਤਾ ਗਿਆ"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ਚਾਲੂ ਕੀਤਾ ਗਿਆ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 7ea2d0c..112ae47 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -547,19 +547,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Zanim utworzysz profil z ograniczeniami, musisz skonfigurować ekran blokady, by chronić aplikacje i osobiste dane."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Ustaw blokadę"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Przełącz na: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Tworzę nowego użytkownika…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Pseudonim"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gościa"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Usuń gościa"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gość"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Zrób zdjęcie"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Wybierz obraz"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Wybierz zdjęcie"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Ustawienie domyślne urządzenia"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Wyłączono"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Włączono"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index de536b2..7354835 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Antes de poder criar um perfil restrito, tem de configurar um bloqueio de ecrã para proteger as suas aplicações e dados pessoais."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Definir bloqueio"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Mudar para <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"A criar novo utilizador…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Pseudónimo"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Tirar uma foto"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Escolher uma imagem"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Selecionar foto"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Predefinição do dispositivo"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desativada"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ativada"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 934ef64..32e70da 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -546,19 +546,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Înainte de a putea crea un profil cu permisiuni limitate, va trebui să configurați blocarea ecranului pentru a vă proteja aplicațiile și datele personale."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Configurați blocarea"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Treceți la <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Se creează un utilizator nou…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Pseudonim"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Adăugați un invitat"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ștergeți invitatul"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invitat"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Faceți o fotografie"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Alegeți o imagine"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Selectați fotografia"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Prestabilit pentru dispozitiv"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Dezactivat"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activat"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index e75ee7f..b04d93b 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -547,19 +547,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Чтобы создать профиль с ограниченным доступом, необходимо предварительно настроить блокировку экрана для защиты приложений и личных данных"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Включить блокировку"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Переключиться на этот аккаунт: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Создаем нового пользователя…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Псевдоним"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Добавить аккаунт гостя"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Удалить аккаунт гостя"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гость"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Сделать снимок"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Выбрать фото"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Выбрать фотографию"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Вариант по умолчанию"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Отключено"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Включено"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index dc9b702..86725c2 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"සීමිත පැතිකඩක් නිර්මාණය කිරීමට කලින්. ඔබගේ යෙදුම් සහ පෞද්ගලික දත්ත ආරක්ෂා කිරීමට තිර අගුලක් සැකසිය යුතුයි."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"අගුල සකසන්න"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> වෙත මාරු වන්න"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"නව පරිශීලක තනමින්…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"අපනාමය"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"අමුත්තා එක් කරන්න"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"අමුත්තා ඉවත් කරන්න"</string>
<string name="guest_nickname" msgid="6332276931583337261">"අමුත්තා"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"ඡායාරූපයක් ගන්න"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"රූපයක් තෝරන්න"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"ඡායාරූපය තෝරන්න"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"උපාංගයේ පෙරනිමිය"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"අබල කළා"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"සබලයි"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 203f253..91e9564 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -547,19 +547,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Pred vytvorením obmedzeného profilu je nutné najprv nastaviť zámku obrazovky na ochranu aplikácií a osobných údajov."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Nastaviť uzamknutie"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Prepnúť na používateľa <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Vytvára sa nový používateľ…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Prezývka"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Pridať hosťa"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Odobrať hosťa"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Hosť"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Odfotiť"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Vybrať obrázok"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Vybrať fotku"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Predvol. nastavenie zariadenia"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Vypnuté"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Zapnuté"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 3bfda06..45ffcde 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -547,19 +547,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Preden lahko ustvarite profil z omejitvami, morate nastaviti zaklepanje zaslona, da zaščitite aplikacije in osebne podatke."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Nastavi zaklepanje"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Preklop na račun <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Ustvarjanje novega uporabnika …"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Vzdevek"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodajanje gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Odstranitev gosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Fotografiranje"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Izberi sliko"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Izbira fotografije"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Privzeta nastavitev naprave"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Onemogočeno"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogočeno"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 859cc70..c398363 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Para se të mund të krijosh një profil të kufizuar, duhet të konfigurosh një kyçje të ekranit për të mbrojtur aplikacionet dhe të dhënat e tua personale."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Cakto kyçjen"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Kalo te <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Po krijohet një përdorues i ri…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Pseudonimi"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Shto të ftuar"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Hiq të ftuarin"</string>
<string name="guest_nickname" msgid="6332276931583337261">"I ftuar"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Bëj një fotografi"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Zgjidh një imazh"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Zgjidh një fotografi"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Parazgjedhja e pajisjes"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Joaktiv"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiv"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 6c02c3c..bb59bd1 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -546,19 +546,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Да бисте могли да направите ограничени профил, треба да подесите закључавање екрана да бисте заштитили апликације и личне податке."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Подеси закључавање"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Пређи на корисника <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Прави се нови корисник…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Надимак"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Додај госта"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Уклони госта"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гост"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Сликај"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Одабери слику"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Изаберите слику"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Подразумевано за уређај"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Онемогућено"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Омогућено"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index dc21675..e7b1482 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Innan du skapar en begränsad profil måste du konfigurera ett skärmlås för att skydda dina appar och personliga data."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Konfigurera lås"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Byt till <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Skapar ny användare …"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Smeknamn"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Lägg till gäst"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ta bort gäst"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gäst"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Ta ett foto"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Välj en bild"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Välj foto"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Enhetens standardinställning"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Inaktiverat"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiverat"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 8f80e55..1f0d167 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Kabla uunde wasifu uliowekekwa vikwazo, utahitajika kuweka skrini iliyofungwa ili kulinda programu zako na data binafsi."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Weka ufunguo"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Badili utumie <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Inaweka mtumiaji mpya…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Jina wakilishi"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Weka mgeni"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ondoa mgeni"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Mgeni"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Piga picha"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Chagua picha"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Chagua picha"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Hali chaguomsingi ya kifaa"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Imezimwa"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Imewashwa"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 1069421..b6d8be8 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"நீங்கள் வரையறுக்கப்பட்டச் சுயவிவரத்தை உருவாக்குவதற்கு முன்பு, உங்கள் ஆப்ஸ் மற்றும் தனிப்பட்ட தரவைப் பாதுகாக்கும் வகையில் நீங்கள் திரைப் பூட்டை அமைக்க வேண்டும்."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"பூட்டை அமை"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>க்கு மாறு"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"புதிய பயனரை உருவாக்குகிறது…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"புனைப்பெயர்"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"கெஸ்ட்டைச் சேர்"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"கெஸ்ட்டை அகற்று"</string>
<string name="guest_nickname" msgid="6332276931583337261">"கெஸ்ட்"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"படமெடுங்கள்"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"படத்தைத் தேர்வுசெய்யுங்கள்"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"படத்தைத் தேர்ந்தெடுங்கள்"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"சாதனத்தின் இயல்புநிலை"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"முடக்கப்பட்டது"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"இயக்கப்பட்டது"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 3ad2375..5a8e734 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"మీరు పరిమితం చేయబడిన ప్రొఫైల్ను సృష్టించడానికి ముందు, మీ అనువర్తనాలు మరియు వ్యక్తిగత డేటాను రక్షించడానికి స్క్రీన్ లాక్ను సెటప్ చేయాల్సి ఉంటుంది."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"లాక్ను సెట్ చేయి"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>కు మార్చు"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"కొత్త యూజర్ను క్రియేట్ చేస్తోంది…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"మారుపేరు"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"అతిథిని జోడించండి"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"అతిథిని తీసివేయండి"</string>
<string name="guest_nickname" msgid="6332276931583337261">"అతిథి"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"ఒక ఫోటో తీయండి"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"ఇమేజ్ను ఎంచుకోండి"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"ఫోటోను ఎంచుకోండి"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"పరికర ఆటోమేటిక్ సెట్టింగ్"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"డిజేబుల్ చేయబడింది"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ఎనేబుల్ చేయబడింది"</string>
diff --git a/packages/SettingsLib/res/values-th/arrays.xml b/packages/SettingsLib/res/values-th/arrays.xml
index 58d8a45..21fe6e4 100644
--- a/packages/SettingsLib/res/values-th/arrays.xml
+++ b/packages/SettingsLib/res/values-th/arrays.xml
@@ -138,15 +138,15 @@
<item msgid="1333279807604675720">"สเตอริโอ"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
- <item msgid="1241278021345116816">"เพิ่มประสิทธิภาพสำหรับคุณภาพเสียง (990 kbps/909 kbps)"</item>
+ <item msgid="1241278021345116816">"เพิ่มประสิทธิภาพเพื่อคุณภาพเสียง (990 kbps/909 kbps)"</item>
<item msgid="3523665555859696539">"คุณภาพเสียงและการเชื่อมต่อที่สมดุล (660 kbps/606 kbps)"</item>
- <item msgid="886408010459747589">"เพิ่มประสิทธิภาพสำหรับคุณภาพการเชื่อมต่อ (330 kbps/303 kbps)"</item>
+ <item msgid="886408010459747589">"เพิ่มประสิทธิภาพเพื่อคุณภาพการเชื่อมต่อ (330 kbps/303 kbps)"</item>
<item msgid="3808414041654351577">"ดีที่สุดเท่าที่ทำได้ (ปรับอัตราบิตอัตโนมัติ)"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
- <item msgid="804499336721569838">"เพิ่มประสิทธิภาพสำหรับคุณภาพเสียง"</item>
+ <item msgid="804499336721569838">"เพิ่มประสิทธิภาพเพื่อคุณภาพเสียง"</item>
<item msgid="7451422070435297462">"คุณภาพเสียงและการเชื่อมต่อที่สมดุล"</item>
- <item msgid="6173114545795428901">"เพิ่มประสิทธิภาพสำหรับคุณภาพการเชื่อมต่อ"</item>
+ <item msgid="6173114545795428901">"เพิ่มประสิทธิภาพเพื่อคุณภาพการเชื่อมต่อ"</item>
<item msgid="4349908264188040530">"ดีที่สุดเท่าที่ทำได้ (ปรับอัตราบิตอัตโนมัติ)"</item>
</string-array>
<string-array name="bluetooth_audio_active_device_summaries">
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index cc0ac74..2ae4131 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"ก่อนที่คุณจะสามารถสร้างโปรไฟล์ที่ถูกจำกัดได้ คุณจะต้องตั้งค่าล็อกหน้าจอเพื่อปกป้องแอปและข้อมูลส่วนตัวของคุณ"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"ตั้งค่าล็อก"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"เปลี่ยนเป็น <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"กำลังสร้างผู้ใช้ใหม่…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"ชื่อเล่น"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"เพิ่มผู้เข้าร่วม"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"นำผู้เข้าร่วมออก"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ผู้ใช้ชั่วคราว"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"ถ่ายรูป"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"เลือกรูปภาพ"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"เลือกรูปภาพ"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"ค่าเริ่มต้นของอุปกรณ์"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ปิดใช้"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"เปิดใช้"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 77ab7cf..e9f1da3 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Bago ka makakalikha ng pinaghihigpitang profile, kakailanganin mong mag-set up ng screen lock upang protektahan ang iyong apps at personal na data."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Itakda ang lock"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Lumipat sa <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Gumagawa ng bagong user…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Magdagdag ng bisita"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Alisin ang bisita"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Bisita"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Kumuha ng larawan"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Pumili ng larawan"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Pumili ng larawan"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Default ng device"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Naka-disable"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Na-enable"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 9d980c4..0502359 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Kısıtlanmış bir profil oluşturabilmeniz için uygulamalarınızı ve kişisel verilerinizi korumak üzere bir ekran kilidi oluşturmanız gerekir."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Kilidi ayarla"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> hesabına geç"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Yeni kullanıcı oluşturuluyor…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Takma ad"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Misafir ekle"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Misafir oturumunu kaldır"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Misafir"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Fotoğraf çek"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Resim seç"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Fotoğraf seç"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Cihaz varsayılanı"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Devre dışı"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Etkin"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 9a7b89f..b68aab4 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -547,19 +547,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Перш ніж створювати обмежений профіль, потрібно налаштувати блокування екрана, щоб захистити свої програми та особисті дані."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Налаштувати блокування"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Перейти до користувача <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Створення нового користувача…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Псевдонім"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Додати гостя"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Видалити гостя"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гість"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Зробити фотографію"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Вибрати зображення"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Вибрати фотографію"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"За умовчанням для пристрою"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Вимкнено"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Увімкнено"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 1cc0859..1802be6 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"ایک محدود پروفائل بنانے سے پہلے، آپ کو اپنی ایپس اور ذاتی ڈیٹا کو محفوظ کرنے کیلئے ایک اسکرین لاک سیٹ اپ کرنا ہوگا۔"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"لاک سیٹ کریں"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> پر سوئچ کریں"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"نیا صارف تخلیق کرنا…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"عرفی نام"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"مہمان کو شامل کریں"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"مہمان کو ہٹائیں"</string>
<string name="guest_nickname" msgid="6332276931583337261">"مہمان"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"ایک تصویر لیں"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"ایک تصویر منتخب کریں"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"تصویر منتخب کریں"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"آلہ ڈیفالٹ"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"غیر فعال"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"فعال"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 2ed6ca8..4d4808f 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Trước khi bạn có thể tạo tiểu sử bị hạn chế, bạn sẽ cần thiết lập một màn hình khóa để bảo vệ các ứng dụng và dữ liệu cá nhân của bạn."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Thiết lập khóa"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Chuyển sang <xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Đang tạo người dùng mới…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Biệt hiệu"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Thêm khách"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Xóa phiên khách"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Khách"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Chụp ảnh"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Chọn một hình ảnh"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Chọn ảnh"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Theo giá trị mặc định của thiết bị"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Đã tắt"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Đã bật"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 024ea79..b6e8eba2 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"您需要先设置锁定屏幕来保护您的应用和个人数据,然后才可以创建受限个人资料。"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"设置屏幕锁定方式"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"切换到<xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"正在创建新用户…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"昵称"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"添加访客"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"移除访客"</string>
<string name="guest_nickname" msgid="6332276931583337261">"访客"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"拍摄照片"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"选择图片"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"选择照片"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"设备默认设置"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"已停用"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"已启用"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 75f050f..07bc887 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"建立限制存取的個人檔案前,您必須先設定上鎖畫面來保護您的應用程式和個人資料。"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"設定上鎖畫面"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"切換至<xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"正在建立新使用者…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"暱稱"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"新增訪客"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"移除訪客"</string>
<string name="guest_nickname" msgid="6332276931583337261">"訪客"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"拍照"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"選擇圖片"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"揀相"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"裝置預設設定"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"已停用"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"已啟用"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 9866b47..833a82f 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"如要建立設有限制的個人資料,你必須先設定螢幕鎖定來保護你的應用程式和個人資料。"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"設定鎖定"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"切換至<xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"正在建立新使用者…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"暱稱"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"新增訪客"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"移除訪客"</string>
<string name="guest_nickname" msgid="6332276931583337261">"訪客"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"拍照"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"選擇圖片"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"選取相片"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"裝置預設設定"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"已停用"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"已啟用"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index b1825c4..0065eb6 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -545,19 +545,14 @@
<string name="user_need_lock_message" msgid="4311424336209509301">"Ngaphambi kokuthi ungadala iphrofayela ekhawulelwe, kuzomele usethe ukukhiya isikrini ukuze uvikele izinhlelo zakho zokusebenza nedatha yakho yomuntu siqu."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Setha ukukhiya"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Shintshela ku-<xliff:g id="USER_NAME">%s</xliff:g>"</string>
- <!-- no translation found for creating_new_user_dialog_message (7232880257538970375) -->
- <skip />
- <!-- no translation found for user_nickname (262624187455825083) -->
- <skip />
+ <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Idala umsebenzisi omusha…"</string>
+ <string name="user_nickname" msgid="262624187455825083">"Isiteketiso"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Engeza isivakashi"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Susa isihambeli"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Isihambeli"</string>
- <!-- no translation found for user_image_take_photo (467512954561638530) -->
- <skip />
- <!-- no translation found for user_image_choose_photo (1363820919146782908) -->
- <skip />
- <!-- no translation found for user_image_photo_selector (433658323306627093) -->
- <skip />
+ <string name="user_image_take_photo" msgid="467512954561638530">"Thatha isithombe"</string>
+ <string name="user_image_choose_photo" msgid="1363820919146782908">"Khetha isithombe"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Khetha isithombe"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Idivayisi ezenzakalelayo"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Ikhutshaziwe"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Inikwe amandla"</string>
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 81cf118..b0a9136 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -1090,7 +1090,7 @@
// Verify second update AP is the same object as the first update AP
assertThat(passpointAccessPointsFirstUpdate.get(0))
- .isSameAs(passpointAccessPointsSecondUpdate.get(0));
+ .isSameInstanceAs(passpointAccessPointsSecondUpdate.get(0));
// Verify second update AP has the average of the first and second update RSSIs
assertThat(passpointAccessPointsSecondUpdate.get(0).getRssi())
.isEqualTo((prevRssi + newRssi) / 2);
@@ -1210,7 +1210,8 @@
providersAndScans, cachedAccessPoints);
// Verify second update AP is the same object as the first update AP
- assertThat(osuAccessPointsFirstUpdate.get(0)).isSameAs(osuAccessPointsSecondUpdate.get(0));
+ assertThat(osuAccessPointsFirstUpdate.get(0))
+ .isSameInstanceAs(osuAccessPointsSecondUpdate.get(0));
// Verify second update AP has the average of the first and second update RSSIs
assertThat(osuAccessPointsSecondUpdate.get(0).getRssi())
.isEqualTo((prevRssi + newRssi) / 2);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java
index a83d7e0..b392c5e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java
@@ -69,7 +69,7 @@
assertWithMessage("Intent filter should contain expected intents")
.that(ipAddressPreferenceController.getConnectivityIntents())
- .asList().containsAllIn(expectedIntents);
+ .asList().containsAtLeastElementsIn(expectedIntents);
}
private static class ConcreteIpAddressPreferenceController extends
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java
index 40b9b13..3705267 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java
@@ -90,7 +90,7 @@
assertWithMessage("Intent filter should contain expected intents")
.that(mController.getConnectivityIntents())
- .asList().containsAllIn(expectedIntents);
+ .asList().containsAtLeastElementsIn(expectedIntents);
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index 1769053..906e06e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -284,7 +284,7 @@
assertThat(outTiles).hasSize(1);
final Bundle newMetaData = outTiles.get(0).getMetaData();
- assertThat(newMetaData).isNotSameAs(oldMetadata);
+ assertThat(newMetaData).isNotSameInstanceAs(oldMetadata);
}
@Test
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 69be144..8bdde8b 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -314,6 +314,7 @@
Settings.Global.KERNEL_CPU_THREAD_READER,
Settings.Global.LANG_ID_UPDATE_CONTENT_URL,
Settings.Global.LANG_ID_UPDATE_METADATA_URL,
+ Settings.Global.LATENCY_TRACKER,
Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
Settings.Global.LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS,
Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index bba29db..5f018a0 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -335,6 +335,9 @@
<!-- Permission required for CTS test - android.server.biometrics -->
<uses-permission android:name="android.permission.TEST_BIOMETRIC" />
+ <!-- Permissions required for CTS test - NotificationManagerTest -->
+ <uses-permission android:name="android.permission.MANAGE_NOTIFICATION_LISTENERS" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SoundPicker/res/values-uz/strings.xml b/packages/SoundPicker/res/values-uz/strings.xml
index 9018e66..a617733 100644
--- a/packages/SoundPicker/res/values-uz/strings.xml
+++ b/packages/SoundPicker/res/values-uz/strings.xml
@@ -21,7 +21,7 @@
<string name="alarm_sound_default" msgid="4787646764557462649">"Standart signal tovushi"</string>
<string name="add_ringtone_text" msgid="6642389991738337529">"Rington qo‘shish"</string>
<string name="add_alarm_text" msgid="3545497316166999225">"Signal qo‘shish"</string>
- <string name="add_notification_text" msgid="4431129543300614788">"Bildirishnoma qo‘shish"</string>
+ <string name="add_notification_text" msgid="4431129543300614788">"Bildirishnoma kiritish"</string>
<string name="delete_ringtone_text" msgid="201443984070732499">"O‘chirish"</string>
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Maxsus rington qo‘shib bo‘lmadi"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Maxsus ringtonni o‘chirib bo‘lmadi"</string>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 31faedf..b50be52 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Skuif af"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Beweeg links"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Beweeg regs"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Vergrotingwisselaar"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Vergroot die hele skerm"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Vergroot \'n deel van die skerm"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Wissel"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Toestelkontroles"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Voeg kontroles vir jou gekoppelde toestelle by"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Stel toestelkontroles op"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 41f6bed..9e8c8ac 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"ወደ ታች ውሰድ"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"ወደ ግራ ውሰድ"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"ወደ ቀኝ ውሰድ"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"የማጉላት ማብሪያ/ማጥፊያ"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"ሙሉውን ማያ ገጽ አጉላ"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"የማያ ገጹን ክፍል አጉላ"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ማብሪያ/ማጥፊያ"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"የመሣሪያ መቆጣጠሪያዎች"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"ለእርስዎ የተገናኙ መሣሪያዎች መቆጣጠሪያዎችን ያክሉ"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"የመሣሪያ መቆጣጠሪያዎችን ያቀናብሩ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index d1f98f0..caae9fb 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -1038,14 +1038,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"نقل للأسفل"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"نقل لليسار"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"نقل لليمين"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"مفتاح تبديل وضع التكبير"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"تكبير الشاشة بالكامل"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"تكبير جزء من الشاشة"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"تبديل"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"أدوات التحكم بالأجهزة"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"إضافة عناصر تحكّم لأجهزتك المتصلة"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"إعداد أدوات التحكم بالجهاز"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 52b6c5a..f5f109e 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"তললৈ নিয়ক"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"বাওঁফাললৈ নিয়ক"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"সোঁফাললৈ নিয়ক"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"বিবৰ্ধনৰ ছুইচ"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"গোটেই স্ক্ৰীনখন বিবৰ্ধন কৰক"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"স্ক্ৰীনৰ কিছু অংশ বিবৰ্ধন কৰক"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ছুইচ"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ডিভাইচৰ নিয়ন্ত্ৰণসমূহ"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"আপোনাৰ সংযোজিত ডিভাইচসমূহৰ বাবে নিয়ন্ত্ৰণসমূহ যোগ কৰক"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ডিভাইচৰ নিয়ন্ত্ৰণসমূহ ছেট আপ কৰক"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index b446718..89149f0 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Aşağı köçürün"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Sola köçürün"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Sağa köçürün"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Böyütmə dəyişdiricisi"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Bütün ekranı böyüdün"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekranın bir hissəsini böyüdün"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Dəyişdirici"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Cihaz idarəetmələri"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Qoşulmuş cihazlarınız üçün nizamlayıcılar əlavə edin"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Cihaz idarəetmələrini ayarlayın"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 3cc10d8..b3b722c9 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -1023,14 +1023,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Pomerite nadole"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Pomerite nalevo"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Pomerite nadesno"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Prelazak na drugi režim uvećanja"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Uvećajte ceo ekran"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Uvećajte deo ekrana"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Pređi"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodajte kontrole za povezane uređaje"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Podesite kontrole uređaja"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 07e7f8a..f68b69c 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -1028,14 +1028,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Перамясціць ніжэй"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Перамясціць улева"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Перамясціць управа"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Пераключальнік павелічэння"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Павялічыць на ўвесь экран"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Павялічыць частку экрана"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Пераключальнік"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Элементы кіравання прыладай"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Дадайце элементы кіравання для падключаных прылад"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Наладзіць элементы кіравання прыладай"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index f33c5cf..7a4b957 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Преместване надолу"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Преместване наляво"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Преместване надясно"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Превключване на увеличението"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Увеличаване на целия екран"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Увеличаване на част от екрана"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Превключване"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Контроли за устройството"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Добавяне на контроли за свързаните ви устройства"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Настройване на контролите за устройството"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index ac68620..1d67443 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -1023,14 +1023,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Pomjeranje prema dolje"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Pomjeranje lijevo"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Pomjeranje desno"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Prekidač za uvećavanje"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Uvećavanje cijelog ekrana"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Uvećavanje dijela ekrana"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Prekidač"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodajte kontrole za povezane uređaje"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Postavite kontrole uređaja"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 5e64aee..5e06f55 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Mou cap avall"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Mou cap a l\'esquerra"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Mou cap a la dreta"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Canvia al mode d\'ampliació"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Amplia tota la pantalla"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Amplia una part de la pantalla"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Canvia"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Controls de dispositius"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Afegeix controls per als teus dispositius connectats"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configura els controls de dispositius"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 5ca5df6..1b03762 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -1028,14 +1028,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Přesunout dolů"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Přesunout doleva"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Přesunout doprava"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Přepínač zvětšení"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Zvětšit celou obrazovku"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Zvětšit část obrazovky"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Přepnout"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Ovládání zařízení"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Přidejte ovládací prvky pro připojená zařízení"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Nastavení ovládání zařízení"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 419740e..fce888e 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Flyt ned"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Flyt til venstre"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Flyt til højre"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Skift forstørrelsestilstand"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Forstør hele skærmen"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Forstør en del af skærmen"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Skift"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Enhedsstyring"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Tilføj styring af dine tilsluttede enheder"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfigurer enhedsstyring"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 4b1be3b..a6d2dfd 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Nach unten bewegen"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Nach links bewegen"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Nach rechts bewegen"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Vergrößerungsschalter"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Ganzen Bildschirm vergrößern"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Teil des Bildschirms vergrößern"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Schalter"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Gerätesteuerung"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Steuerelemente für verbundene Geräte hinzufügen"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Gerätesteuerung einrichten"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 51c6d0d..2003a7d 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Mover hacia abajo"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Mover hacia la izquierda"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Mover hacia la derecha"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Botón para cambiar el modo de ampliación"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Ampliar toda la pantalla"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte de la pantalla"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Cambiar"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Control de dispositivos"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Añade controles para tus dispositivos conectados"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar control de dispositivos"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 6d616b8..286a42b 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Teisalda alla"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Teisalda vasakule"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Teisalda paremale"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Suurenduse lüliti"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Kogu ekraanikuva suurendamine"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekraanikuva osa suurendamine"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Lüliti"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Seadmete juhikud"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Lisage juhtelemendid ühendatud seadmete jaoks"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Seadmete juhtimisvidinate seadistamine"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 05e52f4..b6beec0 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Eraman behera"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Eraman ezkerrera"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Eraman eskuinera"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Lupa aplikatzeko botoia"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Handitu pantaila osoa"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Handitu pantailaren zati bat"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Botoia"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Gailuak kontrolatzeko widgetak"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Gehitu konektatutako gailuak kontrolatzeko widgetak"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfiguratu gailuak kontrolatzeko widgetak"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 1c16b33..7849ea4 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"انتقال به پایین"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"انتقال به راست"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"انتقال به چپ"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"کلید درشتنمایی"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"درشتنمایی تمام صفحه"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"درشتنمایی بخشی از صفحه"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"کلید"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"کنترلهای دستگاه"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"افزودن کنترلها برای دستگاههای متصل"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"تنظیم کنترلهای دستگاه"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 1e900fb..3e5afc7 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Siirrä alas"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Siirrä vasemmalle"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Siirrä oikealle"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Suurennusvalinta"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Suurenna koko näyttö"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Suurenna osa näytöstä"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Vaihda"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Laitteiden hallinta"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Lisää ohjaimia yhdistettyjä laitteita varten"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Laitteiden hallinnan käyttöönotto"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index f390693..250183e 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Déplacer vers le bas"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Déplacer vers la gauche"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Déplacer vers la droite"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Commutateur d\'agrandissement"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Agrandir l\'écran entier"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Agrandir une partie de l\'écran"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Commutateur"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Commandes des appareils"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Ajoutez des commandes pour vos appareils connectés"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurer les commandes des appareils"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index df542bc..2a4c95a 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Déplacer vers le bas"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Déplacer vers la gauche"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Déplacer vers la droite"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Changer de mode d\'agrandissement"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Agrandir tout l\'écran"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Agrandir une partie de l\'écran"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Changer"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Commandes des appareils"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Ajouter des commandes pour vos appareils connectés"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurer les commandes des appareils"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 08149fb..181ae74 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -1020,14 +1020,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"नीचे ले जाएं"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"बाईं ओर ले जाएं"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"दाईं ओर ले जाएं"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"ज़ूम करने की सुविधा वाला स्विच"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"पूरी स्क्रीन को ज़ूम करें"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"स्क्रीन के किसी हिस्से को ज़ूम करें"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"स्विच"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"डिवाइस कंट्रोल"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"कनेक्ट किए गए डिवाइस के लिए कंट्रोल जोड़ें"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"डिवाइस कंट्रोल सेट अप करें"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index b01f58e..f8318d5 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -1023,14 +1023,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Premjesti dolje"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Premjesti ulijevo"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Premjesti udesno"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Prebacivanje povećavanja"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Povećaj cijeli zaslon"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Povećaj dio zaslona"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Prebaci"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodavanje kontrola za povezane uređaje"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Postavljanje kontrola uređaja"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 1fcabcf..690508a 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Mozgatás lefelé"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Mozgatás balra"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Mozgatás jobbra"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Nagyításváltó"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Teljes képernyő nagyítása"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Képernyő bizonyos részének nagyítása"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Váltás"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Eszközvezérlők"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Vezérlők hozzáadása a csatlakoztatott eszközökhöz"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Eszközvezérlők beállítása"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 63737d2..0a966a1 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Տեղափոխել ներքև"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Տեղափոխել ձախ"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Տեղափոխել աջ"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Խոշորացման փոփոխություն"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Խոշորացնել ամբողջ էկրանը"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Խոշորացնել էկրանի որոշակի հատվածը"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Փոխել"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Սարքերի կառավարման տարրեր"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Ավելացրեք կառավարման տարրեր ձեր միացված սարքերի համար"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Սարքերի կառավարման տարրերի կարգավորում"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index da9af02..750a38f 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Pindahkan ke bawah"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Pindahkan ke kiri"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Pindahkan ke kanan"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Tombol pembesaran"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Perbesar seluruh layar"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Perbesar sebagian layar"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Alihkan"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrol perangkat"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Tambahkan kontrol untuk perangkat terhubung"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Siapkan kontrol perangkat"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 64ad21f..944e13f 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Færa niður"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Færa til vinstri"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Færa til hægri"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Stækkunarrofi"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Stækka allan skjáinn"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Stækka hluta skjásins"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Rofi"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Tækjastjórnun"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Bæta við stýringum fyrir tengd tæki"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Setja upp tækjastjórnun"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 90f68d9..68c64f0 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Sposta giù"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Sposta a sinistra"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Sposta a destra"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Opzione Ingrandimento"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Ingrandisci l\'intero schermo"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ingrandisci parte dello schermo"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Opzione"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Controllo dei dispositivi"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Aggiungi controlli per i dispositivi connessi"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configura il controllo dei dispositivi"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 14b19c3..e1ad35d 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -1028,14 +1028,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"הזזה למטה"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"הזזה שמאלה"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"הזזה ימינה"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"מעבר למצב הגדלה"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"הגדלת כל המסך"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"הגדלת חלק מהמסך"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"מעבר"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"פקדי מכשירים"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"יש להוסיף פקדים למכשירים המחוברים"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"הגדרה של פקדי מכשירים"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 98e6984..763a80e 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"下に移動"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"左に移動"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"右に移動"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"拡大スイッチ"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"画面全体を拡大します"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"画面の一部を拡大します"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"スイッチ"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"デバイス コントロール"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"接続済みデバイスのコントロールを追加します"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"デバイス コントロールの設定"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 606350c..f1c0121 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Төмен қарай жылжыту"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Солға жылжыту"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Оңға жылжыту"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Ұлғайту режиміне ауыстырғыш"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Толық экранды ұлғайту"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Экранның бөлігін ұлғайту"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Ауысу"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Құрылғыны басқару элементтері"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Жалғанған құрылғылар үшін басқару виджеттерін қосу"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Құрылғыны басқару элементтерін реттеу"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 9ed01c5..92d7cbf 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"ផ្លាស់ទីចុះក្រោម"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"ផ្លាស់ទីទៅឆ្វេង"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"ផ្លាស់ទីទៅស្តាំ"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"ប៊ូតុងបិទបើកការពង្រីក"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"ពង្រីកអេក្រង់ទាំងមូល"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ពង្រីកផ្នែកនៃអេក្រង់"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ប៊ូតុងបិទបើក"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ផ្ទាំងគ្រប់គ្រងឧបករណ៍"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"បញ្ចូលផ្ទាំងគ្រប់គ្រងសម្រាប់ឧបករណ៍ដែលអ្នកបានភ្ជាប់"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"រៀបចំផ្ទាំងគ្រប់គ្រងឧបករណ៍"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 116241c..2e47e9e 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"ಕೆಳಗೆ ಸರಿಸಿ"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"ಎಡಕ್ಕೆ ಸರಿಸಿ"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"ಬಲಕ್ಕೆ ಸರಿಸಿ"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"ಝೂಮ್ ಮಾಡುವ ಸ್ವಿಚ್"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"ಸ್ಕ್ರೀನ್ನ ಸಂಪೂರ್ಣ ಭಾಗವನ್ನು ಝೂಮ್ ಮಾಡಿ"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ಸ್ಕ್ರೀನ್ನ ಅರ್ಧಭಾಗವನ್ನು ಝೂಮ್ ಮಾಡಿ"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ಸ್ವಿಚ್"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ಸಾಧನ ನಿಯಂತ್ರಣಗಳು"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"ನಿಮ್ಮ ಸಂಪರ್ಕಿತ ಸಾಧನಗಳಿಗೆ ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಿ"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ಸಾಧನ ನಿಯಂತ್ರಣಗಳನ್ನು ಸೆಟಪ್ ಮಾಡಿ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 5bb0d13..fc533be 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"아래로 이동"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"왼쪽으로 이동"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"오른쪽으로 이동"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"확대 전환"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"전체 화면 확대"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"화면 일부 확대"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"전환"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"기기 컨트롤"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"연결된 기기의 컨트롤을 추가하세요."</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"기기 컨트롤 설정"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index dd85504..a4e47b3 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Төмөн жылдыруу"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Солго жылдыруу"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Оңго жылдыруу"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Чоңойтуу режимине которулуу"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Толук экранды чоңойтуу"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Экрандын бир бөлүгүн чоңойтуу"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Которулуу"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Түзмөктү башкаруу элементтери"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Байланышкан түзмөктөрүңүздү башкаруу элементтерин кошосуз"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Түзмөктү башкаруу элементтерин жөндөө"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 3553704..78fdf09 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"ຍ້າຍລົງ"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"ຍ້າຍໄປຊ້າຍ"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"ຍ້າຍໄປຂວາ"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"ສະຫຼັບການຂະຫຍາຍ"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"ຂະຫຍາຍທັງໜ້າຈໍ"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ຂະຫຍາຍບາງສ່ວນຂອງໜ້າຈໍ"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ສະຫຼັບ"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ການຄວບຄຸມອຸປະກອນ"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"ເພີ່ມການຄວບຄຸມສຳລັບອຸປະກອນທີ່ເຊື່ອມຕໍ່ແລ້ວຂອງທ່ານ"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ຕັ້ງຄ່າການຄວບຄຸມອຸປະກອນ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 9a2a8f2..6db8969 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -1028,14 +1028,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Perkelti žemyn"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Perkelti kairėn"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Perkelti dešinėn"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Didinimo jungiklis"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Didinti visą ekraną"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Didinti ekrano dalį"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Perjungti"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Įrenginio valdikliai"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Pridėkite prijungtų įrenginių valdiklių"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Įrenginio valdiklių nustatymas"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 94b66f3..c7807de 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -1023,14 +1023,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Pārvietot uz leju"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Pārvietot pa kreisi"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Pārvietot pa labi"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Palielinājuma slēdzis"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Palielināt visu ekrānu"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Palielināt ekrāna daļu"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Pārslēgt"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Ierīču vadīklas"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Pievienojiet vadīklas pievienotajām ierīcēm"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Ierīču vadīklu iestatīšana"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 567afc0..203f6c2 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Премести надолу"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Премести налево"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Премести надесно"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Прекинувач за зголемување"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Зголеми цел екран"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Зголеми дел од екранот"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Префрли"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Контроли за уредите"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Додајте контроли за поврзаните уреди"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Поставете ги контролите за уредите"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index dc6fe4c..1076eac 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"താഴേക്ക് നീക്കുക"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"ഇടത്തേക്ക് നീക്കുക"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"വലത്തേക്ക് നീക്കുക"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"മാഗ്നിഫിക്കേഷൻ മോഡ് മാറുക"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"മുഴുവൻ സ്ക്രീനും മാഗ്നിഫൈ ചെയ്യുക"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"സ്ക്രീനിന്റെ ഭാഗം മാഗ്നിഫൈ ചെയ്യുക"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"മാറുക"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ഉപകരണ നിയന്ത്രണങ്ങൾ"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"കണക്റ്റ് ചെയ്ത ഉപകരണങ്ങൾക്ക് നിയന്ത്രണങ്ങൾ ചേർക്കുക"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ഉപകരണ നിയന്ത്രണങ്ങൾ സജ്ജീകരിക്കുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index b12c4e0..c1ec99e 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -549,29 +549,29 @@
<string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Таны байгууллага таны ажлын профайлд сертификатын зөвшөөрөл суулгасан байна. Таны аюулгүй сүлжээний ачааллыг өөрчлөх эсвэл хянах боломжтой."</string>
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"Сертификатын зөвшөөрлийг энэ төхөөрөмжид суулгасан байна. Таны аюулгүй сүлжээний ачааллыг өөрчлөх эсвэл хянах боломжтой."</string>
<string name="monitoring_description_management_network_logging" msgid="216983105036994771">"Таны админ төхөөрөмжийн ачааллыг хянадаг сүлжээний логийг асаасан байна."</string>
- <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"Та имэйл, апп, вэб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой <xliff:g id="VPN_APP">%1$s</xliff:g>-д холбогдсон байна."</string>
- <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"Та имэйл, апп, вэб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой <xliff:g id="VPN_APP_0">%1$s</xliff:g>, <xliff:g id="VPN_APP_1">%2$s</xliff:g>-д холбогдсон байна."</string>
- <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"Таны ажлын профайл <xliff:g id="VPN_APP">%1$s</xliff:g>-д холбогдсон байна. Энэ нь таны имэйл, апп, вэб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой."</string>
- <string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"Таны хувийн профайлыг имэйл, апп, вэб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой <xliff:g id="VPN_APP">%1$s</xliff:g>-д холбосон байна."</string>
+ <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"Та имэйл, апп, веб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой <xliff:g id="VPN_APP">%1$s</xliff:g>-д холбогдсон байна."</string>
+ <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"Та имэйл, апп, веб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой <xliff:g id="VPN_APP_0">%1$s</xliff:g>, <xliff:g id="VPN_APP_1">%2$s</xliff:g>-д холбогдсон байна."</string>
+ <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"Таны ажлын профайл <xliff:g id="VPN_APP">%1$s</xliff:g>-д холбогдсон байна. Энэ нь таны имэйл, апп, веб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой."</string>
+ <string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"Таны хувийн профайлыг имэйл, апп, веб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой <xliff:g id="VPN_APP">%1$s</xliff:g>-д холбосон байна."</string>
<string name="monitoring_description_do_header_generic" msgid="6130190408164834986">"Таны төхөөрөмжийг <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> удирддаг."</string>
<string name="monitoring_description_do_header_with_name" msgid="2696255132542779511">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> таны төхөөрөмжийг удирдахын тулд <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>-г ашигладаг."</string>
<string name="monitoring_description_do_body" msgid="7700878065625769970">"Таны админ тохиргоо, байгууллагын хандалт, апп, төхөөрөмжтэй холбоотой өгөгдөл болон таны төхөөрөмжийн байршлын мэдээллийг хянах, удирдах боломжтой."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="1467280496376492558">" "</string>
<string name="monitoring_description_do_learn_more" msgid="645149183455573790">"Дэлгэрэнгүй үзэх"</string>
- <string name="monitoring_description_do_body_vpn" msgid="7699280130070502303">"Таны имэйл, апп, вэб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой <xliff:g id="VPN_APP">%1$s</xliff:g>-д холбогдсон байна."</string>
+ <string name="monitoring_description_do_body_vpn" msgid="7699280130070502303">"Таны имэйл, апп, веб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой <xliff:g id="VPN_APP">%1$s</xliff:g>-д холбогдсон байна."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="8292589617720435430">" "</string>
<string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"VPN тохиргоог нээх"</string>
<string name="monitoring_description_ca_cert_settings_separator" msgid="7107390013344435439">" "</string>
<string name="monitoring_description_ca_cert_settings" msgid="8329781950135541003">"Итгэмжлэгдсэн мандат үнэмлэхийг нээх"</string>
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Таны админ төхөөрөмжийн ачааллыг хянадаг сүлжээний логийг асаасан байна.\n\nДэлгэрэнгүй мэдээлэл авах бол админтайгаа холбогдоно уу."</string>
- <string name="monitoring_description_vpn" msgid="1685428000684586870">"Та апп-д VPN холболт хийхийг зөвшөөрсөн байна.\n\nЭнэхүү апп нь таны имэйл, апп, вэбсайт зэрэг төхөөрөмж болон сүлжээний үйл ажиллагааг хянах боломжтой."</string>
- <string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> таны ажлын профайлыг удирддаг.\n\nТаны админ имэйл, апп болон вэб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой.\n\nДэлгэрэнгүй мэдээлэл авах бол админтайгаа холбогдоно уу.\n\nТа сүлжээний үйл ажиллагааг хянах боломжтой VPN-д холбогдсон байна."</string>
+ <string name="monitoring_description_vpn" msgid="1685428000684586870">"Та апп-д VPN холболт хийхийг зөвшөөрсөн байна.\n\nЭнэхүү апп нь таны имэйл, апп, вебсайт зэрэг төхөөрөмж болон сүлжээний үйл ажиллагааг хянах боломжтой."</string>
+ <string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> таны ажлын профайлыг удирддаг.\n\nТаны админ имэйл, апп болон веб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой.\n\nДэлгэрэнгүй мэдээлэл авах бол админтайгаа холбогдоно уу.\n\nТа сүлжээний үйл ажиллагааг хянах боломжтой VPN-д холбогдсон байна."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
- <string name="monitoring_description_app" msgid="376868879287922929">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вэбсайт зэрэг сүлжээний үйл ажиллагааг хянах боломжтой."</string>
- <string name="monitoring_description_app_personal" msgid="1970094872688265987">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вэбсайт зэрэг сүлжээний хувийн үйл ажиллагааг хянах боломжтой."</string>
- <string name="branded_monitoring_description_app_personal" msgid="1703511985892688885">"Та имэйл, апп, вэб хуудас зэрэг хувийн сүлжээнийхээ үйл ажиллагааг хянах боломжтой <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон байна."</string>
- <string name="monitoring_description_app_work" msgid="3713084153786663662">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг. Энэ нь таны имэйл, апп, вэб хуудас зэрэг ажлын сүлжээний үйл ажиллагааг хянах боломжтой <xliff:g id="APPLICATION">%2$s</xliff:g>-д холбогдсон. \n\nДэлгэрэнгүй мэдээллийг авахын тулд админтай холбогдоно уу."</string>
- <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг. Энэ нь таны имэйл, апп, вэб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>-тай холбогдсон. \n\nМөн таны сүлжээний хувийн үйл ажиллагааг хянах боломжтой <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>-д холбогдсон байна."</string>
+ <string name="monitoring_description_app" msgid="376868879287922929">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вебсайт зэрэг сүлжээний үйл ажиллагааг хянах боломжтой."</string>
+ <string name="monitoring_description_app_personal" msgid="1970094872688265987">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вебсайт зэрэг сүлжээний хувийн үйл ажиллагааг хянах боломжтой."</string>
+ <string name="branded_monitoring_description_app_personal" msgid="1703511985892688885">"Та имэйл, апп, веб хуудас зэрэг хувийн сүлжээнийхээ үйл ажиллагааг хянах боломжтой <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон байна."</string>
+ <string name="monitoring_description_app_work" msgid="3713084153786663662">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг. Энэ нь таны имэйл, апп, веб хуудас зэрэг ажлын сүлжээний үйл ажиллагааг хянах боломжтой <xliff:g id="APPLICATION">%2$s</xliff:g>-д холбогдсон. \n\nДэлгэрэнгүй мэдээллийг авахын тулд админтай холбогдоно уу."</string>
+ <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг. Энэ нь таны имэйл, апп, веб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>-тай холбогдсон. \n\nМөн таны сүлжээний хувийн үйл ажиллагааг хянах боломжтой <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>-д холбогдсон байна."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent-р түгжээгүй байлгасан"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Таныг гараар нээх хүртэл төхөөрөмж түгжээтэй байх болно"</string>
<string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
@@ -653,8 +653,8 @@
<string name="status_bar_alarm" msgid="87160847643623352">"Сэрүүлэг"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Ажлын профайл"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Нислэгийн горим"</string>
- <string name="add_tile" msgid="6239678623873086686">"Вэбсайтын цонх нэмэх"</string>
- <string name="broadcast_tile" msgid="5224010633596487481">"Вэбсайтын цонх дамжуулах"</string>
+ <string name="add_tile" msgid="6239678623873086686">"Вебсайтын цонх нэмэх"</string>
+ <string name="broadcast_tile" msgid="5224010633596487481">"Вебсайтын цонх дамжуулах"</string>
<string name="zen_alarm_warning_indef" msgid="5252866591716504287">"Та өмнө нь унтраагаагүй тохиолдолд <xliff:g id="WHEN">%1$s</xliff:g>-т сэрүүлгээ сонсохгүй"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>-т та дараагийн сэрүүлгээ сонсохгүй"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> цагт"</string>
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Доош зөөх"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Зүүн тийш зөөх"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Баруун тийш зөөх"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Томруулах сэлгэлт"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Дэлгэцийг бүхэлд нь томруулах"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Дэлгэцийн нэг хэсгийг томруулах"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Сэлгэх"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Төхөөрөмжийн хяналт"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Холбогдсон төхөөрөмжүүд дээрээ хяналт нэмэх"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Төхөөрөмжийн хяналтыг тохируулах"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index aa302a9..ac22f4c 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Alih ke bawah"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Alih ke kiri"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Alih ke kanan"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Suis pembesaran"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Besarkan seluruh skrin"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Besarkan sebahagian skrin"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Tukar"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Kawalan peranti"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Tambah kawalan untuk peranti yang disambungkan"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Sediakan kawalan peranti"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index a296b46..c92900c 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"အောက်သို့ရွှေ့ရန်"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"ဘယ်ဘက်သို့ရွှေ့ရန်"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"ညာဘက်သို့ရွှေ့ရန်"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"ချဲ့ရန် ခလုတ်"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"ဖန်သားပြင် တစ်ခုလုံးကို ချဲ့ပါ"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ဖန်သားပြင် တစ်စိတ်တစ်ပိုင်းကို ချဲ့ပါ"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ခလုတ်"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"စက်ထိန်းစနစ်"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"ချိတ်ဆက်စက်များအတွက် ထိန်းချုပ်မှုများထည့်ပါ"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"စက်ထိန်းစနစ် ထည့်သွင်းခြင်း"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 7ebed82..2920af3 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Flytt ned"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Flytt til venstre"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Flytt til høyre"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Forstørringsbryter"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Forstørr hele skjermen"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Forstørr en del av skjermen"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Bytt"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Enhetsstyring"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Legg til kontroller for de tilkoblede enhetene dine"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfigurer enhetsstyring"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 19e1537..b90cd30 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Omlaag verplaatsen"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Naar links verplaatsen"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Naar rechts verplaatsen"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Vergrotingsschakelaar"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Hele scherm vergroten"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Deel van het scherm vergroten"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Schakelen"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Apparaatbediening"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Bedieningselementen voor je gekoppelde apparaten toevoegen"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Apparaatbediening instellen"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index d4e723f..fd7692a 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"ତଳକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"ବାମକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"ଡାହାଣକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"ମ୍ୟାଗ୍ନିଫିକେସନ୍ ସ୍ୱିଚ୍"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"ସମ୍ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନ୍ ମାଗ୍ନିଫାଏ କରନ୍ତୁ"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ସ୍କ୍ରିନର ଅଂଶ ମାଗ୍ନିଫାଏ କରନ୍ତୁ"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ସ୍ୱିଚ୍ କରନ୍ତୁ"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ଡିଭାଇସ୍ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"ଆପଣଙ୍କ ସଂଯୁକ୍ତ ଡିଭାଇସଗୁଡ଼ିକ ପାଇଁ ନିୟନ୍ତ୍ରଣ ଯୋଗ କରନ୍ତୁ"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ଡିଭାଇସ୍ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ସେଟ୍ ଅପ୍ କରନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 810ea37..19cd0e9 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -1028,14 +1028,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Przesuń w dół"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Przesuń w lewo"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Przesuń w prawo"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Przełączanie powiększenia"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Powiększ cały ekran"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Powiększ część ekranu"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Przełącz"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Sterowanie urządzeniami"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodaj elementy sterujące połączonymi urządzeniami"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfigurowanie sterowania urządzeniami"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 966f15c..0b1c5e3 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Mover para baixo"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Mover para a esquerda"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Mover para a direita"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Interruptor de ampliação"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Ampliar o ecrã inteiro"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte do ecrã"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Mudar"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Controlos de dispositivos"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Adicione controlos para os dispositivos associados."</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configure os controlos de dispositivos"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 07653f1..3502161 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -1023,14 +1023,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Deplasați în jos"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Deplasați spre stânga"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Deplasați spre dreapta"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Comutator de mărire"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Măriți întregul ecran"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Măriți o parte a ecranului"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Comutator"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Comenzile dispozitivelor"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Adăugați comenzi pentru dispozitivele conectate"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurați comenzile dispozitivelor"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 5f9f115..7f257a1 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -1028,14 +1028,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Переместить вниз"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Переместить влево"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Переместить вправо"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Переключатель режима увеличения"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Увеличить весь экран"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Увеличить часть экрана"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Переключить"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Управление устройствами"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Добавьте виджеты для управления устройствами."</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Настройте виджеты управления устройствами"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 64e24be..ac743d3 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"පහළට ගෙන යන්න"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"වමට ගෙන යන්න"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"දකුණට ගෙන යන්න"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"විශාලන ස්විචය"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"සම්පූර්ණ තිරය විශාලනය කරන්න"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"තිරයේ කොටසක් විශාලනය කරන්න"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ස්විචය"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"උපාංග පාලන"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"ඔබේ සම්බන්ධිත උපාංග සඳහා පාලන එක් කරන්න"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"උපාංග පාලන පිහිටුවන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index bb75f8f..d29d1e9 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -1028,14 +1028,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Posunúť nadol"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Posunúť doľava"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Posunúť doprava"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Prepínač zväčenia"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Zväčšiť celú obrazovku"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Zväčšiť časť obrazovky"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Prepnúť"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Ovládanie zariadení"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Pridajte si ovládače pripojených zariadení"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Nastavenie ovládania zariadení"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 98abf37..6cb0ccd 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -1028,14 +1028,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Premakni navzdol"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Premakni levo"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Premakni desno"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Stikalo za povečavo"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Povečava celotnega zaslona"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Povečava dela zaslona"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Stikalo"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrolniki naprave"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodajte kontrolnike za povezane naprave"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Nastavitev kontrolnikov naprave"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index e59c0bb..687a1bd 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -1023,14 +1023,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Померите надоле"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Померите налево"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Померите надесно"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Прелазак на други режим увећања"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Увећајте цео екран"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Увећајте део екрана"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Пређи"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Контроле уређаја"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Додајте контроле за повезане уређаје"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Подесите контроле уређаја"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 8213118..3dc89d8 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Flytta nedåt"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Flytta åt vänster"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Flytta åt höger"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Förstoringsreglage"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Förstora hela skärmen"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Förstora en del av skärmen"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Reglage"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Enhetsstyrning"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Lägg till snabbkontroller för anslutna enheter"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfigurera enhetsstyrning"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 0a0e91a..76c1cd4 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Sogeza chini"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Sogeza kushoto"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Sogeza kulia"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Swichi ya ukuzaji"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Kuza skrini yote"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Kuza sehemu ya skrini"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Swichi"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Vidhibiti vya vifaa"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Weka vidhibiti vya vifaa ulivyounganisha"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Weka mipangilio ya vidhibiti vya vifaa"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 27a9d06..7e4ed35 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"கீழே நகர்த்து"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"இடப்புறம் நகர்த்து"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"வலப்புறம் நகர்த்து"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"பெரிதாக்கல் ஸ்விட்ச்"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"முழுத்திரையைப் பெரிதாக்கும்"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"திரையின் ஒரு பகுதியைப் பெரிதாக்கும்"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ஸ்விட்ச்"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"சாதனக் கட்டுப்பாடுகள்"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"இணைக்கப்பட்ட சாதனங்களில் கட்டுப்பாடுகளைச் சேர்க்கலாம்"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"சாதனக் கட்டுப்பாடுகளை அமைத்தல்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 5e35a5c..f26c8b4 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"కిందకి పంపండి"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"ఎడమవైపుగా జరపండి"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"కుడివైపుగా జరపండి"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"మాగ్నిఫికేషన్ స్విచ్"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"స్క్రీన్ మొత్తాన్ని మాగ్నిఫై చేయండి"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"స్క్రీన్లో భాగాన్ని మాగ్నిఫై చేయండి"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"స్విచ్ చేయి"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"పరికరం నియంత్రణలు"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"మీ కనెక్ట్ అయిన పరికరాలకు నియంత్రణలను జోడించండి"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"పరికరం నియంత్రణలను సెటప్ చేయడం"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 3f7e0da..9c61e5e 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"ย้ายลง"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"ย้ายไปทางซ้าย"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"ย้ายไปทางขวา"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"เปลี่ยนการขยาย"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"ขยายทั้งหน้าจอ"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ขยายบางส่วนของหน้าจอ"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"เปลี่ยน"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ระบบควบคุมอุปกรณ์"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"เพิ่มตัวควบคุมของอุปกรณ์ที่เชื่อมต่อ"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ตั้งค่าระบบควบคุมอุปกรณ์"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index d03f0f8..be7bd06 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Ibaba"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Ilipat pakaliwa"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Ilipat pakanan"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Switch ng pag-magnify"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"I-magnify ang buong screen"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"I-magnify ang isang bahagi ng screen"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Switch"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Mga kontrol ng device"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Magdagdag ng kontrol para sa mga nakakonektang device"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"I-set up ang mga kontrol ng device"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 62f3671..5d488365 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Aşağı taşı"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Sola taşı"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Sağa taşı"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Büyütme moduna geçin"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Ekranın tamamını büyütün"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekranın bir parçasını büyütün"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Geç"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Cihaz denetimleri"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Bağlı cihazlarınız için denetimler ekleyin"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Cihaz denetimlerini kur"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 069577f..3b5c44b 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -1028,14 +1028,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Перемістити вниз"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Перемістити ліворуч"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Перемістити праворуч"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Перемикач режиму збільшення"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Збільшити весь екран"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Збільшити частину екрана"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Перемкнути"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Керування пристроями"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Додайте елементи керування для підключених пристроїв"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Налаштувати елементи керування пристроями"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 433eadb..228b80d 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Pastga siljitish"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Chapga siljitish"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Oʻngga siljitish"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Kattalashtirishni almashtirish"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Butun ekranni kattalashtirish"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekran qismini kattalashtirish"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Almashtirish"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Qurilmalarni boshqarish"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Ulangan qurilmalar uchun boshqaruv elementlari"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Qurilma boshqaruv elementlarini sozlash"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index e337c42..8492236 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Di chuyển xuống"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Di chuyển sang trái"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Di chuyển sang phải"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Nút chuyển phóng to"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Phóng to toàn bộ màn hình"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Phóng to một phần màn hình"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Chuyển"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Điều khiển thiết bị"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Thêm các tùy chọn điều khiển cho các thiết bị đã kết nối của bạn"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Thiết lập các tùy chọn điều khiển thiết bị"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 254d974..72e7640 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"下移"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"左移"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"右移"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"切换放大模式"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"放大整个屏幕"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"放大部分屏幕"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"切换"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"设备控制器"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"为您所连接的设备添加控件"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"设置设备控件"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index e8afc0e..c3dc8d2 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"向下移"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"向左移"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"向右移"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"放大開關"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"放大整個螢幕畫面"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"放大部分螢幕畫面"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"切換"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"裝置控制"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"為連接的裝置新增控制選項"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"設定裝置控制"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 0fc7db6..02fc24f 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"向下移"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"向左移"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"向右移"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"切換放大模式"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"放大整個螢幕畫面"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"放大局部螢幕畫面"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"切換"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"裝置控制"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"新增已連結裝置的控制項"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"設定裝置控制"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 3ada5cc..8eb86bc 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -1018,14 +1018,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Yehlisa"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Yisa kwesokunxele"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Yisa kwesokudla"</string>
- <!-- no translation found for magnification_mode_switch_description (2698364322069934733) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_full_screen (2882507327576770574) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_state_window (8597100249594076965) -->
- <skip />
- <!-- no translation found for magnification_mode_switch_click_label (2786203505805898199) -->
- <skip />
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Iswishi yokukhulisa"</string>
+ <string name="magnification_mode_switch_state_full_screen" msgid="2882507327576770574">"Khulisa sonke isikrini"</string>
+ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Khulisa ingxenye eyesikrini"</string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Iswishi"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Izilawuli zezinsiza"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Engeza izilawuli zedivayisi yakho exhunyiwe"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Setha izilawuli zezinsiza"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 3d7b779..6df8b4e 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -54,6 +54,8 @@
<color name="global_actions_emergency_background">@color/GM2_red_400</color>
<color name="global_actions_emergency_text">@color/GM2_grey_100</color>
+ <color name="global_actions_shutdown_ui_text">@color/control_primary_text</color>
+
<!-- Tint color for the content on the notification overflow card. -->
<color name="keyguard_overflow_content_color">#ff686868</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 7cbbaf9..26b3ab8 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1217,7 +1217,7 @@
<!-- Interior padding of the message bubble -->
<dimen name="bubble_message_padding">4dp</dimen>
<!-- Offset between bubbles in their stacked position. -->
- <dimen name="bubble_stack_offset">5dp</dimen>
+ <dimen name="bubble_stack_offset">10dp</dimen>
<!-- How far offscreen the bubble stack rests. Cuts off padding and part of icon bitmap. -->
<dimen name="bubble_stack_offscreen">9dp</dimen>
<!-- How far down the screen the stack starts. -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index b526a92..b81ffb7 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -46,7 +46,6 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -82,13 +81,11 @@
private final PackageManager mPackageManager;
private final BackgroundExecutor mBackgroundExecutor;
- private final TaskStackChangeListeners mTaskStackChangeListeners;
private ActivityManagerWrapper() {
final Context context = AppGlobals.getInitialApplication();
mPackageManager = context.getPackageManager();
mBackgroundExecutor = BackgroundExecutor.get();
- mTaskStackChangeListeners = new TaskStackChangeListeners(Looper.getMainLooper());
}
public static ActivityManagerWrapper getInstance() {
@@ -360,23 +357,17 @@
}
/**
- * Registers a task stack listener with the system.
- * This should be called on the main thread.
+ * @deprecated use {@link TaskStackChangeListeners#registerTaskStackListener}
*/
public void registerTaskStackListener(TaskStackChangeListener listener) {
- synchronized (mTaskStackChangeListeners) {
- mTaskStackChangeListeners.addListener(ActivityManager.getService(), listener);
- }
+ TaskStackChangeListeners.getInstance().registerTaskStackListener(listener);
}
/**
- * Unregisters a task stack listener with the system.
- * This should be called on the main thread.
+ * @deprecated use {@link TaskStackChangeListeners#unregisterTaskStackListener}
*/
public void unregisterTaskStackListener(TaskStackChangeListener listener) {
- synchronized (mTaskStackChangeListeners) {
- mTaskStackChangeListeners.removeListener(listener);
- }
+ TaskStackChangeListeners.getInstance().unregisterTaskStackListener(listener);
}
/**
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java
index 0d5933e..bf4fb0b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java
@@ -28,7 +28,18 @@
return LatencyTracker.isEnabled(context);
}
+ /**
+ * @see LatencyTracker
+ * @deprecated Please use {@link LatencyTrackerCompat#logToggleRecents(Context, int)} instead.
+ */
+ @Deprecated
public static void logToggleRecents(int duration) {
- LatencyTracker.logAction(LatencyTracker.ACTION_TOGGLE_RECENTS, duration);
+ LatencyTracker.logActionDeprecated(LatencyTracker.ACTION_TOGGLE_RECENTS, duration, false);
+ }
+
+ /** @see LatencyTracker */
+ public static void logToggleRecents(Context context, int duration) {
+ LatencyTracker.getInstance(context).logAction(LatencyTracker.ACTION_TOGGLE_RECENTS,
+ duration);
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
index 86129e0..70021b6 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
@@ -65,7 +65,7 @@
public SyncRtSurfaceTransactionApplierCompat(View targetView) {
mTargetViewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
mBarrierSurfaceControl = mTargetViewRootImpl != null
- ? mTargetViewRootImpl.getRenderSurfaceControl() : null;
+ ? mTargetViewRootImpl.getSurfaceControl() : null;
mApplyHandler = new Handler(new Callback() {
@Override
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index f214648..765cd3d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -19,14 +19,12 @@
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.TaskSnapshot;
import android.app.ActivityTaskManager;
-import android.app.IActivityManager;
import android.app.TaskStackListener;
import android.content.ComponentName;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
-import android.os.RemoteException;
import android.os.Trace;
import android.util.Log;
@@ -42,208 +40,40 @@
public class TaskStackChangeListeners extends TaskStackListener {
private static final String TAG = TaskStackChangeListeners.class.getSimpleName();
+ private static final TaskStackChangeListeners INSTANCE = new TaskStackChangeListeners();
+
+ private final Impl mImpl;
+
+ private TaskStackChangeListeners() {
+ mImpl = new Impl(Looper.getMainLooper());
+ }
+
+ public static TaskStackChangeListeners getInstance() {
+ return INSTANCE;
+ }
/**
- * List of {@link TaskStackChangeListener} registered from {@link #addListener}.
+ * Registers a task stack listener with the system.
+ * This should be called on the main thread.
*/
- private final List<TaskStackChangeListener> mTaskStackListeners = new ArrayList<>();
- private final List<TaskStackChangeListener> mTmpListeners = new ArrayList<>();
-
- private final Handler mHandler;
- private boolean mRegistered;
-
- public TaskStackChangeListeners(Looper looper) {
- mHandler = new H(looper);
- }
-
- public void addListener(IActivityManager am, TaskStackChangeListener listener) {
- synchronized (mTaskStackListeners) {
- mTaskStackListeners.add(listener);
- }
- if (!mRegistered) {
- // Register mTaskStackListener to IActivityManager only once if needed.
- try {
- ActivityTaskManager.getService().registerTaskStackListener(this);
- mRegistered = true;
- } catch (Exception e) {
- Log.w(TAG, "Failed to call registerTaskStackListener", e);
- }
+ public void registerTaskStackListener(TaskStackChangeListener listener) {
+ synchronized (mImpl) {
+ mImpl.addListener(listener);
}
}
- public void removeListener(TaskStackChangeListener listener) {
- boolean isEmpty;
- synchronized (mTaskStackListeners) {
- mTaskStackListeners.remove(listener);
- isEmpty = mTaskStackListeners.isEmpty();
- }
- if (isEmpty && mRegistered) {
- // Unregister mTaskStackListener once we have no more listeners
- try {
- ActivityTaskManager.getService().unregisterTaskStackListener(this);
- mRegistered = false;
- } catch (Exception e) {
- Log.w(TAG, "Failed to call unregisterTaskStackListener", e);
- }
+ /**
+ * Unregisters a task stack listener with the system.
+ * This should be called on the main thread.
+ */
+ public void unregisterTaskStackListener(TaskStackChangeListener listener) {
+ synchronized (mImpl) {
+ mImpl.removeListener(listener);
}
}
- @Override
- public void onTaskStackChanged() throws RemoteException {
- // Call the task changed callback for the non-ui thread listeners first. Copy to a set of
- // temp listeners so that we don't lock on mTaskStackListeners while calling all the
- // callbacks. This call is always on the same binder thread, so we can just synchronize
- // on the copying of the listener list.
- synchronized (mTaskStackListeners) {
- mTmpListeners.addAll(mTaskStackListeners);
- }
- for (int i = mTmpListeners.size() - 1; i >= 0; i--) {
- mTmpListeners.get(i).onTaskStackChangedBackground();
- }
- mTmpListeners.clear();
+ private static class Impl extends TaskStackListener implements Handler.Callback {
- mHandler.removeMessages(H.ON_TASK_STACK_CHANGED);
- mHandler.sendEmptyMessage(H.ON_TASK_STACK_CHANGED);
- }
-
- @Override
- public void onActivityPinned(String packageName, int userId, int taskId, int stackId)
- throws RemoteException {
- mHandler.removeMessages(H.ON_ACTIVITY_PINNED);
- mHandler.obtainMessage(H.ON_ACTIVITY_PINNED,
- new PinnedActivityInfo(packageName, userId, taskId, stackId)).sendToTarget();
- }
-
- @Override
- public void onActivityUnpinned() throws RemoteException {
- mHandler.removeMessages(H.ON_ACTIVITY_UNPINNED);
- mHandler.sendEmptyMessage(H.ON_ACTIVITY_UNPINNED);
- }
-
- @Override
- public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
- boolean clearedTask, boolean wasVisible) throws RemoteException {
- final SomeArgs args = SomeArgs.obtain();
- args.arg1 = task;
- args.argi1 = homeTaskVisible ? 1 : 0;
- args.argi2 = clearedTask ? 1 : 0;
- args.argi3 = wasVisible ? 1 : 0;
- mHandler.removeMessages(H.ON_ACTIVITY_RESTART_ATTEMPT);
- mHandler.obtainMessage(H.ON_ACTIVITY_RESTART_ATTEMPT, args).sendToTarget();
- }
-
- @Override
- public void onActivityForcedResizable(String packageName, int taskId, int reason)
- throws RemoteException {
- mHandler.obtainMessage(H.ON_ACTIVITY_FORCED_RESIZABLE, taskId, reason, packageName)
- .sendToTarget();
- }
-
- @Override
- public void onActivityDismissingDockedStack() throws RemoteException {
- mHandler.sendEmptyMessage(H.ON_ACTIVITY_DISMISSING_DOCKED_STACK);
- }
-
- @Override
- public void onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo taskInfo,
- int requestedDisplayId) throws RemoteException {
- mHandler.obtainMessage(H.ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED, requestedDisplayId,
- 0 /* unused */,
- taskInfo).sendToTarget();
- }
-
- @Override
- public void onActivityLaunchOnSecondaryDisplayRerouted(RunningTaskInfo taskInfo,
- int requestedDisplayId) throws RemoteException {
- mHandler.obtainMessage(H.ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED,
- requestedDisplayId, 0 /* unused */, taskInfo).sendToTarget();
- }
-
- @Override
- public void onTaskProfileLocked(int taskId, int userId) throws RemoteException {
- mHandler.obtainMessage(H.ON_TASK_PROFILE_LOCKED, taskId, userId).sendToTarget();
- }
-
- @Override
- public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) throws RemoteException {
- mHandler.obtainMessage(H.ON_TASK_SNAPSHOT_CHANGED, taskId, 0, snapshot).sendToTarget();
- }
-
- @Override
- public void onTaskCreated(int taskId, ComponentName componentName) throws RemoteException {
- mHandler.obtainMessage(H.ON_TASK_CREATED, taskId, 0, componentName).sendToTarget();
- }
-
- @Override
- public void onTaskRemoved(int taskId) throws RemoteException {
- mHandler.obtainMessage(H.ON_TASK_REMOVED, taskId, 0).sendToTarget();
- }
-
- @Override
- public void onTaskMovedToFront(RunningTaskInfo taskInfo)
- throws RemoteException {
- mHandler.obtainMessage(H.ON_TASK_MOVED_TO_FRONT, taskInfo).sendToTarget();
- }
-
- @Override
- public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) throws RemoteException {
- mHandler.obtainMessage(H.ON_BACK_PRESSED_ON_TASK_ROOT, taskInfo).sendToTarget();
- }
-
- @Override
- public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation)
- throws RemoteException {
- mHandler.obtainMessage(H.ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE, taskId,
- requestedOrientation).sendToTarget();
- }
-
- @Override
- public void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken)
- throws RemoteException {
- mHandler.obtainMessage(H.ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED, displayId, 0 /* unused */,
- activityToken).sendToTarget();
- }
-
- @Override
- public void onSingleTaskDisplayDrawn(int displayId) throws RemoteException {
- mHandler.obtainMessage(H.ON_SINGLE_TASK_DISPLAY_DRAWN, displayId,
- 0 /* unused */).sendToTarget();
- }
-
- @Override
- public void onSingleTaskDisplayEmpty(int displayId) throws RemoteException {
- mHandler.obtainMessage(H.ON_SINGLE_TASK_DISPLAY_EMPTY, displayId,
- 0 /* unused */).sendToTarget();
- }
-
- @Override
- public void onTaskDisplayChanged(int taskId, int newDisplayId) throws RemoteException {
- mHandler.obtainMessage(H.ON_TASK_DISPLAY_CHANGED, taskId, newDisplayId).sendToTarget();
- }
-
- @Override
- public void onRecentTaskListUpdated() throws RemoteException {
- mHandler.obtainMessage(H.ON_TASK_LIST_UPDATED).sendToTarget();
- }
-
- @Override
- public void onRecentTaskListFrozenChanged(boolean frozen) {
- mHandler.obtainMessage(H.ON_TASK_LIST_FROZEN_UNFROZEN, frozen ? 1 : 0, 0 /* unused */)
- .sendToTarget();
- }
-
- @Override
- public void onTaskDescriptionChanged(RunningTaskInfo taskInfo) {
- mHandler.obtainMessage(H.ON_TASK_DESCRIPTION_CHANGED, taskInfo).sendToTarget();
- }
-
- @Override
- public void onActivityRotation(int displayId) {
- mHandler.obtainMessage(H.ON_ACTIVITY_ROTATION, displayId, 0 /* unused */)
- .sendToTarget();
- }
-
- private final class H extends Handler {
private static final int ON_TASK_STACK_CHANGED = 1;
private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
private static final int ON_ACTIVITY_PINNED = 3;
@@ -268,13 +98,205 @@
private static final int ON_TASK_DESCRIPTION_CHANGED = 24;
private static final int ON_ACTIVITY_ROTATION = 25;
+ /**
+ * List of {@link TaskStackChangeListener} registered from {@link #addListener}.
+ */
+ private final List<TaskStackChangeListener> mTaskStackListeners = new ArrayList<>();
+ private final List<TaskStackChangeListener> mTmpListeners = new ArrayList<>();
- public H(Looper looper) {
- super(looper);
+ private final Handler mHandler;
+ private boolean mRegistered;
+
+ Impl(Looper looper) {
+ mHandler = new Handler(looper, this);
+ }
+
+ public void addListener(TaskStackChangeListener listener) {
+ synchronized (mTaskStackListeners) {
+ mTaskStackListeners.add(listener);
+ }
+ if (!mRegistered) {
+ // Register mTaskStackListener to IActivityManager only once if needed.
+ try {
+ ActivityTaskManager.getService().registerTaskStackListener(this);
+ mRegistered = true;
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to call registerTaskStackListener", e);
+ }
+ }
+ }
+
+ public void removeListener(TaskStackChangeListener listener) {
+ boolean isEmpty;
+ synchronized (mTaskStackListeners) {
+ mTaskStackListeners.remove(listener);
+ isEmpty = mTaskStackListeners.isEmpty();
+ }
+ if (isEmpty && mRegistered) {
+ // Unregister mTaskStackListener once we have no more listeners
+ try {
+ ActivityTaskManager.getService().unregisterTaskStackListener(this);
+ mRegistered = false;
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to call unregisterTaskStackListener", e);
+ }
+ }
}
@Override
- public void handleMessage(Message msg) {
+ public void onTaskStackChanged() {
+ // Call the task changed callback for the non-ui thread listeners first. Copy to a set
+ // of temp listeners so that we don't lock on mTaskStackListeners while calling all the
+ // callbacks. This call is always on the same binder thread, so we can just synchronize
+ // on the copying of the listener list.
+ synchronized (mTaskStackListeners) {
+ mTmpListeners.addAll(mTaskStackListeners);
+ }
+ for (int i = mTmpListeners.size() - 1; i >= 0; i--) {
+ mTmpListeners.get(i).onTaskStackChangedBackground();
+ }
+ mTmpListeners.clear();
+
+ mHandler.removeMessages(ON_TASK_STACK_CHANGED);
+ mHandler.sendEmptyMessage(ON_TASK_STACK_CHANGED);
+ }
+
+ @Override
+ public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
+ mHandler.removeMessages(ON_ACTIVITY_PINNED);
+ mHandler.obtainMessage(ON_ACTIVITY_PINNED,
+ new PinnedActivityInfo(packageName, userId, taskId, stackId)).sendToTarget();
+ }
+
+ @Override
+ public void onActivityUnpinned() {
+ mHandler.removeMessages(ON_ACTIVITY_UNPINNED);
+ mHandler.sendEmptyMessage(ON_ACTIVITY_UNPINNED);
+ }
+
+ @Override
+ public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+ boolean clearedTask, boolean wasVisible) {
+ final SomeArgs args = SomeArgs.obtain();
+ args.arg1 = task;
+ args.argi1 = homeTaskVisible ? 1 : 0;
+ args.argi2 = clearedTask ? 1 : 0;
+ args.argi3 = wasVisible ? 1 : 0;
+ mHandler.removeMessages(ON_ACTIVITY_RESTART_ATTEMPT);
+ mHandler.obtainMessage(ON_ACTIVITY_RESTART_ATTEMPT, args).sendToTarget();
+ }
+
+ @Override
+ public void onActivityForcedResizable(String packageName, int taskId, int reason) {
+ mHandler.obtainMessage(ON_ACTIVITY_FORCED_RESIZABLE, taskId, reason, packageName)
+ .sendToTarget();
+ }
+
+ @Override
+ public void onActivityDismissingDockedStack() {
+ mHandler.sendEmptyMessage(ON_ACTIVITY_DISMISSING_DOCKED_STACK);
+ }
+
+ @Override
+ public void onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo taskInfo,
+ int requestedDisplayId) {
+ mHandler.obtainMessage(ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED,
+ requestedDisplayId,
+ 0 /* unused */,
+ taskInfo).sendToTarget();
+ }
+
+ @Override
+ public void onActivityLaunchOnSecondaryDisplayRerouted(RunningTaskInfo taskInfo,
+ int requestedDisplayId) {
+ mHandler.obtainMessage(ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED,
+ requestedDisplayId, 0 /* unused */, taskInfo).sendToTarget();
+ }
+
+ @Override
+ public void onTaskProfileLocked(int taskId, int userId) {
+ mHandler.obtainMessage(ON_TASK_PROFILE_LOCKED, taskId, userId).sendToTarget();
+ }
+
+ @Override
+ public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) {
+ mHandler.obtainMessage(ON_TASK_SNAPSHOT_CHANGED, taskId, 0, snapshot).sendToTarget();
+ }
+
+ @Override
+ public void onTaskCreated(int taskId, ComponentName componentName) {
+ mHandler.obtainMessage(ON_TASK_CREATED, taskId, 0, componentName).sendToTarget();
+ }
+
+ @Override
+ public void onTaskRemoved(int taskId) {
+ mHandler.obtainMessage(ON_TASK_REMOVED, taskId, 0).sendToTarget();
+ }
+
+ @Override
+ public void onTaskMovedToFront(RunningTaskInfo taskInfo) {
+ mHandler.obtainMessage(ON_TASK_MOVED_TO_FRONT, taskInfo).sendToTarget();
+ }
+
+ @Override
+ public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
+ mHandler.obtainMessage(ON_BACK_PRESSED_ON_TASK_ROOT, taskInfo).sendToTarget();
+ }
+
+ @Override
+ public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) {
+ mHandler.obtainMessage(ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE, taskId,
+ requestedOrientation).sendToTarget();
+ }
+
+ @Override
+ public void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken) {
+ mHandler.obtainMessage(ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED, displayId,
+ 0 /* unused */,
+ activityToken).sendToTarget();
+ }
+
+ @Override
+ public void onSingleTaskDisplayDrawn(int displayId) {
+ mHandler.obtainMessage(ON_SINGLE_TASK_DISPLAY_DRAWN, displayId,
+ 0 /* unused */).sendToTarget();
+ }
+
+ @Override
+ public void onSingleTaskDisplayEmpty(int displayId) {
+ mHandler.obtainMessage(ON_SINGLE_TASK_DISPLAY_EMPTY, displayId,
+ 0 /* unused */).sendToTarget();
+ }
+
+ @Override
+ public void onTaskDisplayChanged(int taskId, int newDisplayId) {
+ mHandler.obtainMessage(ON_TASK_DISPLAY_CHANGED, taskId, newDisplayId).sendToTarget();
+ }
+
+ @Override
+ public void onRecentTaskListUpdated() {
+ mHandler.obtainMessage(ON_TASK_LIST_UPDATED).sendToTarget();
+ }
+
+ @Override
+ public void onRecentTaskListFrozenChanged(boolean frozen) {
+ mHandler.obtainMessage(ON_TASK_LIST_FROZEN_UNFROZEN, frozen ? 1 : 0, 0 /* unused */)
+ .sendToTarget();
+ }
+
+ @Override
+ public void onTaskDescriptionChanged(RunningTaskInfo taskInfo) {
+ mHandler.obtainMessage(ON_TASK_DESCRIPTION_CHANGED, taskInfo).sendToTarget();
+ }
+
+ @Override
+ public void onActivityRotation(int displayId) {
+ mHandler.obtainMessage(ON_ACTIVITY_ROTATION, displayId, 0 /* unused */)
+ .sendToTarget();
+ }
+
+ @Override
+ public boolean handleMessage(Message msg) {
synchronized (mTaskStackListeners) {
switch (msg.what) {
case ON_TASK_STACK_CHANGED: {
@@ -298,7 +320,8 @@
final PinnedActivityInfo info = (PinnedActivityInfo) msg.obj;
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
mTaskStackListeners.get(i).onActivityPinned(
- info.mPackageName, info.mUserId, info.mTaskId, info.mStackId);
+ info.mPackageName, info.mUserId, info.mTaskId,
+ info.mStackId);
}
break;
}
@@ -404,8 +427,7 @@
}
case ON_SINGLE_TASK_DISPLAY_EMPTY: {
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
- mTaskStackListeners.get(i).onSingleTaskDisplayEmpty(
- msg.arg1);
+ mTaskStackListeners.get(i).onSingleTaskDisplayEmpty(msg.arg1);
}
break;
}
@@ -423,7 +445,8 @@
}
case ON_TASK_LIST_FROZEN_UNFROZEN: {
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
- mTaskStackListeners.get(i).onRecentTaskListFrozenChanged(msg.arg1 != 0);
+ mTaskStackListeners.get(i).onRecentTaskListFrozenChanged(
+ msg.arg1 != 0);
}
break;
}
@@ -445,6 +468,7 @@
if (msg.obj instanceof SomeArgs) {
((SomeArgs) msg.obj).recycle();
}
+ return true;
}
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
index 73783ae..4a28d56 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
@@ -34,10 +34,6 @@
}
public SurfaceControl getRenderSurfaceControl() {
- return mViewRoot == null ? null : mViewRoot.getRenderSurfaceControl();
- }
-
- public SurfaceControl getSurfaceControl() {
return mViewRoot == null ? null : mViewRoot.getSurfaceControl();
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
index 5122f6c..97196d1 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
@@ -102,6 +102,18 @@
}
/**
+ * Sets if app requested fixed orientation should be ignored for given displayId.
+ */
+ public void setIgnoreOrientationRequest(int displayId, boolean ignoreOrientationRequest) {
+ try {
+ WindowManagerGlobal.getWindowManagerService().setIgnoreOrientationRequest(
+ displayId, ignoreOrientationRequest);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to setIgnoreOrientationRequest()", e);
+ }
+ }
+
+ /**
* @return the stable insets for the primary display.
*/
public void getStableInsets(Rect outStableInsets) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 5ad8cad..272954d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -104,6 +104,8 @@
private boolean mSupportsDarkText;
private int[] mColorPalette;
+ private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
+
public KeyguardClockSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -128,6 +130,35 @@
return mClockPlugin != null;
}
+ /**
+ * Update lock screen mode for testing different layouts
+ */
+ public void updateLockScreenMode(int mode) {
+ mLockScreenMode = mode;
+ RelativeLayout.LayoutParams statusAreaLP = (RelativeLayout.LayoutParams)
+ mKeyguardStatusArea.getLayoutParams();
+ RelativeLayout.LayoutParams clockLP = (RelativeLayout.LayoutParams)
+ mSmallClockFrame.getLayoutParams();
+
+ if (mode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
+ statusAreaLP.removeRule(RelativeLayout.BELOW);
+ statusAreaLP.addRule(RelativeLayout.LEFT_OF, R.id.clock_view);
+ statusAreaLP.addRule(RelativeLayout.ALIGN_PARENT_START);
+
+ clockLP.addRule(RelativeLayout.ALIGN_PARENT_END);
+ clockLP.width = ViewGroup.LayoutParams.WRAP_CONTENT;
+ } else {
+ statusAreaLP.removeRule(RelativeLayout.LEFT_OF);
+ statusAreaLP.removeRule(RelativeLayout.ALIGN_PARENT_START);
+ statusAreaLP.addRule(RelativeLayout.BELOW, R.id.clock_view);
+
+ clockLP.removeRule(RelativeLayout.ALIGN_PARENT_END);
+ clockLP.width = ViewGroup.LayoutParams.MATCH_PARENT;
+ }
+
+ requestLayout();
+ }
+
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@@ -363,6 +394,10 @@
* these cases.
*/
void setKeyguardShowingHeader(boolean hasHeader) {
+ if (mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL) {
+ hasHeader = false;
+ }
+
if (mShowingHeader == hasHeader) {
return;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 36d5543..901a736 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -20,7 +20,7 @@
import android.app.Presentation;
import android.content.Context;
import android.graphics.Color;
-import android.graphics.Point;
+import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.media.MediaRouter;
import android.media.MediaRouter.RouteInfo;
@@ -127,7 +127,7 @@
Presentation presentation = mPresentations.get(displayId);
if (presentation == null) {
final Presentation newPresentation = new KeyguardPresentation(mContext, display,
- mKeyguardStatusViewComponentFactory, LayoutInflater.from(mContext));
+ mKeyguardStatusViewComponentFactory);
newPresentation.setOnDismissListener(dialog -> {
if (newPresentation.equals(mPresentations.get(displayId))) {
mPresentations.remove(displayId);
@@ -245,7 +245,6 @@
private static final int VIDEO_SAFE_REGION = 80; // Percentage of display width & height
private static final int MOVE_CLOCK_TIMEOUT = 10000; // 10s
private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
- private final LayoutInflater mLayoutInflater;
private KeyguardClockSwitchController mKeyguardClockSwitchController;
private View mClock;
private int mUsableWidth;
@@ -264,18 +263,16 @@
};
KeyguardPresentation(Context context, Display display,
- KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory,
- LayoutInflater layoutInflater) {
- super(context, display, R.style.Theme_SystemUI_KeyguardPresentation);
+ KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory) {
+ super(context, display, R.style.Theme_SystemUI_KeyguardPresentation,
+ WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
- mLayoutInflater = layoutInflater;
- getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
setCancelable(false);
}
@Override
public void cancel() {
- // Do not allow anything to cancel KeyguardPresetation except KeyguardDisplayManager.
+ // Do not allow anything to cancel KeyguardPresentation except KeyguardDisplayManager.
}
@Override
@@ -287,14 +284,15 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- Point p = new Point();
- getDisplay().getSize(p);
- mUsableWidth = VIDEO_SAFE_REGION * p.x/100;
- mUsableHeight = VIDEO_SAFE_REGION * p.y/100;
- mMarginLeft = (100 - VIDEO_SAFE_REGION) * p.x / 200;
- mMarginTop = (100 - VIDEO_SAFE_REGION) * p.y / 200;
+ final Rect bounds = getWindow().getWindowManager().getMaximumWindowMetrics()
+ .getBounds();
+ mUsableWidth = VIDEO_SAFE_REGION * bounds.width() / 100;
+ mUsableHeight = VIDEO_SAFE_REGION * bounds.height() / 100;
+ mMarginLeft = (100 - VIDEO_SAFE_REGION) * bounds.width() / 200;
+ mMarginTop = (100 - VIDEO_SAFE_REGION) * bounds.height() / 200;
- setContentView(mLayoutInflater.inflate(R.layout.keyguard_presentation, null));
+ setContentView(LayoutInflater.from(getContext())
+ .inflate(R.layout.keyguard_presentation, null));
// Logic to make the lock screen fullscreen
getWindow().getDecorView().setSystemUiVisibility(
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 6e11174..9ef2def 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -79,6 +79,11 @@
private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
@Override
+ public void onLockScreenModeChanged(int mode) {
+ updateLockScreenMode(mode);
+ }
+
+ @Override
public void onTimeChanged() {
refreshTime();
}
@@ -255,6 +260,10 @@
mClockView.refresh();
}
+ private void updateLockScreenMode(int mode) {
+ mClockView.updateLockScreenMode(mode);
+ }
+
private void updateTimeZone(TimeZone timeZone) {
mClockView.onTimeZoneChanged(timeZone);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index bdb34bb..1a98c20 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -100,8 +100,8 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.util.Assert;
@@ -180,6 +180,10 @@
private static final int MSG_USER_STOPPED = 340;
private static final int MSG_USER_REMOVED = 341;
private static final int MSG_KEYGUARD_GOING_AWAY = 342;
+ private static final int MSG_LOCK_SCREEN_MODE = 343;
+
+ public static final int LOCK_SCREEN_MODE_NORMAL = 0;
+ public static final int LOCK_SCREEN_MODE_LAYOUT_1 = 1;
/** Biometric authentication state: Not listening. */
private static final int BIOMETRIC_STATE_STOPPED = 0;
@@ -263,6 +267,7 @@
private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
mCallbacks = Lists.newArrayList();
private ContentObserver mDeviceProvisionedObserver;
+ private ContentObserver mLockScreenModeObserver;
private boolean mSwitchingUser;
@@ -286,6 +291,7 @@
private boolean mLockIconPressed;
private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private final Executor mBackgroundExecutor;
+ private int mLockScreenMode;
/**
* Short delay before restarting fingerprint authentication after a successful try. This should
@@ -1694,6 +1700,9 @@
case MSG_KEYGUARD_GOING_AWAY:
handleKeyguardGoingAway((boolean) msg.obj);
break;
+ case MSG_LOCK_SCREEN_MODE:
+ handleLockScreenMode();
+ break;
default:
super.handleMessage(msg);
break;
@@ -1796,7 +1805,7 @@
mIsAutomotive = isAutomotive();
- ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
+ TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
mUserManager = context.getSystemService(UserManager.class);
mIsPrimaryUser = mUserManager.isPrimaryUser();
int user = ActivityManager.getCurrentUser();
@@ -1828,6 +1837,23 @@
}
}
}
+
+ updateLockScreenMode();
+ mLockScreenModeObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateLockScreenMode();
+ mHandler.sendEmptyMessage(MSG_LOCK_SCREEN_MODE);
+ }
+ };
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.SHOW_NEW_LOCKSCREEN),
+ false, mLockScreenModeObserver);
+ }
+
+ private void updateLockScreenMode() {
+ mLockScreenMode = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.SHOW_NEW_LOCKSCREEN, 0);
}
private final UserSwitchObserver mUserSwitchObserver = new UserSwitchObserver() {
@@ -2350,6 +2376,20 @@
}
/**
+ * Handle {@link #MSG_LOCK_SCREEN_MODE}
+ */
+ private void handleLockScreenMode() {
+ Assert.isMainThread();
+ if (DEBUG) Log.d(TAG, "handleLockScreenMode(" + mLockScreenMode + ")");
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onLockScreenModeChanged(mLockScreenMode);
+ }
+ }
+ }
+
+ /**
* Handle (@line #MSG_TIMEZONE_UPDATE}
*/
private void handleTimeZoneUpdate(String timeZone) {
@@ -2668,6 +2708,8 @@
callback.onClockVisibilityChanged();
callback.onKeyguardVisibilityChangedRaw(mKeyguardIsVisible);
callback.onTelephonyCapable(mTelephonyCapable);
+ callback.onLockScreenModeChanged(mLockScreenMode);
+
for (Entry<Integer, SimData> data : mSimDatas.entrySet()) {
final SimData state = data.getValue();
callback.onSimStateChanged(state.subId, state.slotId, state.simState);
@@ -2959,13 +3001,17 @@
mContext.getContentResolver().unregisterContentObserver(mDeviceProvisionedObserver);
}
+ if (mLockScreenModeObserver != null) {
+ mContext.getContentResolver().unregisterContentObserver(mLockScreenModeObserver);
+ }
+
try {
ActivityManager.getService().unregisterUserSwitchObserver(mUserSwitchObserver);
} catch (RemoteException e) {
Log.d(TAG, "RemoteException onDestroy. cannot unregister userSwitchObserver");
}
- ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskStackListener);
+ TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
mBroadcastDispatcher.unregisterReceiver(mBroadcastAllReceiver);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 12e0ecd..3c5eceb 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -317,4 +317,9 @@
*/
public void onSecondaryLockscreenRequirementChanged(int userId) { }
+ /**
+ * Called to switch lock screen layout/clock layouts
+ */
+ public void onLockScreenModeChanged(int mode) { }
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 4657b06..f210d50 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -72,8 +72,6 @@
Key.QS_HAS_TURNED_OFF_MOBILE_DATA,
Key.TOUCHED_RINGER_TOGGLE,
Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP,
- Key.HAS_SEEN_BUBBLES_EDUCATION,
- Key.HAS_SEEN_BUBBLES_MANAGE_EDUCATION,
Key.HAS_SEEN_REVERSE_BOTTOM_SHEET,
Key.CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT,
Key.HAS_SEEN_PRIORITY_ONBOARDING
@@ -123,8 +121,6 @@
String QS_HAS_TURNED_OFF_MOBILE_DATA = "QsHasTurnedOffMobileData";
String TOUCHED_RINGER_TOGGLE = "TouchedRingerToggle";
String HAS_SEEN_ODI_CAPTIONS_TOOLTIP = "HasSeenODICaptionsTooltip";
- String HAS_SEEN_BUBBLES_EDUCATION = "HasSeenBubblesOnboarding";
- String HAS_SEEN_BUBBLES_MANAGE_EDUCATION = "HasSeenBubblesManageOnboarding";
String HAS_SEEN_REVERSE_BOTTOM_SHEET = "HasSeenReverseBottomSheet";
String CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT = "ControlsStructureSwipeTooltipCount";
/** Tracks whether the user has seen the onboarding screen for priority conversations */
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index c4a305e..2592a2c 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -582,6 +582,10 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
+ if (DEBUG_DISABLE_SCREEN_DECORATIONS) {
+ Log.i(TAG, "ScreenDecorations is disabled");
+ return;
+ }
mHandler.post(() -> {
int oldRotation = mRotation;
mPendingRotationChange = false;
@@ -766,6 +770,10 @@
@Override
public void onTuningChanged(String key, String newValue) {
+ if (DEBUG_DISABLE_SCREEN_DECORATIONS) {
+ Log.i(TAG, "ScreenDecorations is disabled");
+ return;
+ }
mHandler.post(() -> {
if (mOverlays == null) return;
if (SIZE.equals(key)) {
diff --git a/packages/SystemUI/src/com/android/systemui/SizeCompatModeActivityController.java b/packages/SystemUI/src/com/android/systemui/SizeCompatModeActivityController.java
index 34efa35..02f34ac 100644
--- a/packages/SystemUI/src/com/android/systemui/SizeCompatModeActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/SizeCompatModeActivityController.java
@@ -42,8 +42,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.statusbar.CommandQueue;
import java.lang.ref.WeakReference;
@@ -66,11 +66,11 @@
@VisibleForTesting
@Inject
- SizeCompatModeActivityController(Context context, ActivityManagerWrapper am,
+ SizeCompatModeActivityController(Context context, TaskStackChangeListeners listeners,
CommandQueue commandQueue) {
super(context);
mCommandQueue = commandQueue;
- am.registerTaskStackListener(new TaskStackChangeListener() {
+ listeners.registerTaskStackListener(new TaskStackChangeListener() {
@Override
public void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken) {
// Note the callback already runs on main thread.
diff --git a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
index 2365f12..47adffc 100644
--- a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
@@ -111,9 +111,7 @@
final String providerPkg = getIntent().getStringExtra("provider_pkg");
if (providerPkg == null || mProviderPkg.equals(providerPkg)) return;
final String callingPkg = getCallingPkg();
- EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg), String.format(
- "pkg %s (disguised as %s) attempted to request permission to show %s slices in %s",
- callingPkg, providerPkg, mProviderPkg, mCallingPkg));
+ EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg));
}
@Nullable
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index c3474bb..340ca04 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -249,8 +249,8 @@
if ((configDiff & ActivityInfo.CONFIG_DENSITY) != 0) {
updateDimensions();
if (isWindowVisible()) {
- mWm.removeView(mMirrorView);
- createMirrorWindow();
+ deleteWindowMagnification();
+ enableWindowMagnification(Float.NaN, Float.NaN, Float.NaN);
}
} else if ((configDiff & ActivityInfo.CONFIG_ORIENTATION) != 0) {
onRotate();
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
index 02a672b..c1c2de1 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
@@ -47,6 +47,7 @@
import com.android.systemui.shared.system.PackageManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.statusbar.StatusBarState;
import java.io.PrintWriter;
@@ -171,6 +172,7 @@
private final DeviceConfigHelper mDeviceConfigHelper;
private final Lazy<StatusBarStateController> mStatusBarStateController;
private final Lazy<ActivityManagerWrapper> mActivityManagerWrapper;
+ private final Lazy<TaskStackChangeListeners> mTaskStackChangeListeners;
private final Lazy<OverviewProxyService> mOverviewProxyService;
private final Lazy<SysUiState> mSysUiFlagContainer;
private final Lazy<WakefulnessLifecycle> mWakefulnessLifecycle;
@@ -207,6 +209,7 @@
DeviceConfigHelper deviceConfigHelper,
Lazy<StatusBarStateController> statusBarStateController,
Lazy<ActivityManagerWrapper> activityManagerWrapper,
+ Lazy<TaskStackChangeListeners> taskStackChangeListeners,
Lazy<OverviewProxyService> overviewProxyService,
Lazy<SysUiState> sysUiFlagContainer,
Lazy<WakefulnessLifecycle> wakefulnessLifecycle,
@@ -218,6 +221,7 @@
mDeviceConfigHelper = deviceConfigHelper;
mStatusBarStateController = statusBarStateController;
mActivityManagerWrapper = activityManagerWrapper;
+ mTaskStackChangeListeners = taskStackChangeListeners;
mOverviewProxyService = overviewProxyService;
mSysUiFlagContainer = sysUiFlagContainer;
mWakefulnessLifecycle = wakefulnessLifecycle;
@@ -245,7 +249,7 @@
ActivityManager.RunningTaskInfo runningTaskInfo =
mActivityManagerWrapper.get().getRunningTask();
mRunningTaskId = runningTaskInfo == null ? 0 : runningTaskInfo.taskId;
- mActivityManagerWrapper.get().registerTaskStackListener(mTaskStackChangeListener);
+ mTaskStackChangeListeners.get().registerTaskStackListener(mTaskStackChangeListener);
mOverviewProxyService.get().addCallback(mOverviewProxyListener);
mSysUiFlagContainer.get().addCallback(mSysUiStateCallback);
mIsAwake = mWakefulnessLifecycle.get().getWakefulness()
@@ -300,7 +304,7 @@
mContext = null;
}
mStatusBarStateController.get().removeCallback(mStatusBarStateListener);
- mActivityManagerWrapper.get().unregisterTaskStackListener(mTaskStackChangeListener);
+ mTaskStackChangeListeners.get().unregisterTaskStackListener(mTaskStackChangeListener);
mOverviewProxyService.get().removeCallback(mOverviewProxyListener);
mSysUiFlagContainer.get().removeCallback(mSysUiStateCallback);
mWakefulnessLifecycle.get().removeObserver(mWakefulnessLifecycleObserver);
diff --git a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
index 50d559b..61951cc 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
@@ -35,6 +35,7 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.PackageManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -82,7 +83,6 @@
mStatusBarOptionalLazy = statusBarOptionalLazy;
mStatusBarStateController = Dependency.get(StatusBarStateController.class);
- ActivityManagerWrapper activityManagerWrapper = ActivityManagerWrapper.getInstance();
mDefaultHome = getCurrentDefaultHome();
bootCompleteCache.addListener(() -> mDefaultHome = getCurrentDefaultHome());
IntentFilter intentFilter = new IntentFilter();
@@ -95,12 +95,13 @@
mDefaultHome = getCurrentDefaultHome();
}
}, intentFilter);
- mLauncherShowing = isLauncherShowing(activityManagerWrapper.getRunningTask());
- activityManagerWrapper.registerTaskStackListener(new TaskStackChangeListener() {
- @Override
- public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
- mLauncherShowing = isLauncherShowing(taskInfo);
- }
+ mLauncherShowing = isLauncherShowing(ActivityManagerWrapper.getInstance().getRunningTask());
+ TaskStackChangeListeners.getInstance().registerTaskStackListener(
+ new TaskStackChangeListener() {
+ @Override
+ public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
+ mLauncherShowing = isLauncherShowing(taskInfo);
+ }
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 529af22..57d8dc7 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -15,8 +15,8 @@
*/
package com.android.systemui.bubbles;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.os.AsyncTask.Status.FINISHED;
-import static android.view.Display.INVALID_DISPLAY;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
@@ -256,7 +256,8 @@
}
/**
- * Cleanup expanded view for bubbles going into overflow.
+ * Call this to clean up the task for the bubble. Ensure this is always called when done with
+ * the bubble.
*/
void cleanupExpandedView() {
if (mExpandedView != null) {
@@ -270,8 +271,7 @@
}
/**
- * Call when the views should be removed, ensure this is called to clean up ActivityView
- * content.
+ * Call when all the views should be removed/cleaned up.
*/
void cleanupViews() {
cleanupExpandedView();
@@ -468,14 +468,6 @@
return mIntentActive;
}
- /**
- * @return the display id of the virtual display on which bubble contents is drawn.
- */
- @Override
- public int getDisplayId() {
- return mExpandedView != null ? mExpandedView.getVirtualDisplayId() : INVALID_DISPLAY;
- }
-
public InstanceId getInstanceId() {
return mInstanceId;
}
@@ -490,6 +482,14 @@
}
/**
+ * @return the task id of the task in which bubble contents is drawn.
+ */
+ @Override
+ public int getTaskId() {
+ return mExpandedView != null ? mExpandedView.getTaskId() : INVALID_TASK_ID;
+ }
+
+ /**
* Should be invoked whenever a Bubble is accessed (selected while expanded).
*/
void markAsAccessedAt(long lastAccessedMillis) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 2372529..3f94b00 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -16,6 +16,7 @@
package com.android.systemui.bubbles;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.Notification.FLAG_BUBBLE;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;
@@ -27,8 +28,6 @@
import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
import static android.service.notification.NotificationStats.DISMISSAL_BUBBLE;
import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.Display.INVALID_DISPLAY;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
@@ -46,6 +45,7 @@
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityTaskManager;
import android.app.INotificationManager;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -70,7 +70,6 @@
import android.util.Log;
import android.util.Pair;
import android.util.SparseSetArray;
-import android.view.Display;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
@@ -80,15 +79,18 @@
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dumpable;
import com.android.systemui.bubbles.dagger.BubbleModule;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
@@ -111,6 +113,7 @@
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.pip.PinnedStackListenerForwarder;
@@ -168,8 +171,8 @@
private final ShadeController mShadeController;
private final FloatingContentCoordinator mFloatingContentCoordinator;
private final BubbleDataRepository mDataRepository;
- private BubbleLogger mLogger = new BubbleLoggerImpl();
-
+ private BubbleLogger mLogger;
+ private final Handler mMainHandler;
private BubbleData mBubbleData;
private ScrimView mBubbleScrim;
@Nullable private BubbleStackView mStackView;
@@ -241,6 +244,8 @@
private boolean mInflateSynchronously;
+ private MultiWindowTaskListener mTaskListener;
+
// TODO (b/145659174): allow for multiple callbacks to support the "shadow" new notif pipeline
private final List<NotifCallback> mCallbacks = new ArrayList<>();
@@ -365,20 +370,24 @@
FeatureFlags featureFlags,
DumpManager dumpManager,
FloatingContentCoordinator floatingContentCoordinator,
- BubbleDataRepository dataRepository,
SysUiState sysUiState,
INotificationManager notificationManager,
@Nullable IStatusBarService statusBarService,
WindowManager windowManager,
WindowManagerShellWrapper windowManagerShellWrapper,
- LauncherApps launcherApps) {
+ LauncherApps launcherApps,
+ UiEventLogger uiEventLogger,
+ @Main Handler mainHandler,
+ ShellTaskOrganizer organizer) {
+ BubbleLogger logger = new BubbleLogger(uiEventLogger);
return new BubbleController(context, notificationShadeWindowController,
- statusBarStateController, shadeController, new BubbleData(context), synchronizer,
- configurationController, interruptionStateProvider, zenModeController,
+ statusBarStateController, shadeController, new BubbleData(context, logger),
+ synchronizer, configurationController, interruptionStateProvider, zenModeController,
notifUserManager, groupManager, entryManager, notifPipeline, featureFlags,
- dumpManager, floatingContentCoordinator, dataRepository, sysUiState,
- notificationManager, statusBarService, windowManager, windowManagerShellWrapper,
- launcherApps);
+ dumpManager, floatingContentCoordinator,
+ new BubbleDataRepository(context, launcherApps), sysUiState, notificationManager,
+ statusBarService, windowManager, windowManagerShellWrapper, launcherApps, logger,
+ mainHandler, organizer);
}
/**
@@ -407,7 +416,10 @@
@Nullable IStatusBarService statusBarService,
WindowManager windowManager,
WindowManagerShellWrapper windowManagerShellWrapper,
- LauncherApps launcherApps) {
+ LauncherApps launcherApps,
+ BubbleLogger bubbleLogger,
+ Handler mainHandler,
+ ShellTaskOrganizer organizer) {
dumpManager.registerDumpable(TAG, this);
mContext = context;
mShadeController = shadeController;
@@ -417,6 +429,8 @@
mFloatingContentCoordinator = floatingContentCoordinator;
mDataRepository = dataRepository;
mINotificationManager = notificationManager;
+ mLogger = bubbleLogger;
+ mMainHandler = mainHandler;
mZenModeController.addCallback(new ZenModeController.Callback() {
@Override
public void onZenChanged(int zen) {
@@ -480,7 +494,7 @@
statusBarStateController.addCallback(mStatusBarStateListener);
mTaskStackListener = new BubbleTaskStackListener();
- ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
+ TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
try {
windowManagerShellWrapper.addPinnedStackListener(new BubblesImeListener());
@@ -515,6 +529,7 @@
});
mBubbleIconFactory = new BubbleIconFactory(context);
+ mTaskListener = new MultiWindowTaskListener(mMainHandler, organizer);
launcherApps.registerCallback(new LauncherApps.Callback() {
@Override
@@ -577,6 +592,12 @@
}
}
+ private void onBubbleExpandChanged(boolean shouldExpand) {
+ mSysUiState
+ .setFlag(QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED, shouldExpand)
+ .commitUpdate(mContext.getDisplayId());
+ }
+
private void setupNEM() {
mNotificationEntryManager.addNotificationEntryListener(
new NotificationEntryListener() {
@@ -783,6 +804,11 @@
return mBubbleData.getOverflowBubbles();
}
+ @Override
+ public MultiWindowTaskListener getTaskManager() {
+ return mTaskListener;
+ }
+
/**
* BubbleStackView is lazily created by this method the first time a Bubble is added. This
* method initializes the stack view and adds it to the StatusBar just above the scrim.
@@ -791,8 +817,8 @@
if (mStackView == null) {
mStackView = new BubbleStackView(
mContext, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator,
- mSysUiState, this::onAllBubblesAnimatedOut, this::onImeVisibilityChanged,
- this::hideCurrentInputMethod);
+ this::onAllBubblesAnimatedOut, this::onImeVisibilityChanged,
+ this::hideCurrentInputMethod, this::onBubbleExpandChanged);
mStackView.setStackStartPosition(mPositionFromRemovedStack);
mStackView.addView(mBubbleScrim);
if (mExpandListener != null) {
@@ -825,9 +851,8 @@
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
- // Start not focusable - we'll become focusable when expanded so the ActivityView
- // can use the IME.
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
PixelFormat.TRANSLUCENT);
@@ -843,16 +868,13 @@
mAddedToWindowManager = true;
mWindowManager.addView(mStackView, mWmLayoutParams);
} catch (IllegalStateException e) {
- // This means the stack has already been added. This shouldn't happen, since we keep
- // track of that, but just in case, update the previously added view's layout params.
+ // This means the stack has already been added. This shouldn't happen...
e.printStackTrace();
- updateWmFlags();
}
}
private void onImeVisibilityChanged(boolean imeVisible) {
mImeVisible = imeVisible;
- updateWmFlags();
}
/** Removes the BubbleStackView from the WindowManager if it's there. */
@@ -879,35 +901,6 @@
}
/**
- * Updates the BubbleStackView's WindowManager.LayoutParams, and updates the WindowManager with
- * the new params if the stack has been added.
- */
- private void updateWmFlags() {
- if (mStackView == null) {
- return;
- }
- if (isStackExpanded() && !mImeVisible) {
- // If we're expanded, and the IME isn't visible, we want to be focusable. This ensures
- // that any taps within Bubbles (including on the ActivityView) results in Bubbles
- // receiving focus and clearing it from any other windows that might have it.
- mWmLayoutParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- } else {
- // If we're collapsed, we don't want to be focusable since tapping on the stack would
- // steal focus from apps. We also don't want to be focusable if the IME is visible,
- mWmLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- }
-
- if (mAddedToWindowManager) {
- try {
- mWindowManager.updateViewLayout(mStackView, mWmLayoutParams);
- } catch (IllegalArgumentException e) {
- // If the stack is somehow not there, ignore the attempt to update it.
- e.printStackTrace();
- }
- }
- }
-
- /**
* Called by the BubbleStackView and whenever all bubbles have animated out, and none have been
* added in the meantime.
*/
@@ -1015,8 +1008,6 @@
if (listener != null) {
listener.onBubbleExpandChanged(isExpanding, key);
}
-
- updateWmFlags();
});
if (mStackView != null) {
mStackView.setExpandListener(mExpandListener);
@@ -1060,7 +1051,7 @@
@Override
public boolean isBubbleExpanded(NotificationEntry entry) {
return isStackExpanded() && mBubbleData != null && mBubbleData.getSelectedBubble() != null
- && mBubbleData.getSelectedBubble().getKey().equals(entry.getKey()) ? true : false;
+ && mBubbleData.getSelectedBubble().getKey().equals(entry.getKey());
}
@Override
@@ -1115,13 +1106,6 @@
}
}
- @Override
- public void performBackPressIfNeeded() {
- if (mStackView != null) {
- mStackView.performBackPressIfNeeded();
- }
- }
-
/**
* Adds or updates a bubble associated with the provided notification entry.
*
@@ -1602,19 +1586,21 @@
mStackView.updateContentDescription();
}
- @Override
- public int getExpandedDisplayId(Context context) {
+ /**
+ * The task id of the expanded view, if the stack is expanded and not occluded by the
+ * status bar, otherwise returns {@link ActivityTaskManager#INVALID_TASK_ID}.
+ */
+ private int getExpandedTaskId() {
if (mStackView == null) {
- return INVALID_DISPLAY;
+ return INVALID_TASK_ID;
}
- final boolean defaultDisplay = context.getDisplay() != null
- && context.getDisplay().getDisplayId() == DEFAULT_DISPLAY;
final BubbleViewProvider expandedViewProvider = mStackView.getExpandedBubble();
- if (defaultDisplay && expandedViewProvider != null && isStackExpanded()
+ if (expandedViewProvider != null && isStackExpanded()
+ && !mStackView.isExpansionAnimating()
&& !mNotificationShadeWindowController.getPanelExpanded()) {
- return expandedViewProvider.getDisplayId();
+ return expandedViewProvider.getTaskId();
}
- return INVALID_DISPLAY;
+ return INVALID_TASK_ID;
}
@VisibleForTesting
@@ -1648,18 +1634,17 @@
@Override
public void onTaskMovedToFront(RunningTaskInfo taskInfo) {
- if (mStackView != null && taskInfo.displayId == Display.DEFAULT_DISPLAY) {
- if (!mStackView.isExpansionAnimating()) {
- mBubbleData.setExpanded(false);
- }
+ int expandedId = getExpandedTaskId();
+ if (expandedId != INVALID_TASK_ID && expandedId != taskInfo.taskId) {
+ mBubbleData.setExpanded(false);
}
}
@Override
- public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+ public void onActivityRestartAttempt(RunningTaskInfo taskInfo, boolean homeTaskVisible,
boolean clearedTask, boolean wasVisible) {
for (Bubble b : mBubbleData.getBubbles()) {
- if (b.getDisplayId() == task.displayId) {
+ if (taskInfo.taskId == b.getTaskId()) {
mBubbleData.setSelectedBubble(b);
mBubbleData.setExpanded(true);
return;
@@ -1667,43 +1652,6 @@
}
}
- @Override
- public void onActivityLaunchOnSecondaryDisplayRerouted() {
- if (mStackView != null) {
- mBubbleData.setExpanded(false);
- }
- }
-
- @Override
- public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
- if (mStackView != null && taskInfo.displayId == getExpandedDisplayId(mContext)) {
- if (mImeVisible) {
- hideCurrentInputMethod();
- } else {
- mBubbleData.setExpanded(false);
- }
- }
- }
-
- @Override
- public void onSingleTaskDisplayDrawn(int displayId) {
- if (mStackView == null) {
- return;
- }
- mStackView.showExpandedViewContents(displayId);
- }
-
- @Override
- public void onSingleTaskDisplayEmpty(int displayId) {
- final BubbleViewProvider expandedBubble = mStackView != null
- ? mStackView.getExpandedBubble()
- : null;
- int expandedId = expandedBubble != null ? expandedBubble.getDisplayId() : -1;
- if (mStackView != null && mStackView.isExpanded() && expandedId == displayId) {
- mBubbleData.setExpanded(false);
- }
- mBubbleData.notifyDisplayEmpty(displayId);
- }
}
/**
@@ -1747,6 +1695,7 @@
}
/** PinnedStackListener that dispatches IME visibility updates to the stack. */
+ //TODO(b/170442945): Better way to do this / insets listener?
private class BubblesImeListener extends PinnedStackListenerForwarder.PinnedStackListener {
@Override
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index 55ecb22..b4626f2 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -32,10 +32,9 @@
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.systemui.R;
import com.android.systemui.bubbles.BubbleController.DismissReason;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.shared.system.SysUiStatsLog;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -53,10 +52,9 @@
/**
* Keeps track of active bubbles.
*/
-@SysUISingleton
public class BubbleData {
- private BubbleLoggerImpl mLogger = new BubbleLoggerImpl();
+ private BubbleLogger mLogger;
private int mCurrentUserId;
@@ -155,8 +153,9 @@
*/
private HashMap<String, String> mSuppressedGroupKeys = new HashMap<>();
- public BubbleData(Context context) {
+ public BubbleData(Context context, BubbleLogger bubbleLogger) {
mContext = context;
+ mLogger = bubbleLogger;
mBubbles = new ArrayList<>();
mOverflowBubbles = new ArrayList<>();
mPendingBubbles = new HashMap<>();
@@ -552,22 +551,6 @@
dispatchPendingChanges();
}
- /**
- * Indicates that the provided display is no longer in use and should be cleaned up.
- *
- * @param displayId the id of the display to clean up.
- */
- void notifyDisplayEmpty(int displayId) {
- for (Bubble b : mBubbles) {
- if (b.getDisplayId() == displayId) {
- if (b.getExpandedView() != null) {
- b.getExpandedView().notifyDisplayEmpty();
- }
- return;
- }
- }
- }
-
private void dispatchPendingChanges() {
if (mListener != null && mStateChange.anythingChanged()) {
mListener.applyUpdate(mStateChange);
@@ -618,12 +601,12 @@
* @param normalX Normalized x position of the stack
* @param normalY Normalized y position of the stack
*/
- void logBubbleEvent(@Nullable BubbleViewProvider provider, int action, String packageName,
+ void logBubbleEvent(@Nullable BubbleViewProvider provider, int action, String packageName,
int bubbleCount, int bubbleIndex, float normalX, float normalY) {
if (provider == null) {
mLogger.logStackUiChanged(packageName, action, bubbleCount, normalX, normalY);
} else if (provider.getKey().equals(BubbleOverflow.KEY)) {
- if (action == SysUiStatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED) {
+ if (action == FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED) {
mLogger.logShowOverflow(packageName, mCurrentUserId);
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
index f129d31..2ab9e87 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
@@ -17,6 +17,7 @@
import android.annotation.SuppressLint
import android.annotation.UserIdInt
+import android.content.Context
import android.content.pm.LauncherApps
import android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_CACHED
import android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC
@@ -26,21 +27,16 @@
import com.android.systemui.bubbles.storage.BubbleEntity
import com.android.systemui.bubbles.storage.BubblePersistentRepository
import com.android.systemui.bubbles.storage.BubbleVolatileRepository
-import com.android.systemui.dagger.SysUISingleton
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.launch
import kotlinx.coroutines.yield
-import javax.inject.Inject
-@SysUISingleton
-internal class BubbleDataRepository @Inject constructor(
- private val volatileRepository: BubbleVolatileRepository,
- private val persistentRepository: BubblePersistentRepository,
- private val launcherApps: LauncherApps
-) {
+internal class BubbleDataRepository(context: Context, private val launcherApps: LauncherApps) {
+ private val volatileRepository = BubbleVolatileRepository(launcherApps)
+ private val persistentRepository = BubblePersistentRepository(context)
private val ioScope = CoroutineScope(Dispatchers.IO)
private val uiScope = CoroutineScope(Dispatchers.Main)
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 3af36a9..98a2257 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -16,16 +16,10 @@
package com.android.systemui.bubbles;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
-import static android.graphics.PixelFormat.TRANSPARENT;
-import static android.view.Display.INVALID_DISPLAY;
-import static android.view.InsetsState.ITYPE_IME;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_EXPANDED_VIEW;
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
@@ -34,10 +28,7 @@
import android.annotation.NonNull;
import android.annotation.SuppressLint;
-import android.app.ActivityManager;
import android.app.ActivityOptions;
-import android.app.ActivityTaskManager;
-import android.app.ActivityView;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -50,19 +41,13 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.ShapeDrawable;
-import android.hardware.display.VirtualDisplay;
-import android.os.Binder;
import android.os.Bundle;
-import android.os.RemoteException;
import android.util.AttributeSet;
import android.util.Log;
-import android.view.Gravity;
import android.view.SurfaceControl;
-import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
-import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
@@ -84,18 +69,6 @@
*/
public class BubbleExpandedView extends LinearLayout {
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleExpandedView" : TAG_BUBBLES;
- private static final String WINDOW_TITLE = "ImeInsetsWindowWithoutContent";
-
- private enum ActivityViewStatus {
- // ActivityView is being initialized, cannot start an activity yet.
- INITIALIZING,
- // ActivityView is initialized, and ready to start an activity.
- INITIALIZED,
- // Activity runs in the ActivityView.
- ACTIVITY_STARTED,
- // ActivityView is released, so activity launching will no longer be permitted.
- RELEASED,
- }
// The triangle pointing to the expanded view
private View mPointerView;
@@ -103,16 +76,11 @@
@Nullable private int[] mExpandedViewContainerLocation;
private AlphaOptimizedButton mSettingsIcon;
+ private TaskView mTaskView;
- // Views for expanded state
- private ActivityView mActivityView;
+ private int mTaskId = INVALID_TASK_ID;
- private ActivityViewStatus mActivityViewStatus = ActivityViewStatus.INITIALIZING;
- private int mTaskId = -1;
-
- private PendingIntent mPendingIntent;
-
- private boolean mKeyboardVisible;
+ private boolean mImeVisible;
private boolean mNeedsNewHeight;
private Point mDisplaySize;
@@ -123,123 +91,104 @@
private int mPointerHeight;
private ShapeDrawable mPointerDrawable;
private int mExpandedViewPadding;
-
+ private float mCornerRadius = 0f;
@Nullable private Bubble mBubble;
+ private PendingIntent mPendingIntent;
private boolean mIsOverflow;
private Bubbles mBubbles = Dependency.get(Bubbles.class);
private WindowManager mWindowManager;
- private ActivityManager mActivityManager;
-
private BubbleStackView mStackView;
- private View mVirtualImeView;
- private WindowManager mVirtualDisplayWindowManager;
- private boolean mImeShowing = false;
- private float mCornerRadius = 0f;
/**
* Container for the ActivityView that has a solid, round-rect background that shows if the
* ActivityView hasn't loaded.
*/
- private FrameLayout mActivityViewContainer = new FrameLayout(getContext());
+ private final FrameLayout mExpandedViewContainer = new FrameLayout(getContext());
- /** The SurfaceView that the ActivityView draws to. */
- @Nullable private SurfaceView mActivitySurface;
+ private final TaskView.Listener mTaskViewListener = new TaskView.Listener() {
+ private boolean mInitialized = false;
+ private boolean mDestroyed = false;
- private ActivityView.StateCallback mStateCallback = new ActivityView.StateCallback() {
@Override
- public void onActivityViewReady(ActivityView view) {
+ public void onInitialized() {
if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "onActivityViewReady: mActivityViewStatus=" + mActivityViewStatus
+ Log.d(TAG, "onActivityViewReady: destroyed=" + mDestroyed
+ + " initialized=" + mInitialized
+ " bubble=" + getBubbleKey());
}
- switch (mActivityViewStatus) {
- case INITIALIZING:
- case INITIALIZED:
- // Custom options so there is no activity transition animation
- ActivityOptions options = ActivityOptions.makeCustomAnimation(getContext(),
- 0 /* enterResId */, 0 /* exitResId */);
- options.setTaskAlwaysOnTop(true);
- // Soptions.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
- // Post to keep the lifecycle normal
- post(() -> {
- if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "onActivityViewReady: calling startActivity, "
- + "bubble=" + getBubbleKey());
- }
- if (mActivityView == null) {
- mBubbles.removeBubble(getBubbleKey(),
- BubbleController.DISMISS_INVALID_INTENT);
- return;
- }
- try {
- if (!mIsOverflow && mBubble.hasMetadataShortcutId()
- && mBubble.getShortcutInfo() != null) {
- options.setApplyActivityFlagsForBubbles(true);
- mActivityView.startShortcutActivity(mBubble.getShortcutInfo(),
- options, null /* sourceBounds */);
- } else {
- Intent fillInIntent = new Intent();
- // Apply flags to make behaviour match documentLaunchMode=always.
- fillInIntent.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT);
- fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
- if (mBubble != null) {
- mBubble.setIntentActive();
- }
- mActivityView.startActivity(mPendingIntent, fillInIntent, options);
- }
- } catch (RuntimeException e) {
- // If there's a runtime exception here then there's something
- // wrong with the intent, we can't really recover / try to populate
- // the bubble again so we'll just remove it.
- Log.w(TAG, "Exception while displaying bubble: " + getBubbleKey()
- + ", " + e.getMessage() + "; removing bubble");
- mBubbles.removeBubble(getBubbleKey(),
- BubbleController.DISMISS_INVALID_INTENT);
- }
- });
- mActivityViewStatus = ActivityViewStatus.ACTIVITY_STARTED;
- break;
- case ACTIVITY_STARTED:
- post(() -> mActivityManager.moveTaskToFront(mTaskId, 0));
- break;
+
+ if (mDestroyed || mInitialized) {
+ return;
}
+ // Custom options so there is no activity transition animation
+ ActivityOptions options = ActivityOptions.makeCustomAnimation(getContext(),
+ 0 /* enterResId */, 0 /* exitResId */);
+
+ // TODO: I notice inconsistencies in lifecycle
+ // Post to keep the lifecycle normal
+ post(() -> {
+ if (DEBUG_BUBBLE_EXPANDED_VIEW) {
+ Log.d(TAG, "onActivityViewReady: calling startActivity, bubble="
+ + getBubbleKey());
+ }
+ try {
+ if (!mIsOverflow && mBubble.hasMetadataShortcutId()) {
+ mTaskView.startShortcutActivity(mBubble.getShortcutInfo(),
+ options, null /* sourceBounds */);
+ } else {
+ Intent fillInIntent = new Intent();
+ // Apply flags to make behaviour match documentLaunchMode=always.
+ fillInIntent.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT);
+ fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
+ if (mBubble != null) {
+ mBubble.setIntentActive();
+ }
+ mTaskView.startActivity(mPendingIntent, fillInIntent, options);
+ }
+ } catch (RuntimeException e) {
+ // If there's a runtime exception here then there's something
+ // wrong with the intent, we can't really recover / try to populate
+ // the bubble again so we'll just remove it.
+ Log.w(TAG, "Exception while displaying bubble: " + getBubbleKey()
+ + ", " + e.getMessage() + "; removing bubble");
+ mBubbles.removeBubble(getBubbleKey(),
+ BubbleController.DISMISS_INVALID_INTENT);
+ }
+ });
+ mInitialized = true;
}
@Override
- public void onActivityViewDestroyed(ActivityView view) {
- if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "onActivityViewDestroyed: mActivityViewStatus=" + mActivityViewStatus
- + " bubble=" + getBubbleKey());
- }
- mActivityViewStatus = ActivityViewStatus.RELEASED;
+ public void onReleased() {
+ mDestroyed = true;
}
@Override
- public void onTaskCreated(int taskId, ComponentName componentName) {
+ public void onTaskCreated(int taskId, ComponentName name) {
if (DEBUG_BUBBLE_EXPANDED_VIEW) {
Log.d(TAG, "onTaskCreated: taskId=" + taskId
+ " bubble=" + getBubbleKey());
}
- // Since Bubble ActivityView applies singleTaskDisplay this is
- // guaranteed to only be called once per ActivityView. The taskId is
- // saved to use for removeTask, preventing appearance in recent tasks.
+ // The taskId is saved to use for removeTask, preventing appearance in recent tasks.
mTaskId = taskId;
+
+ // With the task org, the taskAppeared callback will only happen once the task has
+ // already drawn
+ setContentVisibility(true);
}
- /**
- * This is only called for tasks on this ActivityView, which is also set to
- * single-task mode -- meaning never more than one task on this display. If a task
- * is being removed, it's the top Activity finishing and this bubble should
- * be removed or collapsed.
- */
+ @Override
+ public void onTaskVisibilityChanged(int taskId, boolean visible) {
+ setContentVisibility(visible);
+ }
+
@Override
public void onTaskRemovalStarted(int taskId) {
if (DEBUG_BUBBLE_EXPANDED_VIEW) {
Log.d(TAG, "onTaskRemovalStarted: taskId=" + taskId
- + " mActivityViewStatus=" + mActivityViewStatus
+ " bubble=" + getBubbleKey());
}
if (mBubble != null) {
@@ -248,6 +197,13 @@
BubbleController.DISMISS_TASK_FINISHED));
}
}
+
+ @Override
+ public void onBackPressedOnTaskRoot(int taskId) {
+ if (mTaskId == taskId && mStackView.isExpanded()) {
+ mBubbles.collapseStack();
+ }
+ }
};
public BubbleExpandedView(Context context) {
@@ -266,7 +222,6 @@
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
updateDimensions();
- mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
}
void updateDimensions() {
@@ -284,9 +239,6 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "onFinishInflate: bubble=" + getBubbleKey());
- }
Resources res = getResources();
mPointerView = findViewById(R.id.pointer_view);
@@ -301,35 +253,21 @@
R.dimen.bubble_manage_button_height);
mSettingsIcon = findViewById(R.id.settings_button);
- mActivityView = new ActivityView.Builder(mContext)
- .setSingleInstance(true)
- .setDisableSurfaceViewBackgroundLayer(true)
- .setUseTrustedDisplay(true)
- .build();
-
+ mTaskView = new TaskView(mContext, mBubbles.getTaskManager());
// Set ActivityView's alpha value as zero, since there is no view content to be shown.
setContentVisibility(false);
- mActivityViewContainer.setOutlineProvider(new ViewOutlineProvider() {
+ mExpandedViewContainer.setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mCornerRadius);
}
});
- mActivityViewContainer.setClipToOutline(true);
- mActivityViewContainer.addView(mActivityView);
- mActivityViewContainer.setLayoutParams(
+ mExpandedViewContainer.setClipToOutline(true);
+ mExpandedViewContainer.addView(mTaskView);
+ mExpandedViewContainer.setLayoutParams(
new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
- addView(mActivityViewContainer);
-
- if (mActivityView != null
- && mActivityView.getChildCount() > 0
- && mActivityView.getChildAt(0) instanceof SurfaceView) {
- // Retrieve the surface from the ActivityView so we can screenshot it and change its
- // z-ordering. This should always be possible, since ActivityView's constructor adds the
- // SurfaceView as its first child.
- mActivitySurface = (SurfaceView) mActivityView.getChildAt(0);
- }
+ addView(mExpandedViewContainer);
// Expanded stack layout, top to bottom:
// Expanded view container
@@ -337,33 +275,22 @@
// ==> expanded view
// ==> activity view
// ==> manage button
- bringChildToFront(mActivityView);
+ bringChildToFront(mTaskView);
bringChildToFront(mSettingsIcon);
+ mTaskView.setListener(mTaskViewListener);
applyThemeAttrs();
- setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
- // Keep track of IME displaying because we should not make any adjustments that might
- // cause a config change while the IME is displayed otherwise it'll loose focus.
- final int keyboardHeight = insets.getSystemWindowInsetBottom()
- - insets.getStableInsetBottom();
- mKeyboardVisible = keyboardHeight != 0;
- if (!mKeyboardVisible && mNeedsNewHeight) {
- updateHeight();
- }
- return view.onApplyWindowInsets(insets);
- });
-
mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
setPadding(mExpandedViewPadding, mExpandedViewPadding, mExpandedViewPadding,
mExpandedViewPadding);
setOnTouchListener((view, motionEvent) -> {
- if (!usingActivityView()) {
+ if (mTaskView == null) {
return false;
}
final Rect avBounds = new Rect();
- mActivityView.getBoundsOnScreen(avBounds);
+ mTaskView.getBoundsOnScreen(avBounds);
// Consume and ignore events on the expanded view padding that are within the
// ActivityView's vertical bounds. These events are part of a back gesture, and so they
@@ -389,51 +316,58 @@
}
/**
- * Asks the ActivityView's surface to draw on top of all other views in the window. This is
- * useful for ordering surfaces during animations, but should otherwise be set to false so that
- * bubbles and menus can draw over the ActivityView.
+ * Sets whether the surface displaying app content should sit on top. This is useful for
+ * ordering surfaces during animations. When content is drawn on top of the app (e.g. bubble
+ * being dragged out, the manage menu) this is set to false, otherwise it should be true.
*/
void setSurfaceZOrderedOnTop(boolean onTop) {
- if (mActivitySurface == null) {
+ if (mTaskView == null) {
return;
}
-
- mActivitySurface.setZOrderedOnTop(onTop, true);
+ mTaskView.setZOrderedOnTop(onTop, true /* allowDynamicChange */);
}
- /** Return a GraphicBuffer with the contents of the ActivityView's underlying surface. */
+ void setImeVisible(boolean visible) {
+ mImeVisible = visible;
+ if (!mImeVisible && mNeedsNewHeight) {
+ updateHeight();
+ }
+ }
+
+ /** Return a GraphicBuffer with the contents of the task view surface. */
@Nullable
SurfaceControl.ScreenshotHardwareBuffer snapshotActivitySurface() {
- if (mActivitySurface == null) {
+ if (mTaskView == null) {
return null;
}
-
return SurfaceControl.captureLayers(
- mActivitySurface.getSurfaceControl(),
- new Rect(0, 0, mActivityView.getWidth(), mActivityView.getHeight()),
+ mTaskView.getSurfaceControl(),
+ new Rect(0, 0, mTaskView.getWidth(), mTaskView.getHeight()),
1 /* scale */);
}
- int[] getActivityViewLocationOnScreen() {
- if (mActivityView != null) {
- return mActivityView.getLocationOnScreen();
+ int[] getTaskViewLocationOnScreen() {
+ if (mTaskView != null) {
+ return mTaskView.getLocationOnScreen();
} else {
return new int[]{0, 0};
}
}
+ // TODO: Could listener be passed when we pass StackView / can we avoid setting this like this
void setManageClickListener(OnClickListener manageClickListener) {
- findViewById(R.id.settings_button).setOnClickListener(manageClickListener);
+ mSettingsIcon.setOnClickListener(manageClickListener);
}
/**
- * Updates the ActivityView's obscured touchable region. This calls onLocationChanged, which
- * results in a call to {@link BubbleStackView#subtractObscuredTouchableRegion}. This is useful
- * if a view has been added or removed from on top of the ActivityView, such as the manage menu.
+ * Updates the obscured touchable region for the task surface. This calls onLocationChanged,
+ * which results in a call to {@link BubbleStackView#subtractObscuredTouchableRegion}. This is
+ * useful if a view has been added or removed from on top of the ActivityView, such as the
+ * manage menu.
*/
void updateObscuredTouchableRegion() {
- if (mActivityView != null) {
- mActivityView.onLocationChanged();
+ if (mTaskView != null) {
+ mTaskView.onLocationChanged();
}
}
@@ -442,12 +376,12 @@
android.R.attr.dialogCornerRadius,
android.R.attr.colorBackgroundFloating});
mCornerRadius = ta.getDimensionPixelSize(0, 0);
- mActivityViewContainer.setBackgroundColor(ta.getColor(1, Color.WHITE));
+ mExpandedViewContainer.setBackgroundColor(ta.getColor(1, Color.WHITE));
ta.recycle();
- if (mActivityView != null && ScreenDecorationsUtils.supportsRoundedCornersOnWindows(
+ if (mTaskView != null && ScreenDecorationsUtils.supportsRoundedCornersOnWindows(
mContext.getResources())) {
- mActivityView.setCornerRadius(mCornerRadius);
+ mTaskView.setCornerRadius(mCornerRadius);
}
final int mode =
@@ -466,11 +400,8 @@
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- mKeyboardVisible = false;
+ mImeVisible = false;
mNeedsNewHeight = false;
- if (mActivityView != null) {
- setImeWindowToDisplay(0, 0);
- }
if (DEBUG_BUBBLE_EXPANDED_VIEW) {
Log.d(TAG, "onDetachedFromWindow: bubble=" + getBubbleKey());
}
@@ -492,84 +423,23 @@
final float alpha = visibility ? 1f : 0f;
mPointerView.setAlpha(alpha);
-
- if (mActivityView != null && alpha != mActivityView.getAlpha()) {
- mActivityView.setAlpha(alpha);
- mActivityView.bringToFront();
+ if (mTaskView == null) {
+ return;
+ }
+ if (alpha != mTaskView.getAlpha()) {
+ mTaskView.setAlpha(alpha);
}
}
- @Nullable ActivityView getActivityView() {
- return mActivityView;
+ @Nullable
+ View getTaskView() {
+ return mTaskView;
}
int getTaskId() {
return mTaskId;
}
- /**
- * Called by {@link BubbleStackView} when the insets for the expanded state should be updated.
- * This should be done post-move and post-animation.
- */
- void updateInsets(WindowInsets insets) {
- if (usingActivityView()) {
- int[] screenLoc = mActivityView.getLocationOnScreen();
- final int activityViewBottom = screenLoc[1] + mActivityView.getHeight();
- final int keyboardTop = mDisplaySize.y - Math.max(insets.getSystemWindowInsetBottom(),
- insets.getDisplayCutout() != null
- ? insets.getDisplayCutout().getSafeInsetBottom()
- : 0);
- setImeWindowToDisplay(getWidth(), Math.max(activityViewBottom - keyboardTop, 0));
- }
- }
-
- private void setImeWindowToDisplay(int w, int h) {
- if (getVirtualDisplayId() == INVALID_DISPLAY) {
- return;
- }
- if (h == 0 || w == 0) {
- if (mImeShowing) {
- mVirtualImeView.setVisibility(GONE);
- mImeShowing = false;
- }
- return;
- }
- final Context virtualDisplayContext = mContext.createDisplayContext(
- getVirtualDisplay().getDisplay());
-
- if (mVirtualDisplayWindowManager == null) {
- mVirtualDisplayWindowManager =
- (WindowManager) virtualDisplayContext.getSystemService(Context.WINDOW_SERVICE);
- }
- if (mVirtualImeView == null) {
- mVirtualImeView = new View(virtualDisplayContext);
- mVirtualImeView.setVisibility(VISIBLE);
- mVirtualDisplayWindowManager.addView(mVirtualImeView,
- getVirtualImeViewAttrs(w, h));
- } else {
- mVirtualDisplayWindowManager.updateViewLayout(mVirtualImeView,
- getVirtualImeViewAttrs(w, h));
- mVirtualImeView.setVisibility(VISIBLE);
- }
-
- mImeShowing = true;
- }
-
- private WindowManager.LayoutParams getVirtualImeViewAttrs(int w, int h) {
- // To use TYPE_NAVIGATION_BAR_PANEL instead of TYPE_IME_BAR to bypass the IME window type
- // token check when adding the window.
- final WindowManager.LayoutParams attrs =
- new WindowManager.LayoutParams(w, h, TYPE_NAVIGATION_BAR_PANEL,
- FLAG_LAYOUT_NO_LIMITS | FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE,
- TRANSPARENT);
- attrs.gravity = Gravity.BOTTOM;
- attrs.setTitle(WINDOW_TITLE);
- attrs.token = new Binder();
- attrs.providesInsetsTypes = new int[]{ITYPE_IME};
- attrs.alpha = 0.0f;
- return attrs;
- }
-
void setStackView(BubbleStackView stackView) {
mStackView = stackView;
}
@@ -581,7 +451,7 @@
Bundle extras = new Bundle();
extras.putBinder(EXTRA_BUBBLE_CONTROLLER, ObjectWrapper.wrap(mBubbles));
target.putExtras(extras);
- mPendingIntent = PendingIntent.getActivity(mContext, /* requestCode */ 0,
+ mPendingIntent = PendingIntent.getActivity(mContext, 0 /* requestCode */,
target, PendingIntent.FLAG_UPDATE_CURRENT);
mSettingsIcon.setVisibility(GONE);
}
@@ -619,7 +489,7 @@
mPendingIntent = mBubble.getBubbleIntent();
if (mPendingIntent != null || mBubble.hasMetadataShortcutId()) {
setContentVisibility(false);
- mActivityView.setVisibility(VISIBLE);
+ mTaskView.setVisibility(VISIBLE);
}
}
applyThemeAttrs();
@@ -629,59 +499,42 @@
}
}
+ /**
+ * Bubbles are backed by a pending intent or a shortcut, once the activity is
+ * started we never change it / restart it on notification updates -- unless the bubbles'
+ * backing data switches.
+ *
+ * This indicates if the new bubble is backed by a different data source than what was
+ * previously shown here (e.g. previously a pending intent & now a shortcut).
+ *
+ * @param newBubble the bubble this view is being updated with.
+ * @return true if the backing content has changed.
+ */
private boolean didBackingContentChange(Bubble newBubble) {
boolean prevWasIntentBased = mBubble != null && mPendingIntent != null;
boolean newIsIntentBased = newBubble.getBubbleIntent() != null;
return prevWasIntentBased != newIsIntentBased;
}
- /**
- * Lets activity view know it should be shown / populated with activity content.
- */
- void populateExpandedView() {
- if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "populateExpandedView: "
- + "bubble=" + getBubbleKey());
- }
-
- if (usingActivityView()) {
- mActivityView.setCallback(mStateCallback);
- } else {
- Log.e(TAG, "Cannot populate expanded view.");
- }
- }
-
- boolean performBackPressIfNeeded() {
- if (!usingActivityView()) {
- return false;
- }
- mActivityView.performBackPress();
- return true;
- }
-
void updateHeight() {
- if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "updateHeight: bubble=" + getBubbleKey());
- }
-
if (mExpandedViewContainerLocation == null) {
return;
}
- if (usingActivityView()) {
+ if (mBubble != null || mIsOverflow) {
float desiredHeight = mOverflowHeight;
if (!mIsOverflow) {
desiredHeight = Math.max(mBubble.getDesiredHeight(mContext), mMinHeight);
}
float height = Math.min(desiredHeight, getMaxExpandedHeight());
- height = Math.max(height, mMinHeight);
- ViewGroup.LayoutParams lp = mActivityView.getLayoutParams();
+ height = Math.max(height, mIsOverflow ? mOverflowHeight : mMinHeight);
+ FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mTaskView.getLayoutParams();
mNeedsNewHeight = lp.height != height;
- if (!mKeyboardVisible) {
- // If the keyboard is visible... don't adjust the height because that will cause
- // a configuration change and the keyboard will be lost.
+ if (!mImeVisible) {
+ // If the ime is visible... don't adjust the height because that will cause
+ // a configuration change and the ime will be lost.
lp.height = (int) height;
- mActivityView.setLayoutParams(lp);
+ mTaskView.setLayoutParams(lp);
mNeedsNewHeight = false;
}
if (DEBUG_BUBBLE_EXPANDED_VIEW) {
@@ -694,12 +547,15 @@
private int getMaxExpandedHeight() {
mWindowManager.getDefaultDisplay().getRealSize(mDisplaySize);
+ int expandedContainerY = mExpandedViewContainerLocation != null
+ ? mExpandedViewContainerLocation[1]
+ : 0;
int bottomInset = getRootWindowInsets() != null
? getRootWindowInsets().getStableInsetBottom()
: 0;
return mDisplaySize.y
- - mExpandedViewContainerLocation[1]
+ - expandedContainerY
- getPaddingTop()
- getPaddingBottom()
- mSettingsIconHeight
@@ -719,14 +575,12 @@
Log.d(TAG, "updateView: bubble="
+ getBubbleKey());
}
-
mExpandedViewContainerLocation = containerLocationOnScreen;
-
- if (usingActivityView()
- && mActivityView.getVisibility() == VISIBLE
- && mActivityView.isAttachedToWindow()) {
- mActivityView.onLocationChanged();
+ if (mTaskView != null
+ && mTaskView.getVisibility() == VISIBLE
+ && mTaskView.isAttachedToWindow()) {
updateHeight();
+ mTaskView.onLocationChanged();
}
}
@@ -749,65 +603,19 @@
}
/**
- * Removes and releases an ActivityView if one was previously created for this bubble.
+ * Cleans up anything related to the task and TaskView.
*/
public void cleanUpExpandedState() {
if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "cleanUpExpandedState: mActivityViewStatus=" + mActivityViewStatus
- + ", bubble=" + getBubbleKey());
+ Log.d(TAG, "cleanUpExpandedState: bubble=" + getBubbleKey() + " task=" + mTaskId);
}
- if (mActivityView == null) {
- return;
+ if (mTaskView != null) {
+ mTaskView.release();
}
- mActivityView.release();
- if (mTaskId != -1) {
- try {
- ActivityTaskManager.getService().removeTask(mTaskId);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to remove taskId " + mTaskId);
- }
- mTaskId = -1;
+ if (mTaskView != null) {
+ removeView(mTaskView);
+ mTaskView = null;
}
- removeView(mActivityView);
-
- mActivityView = null;
- }
-
- /**
- * Called when the last task is removed from a {@link android.hardware.display.VirtualDisplay}
- * which {@link ActivityView} uses.
- */
- void notifyDisplayEmpty() {
- if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "notifyDisplayEmpty: bubble="
- + getBubbleKey()
- + " mActivityViewStatus=" + mActivityViewStatus);
- }
- if (mActivityViewStatus == ActivityViewStatus.ACTIVITY_STARTED) {
- mActivityViewStatus = ActivityViewStatus.INITIALIZED;
- }
- }
-
- private boolean usingActivityView() {
- return (mPendingIntent != null || mBubble.hasMetadataShortcutId())
- && mActivityView != null;
- }
-
- /**
- * @return the display id of the virtual display.
- */
- public int getVirtualDisplayId() {
- if (usingActivityView()) {
- return mActivityView.getVirtualDisplayId();
- }
- return INVALID_DISPLAY;
- }
-
- private VirtualDisplay getVirtualDisplay() {
- if (usingActivityView()) {
- return mActivityView.getVirtualDisplay();
- }
- return null;
}
/**
@@ -817,7 +625,6 @@
@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.print("BubbleExpandedView");
pw.print(" taskId: "); pw.println(mTaskId);
- pw.print(" activityViewStatus: "); pw.println(mActivityViewStatus);
pw.print(" stackView: "); pw.println(mStackView);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
index 69f7828..009114f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
@@ -18,6 +18,8 @@
import static android.graphics.Paint.ANTI_ALIAS_FLAG;
import static android.graphics.Paint.FILTER_BITMAP_FLAG;
+import static com.android.systemui.Interpolators.ALPHA_IN;
+import static com.android.systemui.Interpolators.ALPHA_OUT;
import android.animation.ArgbEvaluator;
import android.content.Context;
@@ -56,6 +58,11 @@
/** Max width of the flyout, in terms of percent of the screen width. */
private static final float FLYOUT_MAX_WIDTH_PERCENT = .6f;
+ /** Translation Y of fade animation. */
+ private static final float FLYOUT_FADE_Y = 40f;
+
+ private static final long FLYOUT_FADE_DURATION = 200L;
+
private final int mFlyoutPadding;
private final int mFlyoutSpaceFromBubble;
private final int mPointerSize;
@@ -104,6 +111,9 @@
/** The bounds of the flyout background, kept up to date as it transitions to the 'new' dot. */
private final RectF mBgRect = new RectF();
+ /** The y position of the flyout, relative to the top of the screen. */
+ private float mFlyoutY = 0f;
+
/**
* Percent progress in the transition from flyout to 'new' dot. These two values are the inverse
* of each other (if we're 40% transitioned to the dot, we're 60% flyout), but it makes the code
@@ -221,18 +231,33 @@
mSenderText.setTextSize(TypedValue.COMPLEX_UNIT_PX, newFontSize);
}
- /** Configures the flyout, collapsed into to dot form. */
- void setupFlyoutStartingAsDot(
- Bubble.FlyoutMessage flyoutMessage,
- PointF stackPos,
- float parentWidth,
- boolean arrowPointingLeft,
- int dotColor,
- @Nullable Runnable onLayoutComplete,
- @Nullable Runnable onHide,
- float[] dotCenter,
- boolean hideDot) {
+ /*
+ * Fade animation for consecutive flyouts.
+ */
+ void animateUpdate(Bubble.FlyoutMessage flyoutMessage, float parentWidth, float stackY) {
+ fade(false /* in */);
+ updateFlyoutMessage(flyoutMessage, parentWidth);
+ // Wait for TextViews to layout with updated height.
+ post(() -> {
+ mFlyoutY = stackY + (mBubbleSize - mFlyoutTextContainer.getHeight()) / 2f;
+ fade(true /* in */);
+ });
+ }
+ private void fade(boolean in) {
+ setAlpha(in ? 0f : 1f);
+ setTranslationY(in ? mFlyoutY : mFlyoutY + FLYOUT_FADE_Y);
+ animate()
+ .alpha(in ? 1f : 0f)
+ .setDuration(FLYOUT_FADE_DURATION)
+ .setInterpolator(in ? ALPHA_IN : ALPHA_OUT);
+ animate()
+ .translationY(in ? mFlyoutY : mFlyoutY - FLYOUT_FADE_Y)
+ .setDuration(FLYOUT_FADE_DURATION)
+ .setInterpolator(in ? ALPHA_IN : ALPHA_OUT);
+ }
+
+ private void updateFlyoutMessage(Bubble.FlyoutMessage flyoutMessage, float parentWidth) {
final Drawable senderAvatar = flyoutMessage.senderAvatar;
if (senderAvatar != null && flyoutMessage.isGroupChat) {
mSenderAvatar.setVisibility(VISIBLE);
@@ -256,6 +281,27 @@
mSenderText.setVisibility(GONE);
}
+ // Set the flyout TextView's max width in terms of percent, and then subtract out the
+ // padding so that the entire flyout view will be the desired width (rather than the
+ // TextView being the desired width + extra padding).
+ mMessageText.setMaxWidth(maxTextViewWidth);
+ mMessageText.setText(flyoutMessage.message);
+ }
+
+ /** Configures the flyout, collapsed into dot form. */
+ void setupFlyoutStartingAsDot(
+ Bubble.FlyoutMessage flyoutMessage,
+ PointF stackPos,
+ float parentWidth,
+ boolean arrowPointingLeft,
+ int dotColor,
+ @Nullable Runnable onLayoutComplete,
+ @Nullable Runnable onHide,
+ float[] dotCenter,
+ boolean hideDot) {
+
+ updateFlyoutMessage(flyoutMessage, parentWidth);
+
mArrowPointingLeft = arrowPointingLeft;
mDotColor = dotColor;
mOnHide = onHide;
@@ -263,24 +309,12 @@
setCollapsePercent(1f);
- // Set the flyout TextView's max width in terms of percent, and then subtract out the
- // padding so that the entire flyout view will be the desired width (rather than the
- // TextView being the desired width + extra padding).
- mMessageText.setMaxWidth(maxTextViewWidth);
- mMessageText.setText(flyoutMessage.message);
-
- // Wait for the TextView to lay out so we know its line count.
+ // Wait for TextViews to layout with updated height.
post(() -> {
- float restingTranslationY;
- // Multi line flyouts get top-aligned to the bubble.
- if (mMessageText.getLineCount() > 1) {
- restingTranslationY = stackPos.y + mBubbleIconTopPadding;
- } else {
- // Single line flyouts are vertically centered with respect to the bubble.
- restingTranslationY =
- stackPos.y + (mBubbleSize - mFlyoutTextContainer.getHeight()) / 2f;
- }
- setTranslationY(restingTranslationY);
+ // Flyout is vertically centered with respect to the bubble.
+ mFlyoutY =
+ stackPos.y + (mBubbleSize - mFlyoutTextContainer.getHeight()) / 2f;
+ setTranslationY(mFlyoutY);
// Calculate the translation required to position the flyout next to the bubble stack,
// with the desired padding.
@@ -300,7 +334,7 @@
final float dotPositionY = stackPos.y + mDotCenter[1] - adjustmentForScaleAway;
final float distanceFromFlyoutLeftToDotCenterX = mRestingTranslationX - dotPositionX;
- final float distanceFromLayoutTopToDotCenterY = restingTranslationY - dotPositionY;
+ final float distanceFromLayoutTopToDotCenterY = mFlyoutY - dotPositionY;
mTranslationXWhenDot = -distanceFromFlyoutLeftToDotCenterX;
mTranslationYWhenDot = -distanceFromLayoutTopToDotCenterY;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLogger.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLogger.java
index 86ba8c5..48c809d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLogger.java
@@ -19,17 +19,22 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
+import com.android.internal.util.FrameworkStatsLog;
/**
- * Interface for handling bubble-specific logging.
+ * Implementation of UiEventLogger for logging bubble UI events.
+ *
+ * See UiEventReported atom in atoms.proto for more context.
*/
-public interface BubbleLogger extends UiEventLogger {
+public class BubbleLogger {
+
+ private final UiEventLogger mUiEventLogger;
/**
* Bubble UI event.
*/
@VisibleForTesting
- enum Event implements UiEventLogger.UiEventEnum {
+ public enum Event implements UiEventLogger.UiEventEnum {
@UiEvent(doc = "User dismissed the bubble via gesture, add bubble to overflow.")
BUBBLE_OVERFLOW_ADD_USER_GESTURE(483),
@@ -70,23 +75,80 @@
}
}
+ public BubbleLogger(UiEventLogger uiEventLogger) {
+ mUiEventLogger = uiEventLogger;
+ }
+
/**
* @param b Bubble involved in this UI event
* @param e UI event
*/
- void log(Bubble b, UiEventEnum e);
+ public void log(Bubble b, UiEventLogger.UiEventEnum e) {
+ mUiEventLogger.logWithInstanceId(e, b.getAppUid(), b.getPackageName(), b.getInstanceId());
+ }
/**
- *
* @param b Bubble removed from overflow
- * @param r Reason that bubble was removed from overflow
+ * @param r Reason that bubble was removed
*/
- void logOverflowRemove(Bubble b, @BubbleController.DismissReason int r);
+ public void logOverflowRemove(Bubble b, @BubbleController.DismissReason int r) {
+ if (r == BubbleController.DISMISS_NOTIF_CANCEL) {
+ log(b, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_CANCEL);
+ } else if (r == BubbleController.DISMISS_GROUP_CANCELLED) {
+ log(b, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_GROUP_CANCEL);
+ } else if (r == BubbleController.DISMISS_NO_LONGER_BUBBLE) {
+ log(b, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_NO_LONGER_BUBBLE);
+ } else if (r == BubbleController.DISMISS_BLOCKED) {
+ log(b, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_BLOCKED);
+ }
+ }
/**
- *
* @param b Bubble added to overflow
* @param r Reason that bubble was added to overflow
*/
- void logOverflowAdd(Bubble b, @BubbleController.DismissReason int r);
-}
+ public void logOverflowAdd(Bubble b, @BubbleController.DismissReason int r) {
+ if (r == BubbleController.DISMISS_AGED) {
+ log(b, Event.BUBBLE_OVERFLOW_ADD_AGED);
+ } else if (r == BubbleController.DISMISS_USER_GESTURE) {
+ log(b, Event.BUBBLE_OVERFLOW_ADD_USER_GESTURE);
+ }
+ }
+
+ void logStackUiChanged(String packageName, int action, int bubbleCount, float normalX,
+ float normalY) {
+ FrameworkStatsLog.write(FrameworkStatsLog.BUBBLE_UI_CHANGED,
+ packageName,
+ null /* notification channel */,
+ 0 /* notification ID */,
+ 0 /* bubble position */,
+ bubbleCount,
+ action,
+ normalX,
+ normalY,
+ false /* unread bubble */,
+ false /* on-going bubble */,
+ false /* isAppForeground (unused) */);
+ }
+
+ void logShowOverflow(String packageName, int currentUserId) {
+ mUiEventLogger.log(BubbleLogger.Event.BUBBLE_OVERFLOW_SELECTED, currentUserId,
+ packageName);
+ }
+
+ void logBubbleUiChanged(Bubble bubble, String packageName, int action, int bubbleCount,
+ float normalX, float normalY, int index) {
+ FrameworkStatsLog.write(FrameworkStatsLog.BUBBLE_UI_CHANGED,
+ packageName,
+ bubble.getChannelId() /* notification channel */,
+ bubble.getNotificationId() /* notification ID */,
+ index,
+ bubbleCount,
+ action,
+ normalX,
+ normalY,
+ bubble.showInShade() /* isUnread */,
+ false /* isOngoing (unused) */,
+ false /* isAppForeground (unused) */);
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java
deleted file mode 100644
index ea612af..0000000
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2020 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.systemui.bubbles;
-
-import android.os.UserHandle;
-
-import com.android.internal.logging.UiEventLoggerImpl;
-import com.android.systemui.shared.system.SysUiStatsLog;
-
-/**
- * Implementation of UiEventLogger for logging bubble UI events.
- *
- * See UiEventReported atom in atoms.proto for more context.
- */
-public class BubbleLoggerImpl extends UiEventLoggerImpl implements BubbleLogger {
-
- /**
- * @param b Bubble involved in this UI event
- * @param e UI event
- */
- public void log(Bubble b, UiEventEnum e) {
- logWithInstanceId(e, b.getAppUid(), b.getPackageName(), b.getInstanceId());
- }
-
- /**
- * @param b Bubble removed from overflow
- * @param r Reason that bubble was removed
- */
- public void logOverflowRemove(Bubble b, @BubbleController.DismissReason int r) {
- if (r == BubbleController.DISMISS_NOTIF_CANCEL) {
- log(b, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_CANCEL);
- } else if (r == BubbleController.DISMISS_GROUP_CANCELLED) {
- log(b, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_GROUP_CANCEL);
- } else if (r == BubbleController.DISMISS_NO_LONGER_BUBBLE) {
- log(b, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_NO_LONGER_BUBBLE);
- } else if (r == BubbleController.DISMISS_BLOCKED) {
- log(b, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_BLOCKED);
- }
- }
-
- /**
- * @param b Bubble added to overflow
- * @param r Reason that bubble was added to overflow
- */
- public void logOverflowAdd(Bubble b, @BubbleController.DismissReason int r) {
- if (r == BubbleController.DISMISS_AGED) {
- log(b, Event.BUBBLE_OVERFLOW_ADD_AGED);
- } else if (r == BubbleController.DISMISS_USER_GESTURE) {
- log(b, Event.BUBBLE_OVERFLOW_ADD_USER_GESTURE);
- }
- }
-
- void logStackUiChanged(String packageName, int action, int bubbleCount, float normalX,
- float normalY) {
- SysUiStatsLog.write(SysUiStatsLog.BUBBLE_UI_CHANGED,
- packageName,
- null /* notification channel */,
- 0 /* notification ID */,
- 0 /* bubble position */,
- bubbleCount,
- action,
- normalX,
- normalY,
- false /* unread bubble */,
- false /* on-going bubble */,
- false /* isAppForeground (unused) */);
- }
-
- void logShowOverflow(String packageName, int currentUserId) {
- super.log(BubbleLogger.Event.BUBBLE_OVERFLOW_SELECTED, currentUserId,
- packageName);
- }
-
- void logBubbleUiChanged(Bubble bubble, String packageName, int action, int bubbleCount,
- float normalX, float normalY, int index) {
- SysUiStatsLog.write(SysUiStatsLog.BUBBLE_UI_CHANGED,
- packageName,
- bubble.getChannelId() /* notification channel */,
- bubble.getNotificationId() /* notification ID */,
- index,
- bubbleCount,
- action,
- normalX,
- normalY,
- bubble.showInShade() /* isUnread */,
- false /* isOngoing (unused) */,
- false /* isAppForeground (unused) */);
- }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt
index bf7c860..102055d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt
@@ -16,6 +16,7 @@
package com.android.systemui.bubbles
+import android.app.ActivityTaskManager.INVALID_TASK_ID
import android.content.Context
import android.content.res.Configuration
import android.graphics.Bitmap
@@ -37,8 +38,8 @@
private val stack: BubbleStackView
) : BubbleViewProvider {
- private lateinit var bitmap : Bitmap
- private lateinit var dotPath : Path
+ private lateinit var bitmap: Bitmap
+ private lateinit var dotPath: Path
private var bitmapSize = 0
private var iconBitmapSize = 0
@@ -167,8 +168,8 @@
return KEY
}
- override fun getDisplayId(): Int {
- return expandedView.virtualDisplayId
+ override fun getTaskId(): Int {
+ return if (expandedView != null) expandedView.getTaskId() else INVALID_TASK_ID
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index e83954b..431719f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -27,7 +27,6 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
-import android.app.ActivityView;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -74,18 +73,13 @@
import androidx.dynamicanimation.animation.SpringForce;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.systemui.Interpolators;
-import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.bubbles.animation.AnimatableScaleMatrix;
import com.android.systemui.bubbles.animation.ExpandedAnimationController;
import com.android.systemui.bubbles.animation.PhysicsAnimationLayout;
import com.android.systemui.bubbles.animation.StackAnimationController;
-import com.android.systemui.model.SysUiState;
-import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.shared.system.SysUiStatsLog;
-import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
-import com.android.systemui.util.RelativeTouchListener;
import com.android.wm.shell.animation.PhysicsAnimator;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
@@ -121,6 +115,8 @@
/** Duration of the flyout alpha animations. */
private static final int FLYOUT_ALPHA_ANIMATION_DURATION = 100;
+ private static final int FADE_IN_DURATION = 320;
+
/** Percent to darken the bubbles when they're in the dismiss target. */
private static final float DARKEN_PERCENT = 0.3f;
@@ -302,7 +298,7 @@
pw.println(" expandedViewAlpha: " + expandedView.getAlpha());
pw.println(" expandedViewTaskId: " + expandedView.getTaskId());
- final ActivityView av = expandedView.getActivityView();
+ final View av = expandedView.getTaskView();
if (av != null) {
pw.println(" activityViewVis: " + av.getVisibility());
@@ -323,8 +319,6 @@
/** Callback to run when we want to unbubble the given notification's conversation. */
private Consumer<String> mUnbubbleConversationCallback;
- private SysUiState mSysUiState;
-
private boolean mViewUpdatedRequested = false;
private boolean mIsExpansionAnimating = false;
private boolean mIsBubbleSwitchAnimating = false;
@@ -332,8 +326,6 @@
/** The view to desaturate/darken when magneted to the dismiss target. */
@Nullable private View mDesaturateAndDarkenTargetView;
- private LayoutInflater mInflater;
-
private Rect mTempRect = new Rect();
private final List<Rect> mSystemGestureExclusionRects = Collections.singletonList(new Rect());
@@ -401,6 +393,11 @@
public final Consumer<Boolean> mOnImeVisibilityChanged;
/**
+ * Callback to run when the bubble expand status changes.
+ */
+ private final Consumer<Boolean> mOnBubbleExpandChanged;
+
+ /**
* Callback to run to ask BubbleController to hide the current IME.
*/
private final Runnable mHideCurrentInputMethodCallback;
@@ -660,7 +657,7 @@
viewInitialX + dx, velX, velY) <= 0;
updateBubbleIcons();
logBubbleEvent(null /* no bubble associated with bubble stack move */,
- SysUiStatsLog.BUBBLE_UICHANGED__ACTION__STACK_MOVED);
+ FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__STACK_MOVED);
}
mDismissView.hide();
}
@@ -742,16 +739,13 @@
public BubbleStackView(Context context, BubbleData data,
@Nullable SurfaceSynchronizer synchronizer,
FloatingContentCoordinator floatingContentCoordinator,
- SysUiState sysUiState,
Runnable allBubblesAnimatedOutAction,
Consumer<Boolean> onImeVisibilityChanged,
- Runnable hideCurrentInputMethodCallback) {
+ Runnable hideCurrentInputMethodCallback,
+ Consumer<Boolean> onBubbleExpandChanged) {
super(context);
mBubbleData = data;
- mInflater = LayoutInflater.from(context);
-
- mSysUiState = sysUiState;
Resources res = getResources();
mMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered);
@@ -865,21 +859,13 @@
mOnImeVisibilityChanged = onImeVisibilityChanged;
mHideCurrentInputMethodCallback = hideCurrentInputMethodCallback;
+ mOnBubbleExpandChanged = onBubbleExpandChanged;
setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
onImeVisibilityChanged.accept(insets.getInsets(WindowInsets.Type.ime()).bottom > 0);
-
if (!mIsExpanded || mIsExpansionAnimating) {
return view.onApplyWindowInsets(insets);
}
- mExpandedAnimationController.updateYPosition(
- // Update the insets after we're done translating otherwise position
- // calculation for them won't be correct.
- () -> {
- if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
- mExpandedBubble.getExpandedView().updateInsets(insets);
- }
- });
return view.onApplyWindowInsets(insets);
});
@@ -974,7 +960,7 @@
animate()
.setInterpolator(Interpolators.PANEL_CLOSE_ACCELERATED)
- .setDuration(CollapsedStatusBarFragment.FADE_IN_DURATION);
+ .setDuration(FADE_IN_DURATION);
}
/**
@@ -1066,7 +1052,7 @@
mBubbleData.setExpanded(false);
mContext.startActivityAsUser(intent, bubble.getUser());
logBubbleEvent(bubble,
- SysUiStatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_SETTINGS);
+ FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_SETTINGS);
}
});
@@ -1082,8 +1068,7 @@
* Whether the educational view should show for the expanded view "manage" menu.
*/
private boolean shouldShowManageEdu() {
- final boolean seen = Prefs.getBoolean(mContext,
- Prefs.Key.HAS_SEEN_BUBBLES_MANAGE_EDUCATION, false /* default */);
+ final boolean seen = getPrefBoolean(ManageEducationViewKt.PREF_MANAGED_EDUCATION);
final boolean shouldShow = (!seen || BubbleDebugConfig.forceShowUserEducation(mContext))
&& mExpandedBubble != null;
if (BubbleDebugConfig.DEBUG_USER_EDUCATION) {
@@ -1107,8 +1092,7 @@
* Whether education view should show for the collapsed stack.
*/
private boolean shouldShowStackEdu() {
- final boolean seen = Prefs.getBoolean(getContext(),
- Prefs.Key.HAS_SEEN_BUBBLES_EDUCATION, false /* default */);
+ final boolean seen = getPrefBoolean(StackEducationViewKt.PREF_STACK_EDUCATION);
final boolean shouldShow = !seen || BubbleDebugConfig.forceShowUserEducation(mContext);
if (BubbleDebugConfig.DEBUG_USER_EDUCATION) {
Log.d(TAG, "Show stack edu: " + shouldShow);
@@ -1116,6 +1100,11 @@
return shouldShow;
}
+ private boolean getPrefBoolean(String key) {
+ return mContext.getSharedPreferences(mContext.getPackageName(), Context.MODE_PRIVATE)
+ .getBoolean(key, false /* default */);
+ }
+
/**
* @return true if education view for collapsed stack should show and was not showing before.
*/
@@ -1254,7 +1243,15 @@
mTempRect.setEmpty();
getTouchableRegion(mTempRect);
- inoutInfo.touchableRegion.set(mTempRect);
+ if (mIsExpanded && mExpandedBubble != null
+ && mExpandedBubble.getExpandedView() != null
+ && mExpandedBubble.getExpandedView().getTaskView() != null) {
+ inoutInfo.touchableRegion.set(mTempRect);
+ mExpandedBubble.getExpandedView().getTaskView().getBoundsOnScreen(mTempRect);
+ inoutInfo.touchableRegion.op(mTempRect, Region.Op.DIFFERENCE);
+ } else {
+ inoutInfo.touchableRegion.set(mTempRect);
+ }
}
@Override
@@ -1442,13 +1439,6 @@
}
/**
- * The {@link BadgedImageView} that is expanded, null if one does not exist.
- */
- View getExpandedBubbleView() {
- return mExpandedBubble != null ? mExpandedBubble.getIconView() : null;
- }
-
- /**
* The {@link Bubble} that is expanded, null if one does not exist.
*/
@Nullable
@@ -1488,7 +1478,7 @@
new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
animateInFlyoutForBubble(bubble);
requestUpdate();
- logBubbleEvent(bubble, SysUiStatsLog.BUBBLE_UICHANGED__ACTION__POSTED);
+ logBubbleEvent(bubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__POSTED);
}
// via BubbleData.Listener
@@ -1508,7 +1498,7 @@
bubble.cleanupViews();
}
updatePointerPosition();
- logBubbleEvent(bubble, SysUiStatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED);
+ logBubbleEvent(bubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED);
return;
}
}
@@ -1526,7 +1516,7 @@
void updateBubble(Bubble bubble) {
animateInFlyoutForBubble(bubble);
requestUpdate();
- logBubbleEvent(bubble, SysUiStatsLog.BUBBLE_UICHANGED__ACTION__UPDATED);
+ logBubbleEvent(bubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__UPDATED);
}
public void updateBubbleOrder(List<Bubble> bubbles) {
@@ -1563,7 +1553,7 @@
return;
}
- if (bubbleToSelect.getKey() == BubbleOverflow.KEY) {
+ if (bubbleToSelect.getKey().equals(BubbleOverflow.KEY)) {
mBubbleData.setShowingOverflow(true);
} else {
mBubbleData.setShowingOverflow(false);
@@ -1622,8 +1612,9 @@
requestUpdate();
logBubbleEvent(previouslySelected,
- SysUiStatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
- logBubbleEvent(bubbleToSelect, SysUiStatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED);
+ FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
+ logBubbleEvent(bubbleToSelect,
+ FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED);
notifyExpansionChanged(previouslySelected, false /* expanded */);
notifyExpansionChanged(bubbleToSelect, true /* expanded */);
});
@@ -1653,30 +1644,21 @@
hideCurrentInputMethod();
- mSysUiState
- .setFlag(QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED, shouldExpand)
- .commitUpdate(mContext.getDisplayId());
+ mOnBubbleExpandChanged.accept(shouldExpand);
if (mIsExpanded) {
animateCollapse();
- logBubbleEvent(mExpandedBubble, SysUiStatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
+ logBubbleEvent(mExpandedBubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
} else {
animateExpansion();
// TODO: move next line to BubbleData
- logBubbleEvent(mExpandedBubble, SysUiStatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED);
- logBubbleEvent(mExpandedBubble, SysUiStatsLog.BUBBLE_UICHANGED__ACTION__STACK_EXPANDED);
+ logBubbleEvent(mExpandedBubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED);
+ logBubbleEvent(mExpandedBubble,
+ FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__STACK_EXPANDED);
}
notifyExpansionChanged(mExpandedBubble, mIsExpanded);
}
- void showExpandedViewContents(int displayId) {
- if (mExpandedBubble != null
- && mExpandedBubble.getExpandedView() != null
- && mExpandedBubble.getExpandedView().getVirtualDisplayId() == displayId) {
- mExpandedBubble.setContentVisibility(true);
- }
- }
-
/**
* Asks the BubbleController to hide the IME from anywhere, whether it's focused on Bubbles or
* not.
@@ -1711,7 +1693,6 @@
updateOverflowVisibility();
updatePointerPosition();
mExpandedAnimationController.expandFromStack(() -> {
- afterExpandedViewAnimation();
if (mIsExpanded && mExpandedBubble.getExpandedView() != null) {
maybeShowManageEdu();
}
@@ -1774,11 +1755,10 @@
mExpandedViewContainerMatrix);
})
.withEndActions(() -> {
+ afterExpandedViewAnimation();
if (mExpandedBubble != null
&& mExpandedBubble.getExpandedView() != null) {
mExpandedBubble.getExpandedView()
- .setContentVisibility(true);
- mExpandedBubble.getExpandedView()
.setSurfaceZOrderedOnTop(false);
}
})
@@ -1922,7 +1902,6 @@
})
.withEndActions(() -> {
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
- mExpandedBubble.getExpandedView().setContentVisibility(true);
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
}
@@ -1958,13 +1937,6 @@
}
}
- /** Return the BubbleView at the given index from the bubble container. */
- public BadgedImageView getBubbleAt(int i) {
- return getBubbleCount() > i
- ? (BadgedImageView) mBubbleContainer.getChildAt(i)
- : null;
- }
-
/** Moves the bubbles out of the way if they're going to be over the keyboard. */
public void onImeVisibilityChanged(boolean visible, int height) {
mStackAnimationController.setImeHeight(visible ? height + mImeOffset : 0);
@@ -1986,6 +1958,9 @@
FLYOUT_IME_ANIMATION_SPRING_CONFIG)
.start();
}
+ } else if (mIsExpanded && mExpandedBubble != null
+ && mExpandedBubble.getExpandedView() != null) {
+ mExpandedBubble.getExpandedView().setImeVisible(visible);
}
}
@@ -2196,11 +2171,7 @@
return getStatusBarHeight() + mBubbleSize + mBubblePaddingTop;
}
- /**
- * Animates in the flyout for the given bubble, if available, and then hides it after some time.
- */
- @VisibleForTesting
- void animateInFlyoutForBubble(Bubble bubble) {
+ private boolean shouldShowFlyout(Bubble bubble) {
Bubble.FlyoutMessage flyoutMessage = bubble.getFlyoutMessage();
final BadgedImageView bubbleView = bubble.getIconView();
if (flyoutMessage == null
@@ -2212,11 +2183,22 @@
|| mIsGestureInProgress
|| mBubbleToExpandAfterFlyoutCollapse != null
|| bubbleView == null) {
- if (bubbleView != null) {
+ if (bubbleView != null && mFlyout.getVisibility() != VISIBLE) {
bubbleView.removeDotSuppressionFlag(BadgedImageView.SuppressionFlag.FLYOUT_VISIBLE);
}
// Skip the message if none exists, we're expanded or animating expansion, or we're
// about to expand a bubble from the previous tapped flyout, or if bubble view is null.
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Animates in the flyout for the given bubble, if available, and then hides it after some time.
+ */
+ @VisibleForTesting
+ void animateInFlyoutForBubble(Bubble bubble) {
+ if (!shouldShowFlyout(bubble)) {
return;
}
@@ -2234,25 +2216,22 @@
}
// Stop suppressing the dot now that the flyout has morphed into the dot.
- bubbleView.removeDotSuppressionFlag(
+ bubble.getIconView().removeDotSuppressionFlag(
BadgedImageView.SuppressionFlag.FLYOUT_VISIBLE);
- mFlyout.setVisibility(INVISIBLE);
-
// Hide the stack after a delay, if needed.
updateTemporarilyInvisibleAnimation(false /* hideImmediately */);
};
- mFlyout.setVisibility(INVISIBLE);
// Suppress the dot when we are animating the flyout.
- bubbleView.addDotSuppressionFlag(
+ bubble.getIconView().addDotSuppressionFlag(
BadgedImageView.SuppressionFlag.FLYOUT_VISIBLE);
// Start flyout expansion. Post in case layout isn't complete and getWidth returns 0.
post(() -> {
// An auto-expanding bubble could have been posted during the time it takes to
// layout.
- if (isExpanded()) {
+ if (isExpanded() || bubble.getIconView() == null) {
return;
}
final Runnable expandFlyoutAfterDelay = () -> {
@@ -2269,23 +2248,26 @@
mFlyout.postDelayed(mAnimateInFlyout, 200);
};
- if (bubble.getIconView() == null) {
- return;
- }
- mFlyout.setupFlyoutStartingAsDot(flyoutMessage,
- mStackAnimationController.getStackPosition(), getWidth(),
- mStackAnimationController.isStackOnLeftSide(),
- bubble.getIconView().getDotColor() /* dotColor */,
- expandFlyoutAfterDelay /* onLayoutComplete */,
- mAfterFlyoutHidden,
- bubble.getIconView().getDotCenter(),
- !bubble.showDot());
+ if (mFlyout.getVisibility() == View.VISIBLE) {
+ mFlyout.animateUpdate(bubble.getFlyoutMessage(), getWidth(),
+ mStackAnimationController.getStackPosition().y);
+ } else {
+ mFlyout.setVisibility(INVISIBLE);
+ mFlyout.setupFlyoutStartingAsDot(bubble.getFlyoutMessage(),
+ mStackAnimationController.getStackPosition(), getWidth(),
+ mStackAnimationController.isStackOnLeftSide(),
+ bubble.getIconView().getDotColor() /* dotColor */,
+ expandFlyoutAfterDelay /* onLayoutComplete */,
+ mAfterFlyoutHidden,
+ bubble.getIconView().getDotCenter(),
+ !bubble.showDot());
+ }
mFlyout.bringToFront();
});
mFlyout.removeCallbacks(mHideFlyout);
mFlyout.postDelayed(mHideFlyout, FLYOUT_HIDE_AFTER);
- logBubbleEvent(bubble, SysUiStatsLog.BUBBLE_UICHANGED__ACTION__FLYOUT);
+ logBubbleEvent(bubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__FLYOUT);
}
/** Hide the flyout immediately and cancel any pending hide runnables. */
@@ -2393,7 +2375,6 @@
final float targetY = mTempRect.bottom - mManageMenu.getHeight();
final float xOffsetForAnimation = (isLtr ? 1 : -1) * mManageMenu.getWidth() / 4f;
-
if (show) {
mManageMenu.setScaleX(0.5f);
mManageMenu.setScaleY(0.5f);
@@ -2410,6 +2391,8 @@
.withEndActions(() -> {
View child = mManageMenu.getChildAt(0);
child.requestAccessibilityFocus();
+ // Update the AV's obscured touchable region for the new visibility state.
+ mExpandedBubble.getExpandedView().updateObscuredTouchableRegion();
})
.start();
@@ -2421,12 +2404,15 @@
.spring(DynamicAnimation.SCALE_Y, 0.5f)
.spring(DynamicAnimation.TRANSLATION_X, targetX - xOffsetForAnimation)
.spring(DynamicAnimation.TRANSLATION_Y, targetY + mManageMenu.getHeight() / 4f)
- .withEndActions(() -> mManageMenu.setVisibility(View.INVISIBLE))
+ .withEndActions(() -> {
+ mManageMenu.setVisibility(View.INVISIBLE);
+ if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+ // Update the AV's obscured touchable region for the new state.
+ mExpandedBubble.getExpandedView().updateObscuredTouchableRegion();
+ }
+ })
.start();
}
-
- // Update the AV's obscured touchable region for the new menu visibility state.
- mExpandedBubble.getExpandedView().updateObscuredTouchableRegion();
}
private void updateExpandedBubble() {
@@ -2446,7 +2432,6 @@
mExpandedViewContainer.setAlpha(0f);
mExpandedViewContainer.addView(bev);
bev.setManageClickListener((view) -> showManageMenu(!mShowingManage));
- bev.populateExpandedView();
if (!mIsExpansionAnimating) {
mSurfaceSynchronizer.syncSurfaceAndRun(() -> {
@@ -2503,7 +2488,7 @@
mAnimatingOutSurfaceContainer.setTranslationY(0);
final int[] activityViewLocation =
- mExpandedBubble.getExpandedView().getActivityViewLocationOnScreen();
+ mExpandedBubble.getExpandedView().getTaskViewLocationOnScreen();
final int[] surfaceViewLocation = mAnimatingOutSurfaceView.getLocationOnScreen();
// Translate the surface to overlap the real ActivityView.
@@ -2679,17 +2664,6 @@
getNormalizedYPosition());
}
- /**
- * Called when a back gesture should be directed to the Bubbles stack. When expanded,
- * a back key down/up event pair is forwarded to the bubble Activity.
- */
- boolean performBackPressIfNeeded() {
- if (!isExpanded() || mExpandedBubble == null || mExpandedBubble.getExpandedView() == null) {
- return false;
- }
- return mExpandedBubble.getExpandedView().performBackPressIfNeeded();
- }
-
/** For debugging only */
List<Bubble> getBubblesOnScreen() {
List<Bubble> bubbles = new ArrayList<>();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTaskView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTaskView.java
deleted file mode 100644
index 06205c5..0000000
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTaskView.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (C) 2020 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.systemui.bubbles;
-
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.ActivityOptions;
-import android.app.PendingIntent;
-import android.window.TaskEmbedder;
-import android.window.TaskOrganizerTaskEmbedder;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ShortcutInfo;
-import android.graphics.Matrix;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.view.IWindow;
-import android.view.SurfaceControl;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-
-import dalvik.system.CloseGuard;
-
-
-public class BubbleTaskView extends SurfaceView implements SurfaceHolder.Callback,
- TaskEmbedder.Host {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleTaskView" : TAG_BUBBLES;
-
- private final CloseGuard mGuard = CloseGuard.get();
- private boolean mOpened; // Protected by mGuard.
-
- private TaskEmbedder mTaskEmbedder;
- private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
- private final Rect mTmpRect = new Rect();
-
- public BubbleTaskView(Context context) {
- super(context);
-
- mTaskEmbedder = new TaskOrganizerTaskEmbedder(context, this);
- setUseAlpha();
- getHolder().addCallback(this);
-
- mOpened = true;
- mGuard.open("release");
- }
-
- public void setCallback(TaskEmbedder.Listener callback) {
- if (callback == null) {
- mTaskEmbedder.setListener(null);
- return;
- }
- mTaskEmbedder.setListener(callback);
- }
-
- public void startShortcutActivity(@NonNull ShortcutInfo shortcut,
- @NonNull ActivityOptions options, @Nullable Rect sourceBounds) {
- mTaskEmbedder.startShortcutActivity(shortcut, options, sourceBounds);
- }
-
- public void startActivity(@NonNull PendingIntent pendingIntent, @Nullable Intent fillInIntent,
- @NonNull ActivityOptions options) {
- mTaskEmbedder.startActivity(pendingIntent, fillInIntent, options);
- }
-
- public void onLocationChanged() {
- mTaskEmbedder.notifyBoundsChanged();
- }
-
- @Override
- public Rect getScreenBounds() {
- getBoundsOnScreen(mTmpRect);
- return mTmpRect;
- }
-
- @Override
- public void onTaskBackgroundColorChanged(TaskEmbedder ts, int bgColor) {
- setResizeBackgroundColor(bgColor);
- }
-
- @Override
- public Region getTapExcludeRegion() {
- // Not used
- return null;
- }
-
- @Override
- public Matrix getScreenToTaskMatrix() {
- // Not used
- return null;
- }
-
- @Override
- public IWindow getWindow() {
- // Not used
- return null;
- }
-
- @Override
- public Point getPositionInWindow() {
- // Not used
- return null;
- }
-
- @Override
- public boolean canReceivePointerEvents() {
- // Not used
- return false;
- }
-
- public void release() {
- if (!mTaskEmbedder.isInitialized()) {
- throw new IllegalStateException(
- "Trying to release container that is not initialized.");
- }
- performRelease();
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- if (mGuard != null) {
- mGuard.warnIfOpen();
- performRelease();
- }
- } finally {
- super.finalize();
- }
- }
-
- private void performRelease() {
- if (!mOpened) {
- return;
- }
- getHolder().removeCallback(this);
- mTaskEmbedder.release();
- mTaskEmbedder.setListener(null);
-
- mGuard.close();
- mOpened = false;
- }
-
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- if (!mTaskEmbedder.isInitialized()) {
- mTaskEmbedder.initialize(getSurfaceControl());
- } else {
- mTmpTransaction.reparent(mTaskEmbedder.getSurfaceControl(),
- getSurfaceControl()).apply();
- }
- mTaskEmbedder.start();
- }
-
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- mTaskEmbedder.resizeTask(width, height);
- mTaskEmbedder.notifyBoundsChanged();
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- mTaskEmbedder.stop();
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java
index 916ad18..5cc24ce 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java
@@ -48,5 +48,5 @@
boolean showDot();
- int getDisplayId();
+ int getTaskId();
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubbles.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubbles.java
index 34828b3..39c750d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubbles.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubbles.java
@@ -17,8 +17,6 @@
package com.android.systemui.bubbles;
import android.annotation.NonNull;
-import android.content.Context;
-import android.view.Display;
import androidx.annotation.MainThread;
@@ -57,12 +55,6 @@
*/
ScrimView getScrimForBubble();
- /**
- * @return the display id of the expanded view, if the stack is expanded and not occluded by the
- * status bar, otherwise returns {@link Display#INVALID_DISPLAY}.
- */
- int getExpandedDisplayId(Context context);
-
/** @return Bubbles for updating overflow. */
List<Bubble> getOverflowBubbles();
@@ -77,13 +69,6 @@
*/
void expandStackAndSelectBubble(NotificationEntry entry);
-
- /**
- * Directs a back gesture at the bubble stack. When opened, the current expanded bubble
- * is forwarded a back key down/up pair.
- */
- void performBackPressIfNeeded();
-
/** Promote the provided bubbles when overflow view. */
void promoteBubbleFromOverflow(Bubble bubble);
@@ -142,4 +127,7 @@
/** Set a listener to be notified of when overflow view update. */
void setOverflowListener(BubbleData.Listener listener);
+
+ /** The task listener for events in bubble tasks. **/
+ MultiWindowTaskListener getTaskManager();
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt b/packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt
index 26a9773..3db07c2 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt
@@ -25,8 +25,6 @@
import android.widget.TextView
import com.android.internal.util.ContrastColorUtil
import com.android.systemui.Interpolators
-import com.android.systemui.Prefs
-import com.android.systemui.Prefs.Key.HAS_SEEN_BUBBLES_MANAGE_EDUCATION
import com.android.systemui.R
/**
@@ -38,8 +36,8 @@
private val TAG = if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "BubbleManageEducationView"
else BubbleDebugConfig.TAG_BUBBLES
- private val ANIMATE_DURATION : Long = 200
- private val ANIMATE_DURATION_SHORT : Long = 40
+ private val ANIMATE_DURATION: Long = 200
+ private val ANIMATE_DURATION_SHORT: Long = 40
private val manageView by lazy { findViewById<View>(R.id.manage_education_view) }
private val manageButton by lazy { findViewById<Button>(R.id.manage) }
@@ -50,7 +48,7 @@
private var isHiding = false
init {
- LayoutInflater.from(context).inflate(R.layout.bubbles_manage_button_education, this);
+ LayoutInflater.from(context).inflate(R.layout.bubbles_manage_button_education, this)
visibility = View.GONE
elevation = resources.getDimensionPixelSize(R.dimen.bubble_elevation).toFloat()
@@ -95,7 +93,7 @@
*
* @param show whether the user education view should show or not.
*/
- fun show(expandedView: BubbleExpandedView, rect : Rect) {
+ fun show(expandedView: BubbleExpandedView, rect: Rect) {
if (visibility == VISIBLE) return
alpha = 0f
@@ -136,10 +134,13 @@
.withEndAction {
isHiding = false
visibility = GONE
- };
+ }
}
private fun setShouldShow(shouldShow: Boolean) {
- Prefs.putBoolean(context, HAS_SEEN_BUBBLES_MANAGE_EDUCATION, !shouldShow)
+ context.getSharedPreferences(context.packageName, Context.MODE_PRIVATE)
+ .edit().putBoolean(PREF_MANAGED_EDUCATION, !shouldShow).apply()
}
-}
\ No newline at end of file
+}
+
+const val PREF_MANAGED_EDUCATION: String = "HasSeenBubblesManageOnboarding"
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/MultiWindowTaskListener.java b/packages/SystemUI/src/com/android/systemui/bubbles/MultiWindowTaskListener.java
new file mode 100644
index 0000000..dff8bec
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/MultiWindowTaskListener.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2020 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.systemui.bubbles;
+
+import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_MULTI_WINDOW;
+
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityTaskManager;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.view.SurfaceControl;
+import android.window.TaskOrganizer;
+import android.window.WindowContainerToken;
+
+import com.android.wm.shell.ShellTaskOrganizer;
+
+/**
+ * Manages tasks that are displayed in multi-window (e.g. bubbles). These are displayed in a
+ * {@link TaskView}.
+ *
+ * This class listens on {@link TaskOrganizer} callbacks for events. Once visible, these tasks will
+ * intercept back press events.
+ *
+ * @see android.app.WindowConfiguration#WINDOWING_MODE_MULTI_WINDOW
+ * @see TaskView
+ */
+// TODO: Place in com.android.wm.shell vs. com.android.wm.shell.bubbles on shell migration.
+public class MultiWindowTaskListener implements ShellTaskOrganizer.TaskListener {
+ private static final String TAG = MultiWindowTaskListener.class.getSimpleName();
+
+ private static final boolean DEBUG = false;
+
+ //TODO(b/170153209): Have shell listener allow per task registration and remove this.
+ public interface Listener {
+ void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash);
+ void onTaskVanished(RunningTaskInfo taskInfo);
+ void onTaskInfoChanged(RunningTaskInfo taskInfo);
+ void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo);
+ }
+
+ private static class TaskData {
+ final RunningTaskInfo taskInfo;
+ final Listener listener;
+
+ TaskData(RunningTaskInfo info, Listener l) {
+ taskInfo = info;
+ listener = l;
+ }
+ }
+
+ private final Handler mHandler;
+ private final ShellTaskOrganizer mTaskOrganizer;
+ private final ArrayMap<WindowContainerToken, TaskData> mTasks = new ArrayMap<>();
+
+ private MultiWindowTaskListener.Listener mPendingListener;
+
+ /**
+ * Create a listener for tasks in multi-window mode.
+ */
+ public MultiWindowTaskListener(Handler handler, ShellTaskOrganizer organizer) {
+ mHandler = handler;
+ mTaskOrganizer = organizer;
+ mTaskOrganizer.addListener(this, TASK_LISTENER_TYPE_MULTI_WINDOW);
+ }
+
+ /**
+ * @return the task organizer that is listened to.
+ */
+ public TaskOrganizer getTaskOrganizer() {
+ return mTaskOrganizer;
+ }
+
+ // TODO(b/129067201): track launches for bubbles
+ // Once we have key in ActivityOptions, match listeners via that key
+ public void setPendingListener(Listener listener) {
+ mPendingListener = listener;
+ }
+
+ /**
+ * Removes a task listener previously registered when starting a new activity.
+ */
+ public void removeListener(Listener listener) {
+ if (DEBUG) {
+ Log.d(TAG, "removeListener: listener=" + listener);
+ }
+ if (mPendingListener == listener) {
+ mPendingListener = null;
+ }
+ for (int i = 0; i < mTasks.size(); i++) {
+ if (mTasks.valueAt(i).listener == listener) {
+ mTasks.removeAt(i);
+ }
+ }
+ }
+
+ @Override
+ public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
+ if (DEBUG) {
+ Log.d(TAG, "onTaskAppeared: taskInfo=" + taskInfo
+ + " mPendingListener=" + mPendingListener);
+ }
+ if (mPendingListener == null) {
+ // If there is no pending listener, then we are either receiving this task as a part of
+ // registering the task org again (ie. after SysUI dies) or the previously started
+ // task is no longer needed (ie. bubble is closed soon after), for now, just finish the
+ // associated task
+ try {
+ ActivityTaskManager.getService().removeTask(taskInfo.taskId);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to remove taskId " + taskInfo.taskId);
+ }
+ return;
+ }
+
+ mTaskOrganizer.setInterceptBackPressedOnTaskRoot(taskInfo.token, true);
+
+ final TaskData data = new TaskData(taskInfo, mPendingListener);
+ mTasks.put(taskInfo.token, data);
+ mHandler.post(() -> data.listener.onTaskAppeared(taskInfo, leash));
+ mPendingListener = null;
+ }
+
+ @Override
+ public void onTaskVanished(RunningTaskInfo taskInfo) {
+ final TaskData data = mTasks.remove(taskInfo.token);
+ if (data == null) {
+ return;
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "onTaskVanished: taskInfo=" + taskInfo + " listener=" + data.listener);
+ }
+ mHandler.post(() -> data.listener.onTaskVanished(taskInfo));
+ }
+
+ @Override
+ public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
+ final TaskData data = mTasks.get(taskInfo.token);
+ if (data == null) {
+ return;
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "onTaskInfoChanged: taskInfo=" + taskInfo + " listener=" + data.listener);
+ }
+ mHandler.post(() -> data.listener.onTaskInfoChanged(taskInfo));
+ }
+
+ @Override
+ public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
+ final TaskData data = mTasks.get(taskInfo.token);
+ if (data == null) {
+ return;
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "onTaskInfoChanged: taskInfo=" + taskInfo + " listener=" + data.listener);
+ }
+ mHandler.post(() -> data.listener.onBackPressedOnTaskRoot(taskInfo));
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/RelativeTouchListener.kt b/packages/SystemUI/src/com/android/systemui/bubbles/RelativeTouchListener.kt
similarity index 99%
rename from packages/SystemUI/src/com/android/systemui/util/RelativeTouchListener.kt
rename to packages/SystemUI/src/com/android/systemui/bubbles/RelativeTouchListener.kt
index 8880df9..b1291a5 100644
--- a/packages/SystemUI/src/com/android/systemui/util/RelativeTouchListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/RelativeTouchListener.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.util
+package com.android.systemui.bubbles
import android.graphics.PointF
import android.os.Handler
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt b/packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt
index 3e4c729..216df2e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt
@@ -24,21 +24,19 @@
import android.widget.TextView
import com.android.internal.util.ContrastColorUtil
import com.android.systemui.Interpolators
-import com.android.systemui.Prefs
-import com.android.systemui.Prefs.Key.HAS_SEEN_BUBBLES_EDUCATION
import com.android.systemui.R
/**
* User education view to highlight the collapsed stack of bubbles.
* Shown only the first time a user taps the stack.
*/
-class StackEducationView constructor(context: Context) : LinearLayout(context){
+class StackEducationView constructor(context: Context) : LinearLayout(context) {
private val TAG = if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "BubbleStackEducationView"
else BubbleDebugConfig.TAG_BUBBLES
- private val ANIMATE_DURATION : Long = 200
- private val ANIMATE_DURATION_SHORT : Long = 40
+ private val ANIMATE_DURATION: Long = 200
+ private val ANIMATE_DURATION_SHORT: Long = 40
private val view by lazy { findViewById<View>(R.id.stack_education_layout) }
private val titleTextView by lazy { findViewById<TextView>(R.id.stack_education_title) }
@@ -47,7 +45,7 @@
private var isHiding = false
init {
- LayoutInflater.from(context).inflate(R.layout.bubble_stack_user_education, this);
+ LayoutInflater.from(context).inflate(R.layout.bubble_stack_user_education, this)
visibility = View.GONE
elevation = resources.getDimensionPixelSize(R.dimen.bubble_elevation).toFloat()
@@ -93,7 +91,7 @@
*
* @return true if user education was shown, false otherwise.
*/
- fun show(stackPosition: PointF) : Boolean{
+ fun show(stackPosition: PointF): Boolean {
if (visibility == VISIBLE) return false
setAlpha(0f)
@@ -129,6 +127,9 @@
}
private fun setShouldShow(shouldShow: Boolean) {
- Prefs.putBoolean(context, HAS_SEEN_BUBBLES_EDUCATION, !shouldShow)
+ context.getSharedPreferences(context.packageName, Context.MODE_PRIVATE)
+ .edit().putBoolean(PREF_STACK_EDUCATION, !shouldShow).apply()
}
-}
\ No newline at end of file
+}
+
+const val PREF_STACK_EDUCATION: String = "HasSeenBubblesOnboarding"
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/TaskView.java b/packages/SystemUI/src/com/android/systemui/bubbles/TaskView.java
new file mode 100644
index 0000000..524fa42
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/TaskView.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2020 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.systemui.bubbles;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutInfo;
+import android.graphics.Rect;
+import android.view.SurfaceControl;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
+
+import dalvik.system.CloseGuard;
+
+/**
+ * View that can display a task.
+ */
+// TODO: Place in com.android.wm.shell vs. com.android.wm.shell.bubbles on shell migration.
+public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
+ MultiWindowTaskListener.Listener {
+
+ public interface Listener {
+ /** Called when the container is ready for launching activities. */
+ default void onInitialized() {}
+
+ /** Called when the container can no longer launch activities. */
+ default void onReleased() {}
+
+ /** Called when a task is created inside the container. */
+ default void onTaskCreated(int taskId, ComponentName name) {}
+
+ /** Called when a task visibility changes. */
+ default void onTaskVisibilityChanged(int taskId, boolean visible) {}
+
+ /** Called when a task is about to be removed from the stack inside the container. */
+ default void onTaskRemovalStarted(int taskId) {}
+
+ /** Called when a task is created inside the container. */
+ default void onBackPressedOnTaskRoot(int taskId) {}
+ }
+
+ private final CloseGuard mGuard = CloseGuard.get();
+
+ private final MultiWindowTaskListener mMultiWindowTaskListener;
+
+ private ActivityManager.RunningTaskInfo mTaskInfo;
+ private WindowContainerToken mTaskToken;
+ private SurfaceControl mTaskLeash;
+ private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+ private boolean mSurfaceCreated;
+ private boolean mIsInitialized;
+ private Listener mListener;
+
+ private final Rect mTmpRect = new Rect();
+ private final Rect mTmpRootRect = new Rect();
+
+ public TaskView(Context context, MultiWindowTaskListener taskListener) {
+ super(context, null, 0, 0, true /* disableBackgroundLayer */);
+
+ mMultiWindowTaskListener = taskListener;
+ setUseAlpha();
+ getHolder().addCallback(this);
+ mGuard.open("release");
+ }
+
+ /**
+ * Only one listener may be set on the view, throws an exception otherwise.
+ */
+ public void setListener(Listener listener) {
+ if (mListener != null) {
+ throw new IllegalStateException(
+ "Trying to set a listener when one has already been set");
+ }
+ mListener = listener;
+ }
+
+ /**
+ * Launch an activity represented by {@link ShortcutInfo}.
+ * <p>The owner of this container must be allowed to access the shortcut information,
+ * as defined in {@link LauncherApps#hasShortcutHostPermission()} to use this method.
+ *
+ * @param shortcut the shortcut used to launch the activity.
+ * @param options options for the activity.
+ * @param sourceBounds the rect containing the source bounds of the clicked icon to open
+ * this shortcut.
+ */
+ public void startShortcutActivity(@NonNull ShortcutInfo shortcut,
+ @NonNull ActivityOptions options, @Nullable Rect sourceBounds) {
+ mMultiWindowTaskListener.setPendingListener(this);
+ prepareActivityOptions(options);
+ LauncherApps service = mContext.getSystemService(LauncherApps.class);
+ try {
+ service.startShortcut(shortcut, sourceBounds, options.toBundle());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Launch a new activity.
+ *
+ * @param pendingIntent Intent used to launch an activity.
+ * @param fillInIntent Additional Intent data, see {@link Intent#fillIn Intent.fillIn()}
+ * @param options options for the activity.
+ */
+ public void startActivity(@NonNull PendingIntent pendingIntent, @Nullable Intent fillInIntent,
+ @NonNull ActivityOptions options) {
+ mMultiWindowTaskListener.setPendingListener(this);
+ prepareActivityOptions(options);
+ try {
+ pendingIntent.send(mContext, 0 /* code */, fillInIntent,
+ null /* onFinished */, null /* handler */, null /* requiredPermission */,
+ options.toBundle());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void prepareActivityOptions(ActivityOptions options) {
+ options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ options.setTaskAlwaysOnTop(true);
+ }
+
+ /**
+ * Call when view position or size has changed. Do not call when animating.
+ */
+ public void onLocationChanged() {
+ if (mTaskToken == null) {
+ return;
+ }
+ // Update based on the screen bounds
+ getBoundsOnScreen(mTmpRect);
+ getRootView().getBoundsOnScreen(mTmpRootRect);
+ if (!mTmpRootRect.contains(mTmpRect)) {
+ mTmpRect.offsetTo(0, 0);
+ }
+
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.setBounds(mTaskToken, mTmpRect);
+ // TODO(b/151449487): Enable synchronization
+ mMultiWindowTaskListener.getTaskOrganizer().applyTransaction(wct);
+ }
+
+ /**
+ * Release this container if it is initialized.
+ */
+ public void release() {
+ performRelease();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (mGuard != null) {
+ mGuard.warnIfOpen();
+ performRelease();
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+
+ private void performRelease() {
+ getHolder().removeCallback(this);
+ mMultiWindowTaskListener.removeListener(this);
+ resetTaskInfo();
+ mGuard.close();
+ if (mListener != null && mIsInitialized) {
+ mListener.onReleased();
+ mIsInitialized = false;
+ }
+ }
+
+ private void resetTaskInfo() {
+ mTaskInfo = null;
+ mTaskToken = null;
+ mTaskLeash = null;
+ }
+
+ private void updateTaskVisibility() {
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.setHidden(mTaskToken, !mSurfaceCreated /* hidden */);
+ mMultiWindowTaskListener.getTaskOrganizer().applyTransaction(wct);
+ // TODO(b/151449487): Only call callback once we enable synchronization
+ if (mListener != null) {
+ mListener.onTaskVisibilityChanged(mTaskInfo.taskId, mSurfaceCreated);
+ }
+ }
+
+ @Override
+ public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo,
+ SurfaceControl leash) {
+ mTaskInfo = taskInfo;
+ mTaskToken = taskInfo.token;
+ mTaskLeash = leash;
+
+ if (mSurfaceCreated) {
+ // Surface is ready, so just reparent the task to this surface control
+ mTransaction.reparent(mTaskLeash, getSurfaceControl())
+ .show(mTaskLeash)
+ .apply();
+ } else {
+ // The surface has already been destroyed before the task has appeared, so go ahead and
+ // hide the task entirely
+ updateTaskVisibility();
+ }
+
+ // TODO: Synchronize show with the resize
+ onLocationChanged();
+ setResizeBackgroundColor(taskInfo.taskDescription.getBackgroundColor());
+
+ if (mListener != null) {
+ mListener.onTaskCreated(taskInfo.taskId, taskInfo.baseActivity);
+ }
+ }
+
+ @Override
+ public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
+ if (mTaskToken != null && mTaskToken.equals(taskInfo.token)) {
+ if (mListener != null) {
+ mListener.onTaskRemovalStarted(taskInfo.taskId);
+ }
+
+ // Unparent the task when this surface is destroyed
+ mTransaction.reparent(mTaskLeash, null).apply();
+ resetTaskInfo();
+ }
+ }
+
+ @Override
+ public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ mTaskInfo.taskDescription = taskInfo.taskDescription;
+ setResizeBackgroundColor(taskInfo.taskDescription.getBackgroundColor());
+ }
+
+ @Override
+ public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
+ if (mTaskToken != null && mTaskToken.equals(taskInfo.token)) {
+ if (mListener != null) {
+ mListener.onBackPressedOnTaskRoot(taskInfo.taskId);
+ }
+ }
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ mSurfaceCreated = true;
+ if (mListener != null && !mIsInitialized) {
+ mIsInitialized = true;
+ mListener.onInitialized();
+ }
+ if (mTaskToken == null) {
+ // Nothing to update, task is not yet available
+ return;
+ }
+ // Reparent the task when this surface is created
+ mTransaction.reparent(mTaskLeash, getSurfaceControl())
+ .show(mTaskLeash)
+ .apply();
+ updateTaskVisibility();
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ if (mTaskToken == null) {
+ return;
+ }
+ onLocationChanged();
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ mSurfaceCreated = false;
+ if (mTaskToken == null) {
+ // Nothing to update, task is not yet available
+ return;
+ }
+
+ // Unparent the task when this surface is destroyed
+ mTransaction.reparent(mTaskLeash, null).apply();
+ updateTaskVisibility();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
index 9f88ee5..7fdc019 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
@@ -58,6 +58,9 @@
/** Duration of the expand/collapse target path animation. */
public static final int EXPAND_COLLAPSE_TARGET_ANIM_DURATION = 175;
+ /** Damping ratio for expand/collapse spring. */
+ private static final float DAMPING_RATIO_MEDIUM_LOW_BOUNCY = 0.65f;
+
/** Stiffness for the expand/collapse path-following animation. */
private static final int EXPAND_COLLAPSE_ANIM_STIFFNESS = 1000;
@@ -271,16 +274,14 @@
// Then, draw a line across the screen to the bubble's resting position.
path.lineTo(getBubbleLeft(index), expandedY);
} else {
- final float sideMultiplier =
- mLayout.isFirstChildXLeftOfCenter(mCollapsePoint.x) ? -1 : 1;
- final float stackedX = mCollapsePoint.x + (sideMultiplier * index * mStackOffsetPx);
+ final float stackedX = mCollapsePoint.x;
// If we're collapsing, draw a line from the bubble's current position to the side
// of the screen where the bubble will be stacked.
path.lineTo(stackedX, expandedY);
// Then, draw a line down to the stack position.
- path.lineTo(stackedX, mCollapsePoint.y);
+ path.lineTo(stackedX, mCollapsePoint.y + index * mStackOffsetPx);
}
// The lead bubble should be the bubble with the longest distance to travel when we're
@@ -510,7 +511,7 @@
@Override
SpringForce getSpringForce(DynamicAnimation.ViewProperty property, View view) {
return new SpringForce()
- .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
+ .setDampingRatio(DAMPING_RATIO_MEDIUM_LOW_BOUNCY)
.setStiffness(SpringForce.STIFFNESS_LOW);
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
index 4c902b9..1205124 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -744,15 +744,13 @@
@Override
float getOffsetForChainedPropertyAnimation(DynamicAnimation.ViewProperty property) {
- if (property.equals(DynamicAnimation.TRANSLATION_X)) {
+ if (property.equals(DynamicAnimation.TRANSLATION_Y)) {
// If we're in the dismiss target, have the bubbles pile on top of each other with no
// offset.
if (isStackStuckToTarget()) {
return 0f;
} else {
- // Offset to the left if we're on the left, or the right otherwise.
- return mLayout.isFirstChildXLeftOfCenter(mStackPosition.x)
- ? -mStackOffset : mStackOffset;
+ return mStackOffset;
}
} else {
return 0f;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
index 00ae3a3..6b5f237 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
@@ -19,13 +19,15 @@
import android.app.INotificationManager;
import android.content.Context;
import android.content.pm.LauncherApps;
+import android.os.Handler;
import android.view.WindowManager;
+import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.bubbles.BubbleController;
-import com.android.systemui.bubbles.BubbleDataRepository;
import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -39,6 +41,7 @@
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.FloatingContentCoordinator;
@@ -68,13 +71,15 @@
FeatureFlags featureFlags,
DumpManager dumpManager,
FloatingContentCoordinator floatingContentCoordinator,
- BubbleDataRepository bubbleDataRepository,
SysUiState sysUiState,
INotificationManager notifManager,
IStatusBarService statusBarService,
WindowManager windowManager,
WindowManagerShellWrapper windowManagerShellWrapper,
- LauncherApps launcherApps) {
+ LauncherApps launcherApps,
+ UiEventLogger uiEventLogger,
+ @Main Handler mainHandler,
+ ShellTaskOrganizer organizer) {
return BubbleController.create(
context,
notificationShadeWindowController,
@@ -91,12 +96,14 @@
featureFlags,
dumpManager,
floatingContentCoordinator,
- bubbleDataRepository,
sysUiState,
notifManager,
statusBarService,
windowManager,
windowManagerShellWrapper,
- launcherApps);
+ launcherApps,
+ uiEventLogger,
+ mainHandler,
+ organizer);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt
index f447965..ce0786d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt
@@ -18,16 +18,11 @@
import android.content.Context
import android.util.AtomicFile
import android.util.Log
-import com.android.systemui.dagger.SysUISingleton
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
-import javax.inject.Inject
-@SysUISingleton
-class BubblePersistentRepository @Inject constructor(
- context: Context
-) {
+class BubblePersistentRepository(context: Context) {
private val bubbleFile: AtomicFile = AtomicFile(File(context.filesDir,
"overflow_bubbles.xml"), "overflow-bubbles")
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt
index c6d5732..e0a7c78 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt
@@ -19,8 +19,6 @@
import android.os.UserHandle
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.bubbles.ShortcutKey
-import com.android.systemui.dagger.SysUISingleton
-import javax.inject.Inject
private const val CAPACITY = 16
@@ -28,10 +26,7 @@
* BubbleVolatileRepository holds the most updated snapshot of list of bubbles for in-memory
* manipulation.
*/
-@SysUISingleton
-class BubbleVolatileRepository @Inject constructor(
- private val launcherApps: LauncherApps
-) {
+class BubbleVolatileRepository(private val launcherApps: LauncherApps) {
/**
* An ordered set of bubbles based on their natural ordering.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index e303754..cb90b61 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -66,6 +66,7 @@
import com.android.systemui.shared.plugins.PluginManagerImpl;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
+import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.shared.system.WindowManagerWrapper;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -263,6 +264,13 @@
return ActivityManagerWrapper.getInstance();
}
+ /** */
+ @Provides
+ @SysUISingleton
+ public TaskStackChangeListeners provideTaskStackChangeListeners() {
+ return TaskStackChangeListeners.getInstance();
+ }
+
/** Provides and initializes the {#link BroadcastDispatcher} for SystemUI */
@Provides
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index 6154a4e..f470a6b 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -123,6 +123,14 @@
}
/**
+ * Appends dozing event to the logs
+ * @param suppressed true if dozing is suppressed
+ */
+ public void traceDozingSuppressed(boolean suppressed) {
+ mLogger.logDozingSuppressed(suppressed);
+ }
+
+ /**
* Appends fling event to the logs
*/
public void traceFling(boolean expand, boolean aboveThreshold, boolean thresholdNeeded,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
index 46cec95..0c9e143 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
@@ -64,6 +64,14 @@
})
}
+ fun logDozingSuppressed(isDozingSuppressed: Boolean) {
+ buffer.log(TAG, INFO, {
+ bool1 = isDozingSuppressed
+ }, {
+ "DozingSuppressed=$bool1"
+ })
+ }
+
fun logFling(
expand: Boolean,
aboveThreshold: Boolean,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 1e0460b..befb648 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -413,6 +413,7 @@
pw.print(" state="); pw.println(mState);
pw.print(" wakeLockHeldForCurrentState="); pw.println(mWakeLockHeldForCurrentState);
pw.print(" wakeLock="); pw.println(mWakeLock);
+ pw.print(" isDozeSuppressed="); pw.println(mDozeHost.isDozeSuppressed());
pw.println("Parts:");
for (Part p : mParts) {
p.dump(pw);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeScope.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeScope.java
index 7a8b816..435859a 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeScope.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeScope.java
@@ -24,7 +24,7 @@
import javax.inject.Scope;
/**
- * Scope annotation for singleton items within the StatusBarComponent.
+ * Scope annotation for singleton items within the DozeComponent.
*/
@Documented
@Retention(RUNTIME)
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index b55b29a..a330be6 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -140,8 +140,14 @@
d.setContentView(R.layout.shutdown_dialog);
d.setCancelable(false);
- int color = Utils.getColorAttrDefaultColor(mContext,
- com.android.systemui.R.attr.wallpaperTextColor);
+ int color;
+ if (mBlurUtils.supportsBlursOnWindows()) {
+ color = Utils.getColorAttrDefaultColor(mContext,
+ com.android.systemui.R.attr.wallpaperTextColor);
+ } else {
+ color = mContext.getResources().getColor(
+ com.android.systemui.R.color.global_actions_shutdown_ui_text);
+ }
ProgressBar bar = d.findViewById(R.id.progress);
bar.getIndeterminateDrawable().setTint(color);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
index c281ece..7585110 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
@@ -30,8 +30,8 @@
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.shared.system.TaskStackChangeListeners;
public class WorkLockActivityController {
private static final String TAG = WorkLockActivityController.class.getSimpleName();
@@ -40,16 +40,16 @@
private final IActivityTaskManager mIatm;
public WorkLockActivityController(Context context) {
- this(context, ActivityManagerWrapper.getInstance(), ActivityTaskManager.getService());
+ this(context, TaskStackChangeListeners.getInstance(), ActivityTaskManager.getService());
}
@VisibleForTesting
WorkLockActivityController(
- Context context, ActivityManagerWrapper am, IActivityTaskManager iAtm) {
+ Context context, TaskStackChangeListeners tscl, IActivityTaskManager iAtm) {
mContext = context;
mIatm = iAtm;
- am.registerTaskStackListener(mLockListener);
+ tscl.registerTaskStackListener(mLockListener);
}
private void startWorkChallengeInTask(int taskId, int userId) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
index d80aafb..cb14f31 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
@@ -282,10 +282,12 @@
scrollXAmount = -1 * relativePos
}
if (scrollXAmount != 0) {
+ val dx = if (isRtl) -scrollXAmount else scrollXAmount
+ val newScrollX = scrollView.relativeScrollX + dx
// Delay the scrolling since scrollView calls springback which cancels
// the animation again..
mainExecutor.execute {
- scrollView.smoothScrollBy(if (isRtl) -scrollXAmount else scrollXAmount, 0)
+ scrollView.smoothScrollTo(newScrollX, scrollView.scrollY)
}
}
val currentTranslation = scrollView.getContentTranslation()
@@ -553,4 +555,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
index 11551ac..666a603 100644
--- a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
@@ -23,7 +23,6 @@
import android.widget.ImageView
import android.widget.SeekBar
import android.widget.TextView
-import androidx.constraintlayout.widget.ConstraintSet
import com.android.systemui.R
import com.android.systemui.util.animation.TransitionLayout
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
index 6cbf065..df9e7a4 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
@@ -47,6 +47,7 @@
import com.android.systemui.navigationbar.buttons.KeyButtonDrawable;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.RotationLockController;
@@ -156,7 +157,7 @@
throw e.rethrowFromSystemServer();
}
- ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
+ TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
}
void unregisterListeners() {
@@ -171,7 +172,7 @@
throw e.rethrowFromSystemServer();
}
- ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskStackListener);
+ TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
}
void addRotationCallback(Consumer<Integer> watcher) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java
index af851a7..4efe4d8 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java
@@ -58,7 +58,6 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.shared.system.QuickStepContract;
@@ -426,12 +425,6 @@
if (getDisplay() != null) {
displayId = getDisplay().getDisplayId();
}
- // Bubbles will give us a valid display id if it should get the back event
- Bubbles Bubbles = Dependency.get(Bubbles.class);
- int bubbleDisplayId = Bubbles.getExpandedDisplayId(mContext);
- if (mCode == KeyEvent.KEYCODE_BACK && bubbleDisplayId != INVALID_DISPLAY) {
- displayId = bubbleDisplayId;
- }
if (displayId != INVALID_DISPLAY) {
ev.setDisplayId(displayId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index fc9c3d9..18cc746 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -15,8 +15,6 @@
*/
package com.android.systemui.navigationbar.gestural;
-import static android.view.Display.INVALID_DISPLAY;
-
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
@@ -57,7 +55,6 @@
import com.android.systemui.R;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.navigationbar.NavigationModeController;
@@ -71,6 +68,7 @@
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.shared.tracing.ProtoTraceable;
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.tracing.nano.EdgeBackGestureHandlerProto;
@@ -387,7 +385,7 @@
mGestureNavigationSettingsObserver.unregister();
mContext.getSystemService(DisplayManager.class).unregisterDisplayListener(this);
mPluginManager.removePluginListener(this);
- ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskStackListener);
+ TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
try {
@@ -403,7 +401,7 @@
updateDisplaySize();
mContext.getSystemService(DisplayManager.class).registerDisplayListener(this,
mContext.getMainThreadHandler());
- ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
+ TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
runnable -> (mContext.getMainThreadHandler()).post(runnable),
mOnPropertiesChangedListener);
@@ -733,13 +731,7 @@
KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
InputDevice.SOURCE_KEYBOARD);
- // Bubbles will give us a valid display id if it should get the back event
- final int bubbleDisplayId = Dependency.get(Bubbles.class).getExpandedDisplayId(mContext);
- if (bubbleDisplayId != INVALID_DISPLAY) {
- ev.setDisplayId(bubbleDisplayId);
- } else {
- ev.setDisplayId(mContext.getDisplay().getDisplayId());
- }
+ ev.setDisplayId(mContext.getDisplay().getDisplayId());
InputManager.getInstance().injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
index 284f41a..fbbda5f 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
@@ -16,6 +16,8 @@
package com.android.systemui.navigationbar.gestural;
+import static android.view.Display.DEFAULT_DISPLAY;
+
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Configuration;
@@ -334,6 +336,7 @@
.getDimension(R.dimen.navigation_edge_action_drag_threshold);
setVisibility(GONE);
+ boolean isPrimaryDisplay = mContext.getDisplayId() == DEFAULT_DISPLAY;
mRegionSamplingHelper = new RegionSamplingHelper(this,
new RegionSamplingHelper.SamplingCallback() {
@Override
@@ -345,8 +348,14 @@
public Rect getSampledRegion(View sampledView) {
return mSamplingRect;
}
+
+ @Override
+ public boolean isSamplingEnabled() {
+ return isPrimaryDisplay;
+ }
});
mRegionSamplingHelper.setWindowVisible(true);
+ mShowProtection = !isPrimaryDisplay;
}
@Override
@@ -366,11 +375,6 @@
updateIsDark(animate);
}
- private void setShowProtection(boolean showProtection) {
- mShowProtection = showProtection;
- invalidate();
- }
-
@Override
public void setIsLeftPanel(boolean isLeftPanel) {
mIsLeftPanel = isLeftPanel;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 5279a20..ddf30ad 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -95,7 +95,6 @@
import com.android.wm.shell.onehanded.OneHandedEvents;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipAnimationController;
-import com.android.wm.shell.pip.phone.PipUtils;
import com.android.wm.shell.splitscreen.SplitScreen;
import java.io.FileDescriptor;
@@ -151,7 +150,6 @@
private int mConnectionBackoffAttempts;
private boolean mBound;
private boolean mIsEnabled;
- private boolean mHasPipFeature;
private int mCurrentBoundedUserId = -1;
private float mNavBarButtonAlpha;
private boolean mInputFocusTransferStarted;
@@ -377,9 +375,7 @@
@Override
public void setShelfHeight(boolean visible, int shelfHeight) {
- if (!verifyCaller("setShelfHeight") || !mHasPipFeature) {
- Log.w(TAG_OPS,
- "ByPass setShelfHeight, FEATURE_PICTURE_IN_PICTURE:" + mHasPipFeature);
+ if (!verifyCaller("setShelfHeight")) {
return;
}
final long token = Binder.clearCallingIdentity();
@@ -405,9 +401,7 @@
@Override
public void notifySwipeToHomeFinished() {
- if (!verifyCaller("notifySwipeToHomeFinished") || !mHasPipFeature) {
- Log.w(TAG_OPS, "ByPass notifySwipeToHomeFinished, FEATURE_PICTURE_IN_PICTURE:"
- + mHasPipFeature);
+ if (!verifyCaller("notifySwipeToHomeFinished")) {
return;
}
final long token = Binder.clearCallingIdentity();
@@ -422,9 +416,7 @@
@Override
public void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) {
- if (!verifyCaller("setPinnedStackAnimationListener") || !mHasPipFeature) {
- Log.w(TAG_OPS, "ByPass setPinnedStackAnimationListener, FEATURE_PICTURE_IN_PICTURE:"
- + mHasPipFeature);
+ if (!verifyCaller("setPinnedStackAnimationListener")) {
return;
}
mIPinnedStackAnimationListener = listener;
@@ -509,7 +501,7 @@
public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
PictureInPictureParams pictureInPictureParams,
int launcherRotation, int shelfHeight) {
- if (!verifyCaller("startSwipePipToHome") || !mHasPipFeature) {
+ if (!verifyCaller("startSwipePipToHome")) {
return null;
}
final long binderToken = Binder.clearCallingIdentity();
@@ -525,7 +517,7 @@
@Override
public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
- if (!verifyCaller("stopSwipePipToHome") || !mHasPipFeature) {
+ if (!verifyCaller("stopSwipePipToHome")) {
return;
}
final long binderToken = Binder.clearCallingIdentity();
@@ -650,7 +642,6 @@
super(broadcastDispatcher);
mContext = context;
mPipOptional = pipOptional;
- mHasPipFeature = PipUtils.hasSystemFeature(mContext);
mStatusBarOptionalLazy = statusBarOptionalLazy;
mHandler = new Handler();
mNavBarControllerLazy = navBarControllerLazy;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index 9c5a3de..ccf2598 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -67,6 +67,7 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.shared.system.TaskStackChangeListeners;
import java.io.PrintWriter;
import java.util.Collections;
@@ -365,7 +366,7 @@
mOverviewProxyListenerRegistered = true;
}
if (!mTaskListenerRegistered) {
- ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskListener);
+ TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskListener);
mTaskListenerRegistered = true;
}
}
@@ -377,7 +378,7 @@
mOverviewProxyListenerRegistered = false;
}
if (mTaskListenerRegistered) {
- ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskListener);
+ TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskListener);
mTaskListenerRegistered = false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index fe32227..aaa335c 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -321,8 +321,17 @@
Insets visibleInsets, int taskId, int userId, ComponentName topComponent,
Consumer<Uri> finisher, Runnable onComplete) {
// TODO: use task Id, userId, topComponent for smart handler
-
mOnCompleteRunnable = onComplete;
+
+ if (screenshot == null) {
+ Log.e(TAG, "Got null bitmap from screenshot message");
+ mNotificationsController.notifyScreenshotError(
+ R.string.screenshot_failed_to_capture_text);
+ finisher.accept(null);
+ mOnCompleteRunnable.run();
+ return;
+ }
+
if (aspectRatiosMatch(screenshot, visibleInsets, screenshotScreenBounds)) {
saveScreenshot(screenshot, finisher, screenshotScreenBounds, visibleInsets, false);
} else {
@@ -569,7 +578,17 @@
.build();
final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
SurfaceControl.captureDisplay(captureArgs);
- final Bitmap screenshot = screenshotBuffer == null ? null : screenshotBuffer.asBitmap();
+ Bitmap screenshot = screenshotBuffer == null ? null : screenshotBuffer.asBitmap();
+
+ if (screenshot == null) {
+ Log.e(TAG, "Screenshot bitmap was null");
+ mNotificationsController.notifyScreenshotError(
+ R.string.screenshot_failed_to_capture_text);
+ finisher.accept(null);
+ mOnCompleteRunnable.run();
+ return;
+ }
+
saveScreenshot(screenshot, finisher, screenRect, Insets.NONE, true);
}
@@ -593,14 +612,6 @@
mScreenBitmap = screenshot;
- if (mScreenBitmap == null) {
- mNotificationsController.notifyScreenshotError(
- R.string.screenshot_failed_to_capture_text);
- finisher.accept(null);
- mOnCompleteRunnable.run();
- return;
- }
-
if (!isUserSetupComplete()) {
// User setup isn't complete, so we don't want to show any UI beyond a toast, as editing
// and sharing shouldn't be exposed to the user.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 0184fa7..dcee9fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -140,6 +140,8 @@
private static final int MSG_SUPPRESS_AMBIENT_DISPLAY = 56 << MSG_SHIFT;
private static final int MSG_REQUEST_WINDOW_MAGNIFICATION_CONNECTION = 57 << MSG_SHIFT;
private static final int MSG_HANDLE_WINDOW_MANAGER_LOGGING_COMMAND = 58 << MSG_SHIFT;
+ //TODO(b/169175022) Update name and when feature name is locked.
+ private static final int MSG_EMERGENCY_ACTION_LAUNCH_GESTURE = 59 << MSG_SHIFT;
public static final int FLAG_EXCLUDE_NONE = 0;
public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -258,6 +260,11 @@
default void showAssistDisclosure() { }
default void startAssist(Bundle args) { }
default void onCameraLaunchGestureDetected(int source) { }
+
+ /**
+ * Notifies SysUI that the emergency action gesture was detected.
+ */
+ default void onEmergencyActionLaunchGestureDetected() { }
default void showPictureInPictureMenu() { }
default void setTopAppHidesStatusBar(boolean topAppHidesStatusBar) { }
@@ -730,6 +737,14 @@
}
@Override
+ public void onEmergencyActionLaunchGestureDetected() {
+ synchronized (mLock) {
+ mHandler.removeMessages(MSG_EMERGENCY_ACTION_LAUNCH_GESTURE);
+ mHandler.obtainMessage(MSG_EMERGENCY_ACTION_LAUNCH_GESTURE).sendToTarget();
+ }
+ }
+
+ @Override
public void addQsTile(ComponentName tile) {
synchronized (mLock) {
mHandler.obtainMessage(MSG_ADD_QS_TILE, tile).sendToTarget();
@@ -1186,6 +1201,10 @@
mCallbacks.get(i).onCameraLaunchGestureDetected(msg.arg1);
}
break;
+ case MSG_EMERGENCY_ACTION_LAUNCH_GESTURE:
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ mCallbacks.get(i).onEmergencyActionLaunchGestureDetected();
+ }
case MSG_SHOW_PICTURE_IN_PICTURE_MENU:
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).showPictureInPictureMenu();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index f1727ec..094e866 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -124,6 +124,7 @@
private float mAppearAnimationTranslation;
private int mNormalColor;
private boolean mIsBelowSpeedBump;
+ private long mLastActionUpTime;
private float mNormalBackgroundVisibilityAmount;
private float mDimmedBackgroundFadeInAmount = -1;
@@ -225,6 +226,22 @@
return super.onInterceptTouchEvent(ev);
}
+ /** Sets the last action up time this view was touched. */
+ void setLastActionUpTime(long eventTime) {
+ mLastActionUpTime = eventTime;
+ }
+
+ /**
+ * Returns the last action up time. The last time will also be cleared because the source of
+ * action is not only from touch event. That prevents the caller from utilizing the time with
+ * unrelated event. The time can be 0 if the event is unavailable.
+ */
+ public long getAndResetLastActionUpTime() {
+ long lastActionUpTime = mLastActionUpTime;
+ mLastActionUpTime = 0;
+ return lastActionUpTime;
+ }
+
protected boolean disallowSingleClick(MotionEvent ev) {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
index dd30c89..41ce51c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.row;
+import android.os.SystemClock;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
@@ -92,6 +93,9 @@
mBlockNextTouch = false;
return true;
}
+ if (ev.getAction() == MotionEvent.ACTION_UP) {
+ mView.setLastActionUpTime(SystemClock.uptimeMillis());
+ }
if (mNeedsDimming && !mAccessibilityManager.isTouchExplorationEnabled()
&& mView.isInteractive()) {
if (mNeedsDimming && !mView.isDimmed()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index efb2469..a5667bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -456,6 +456,7 @@
return;
}
mSuppressed = suppressed;
+ mDozeLog.traceDozingSuppressed(mSuppressed);
for (Callback callback : mCallbacks) {
callback.onDozeSuppressedChanged(suppressed);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index a3f14ba..ef4108b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -23,6 +23,7 @@
import android.util.MathUtils;
import com.android.keyguard.KeyguardStatusView;
+import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -122,6 +123,8 @@
*/
private int mUnlockedStackScrollerPadding;
+ private int mLockScreenMode;
+
/**
* Refreshes the dimension values.
*/
@@ -171,6 +174,13 @@
result.clockX = (int) interpolate(0, burnInPreventionOffsetX(), mDarkAmount);
}
+ /**
+ * Update lock screen mode for testing different layouts
+ */
+ public void onLockScreenModeChanged(int mode) {
+ mLockScreenMode = mode;
+ }
+
public float getMinStackScrollerPadding() {
return mBypassEnabled ? mUnlockedStackScrollerPadding
: mMinTopMargin + mKeyguardStatusHeight + mClockNotificationsMargin;
@@ -185,6 +195,9 @@
}
private int getExpandedPreferredClockY() {
+ if (mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL) {
+ return mMinTopMargin;
+ }
return (mHasCustomClock && (!mHasVisibleNotifs || mBypassEnabled)) ? getPreferredClockY()
: getExpandedClockPosition();
}
@@ -228,6 +241,13 @@
clockYDark = MathUtils.lerp(clockYBouncer, clockYDark, shadeExpansion);
float darkAmount = mBypassEnabled && !mHasCustomClock ? 1.0f : mDarkAmount;
+
+ // TODO(b/12836565) - prototyping only adjustment
+ if (mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL) {
+ // This will keep the clock at the top for AOD
+ darkAmount = 0f;
+ }
+
return (int) (MathUtils.lerp(clockY, clockYDark, darkAmount) + mEmptyDragAmount);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 3f636ff..86d4ac1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -221,6 +221,11 @@
new KeyguardUpdateMonitorCallback() {
@Override
+ public void onLockScreenModeChanged(int mode) {
+ mClockPositionAlgorithm.onLockScreenModeChanged(mode);
+ }
+
+ @Override
public void onBiometricAuthenticated(int userId,
BiometricSourceType biometricSourceType,
boolean isStrongBiometric) {
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 e7c29b6..88a387d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -69,6 +69,7 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.PointF;
@@ -152,6 +153,7 @@
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeCommandReceiver;
import com.android.systemui.demomode.DemoModeController;
+import com.android.systemui.emergency.EmergencyGesture;
import com.android.systemui.fragments.ExtensionFragmentListener;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.keyguard.DismissCallbackRegistry;
@@ -819,7 +821,7 @@
updateScrimController();
};
-
+ mActivityIntentHelper = new ActivityIntentHelper(mContext);
DateTimeView.setReceiverHandler(timeTickHandler);
}
@@ -833,8 +835,6 @@
mBubblesOptional.get().setExpandListener(mBubbleExpandListener);
}
- mActivityIntentHelper = new ActivityIntentHelper(mContext);
-
mColorExtractor.addOnColorsChangedListener(this);
mStatusBarStateController.addCallback(this,
SysuiStatusBarStateController.RANK_STATUS_BAR);
@@ -3539,8 +3539,6 @@
if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) {
if (mNotificationPanelViewController.canPanelBeCollapsed()) {
mShadeController.animateCollapsePanels();
- } else if (mBubblesOptional.isPresent()) {
- mBubblesOptional.get().performBackPressIfNeeded();
}
return true;
}
@@ -3982,6 +3980,27 @@
}
}
+ @Override
+ public void onEmergencyActionLaunchGestureDetected() {
+ // TODO (b/169793384) Polish the panic gesture to be just like its older brother, camera.
+ Intent emergencyIntent = new Intent(EmergencyGesture.ACTION_LAUNCH_EMERGENCY);
+ PackageManager pm = mContext.getPackageManager();
+ ResolveInfo resolveInfo = pm.resolveActivity(emergencyIntent, /*flags=*/0);
+ if (resolveInfo == null) {
+ Log.wtf(TAG, "Couldn't find an app to process the emergency intent.");
+ return;
+ }
+
+ if (mVibrator != null && mVibrator.hasVibrator()) {
+ mVibrator.vibrate(500L);
+ }
+
+ emergencyIntent.setComponent(new ComponentName(resolveInfo.activityInfo.packageName,
+ resolveInfo.activityInfo.name));
+ emergencyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(emergencyIntent, /*dismissShade=*/true);
+ }
+
boolean isCameraAllowedByAdmin() {
if (mDevicePolicyManager.getCameraDisabled(null,
mLockscreenUserManager.getCurrentUserId())) {
@@ -4284,6 +4303,19 @@
}
public static Bundle getActivityOptions(@Nullable RemoteAnimationAdapter animationAdapter) {
+ return getDefaultActivityOptions(animationAdapter).toBundle();
+ }
+
+ public static Bundle getActivityOptions(@Nullable RemoteAnimationAdapter animationAdapter,
+ boolean isKeyguardShowing, long eventTime) {
+ ActivityOptions options = getDefaultActivityOptions(animationAdapter);
+ options.setSourceInfo(isKeyguardShowing ? ActivityOptions.SourceInfo.TYPE_LOCKSCREEN
+ : ActivityOptions.SourceInfo.TYPE_NOTIFICATION, eventTime);
+ return options.toBundle();
+ }
+
+ public static ActivityOptions getDefaultActivityOptions(
+ @Nullable RemoteAnimationAdapter animationAdapter) {
ActivityOptions options;
if (animationAdapter != null) {
options = ActivityOptions.makeRemoteAnimation(animationAdapter);
@@ -4293,7 +4325,7 @@
// Anything launched from the notification shade should always go into the secondary
// split-screen windowing mode.
options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
- return options.toBundle();
+ return options;
}
void visibilityChanged(boolean visible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index aa01642..256ee20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -30,6 +30,7 @@
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
@@ -40,7 +41,6 @@
import android.text.TextUtils;
import android.util.EventLog;
import android.view.RemoteAnimationAdapter;
-import android.view.View;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.NotificationVisibility;
@@ -402,7 +402,7 @@
PendingIntent intent,
Intent fillInIntent,
NotificationEntry entry,
- View row,
+ ExpandableNotificationRow row,
boolean wasOccluded,
boolean isActivityIntent) {
RemoteAnimationAdapter adapter = mActivityLaunchAnimator.getLaunchAnimation(row,
@@ -414,8 +414,11 @@
.registerRemoteAnimationForNextActivityStart(
intent.getCreatorPackage(), adapter);
}
+ long eventTime = row.getAndResetLastActionUpTime();
+ Bundle options = eventTime > 0 ? getActivityOptions(adapter,
+ mKeyguardStateController.isShowing(), eventTime) : getActivityOptions(adapter);
int launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
- null, null, getActivityOptions(adapter));
+ null, null, options);
mMainThreadHandler.post(() -> {
mActivityLaunchAnimator.setLaunchResult(launchResult, isActivityIntent);
});
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
index 247baf8..28343ed 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
@@ -26,6 +26,7 @@
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipUiEventLogger;
@@ -45,20 +46,24 @@
*/
@Module
public abstract class TvPipModule {
-
@SysUISingleton
@Provides
- static Pip providePipController(Context context,
+ static Optional<Pip> providePip(
+ Context context,
PipBoundsHandler pipBoundsHandler,
PipTaskOrganizer pipTaskOrganizer,
WindowManagerShellWrapper windowManagerShellWrapper) {
- return new PipController(context, pipBoundsHandler, pipTaskOrganizer,
- windowManagerShellWrapper);
+ return Optional.of(
+ new PipController(
+ context,
+ pipBoundsHandler,
+ pipTaskOrganizer,
+ windowManagerShellWrapper));
}
@SysUISingleton
@Provides
- static PipControlsViewController providePipControlsViewContrller(
+ static PipControlsViewController providePipControlsViewController(
PipControlsView pipControlsView, PipController pipController,
LayoutInflater layoutInflater, Handler handler) {
return new PipControlsViewController(pipControlsView, pipController, layoutInflater,
@@ -86,12 +91,19 @@
@SysUISingleton
@Provides
+ static PipBoundsState providePipBoundsState() {
+ return new PipBoundsState();
+ }
+
+ @SysUISingleton
+ @Provides
static PipTaskOrganizer providePipTaskOrganizer(Context context,
+ PipBoundsState pipBoundsState,
PipBoundsHandler pipBoundsHandler,
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
Optional<SplitScreen> splitScreenOptional, DisplayController displayController,
PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) {
- return new PipTaskOrganizer(context, pipBoundsHandler,
+ return new PipTaskOrganizer(context, pipBoundsState, pipBoundsHandler,
pipSurfaceTransactionHelper, splitScreenOptional, displayController,
pipUiEventLogger, shellTaskOrganizer);
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
index 56efffc..7e1a2e8 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
@@ -52,6 +52,8 @@
transactionPool);
}
+ @SysUISingleton
+ @Provides
static SplitScreen provideSplitScreen(Context context,
DisplayController displayController, SystemWindows systemWindows,
DisplayImeController displayImeController, @Main Handler handler,
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index a948103..3c4c3fc 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -55,9 +55,9 @@
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.shared.tracing.ProtoTraceable;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -104,7 +104,7 @@
private final DisplayImeController mDisplayImeController;
private final InputConsumerController mInputConsumerController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final ActivityManagerWrapper mActivityManagerWrapper;
+ private final TaskStackChangeListeners mTaskStackChangeListeners;
private final NavigationModeController mNavigationModeController;
private final ScreenLifecycle mScreenLifecycle;
private final SysUiState mSysUiState;
@@ -125,7 +125,7 @@
ConfigurationController configurationController,
InputConsumerController inputConsumerController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- ActivityManagerWrapper activityManagerWrapper,
+ TaskStackChangeListeners taskStackChangeListeners,
DisplayImeController displayImeController,
NavigationModeController navigationModeController,
ScreenLifecycle screenLifecycle,
@@ -140,7 +140,7 @@
mConfigurationController = configurationController;
mInputConsumerController = inputConsumerController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mActivityManagerWrapper = activityManagerWrapper;
+ mTaskStackChangeListeners = taskStackChangeListeners;
mDisplayImeController = displayImeController;
mNavigationModeController = navigationModeController;
mScreenLifecycle = screenLifecycle;
@@ -167,9 +167,6 @@
@VisibleForTesting
void initPip(Pip pip) {
- if (!PipUtils.hasSystemFeature(mContext)) {
- return;
- }
mCommandQueue.addCallback(new CommandQueue.Callbacks() {
@Override
public void showPictureInPictureMenu() {
@@ -205,7 +202,7 @@
});
// Handle for system task stack changes.
- mActivityManagerWrapper.registerTaskStackListener(
+ mTaskStackChangeListeners.registerTaskStackListener(
new TaskStackChangeListener() {
@Override
public void onTaskStackChanged() {
@@ -276,7 +273,7 @@
};
mKeyguardUpdateMonitor.registerCallback(mSplitScreenKeyguardCallback);
- mActivityManagerWrapper.registerTaskStackListener(
+ mTaskStackChangeListeners.registerTaskStackListener(
new TaskStackChangeListener() {
@Override
public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
@@ -388,7 +385,7 @@
}
});
- mActivityManagerWrapper.registerTaskStackListener(
+ mTaskStackChangeListeners.registerTaskStackListener(
new TaskStackChangeListener() {
@Override
public void onTaskCreated(int taskId, ComponentName componentName) {
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 09678b5..ac6e5de 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -41,7 +41,6 @@
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.onehanded.OneHandedController;
-import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.pip.phone.PipAppOpsListener;
@@ -117,7 +116,7 @@
@SysUISingleton
@Provides
- static PipSurfaceTransactionHelper providesPipSurfaceTransactionHelper(Context context) {
+ static PipSurfaceTransactionHelper providePipSurfaceTransactionHelper(Context context) {
return new PipSurfaceTransactionHelper(context);
}
@@ -159,9 +158,6 @@
}
@BindsOptionalOf
- abstract Pip optionalPip();
-
- @BindsOptionalOf
abstract SplitScreen optionalSplitScreen();
@BindsOptionalOf
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index ae7b108..81cb1f4 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -32,6 +32,7 @@
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipUiEventLogger;
@@ -67,22 +68,6 @@
@SysUISingleton
@Provides
- static Pip providePipController(Context context,
- DisplayController displayController,
- PipAppOpsListener pipAppOpsListener,
- PipBoundsHandler pipBoundsHandler,
- PipMediaController pipMediaController,
- PipMenuActivityController pipMenuActivityController,
- PipTaskOrganizer pipTaskOrganizer,
- PipTouchHandler pipTouchHandler,
- WindowManagerShellWrapper windowManagerShellWrapper) {
- return new PipController(context, displayController,
- pipAppOpsListener, pipBoundsHandler, pipMediaController, pipMenuActivityController,
- pipTaskOrganizer, pipTouchHandler, windowManagerShellWrapper);
- }
-
- @SysUISingleton
- @Provides
static SplitScreen provideSplitScreen(Context context,
DisplayController displayController, SystemWindows systemWindows,
DisplayImeController displayImeController, @Main Handler handler,
@@ -94,36 +79,57 @@
@SysUISingleton
@Provides
- static PipBoundsHandler providesPipBoundsHandler(Context context) {
+ static Optional<Pip> providePip(Context context, DisplayController displayController,
+ PipAppOpsListener pipAppOpsListener, PipBoundsHandler pipBoundsHandler,
+ PipBoundsState pipBoundsState, PipMediaController pipMediaController,
+ PipMenuActivityController pipMenuActivityController, PipTaskOrganizer pipTaskOrganizer,
+ PipTouchHandler pipTouchHandler, WindowManagerShellWrapper windowManagerShellWrapper) {
+ return Optional.ofNullable(PipController.create(context, displayController,
+ pipAppOpsListener, pipBoundsHandler, pipBoundsState, pipMediaController,
+ pipMenuActivityController, pipTaskOrganizer, pipTouchHandler,
+ windowManagerShellWrapper));
+ }
+
+ @SysUISingleton
+ @Provides
+ static PipBoundsState providePipBoundsState() {
+ return new PipBoundsState();
+ }
+
+ @SysUISingleton
+ @Provides
+ static PipBoundsHandler providePipBoundsHandler(Context context) {
return new PipBoundsHandler(context);
}
@SysUISingleton
@Provides
- static PipMenuActivityController providesPipMenuActivityController(Context context,
+ static PipMenuActivityController providePipMenuActivityController(Context context,
PipMediaController pipMediaController, PipTaskOrganizer pipTaskOrganizer) {
return new PipMenuActivityController(context, pipMediaController, pipTaskOrganizer);
}
@SysUISingleton
@Provides
- static PipTouchHandler providesPipTouchHandler(Context context,
+ static PipTouchHandler providePipTouchHandler(Context context,
PipMenuActivityController menuActivityController, PipBoundsHandler pipBoundsHandler,
+ PipBoundsState pipBoundsState,
PipTaskOrganizer pipTaskOrganizer,
FloatingContentCoordinator floatingContentCoordinator,
PipUiEventLogger pipUiEventLogger) {
return new PipTouchHandler(context, menuActivityController, pipBoundsHandler,
- pipTaskOrganizer, floatingContentCoordinator, pipUiEventLogger);
+ pipBoundsState, pipTaskOrganizer, floatingContentCoordinator, pipUiEventLogger);
}
@SysUISingleton
@Provides
- static PipTaskOrganizer providesPipTaskOrganizer(Context context,
+ static PipTaskOrganizer providePipTaskOrganizer(Context context,
+ PipBoundsState pipBoundsState,
PipBoundsHandler pipBoundsHandler,
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
Optional<SplitScreen> splitScreenOptional, DisplayController displayController,
PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) {
- return new PipTaskOrganizer(context, pipBoundsHandler,
+ return new PipTaskOrganizer(context, pipBoundsState, pipBoundsHandler,
pipSurfaceTransactionHelper, splitScreenOptional, displayController,
pipUiEventLogger, shellTaskOrganizer);
}
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 2b4ed4e..d541c8f 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -70,6 +70,13 @@
android:exported="false"
android:resizeableActivity="true" />
+ <activity android:name="com.android.systemui.emergency.EmergencyActivityTest"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.systemui.action.LAUNCH_EMERGENCY"/>
+ </intent-filter>
+ </activity>
+
<activity
android:name="com.android.systemui.globalactions.GlobalActionsImeTest$TestActivity"
android:excludeFromRecents="true"
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
index ae159c7..62906f3 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
@@ -20,9 +20,11 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.hardware.display.DisplayManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.AttributeSet;
+import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
@@ -104,9 +106,10 @@
@Test
public void testInflation_doesntCrash() {
- KeyguardPresentation keyguardPresentation = new KeyguardPresentation(mContext,
- mContext.getDisplayNoVerify(), mKeyguardStatusViewComponentFactory,
- mLayoutInflater);
+ final Display display = mContext.getSystemService(DisplayManager.class).getDisplay(
+ Display.DEFAULT_DISPLAY);
+ KeyguardPresentation keyguardPresentation = new KeyguardPresentation(mContext, display,
+ mKeyguardStatusViewComponentFactory);
keyguardPresentation.onCreate(null /*savedInstanceState */);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
index 353fe62..35fe1ba 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
@@ -168,7 +168,7 @@
verify(mMockListener2).onClockChanged(captor2.capture());
assertThat(captor1.getValue()).isInstanceOf(BUBBLE_CLOCK_CLASS);
assertThat(captor2.getValue()).isInstanceOf(BUBBLE_CLOCK_CLASS);
- assertThat(captor1.getValue()).isNotSameAs(captor2.getValue());
+ assertThat(captor1.getValue()).isNotSameInstanceAs(captor2.getValue());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SizeCompatModeActivityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/SizeCompatModeActivityControllerTest.java
index 1638ea1..71a0434 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SizeCompatModeActivityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SizeCompatModeActivityControllerTest.java
@@ -29,8 +29,8 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.SizeCompatModeActivityController.RestartActivityButton;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.statusbar.CommandQueue;
import org.junit.Before;
@@ -50,7 +50,7 @@
private SizeCompatModeActivityController mController;
private TaskStackChangeListener mTaskStackListener;
- private @Mock ActivityManagerWrapper mMockAm;
+ private @Mock TaskStackChangeListeners mMockTaskListeners;
private @Mock RestartActivityButton mMockButton;
private @Mock IBinder mMockActivityToken;
@@ -59,7 +59,7 @@
MockitoAnnotations.initMocks(this);
doReturn(true).when(mMockButton).show();
- mController = new SizeCompatModeActivityController(mContext, mMockAm,
+ mController = new SizeCompatModeActivityController(mContext, mMockTaskListeners,
new CommandQueue(mContext)) {
@Override
RestartActivityButton createRestartButton(Context context) {
@@ -69,7 +69,7 @@
ArgumentCaptor<TaskStackChangeListener> listenerCaptor =
ArgumentCaptor.forClass(TaskStackChangeListener.class);
- verify(mMockAm).registerTaskStackListener(listenerCaptor.capture());
+ verify(mMockTaskListeners).registerTaskStackListener(listenerCaptor.capture());
mTaskStackListener = listenerCaptor.getValue();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 5f2fd69..f1606c5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -224,11 +224,12 @@
@Test
- public void onDensityChanged_enabled_updateDimensionsAndLayout() {
+ public void onDensityChanged_enabled_updateDimensionsAndResetWindowMagnification() {
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
Float.NaN);
Mockito.reset(mWindowManager);
+ Mockito.reset(mMirrorWindowControl);
});
mInstrumentation.runOnMainSync(() -> {
@@ -237,7 +238,9 @@
verify(mResources, atLeastOnce()).getDimensionPixelSize(anyInt());
verify(mWindowManager).removeView(any());
+ verify(mMirrorWindowControl).destroyControl();
verify(mWindowManager).addView(any(), any());
+ verify(mMirrorWindowControl).showControl();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 08ccd854..b082d17 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -91,6 +91,7 @@
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.FloatingContentCoordinator;
@@ -194,6 +195,8 @@
@Mock private WindowManagerShellWrapper mWindowManagerShellWrapper;
+ @Mock private BubbleLogger mBubbleLogger;
+
private BubbleData mBubbleData;
private TestableLooper mTestableLooper;
@@ -249,7 +252,7 @@
mock(HeadsUpManager.class),
mock(Handler.class)
);
- mBubbleData = new BubbleData(mContext);
+ mBubbleData = new BubbleData(mContext, mBubbleLogger);
when(mFeatureFlagsOldPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
mBubbleController = new TestableBubbleController(
mContext,
@@ -273,7 +276,10 @@
mStatusBarService,
mWindowManager,
mWindowManagerShellWrapper,
- mLauncherApps);
+ mLauncherApps,
+ mBubbleLogger,
+ mock(Handler.class),
+ mock(ShellTaskOrganizer.class));
mBubbleController.setExpandListener(mBubbleExpandListener);
// Get a reference to the BubbleController's entry listener
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
index 6e2c7e5..0c872db 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
@@ -17,6 +17,7 @@
package com.android.systemui.bubbles;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
@@ -94,6 +95,8 @@
private PendingIntent mExpandIntent;
@Mock
private PendingIntent mDeleteIntent;
+ @Mock
+ private BubbleLogger mBubbleLogger;
@Captor
private ArgumentCaptor<BubbleData.Update> mUpdateCaptor;
@@ -133,7 +136,7 @@
mBubbleB3 = new Bubble(mEntryB3, mSuppressionListener, mPendingIntentCanceledListener);
mBubbleC1 = new Bubble(mEntryC1, mSuppressionListener, mPendingIntentCanceledListener);
- mBubbleData = new BubbleData(getContext());
+ mBubbleData = new BubbleData(getContext(), mBubbleLogger);
// Used by BubbleData to set lastAccessedTime
when(mTimeSource.currentTimeMillis()).thenReturn(1000L);
@@ -801,47 +804,48 @@
private void assertBubbleAdded(Bubble expected) {
BubbleData.Update update = mUpdateCaptor.getValue();
- assertThat(update.addedBubble).named("addedBubble").isEqualTo(expected);
+ assertWithMessage("addedBubble").that(update.addedBubble).isEqualTo(expected);
}
private void assertBubbleRemoved(Bubble expected, @BubbleController.DismissReason int reason) {
BubbleData.Update update = mUpdateCaptor.getValue();
- assertThat(update.removedBubbles).named("removedBubbles")
+ assertWithMessage("removedBubbles").that(update.removedBubbles)
.isEqualTo(ImmutableList.of(Pair.create(expected, reason)));
}
private void assertOrderNotChanged() {
BubbleData.Update update = mUpdateCaptor.getValue();
- assertThat(update.orderChanged).named("orderChanged").isFalse();
+ assertWithMessage("orderChanged").that(update.orderChanged).isFalse();
}
private void assertOrderChangedTo(Bubble... order) {
BubbleData.Update update = mUpdateCaptor.getValue();
- assertThat(update.orderChanged).named("orderChanged").isTrue();
- assertThat(update.bubbles).named("bubble order").isEqualTo(ImmutableList.copyOf(order));
+ assertWithMessage("orderChanged").that(update.orderChanged).isTrue();
+ assertWithMessage("bubble order").that(update.bubbles)
+ .isEqualTo(ImmutableList.copyOf(order));
}
private void assertSelectionNotChanged() {
BubbleData.Update update = mUpdateCaptor.getValue();
- assertThat(update.selectionChanged).named("selectionChanged").isFalse();
+ assertWithMessage("selectionChanged").that(update.selectionChanged).isFalse();
}
private void assertSelectionChangedTo(Bubble bubble) {
BubbleData.Update update = mUpdateCaptor.getValue();
- assertThat(update.selectionChanged).named("selectionChanged").isTrue();
- assertThat(update.selectedBubble).named("selectedBubble").isEqualTo(bubble);
+ assertWithMessage("selectionChanged").that(update.selectionChanged).isTrue();
+ assertWithMessage("selectedBubble").that(update.selectedBubble).isEqualTo(bubble);
}
private void assertSelectionCleared() {
BubbleData.Update update = mUpdateCaptor.getValue();
- assertThat(update.selectionChanged).named("selectionChanged").isTrue();
- assertThat(update.selectedBubble).named("selectedBubble").isNull();
+ assertWithMessage("selectionChanged").that(update.selectionChanged).isTrue();
+ assertWithMessage("selectedBubble").that(update.selectedBubble).isNull();
}
private void assertExpandedChangedTo(boolean expected) {
BubbleData.Update update = mUpdateCaptor.getValue();
- assertThat(update.expandedChanged).named("expandedChanged").isTrue();
- assertThat(update.expanded).named("expanded").isEqualTo(expected);
+ assertWithMessage("expandedChanged").that(update.expandedChanged).isTrue();
+ assertWithMessage("expanded").that(update.expanded).isEqualTo(expected);
}
private void assertOverflowChangedTo(ImmutableList<Bubble> bubbles) {
@@ -913,4 +917,4 @@
setCurrentTime(time);
mBubbleData.setExpanded(shouldBeExpanded);
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/MultiWindowTaskListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/MultiWindowTaskListenerTest.java
new file mode 100644
index 0000000..7c1b414
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/MultiWindowTaskListenerTest.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2020 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.systemui.bubbles;
+
+import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_MULTI_WINDOW;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManager;
+import android.os.Handler;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.SurfaceControl;
+import android.window.WindowContainerToken;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.wm.shell.ShellTaskOrganizer;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+// TODO: Place in com.android.wm.shell vs. com.android.wm.shell.bubbles on shell migration.
+public class MultiWindowTaskListenerTest extends SysuiTestCase {
+
+ @Mock
+ ShellTaskOrganizer mOrganizer;
+ @Mock
+ MultiWindowTaskListener.Listener mPendingListener;
+ @Mock
+ SurfaceControl mLeash;
+ @Mock
+ ActivityManager.RunningTaskInfo mTaskInfo;
+ @Mock
+ WindowContainerToken mToken;
+
+ Handler mHandler;
+ MultiWindowTaskListener mTaskListener;
+ TestableLooper mTestableLooper;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mTestableLooper = TestableLooper.get(this);
+ mHandler = new Handler(mTestableLooper.getLooper());
+
+ mTaskInfo = new ActivityManager.RunningTaskInfo();
+ mTaskInfo.token = mToken;
+
+ mTaskListener = new MultiWindowTaskListener(mHandler, mOrganizer);
+ }
+
+ private void addTaskAndVerify() {
+ mTaskListener.setPendingListener(mPendingListener);
+ mTaskListener.onTaskAppeared(mTaskInfo, mLeash);
+ mTestableLooper.processAllMessages();
+ verify(mPendingListener).onTaskAppeared(eq(mTaskInfo), eq(mLeash));
+ }
+
+ @Test
+ public void testListenForMultiWindowMode() {
+ mTaskListener = new MultiWindowTaskListener(mHandler, mOrganizer);
+ verify(mOrganizer).addListener(eq(mTaskListener), eq(TASK_LISTENER_TYPE_MULTI_WINDOW));
+ }
+
+ @Test
+ public void testRemovePendingListener() {
+ addTaskAndVerify();
+ reset(mPendingListener);
+
+ mTaskListener.removeListener(mPendingListener);
+
+ // If it was removed, our pendingListener shouldn't get triggered:
+ mTaskListener.onTaskAppeared(mTaskInfo, mLeash);
+ mTaskListener.onTaskInfoChanged(mTaskInfo);
+ mTaskListener.onBackPressedOnTaskRoot(mTaskInfo);
+ mTaskListener.onTaskVanished(mTaskInfo);
+
+ mTestableLooper.processAllMessages();
+ verify(mPendingListener, never()).onTaskAppeared(any(), any());
+ verify(mPendingListener, never()).onTaskInfoChanged(any());
+ verify(mPendingListener, never()).onBackPressedOnTaskRoot(any());
+ verify(mPendingListener, never()).onTaskVanished(any());
+ }
+
+ @Test
+ public void testOnTaskAppeared() {
+ addTaskAndVerify();
+ verify(mOrganizer).setInterceptBackPressedOnTaskRoot(eq(mToken), eq(true));
+ }
+
+ @Test
+ public void testOnTaskAppeared_nullListener() {
+ mTaskListener.onTaskAppeared(mTaskInfo, mLeash);
+ mTestableLooper.processAllMessages();
+
+ verify(mOrganizer, never()).setInterceptBackPressedOnTaskRoot(any(), anyBoolean());
+ verify(mPendingListener, never()).onTaskAppeared(any(), any());
+ }
+
+ @Test
+ public void testOnTaskVanished() {
+ addTaskAndVerify();
+ mTaskListener.onTaskVanished(mTaskInfo);
+ mTestableLooper.processAllMessages();
+
+ verify(mPendingListener).onTaskVanished(eq(mTaskInfo));
+ }
+
+ @Test
+ public void testOnTaskVanished_neverAdded() {
+ mTaskListener.onTaskVanished(mTaskInfo);
+ mTestableLooper.processAllMessages();
+
+ verify(mPendingListener, never()).onTaskVanished(any());
+ }
+
+ @Test
+ public void testOnTaskInfoChanged() {
+ addTaskAndVerify();
+ mTaskListener.onTaskInfoChanged(mTaskInfo);
+ mTestableLooper.processAllMessages();
+
+ verify(mPendingListener).onTaskInfoChanged(eq(mTaskInfo));
+ }
+
+ @Test
+ public void testOnTaskInfoChanged_neverAdded() {
+ mTaskListener.onTaskInfoChanged(mTaskInfo);
+ mTestableLooper.processAllMessages();
+
+ verify(mPendingListener, never()).onTaskInfoChanged(any());
+ }
+
+ @Test
+ public void testOnBackPressedOnTaskRoot() {
+ addTaskAndVerify();
+ mTaskListener.onBackPressedOnTaskRoot(mTaskInfo);
+ mTestableLooper.processAllMessages();
+
+ verify(mPendingListener).onBackPressedOnTaskRoot(eq(mTaskInfo));
+ }
+
+ @Test
+ public void testOnBackPressedOnTaskRoot_neverAdded() {
+ mTaskListener.onBackPressedOnTaskRoot(mTaskInfo);
+ mTestableLooper.processAllMessages();
+
+ verify(mPendingListener, never()).onBackPressedOnTaskRoot(any());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
index 1eaa6a4..cbacd53 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -91,6 +91,7 @@
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.InjectionInflationController;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.FloatingContentCoordinator;
@@ -188,6 +189,8 @@
private LauncherApps mLauncherApps;
@Mock
private WindowManagerShellWrapper mWindowManagerShellWrapper;
+ @Mock
+ private BubbleLogger mBubbleLogger;
private BubbleData mBubbleData;
@@ -251,7 +254,7 @@
mock(HeadsUpManager.class),
mock(Handler.class)
);
- mBubbleData = new BubbleData(mContext);
+ mBubbleData = new BubbleData(mContext, mBubbleLogger);
when(mFeatureFlagsNewPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(true);
mBubbleController = new TestableBubbleController(
mContext,
@@ -275,7 +278,10 @@
mStatusBarService,
mWindowManager,
mWindowManagerShellWrapper,
- mLauncherApps);
+ mLauncherApps,
+ mBubbleLogger,
+ mock(Handler.class),
+ mock(ShellTaskOrganizer.class));
mBubbleController.addNotifCallback(mNotifCallback);
mBubbleController.setExpandListener(mBubbleExpandListener);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TaskViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TaskViewTest.java
new file mode 100644
index 0000000..6f3968d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TaskViewTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2020 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.systemui.bubbles;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.SurfaceControl;
+import android.view.SurfaceHolder;
+import android.view.SurfaceSession;
+import android.window.WindowContainerToken;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.wm.shell.ShellTaskOrganizer;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+// TODO: Place in com.android.wm.shell vs. com.android.wm.shell.bubbles on shell migration.
+public class TaskViewTest extends SysuiTestCase {
+
+ @Mock
+ TaskView.Listener mViewListener;
+ @Mock
+ ActivityManager.RunningTaskInfo mTaskInfo;
+ @Mock
+ WindowContainerToken mToken;
+ @Mock
+ ShellTaskOrganizer mOrganizer;
+ @Mock
+ MultiWindowTaskListener mTaskListener;
+
+ SurfaceSession mSession;
+ SurfaceControl mLeash;
+
+ Context mContext;
+ TaskView mTaskView;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mLeash = new SurfaceControl.Builder(mSession)
+ .setName("test")
+ .build();
+
+ mContext = getContext();
+
+ when(mTaskListener.getTaskOrganizer()).thenReturn(mOrganizer);
+ mTaskInfo = new ActivityManager.RunningTaskInfo();
+ mTaskInfo.token = mToken;
+ mTaskInfo.taskId = 314;
+ mTaskInfo.taskDescription = mock(ActivityManager.TaskDescription.class);
+
+ mTaskView = new TaskView(mContext, mTaskListener);
+ mTaskView.setListener(mViewListener);
+ }
+
+ @After
+ public void tearDown() {
+ if (mTaskView != null) {
+ mTaskView.release();
+ }
+ }
+
+ @Test
+ public void testSetPendingListener_throwsException() {
+ TaskView taskView = new TaskView(mContext, mTaskListener);
+ taskView.setListener(mViewListener);
+ try {
+ taskView.setListener(mViewListener);
+ } catch (IllegalStateException e) {
+ // pass
+ return;
+ }
+ fail("Expected IllegalStateException");
+ }
+
+ @Test
+ public void testStartActivity() {
+ ActivityOptions options = ActivityOptions.makeBasic();
+ mTaskView.startActivity(mock(PendingIntent.class), null, options);
+
+ verify(mTaskListener).setPendingListener(eq(mTaskView));
+ assertThat(options.getLaunchWindowingMode()).isEqualTo(WINDOWING_MODE_MULTI_WINDOW);
+ assertThat(options.getTaskAlwaysOnTop()).isTrue();
+ }
+
+ @Test
+ public void testOnTaskAppeared_noSurface() {
+ mTaskView.onTaskAppeared(mTaskInfo, mLeash);
+
+ verify(mViewListener).onTaskCreated(eq(mTaskInfo.taskId), any());
+ verify(mViewListener, never()).onInitialized();
+ // If there's no surface the task should be made invisible
+ verify(mViewListener).onTaskVisibilityChanged(eq(mTaskInfo.taskId), eq(false));
+ }
+
+ @Test
+ public void testOnTaskAppeared_withSurface() {
+ mTaskView.surfaceCreated(mock(SurfaceHolder.class));
+ mTaskView.onTaskAppeared(mTaskInfo, mLeash);
+
+ verify(mViewListener).onTaskCreated(eq(mTaskInfo.taskId), any());
+ verify(mViewListener, never()).onTaskVisibilityChanged(anyInt(), anyBoolean());
+ }
+
+ @Test
+ public void testSurfaceCreated_noTask() {
+ mTaskView.surfaceCreated(mock(SurfaceHolder.class));
+
+ verify(mViewListener).onInitialized();
+ // No task, no visibility change
+ verify(mViewListener, never()).onTaskVisibilityChanged(anyInt(), anyBoolean());
+ }
+
+ @Test
+ public void testSurfaceCreated_withTask() {
+ mTaskView.onTaskAppeared(mTaskInfo, mLeash);
+ mTaskView.surfaceCreated(mock(SurfaceHolder.class));
+
+ verify(mViewListener).onInitialized();
+ verify(mViewListener).onTaskVisibilityChanged(eq(mTaskInfo.taskId), eq(true));
+ }
+
+ @Test
+ public void testSurfaceDestroyed_noTask() {
+ SurfaceHolder sh = mock(SurfaceHolder.class);
+ mTaskView.surfaceCreated(sh);
+ mTaskView.surfaceDestroyed(sh);
+
+ verify(mViewListener, never()).onTaskVisibilityChanged(anyInt(), anyBoolean());
+ }
+
+ @Test
+ public void testSurfaceDestroyed_withTask() {
+ SurfaceHolder sh = mock(SurfaceHolder.class);
+ mTaskView.onTaskAppeared(mTaskInfo, mLeash);
+ mTaskView.surfaceCreated(sh);
+ reset(mViewListener);
+ mTaskView.surfaceDestroyed(sh);
+
+ verify(mViewListener).onTaskVisibilityChanged(eq(mTaskInfo.taskId), eq(false));
+ }
+
+ @Test
+ public void testOnReleased() {
+ mTaskView.onTaskAppeared(mTaskInfo, mLeash);
+ mTaskView.surfaceCreated(mock(SurfaceHolder.class));
+ mTaskView.release();
+
+ verify(mTaskListener).removeListener(eq(mTaskView));
+ verify(mViewListener).onReleased();
+ }
+
+ @Test
+ public void testOnTaskVanished() {
+ mTaskView.onTaskAppeared(mTaskInfo, mLeash);
+ mTaskView.surfaceCreated(mock(SurfaceHolder.class));
+ mTaskView.onTaskVanished(mTaskInfo);
+
+ verify(mViewListener).onTaskRemovalStarted(eq(mTaskInfo.taskId));
+ }
+
+ @Test
+ public void testOnBackPressedOnTaskRoot() {
+ mTaskView.onTaskAppeared(mTaskInfo, mLeash);
+ mTaskView.onBackPressedOnTaskRoot(mTaskInfo);
+
+ verify(mViewListener).onBackPressedOnTaskRoot(eq(mTaskInfo.taskId));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
index 87ea22a..27c6fc1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
@@ -19,6 +19,7 @@
import android.app.INotificationManager;
import android.content.Context;
import android.content.pm.LauncherApps;
+import android.os.Handler;
import android.view.WindowManager;
import com.android.internal.statusbar.IStatusBarService;
@@ -35,10 +36,10 @@
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.FloatingContentCoordinator;
-
/**
* Testable BubbleController subclass that immediately synchronizes surfaces.
*/
@@ -66,14 +67,18 @@
IStatusBarService statusBarService,
WindowManager windowManager,
WindowManagerShellWrapper windowManagerShellWrapper,
- LauncherApps launcherApps) {
+ LauncherApps launcherApps,
+ BubbleLogger bubbleLogger,
+ Handler mainHandler,
+ ShellTaskOrganizer shellTaskOrganizer) {
super(context,
notificationShadeWindowController, statusBarStateController, shadeController,
data, Runnable::run, configurationController, interruptionStateProvider,
zenModeController, lockscreenUserManager, groupManager, entryManager,
notifPipeline, featureFlags, dumpManager, floatingContentCoordinator,
dataRepository, sysUiState, notificationManager, statusBarService,
- windowManager, windowManagerShellWrapper, launcherApps);
+ windowManager, windowManagerShellWrapper, launcherApps, bubbleLogger,
+ mainHandler, shellTaskOrganizer);
setInflateSynchronously(true);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/emergency/EmergencyActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/emergency/EmergencyActivityTest.java
new file mode 100644
index 0000000..a52a598
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/emergency/EmergencyActivityTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 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.systemui.emergency;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.systemui.R;
+
+/**
+ * Test activity for resolving {@link EmergencyGesture#ACTION_LAUNCH_EMERGENCY} action.
+ */
+public class EmergencyActivityTest extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
index 3439fe5..cd5740d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
@@ -41,8 +41,8 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.shared.system.TaskStackChangeListeners;
import org.junit.Before;
import org.junit.Test;
@@ -62,7 +62,7 @@
private static final int TASK_ID = 444;
private @Mock Context mContext;
- private @Mock ActivityManagerWrapper mActivityManager;
+ private @Mock TaskStackChangeListeners mTaskStackChangeListeners;
private @Mock IActivityTaskManager mIActivityTaskManager;
private WorkLockActivityController mController;
@@ -78,10 +78,10 @@
// Construct controller. Save the TaskStackListener for injecting events.
final ArgumentCaptor<TaskStackChangeListener> listenerCaptor =
ArgumentCaptor.forClass(TaskStackChangeListener.class);
- mController = new WorkLockActivityController(mContext, mActivityManager,
+ mController = new WorkLockActivityController(mContext, mTaskStackChangeListeners,
mIActivityTaskManager);
- verify(mActivityManager).registerTaskStackListener(listenerCaptor.capture());
+ verify(mTaskStackChangeListeners).registerTaskStackListener(listenerCaptor.capture());
mTaskStackListener = listenerCaptor.getValue();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java
index 9b6dd05..3494bd6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java
@@ -32,15 +32,11 @@
import static com.android.systemui.navigationbar.buttons.KeyButtonView.NavBarButtonEvent.NAVBAR_OVERVIEW_BUTTON_LONGPRESS;
import static com.android.systemui.navigationbar.buttons.KeyButtonView.NavBarButtonEvent.NAVBAR_OVERVIEW_BUTTON_TAP;
-import static junit.framework.Assert.assertEquals;
-
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import android.hardware.input.InputManager;
import android.testing.AndroidTestingRunner;
@@ -151,19 +147,4 @@
verify(mUiEventLogger, times(1)).log(expected);
}
}
-
- @Test
- public void testBubbleEvents_bubbleExpanded() {
- when(mBubbles.getExpandedDisplayId(mContext)).thenReturn(3);
-
- int action = KeyEvent.ACTION_DOWN;
- int flags = 0;
- int code = KeyEvent.KEYCODE_BACK;
- mKeyButtonView.setCode(code);
- mKeyButtonView.sendEvent(action, flags);
-
- verify(mInputManager, times(1)).injectInputEvent(mInputEventCaptor.capture(),
- anyInt());
- assertEquals(3, mInputEventCaptor.getValue().getDisplayId());
- }
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt
index 72e6df2..724ea02 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt
@@ -80,7 +80,7 @@
val background2 = processor.processArtwork(context, artwork)!!
// THEN the two bitmaps are the same
// Note: This is currently broken and trying to use caching causes issues
- assertThat(background1).isNotSameAs(background2)
+ assertThat(background1).isNotSameInstanceAs(background2)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
index d0dfb171..524ead2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
@@ -34,6 +34,7 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -64,6 +65,7 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mDependency.injectMockDependency(MediaOutputDialogFactory.class);
allowTestableLooperAsMainThread();
when(mBindStage.getStageParams(any())).thenReturn(new RowContentBindParams());
mDynamicChildBindController =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
index 79fa436..5898664 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
@@ -118,7 +118,7 @@
val people = viewModel.people.toList()
assertThat(people.size).isEqualTo(1)
assertThat(people[0].name).isEqualTo("name")
- assertThat(people[0].icon).isSameAs(fakePerson.avatar)
+ assertThat(people[0].icon).isSameInstanceAs(fakePerson.avatar)
people[0].onClick()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
index c2091da..d08b2b7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
@@ -25,8 +25,6 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.app.AppOpsManager;
-import android.util.ArraySet;
import android.view.NotificationHeaderView;
import android.view.View;
import android.view.ViewPropertyAnimator;
@@ -37,6 +35,7 @@
import com.android.internal.widget.NotificationExpandButton;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import org.junit.Before;
import org.junit.Test;
@@ -51,6 +50,8 @@
@Before
@UiThreadTest
public void setup() {
+ mDependency.injectMockDependency(MediaOutputDialogFactory.class);
+
mView = new NotificationContentView(mContext, null);
ExpandableNotificationRow row = new ExpandableNotificationRow(mContext, null);
ExpandableNotificationRow mockRow = spy(row);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index 1255b6d..8a5afe6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -45,6 +45,7 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.media.MediaFeatureFlag;
+import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.plugins.PluginManager;
@@ -152,6 +153,7 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
mDependency.injectMockDependency(SmartReplyController.class);
+ mDependency.injectMockDependency(MediaOutputDialogFactory.class);
mHandler = Handler.createAsync(TestableLooper.get(this).getLooper());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index fb37ed5..847e0a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -48,6 +48,7 @@
import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.bubbles.BubblesTestActivity;
import com.android.systemui.media.MediaFeatureFlag;
+import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -115,6 +116,7 @@
mTestLooper = testLooper;
dependency.injectMockDependency(NotificationMediaManager.class);
dependency.injectMockDependency(NotificationShadeWindowController.class);
+ dependency.injectMockDependency(MediaOutputDialogFactory.class);
mStatusBarStateController = mock(StatusBarStateController.class);
mGroupMembershipManager = new NotificationGroupManagerLegacy(
mStatusBarStateController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 7ee27c9..3868443 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -350,7 +350,7 @@
mAccessibiltyDelegate.onInitializeAccessibilityNodeInfo(mView, nodeInfo);
List<AccessibilityNodeInfo.AccessibilityAction> actionList = nodeInfo.getActionList();
- assertThat(actionList).containsAllIn(
+ assertThat(actionList).containsAtLeastElementsIn(
new AccessibilityNodeInfo.AccessibilityAction[] {
AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD,
AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index a6ea9966a..d6a7acb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -24,6 +24,7 @@
import static junit.framework.Assert.assertTrue;
import static junit.framework.TestCase.fail;
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -34,6 +35,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -43,6 +45,7 @@
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
+import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.fingerprint.FingerprintManager;
@@ -84,6 +87,7 @@
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.demomode.DemoModeController;
+import com.android.systemui.emergency.EmergencyGesture;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
@@ -146,6 +150,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -873,6 +878,19 @@
verify(mDozeServiceHost).setDozeSuppressed(false);
}
+ @Test
+ public void onEmergencyActionLaunchGesture_launchesEmergencyIntent() {
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ StatusBar statusBarSpy = spy(mStatusBar);
+
+ statusBarSpy.onEmergencyActionLaunchGestureDetected();
+
+ verify(statusBarSpy).startActivity(intentCaptor.capture(), eq(true));
+ Intent sentIntent = intentCaptor.getValue();
+ assertEquals(sentIntent.getAction(), EmergencyGesture.ACTION_LAUNCH_EMERGENCY);
+
+ }
+
public static class TestableNotificationInterruptStateProviderImpl extends
NotificationInterruptStateProviderImpl {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index 76fe3bf..a58f1fd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -16,17 +16,12 @@
package com.android.systemui.wmshell;
-import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
-
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.pm.PackageManager;
import android.test.suitebuilder.annotation.SmallTest;
-import android.testing.TestableContext;
import androidx.test.runner.AndroidJUnit4;
@@ -36,9 +31,9 @@
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tracing.ProtoTracer;
@@ -68,7 +63,7 @@
@Mock CommandQueue mCommandQueue;
@Mock ConfigurationController mConfigurationController;
@Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- @Mock ActivityManagerWrapper mActivityManagerWrapper;
+ @Mock TaskStackChangeListeners mTaskStackChangeListeners;
@Mock DisplayImeController mDisplayImeController;
@Mock InputConsumerController mMockInputConsumerController;
@Mock NavigationModeController mNavigationModeController;
@@ -88,13 +83,12 @@
mInputConsumerController = InputConsumerController.getPipInputConsumer();
mWMShell = new WMShell(mContext, mCommandQueue, mConfigurationController,
- mInputConsumerController, mKeyguardUpdateMonitor, mActivityManagerWrapper,
+ mInputConsumerController, mKeyguardUpdateMonitor, mTaskStackChangeListeners,
mDisplayImeController, mNavigationModeController, mScreenLifecycle, mSysUiState,
Optional.of(mPip), Optional.of(mSplitScreen), Optional.of(mOneHanded),
mTaskOrganizer, mProtoTracer);
when(mPip.getPipTouchHandler()).thenReturn(mPipTouchHandler);
-
}
@Test
@@ -112,31 +106,11 @@
}
@Test
- public void nonPipDevice_shouldNotInitPip() {
- final TestableContext nonPipContext = getNonPipFeatureContext();
- final WMShell nonPipWMShell = new WMShell(nonPipContext, mCommandQueue,
- mConfigurationController, mMockInputConsumerController, mKeyguardUpdateMonitor,
- mActivityManagerWrapper, mDisplayImeController, mNavigationModeController,
- mScreenLifecycle, mSysUiState, Optional.of(mPip), Optional.of(mSplitScreen),
- Optional.of(mOneHanded), mTaskOrganizer, mProtoTracer);
- nonPipWMShell.initPip(mPip);
-
- verify(mCommandQueue, never()).addCallback(any());
- verify(mKeyguardUpdateMonitor, never()).registerCallback(any());
- verify(mConfigurationController, never()).addCallback(any());
- verify(mSysUiState, never()).addCallback(any());
- verify(mActivityManagerWrapper, never()).registerTaskStackListener(any());
- verify(mMockInputConsumerController, never()).setInputListener(any());
- verify(mMockInputConsumerController, never()).setRegistrationListener(any());
- verify(mPip, never()).registerSessionListenerForCurrentUser();
- }
-
- @Test
public void initSplitScreen_registersCallbacks() {
mWMShell.initSplitScreen(mSplitScreen);
verify(mKeyguardUpdateMonitor).registerCallback(any(KeyguardUpdateMonitorCallback.class));
- verify(mActivityManagerWrapper).registerTaskStackListener(
+ verify(mTaskStackChangeListeners).registerTaskStackListener(
any(TaskStackChangeListener.class));
}
@@ -149,18 +123,11 @@
verify(mScreenLifecycle).addObserver(any(ScreenLifecycle.Observer.class));
verify(mNavigationModeController).addListener(
any(NavigationModeController.ModeChangedListener.class));
- verify(mActivityManagerWrapper).registerTaskStackListener(
+ verify(mTaskStackChangeListeners).registerTaskStackListener(
any(TaskStackChangeListener.class));
verify(mOneHanded).registerGestureCallback(any(
OneHandedGestureHandler.OneHandedGestureEventCallback.class));
verify(mOneHanded).registerTransitionCallback(any(OneHandedTransitionCallback.class));
}
-
- TestableContext getNonPipFeatureContext() {
- TestableContext spiedContext = spy(mContext);
- when(mMockPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)).thenReturn(false);
- when(spiedContext.getPackageManager()).thenReturn(mMockPackageManager);
- return spiedContext;
- }
}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java
index 645b000..0b223f4 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java
@@ -19,7 +19,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -34,7 +33,6 @@
* @hide
*/
@SystemApi
-@TestApi
public final class TetheredClient implements Parcelable {
@NonNull
private final MacAddress mMacAddress;
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index db84368..13b05a8 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -23,7 +23,6 @@
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.content.Context;
import android.os.Bundle;
import android.os.ConditionVariable;
@@ -55,7 +54,6 @@
* @hide
*/
@SystemApi
-@TestApi
public class TetheringManager {
private static final String TAG = TetheringManager.class.getSimpleName();
private static final int DEFAULT_TIMEOUT_MS = 60_000;
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
index 6276c4e..9fc1d7e 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
@@ -20,6 +20,10 @@
import static android.net.TetheringManager.TETHERING_WIFI_P2P;
import static android.net.util.PrefixUtils.asIpPrefix;
+import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH;
+import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
+import static com.android.net.module.util.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTH;
+
import static java.util.Arrays.asList;
import android.content.Context;
@@ -32,14 +36,16 @@
import android.util.ArraySet;
import android.util.SparseArray;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
+import java.net.Inet4Address;
import java.net.InetAddress;
-import java.net.UnknownHostException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
@@ -58,10 +64,6 @@
public class PrivateAddressCoordinator {
public static final int PREFIX_LENGTH = 24;
- private static final int MAX_UBYTE = 256;
- private static final int BYTE_MASK = 0xff;
- private static final byte DEFAULT_ID = (byte) 42;
-
// Upstream monitor would be stopped when tethering is down. When tethering restart, downstream
// address may be requested before coordinator get current upstream notification. To ensure
// coordinator do not select conflict downstream prefix, mUpstreamPrefixMap would not be cleared
@@ -69,22 +71,22 @@
// mUpstreamPrefixMap when tethering is starting. See #maybeRemoveDeprecatedUpstreams().
private final ArrayMap<Network, List<IpPrefix>> mUpstreamPrefixMap;
private final ArraySet<IpServer> mDownstreams;
- // IANA has reserved the following three blocks of the IP address space for private intranets:
- // 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
- // Tethering use 192.168.0.0/16 that has 256 contiguous class C network numbers.
- private static final String DEFAULT_TETHERING_PREFIX = "192.168.0.0/16";
private static final String LEGACY_WIFI_P2P_IFACE_ADDRESS = "192.168.49.1/24";
private static final String LEGACY_BLUETOOTH_IFACE_ADDRESS = "192.168.44.1/24";
- private final IpPrefix mTetheringPrefix;
+ private final List<IpPrefix> mTetheringPrefixes;
private final ConnectivityManager mConnectivityMgr;
private final TetheringConfiguration mConfig;
// keyed by downstream type(TetheringManager.TETHERING_*).
private final SparseArray<LinkAddress> mCachedAddresses;
public PrivateAddressCoordinator(Context context, TetheringConfiguration config) {
+ this(context, config, new ArrayList<>(Arrays.asList(new IpPrefix("192.168.0.0/16"))));
+ }
+
+ public PrivateAddressCoordinator(Context context, TetheringConfiguration config,
+ List<IpPrefix> prefixPools) {
mDownstreams = new ArraySet<>();
mUpstreamPrefixMap = new ArrayMap<>();
- mTetheringPrefix = new IpPrefix(DEFAULT_TETHERING_PREFIX);
mConnectivityMgr = (ConnectivityManager) context.getSystemService(
Context.CONNECTIVITY_SERVICE);
mConfig = config;
@@ -92,6 +94,8 @@
// Reserved static addresses for bluetooth and wifi p2p.
mCachedAddresses.put(TETHERING_BLUETOOTH, new LinkAddress(LEGACY_BLUETOOTH_IFACE_ADDRESS));
mCachedAddresses.put(TETHERING_WIFI_P2P, new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS));
+
+ mTetheringPrefixes = prefixPools;
}
/**
@@ -132,7 +136,6 @@
private void handleMaybePrefixConflict(final List<IpPrefix> prefixes) {
for (IpServer downstream : mDownstreams) {
final IpPrefix target = getDownstreamPrefix(downstream);
- if (target == null) continue;
for (IpPrefix source : prefixes) {
if (isConflictPrefix(source, target)) {
@@ -176,55 +179,152 @@
final LinkAddress cachedAddress = mCachedAddresses.get(ipServer.interfaceType());
if (useLastAddress && cachedAddress != null
&& !isConflictWithUpstream(asIpPrefix(cachedAddress))) {
+ mDownstreams.add(ipServer);
return cachedAddress;
}
- // Address would be 192.168.[subAddress]/24.
- final byte[] bytes = mTetheringPrefix.getRawAddress();
- final int subAddress = getRandomSubAddr();
- final int subNet = (subAddress >> 8) & BYTE_MASK;
- bytes[3] = getSanitizedAddressSuffix(subAddress, (byte) 0, (byte) 1, (byte) 0xff);
- for (int i = 0; i < MAX_UBYTE; i++) {
- final int newSubNet = (subNet + i) & BYTE_MASK;
- bytes[2] = (byte) newSubNet;
-
- final InetAddress addr;
- try {
- addr = InetAddress.getByAddress(bytes);
- } catch (UnknownHostException e) {
- throw new IllegalStateException("Invalid address, shouldn't happen.", e);
+ for (IpPrefix prefixRange : mTetheringPrefixes) {
+ final LinkAddress newAddress = chooseDownstreamAddress(prefixRange);
+ if (newAddress != null) {
+ mDownstreams.add(ipServer);
+ mCachedAddresses.put(ipServer.interfaceType(), newAddress);
+ return newAddress;
}
-
- if (isConflict(new IpPrefix(addr, PREFIX_LENGTH))) continue;
-
- mDownstreams.add(ipServer);
- final LinkAddress newAddress = new LinkAddress(addr, PREFIX_LENGTH);
- mCachedAddresses.put(ipServer.interfaceType(), newAddress);
- return newAddress;
}
// No available address.
return null;
}
- private boolean isConflict(final IpPrefix prefix) {
- // Check whether this prefix is in use or conflict with any current upstream network.
- return isDownstreamPrefixInUse(prefix) || isConflictWithUpstream(prefix);
+ private int getPrefixBaseAddress(final IpPrefix prefix) {
+ return inet4AddressToIntHTH((Inet4Address) prefix.getAddress());
}
- /** Get random sub address value. Return value is in 0 ~ 0xffff. */
- @VisibleForTesting
- public int getRandomSubAddr() {
- return ((new Random()).nextInt()) & 0xffff; // subNet is in 0 ~ 0xffff.
+ /**
+ * Check whether input prefix conflict with upstream prefixes or in-use downstream prefixes.
+ * If yes, return one of them.
+ */
+ private IpPrefix getConflictPrefix(final IpPrefix prefix) {
+ final IpPrefix upstream = getConflictWithUpstream(prefix);
+ if (upstream != null) return upstream;
+
+ return getInUseDownstreamPrefix(prefix);
}
- private byte getSanitizedAddressSuffix(final int source, byte... excluded) {
- final byte subId = (byte) (source & BYTE_MASK);
- for (byte value : excluded) {
- if (subId == value) return DEFAULT_ID;
+ // Get the next non-conflict sub prefix. E.g: To get next sub prefix from 10.0.0.0/8, if the
+ // previously selected prefix is 10.20.42.0/24(subPrefix: 0.20.42.0) and the conflicting prefix
+ // is 10.16.0.0/20 (10.16.0.0 ~ 10.16.15.255), then the max address under subPrefix is
+ // 0.16.15.255 and the next subPrefix is 0.16.16.255/24 (0.16.15.255 + 0.0.1.0).
+ // Note: the sub address 0.0.0.255 here is fine to be any value that it will be replaced as
+ // selected random sub address later.
+ private int getNextSubPrefix(final IpPrefix conflictPrefix, final int prefixRangeMask) {
+ final int suffixMask = ~prefixLengthToV4NetmaskIntHTH(conflictPrefix.getPrefixLength());
+ // The largest offset within the prefix assignment block that still conflicts with
+ // conflictPrefix.
+ final int maxConflict =
+ (getPrefixBaseAddress(conflictPrefix) | suffixMask) & ~prefixRangeMask;
+
+ final int prefixMask = prefixLengthToV4NetmaskIntHTH(PREFIX_LENGTH);
+ // Pick a sub prefix a full prefix (1 << (32 - PREFIX_LENGTH) addresses) greater than
+ // maxConflict. This ensures that the selected prefix never overlaps with conflictPrefix.
+ // There is no need to mask the result with PREFIX_LENGTH bits because this is done by
+ // findAvailablePrefixFromRange when it constructs the prefix.
+ return maxConflict + (1 << (32 - PREFIX_LENGTH));
+ }
+
+ private LinkAddress chooseDownstreamAddress(final IpPrefix prefixRange) {
+ // The netmask of the prefix assignment block (e.g., 0xfff00000 for 172.16.0.0/12).
+ final int prefixRangeMask = prefixLengthToV4NetmaskIntHTH(prefixRange.getPrefixLength());
+
+ // The zero address in the block (e.g., 0xac100000 for 172.16.0.0/12).
+ final int baseAddress = getPrefixBaseAddress(prefixRange);
+
+ // The subnet mask corresponding to PREFIX_LENGTH.
+ final int prefixMask = prefixLengthToV4NetmaskIntHTH(PREFIX_LENGTH);
+
+ // The offset within prefixRange of a randomly-selected prefix of length PREFIX_LENGTH.
+ // This may not be the prefix of the address returned by this method:
+ // - If it is already in use, the method will return an address in another prefix.
+ // - If all prefixes within prefixRange are in use, the method will return null. For
+ // example, for a /24 prefix within 172.26.0.0/12, this will be a multiple of 256 in
+ // [0, 1048576). In other words, a random 32-bit number with mask 0x000fff00.
+ //
+ // prefixRangeMask is required to ensure no wrapping. For example, consider:
+ // - prefixRange 127.0.0.0/8
+ // - randomPrefixStart 127.255.255.0
+ // - A conflicting prefix of 127.255.254.0/23
+ // In this case without prefixRangeMask, getNextSubPrefix would return 128.0.0.0, which
+ // means the "start < end" check in findAvailablePrefixFromRange would not reject the prefix
+ // because Java doesn't have unsigned integers, so 128.0.0.0 = 0x80000000 = -2147483648
+ // is less than 127.0.0.0 = 0x7f000000 = 2130706432.
+ //
+ // Additionally, it makes debug output easier to read by making the numbers smaller.
+ final int randomPrefixStart = getRandomInt() & ~prefixRangeMask & prefixMask;
+
+ // A random offset within the prefix. Used to determine the local address once the prefix
+ // is selected. It does not result in an IPv4 address ending in .0, .1, or .255
+ // For a PREFIX_LENGTH of 255, this is a number between 2 and 254.
+ final int subAddress = getSanitizedSubAddr(~prefixMask);
+
+ // Find a prefix length PREFIX_LENGTH between randomPrefixStart and the end of the block,
+ // such that the prefix does not conflict with any upstream.
+ IpPrefix downstreamPrefix = findAvailablePrefixFromRange(
+ randomPrefixStart, (~prefixRangeMask) + 1, baseAddress, prefixRangeMask);
+ if (downstreamPrefix != null) return getLinkAddress(downstreamPrefix, subAddress);
+
+ // If that failed, do the same, but between 0 and randomPrefixStart.
+ downstreamPrefix = findAvailablePrefixFromRange(
+ 0, randomPrefixStart, baseAddress, prefixRangeMask);
+
+ return getLinkAddress(downstreamPrefix, subAddress);
+ }
+
+ private LinkAddress getLinkAddress(final IpPrefix prefix, final int subAddress) {
+ if (prefix == null) return null;
+
+ final InetAddress address = intToInet4AddressHTH(getPrefixBaseAddress(prefix) | subAddress);
+ return new LinkAddress(address, PREFIX_LENGTH);
+ }
+
+ private IpPrefix findAvailablePrefixFromRange(final int start, final int end,
+ final int baseAddress, final int prefixRangeMask) {
+ int newSubPrefix = start;
+ while (newSubPrefix < end) {
+ final InetAddress address = intToInet4AddressHTH(baseAddress | newSubPrefix);
+ final IpPrefix prefix = new IpPrefix(address, PREFIX_LENGTH);
+
+ final IpPrefix conflictPrefix = getConflictPrefix(prefix);
+
+ if (conflictPrefix == null) return prefix;
+
+ newSubPrefix = getNextSubPrefix(conflictPrefix, prefixRangeMask);
}
- return subId;
+ return null;
+ }
+
+ /** Get random int which could be used to generate random address. */
+ @VisibleForTesting
+ public int getRandomInt() {
+ return (new Random()).nextInt();
+ }
+
+ /** Get random subAddress and avoid selecting x.x.x.0, x.x.x.1 and x.x.x.255 address. */
+ private int getSanitizedSubAddr(final int subAddrMask) {
+ final int randomSubAddr = getRandomInt() & subAddrMask;
+ // If prefix length > 30, the selecting speace would be less than 4 which may be hard to
+ // avoid 3 consecutive address.
+ if (PREFIX_LENGTH > 30) return randomSubAddr;
+
+ // TODO: maybe it is not necessary to avoid .0, .1 and .255 address because tethering
+ // address would not be conflicted. This code only works because PREFIX_LENGTH is not longer
+ // than 24
+ final int candidate = randomSubAddr & 0xff;
+ if (candidate == 0 || candidate == 1 || candidate == 255) {
+ return (randomSubAddr & 0xfffffffc) + 2;
+ }
+
+ return randomSubAddr;
}
/** Release downstream record for IpServer. */
@@ -237,14 +337,18 @@
mUpstreamPrefixMap.clear();
}
- private boolean isConflictWithUpstream(final IpPrefix source) {
+ private IpPrefix getConflictWithUpstream(final IpPrefix prefix) {
for (int i = 0; i < mUpstreamPrefixMap.size(); i++) {
final List<IpPrefix> list = mUpstreamPrefixMap.valueAt(i);
- for (IpPrefix target : list) {
- if (isConflictPrefix(source, target)) return true;
+ for (IpPrefix upstream : list) {
+ if (isConflictPrefix(prefix, upstream)) return upstream;
}
}
- return false;
+ return null;
+ }
+
+ private boolean isConflictWithUpstream(final IpPrefix prefix) {
+ return getConflictWithUpstream(prefix) != null;
}
private boolean isConflictPrefix(final IpPrefix prefix1, final IpPrefix prefix2) {
@@ -257,33 +361,38 @@
// InUse Prefixes are prefixes of mCachedAddresses which are active downstream addresses, last
// downstream addresses(reserved for next time) and static addresses(e.g. bluetooth, wifi p2p).
- private boolean isDownstreamPrefixInUse(final IpPrefix prefix) {
- // This class always generates downstream prefixes with the same prefix length, so
- // prefixes cannot be contained in each other. They can only be equal to each other.
+ private IpPrefix getInUseDownstreamPrefix(final IpPrefix prefix) {
for (int i = 0; i < mCachedAddresses.size(); i++) {
- if (prefix.equals(asIpPrefix(mCachedAddresses.valueAt(i)))) return true;
+ final IpPrefix downstream = asIpPrefix(mCachedAddresses.valueAt(i));
+ if (isConflictPrefix(prefix, downstream)) return downstream;
}
// IpServer may use manually-defined address (mStaticIpv4ServerAddr) which does not include
// in mCachedAddresses.
for (IpServer downstream : mDownstreams) {
final IpPrefix target = getDownstreamPrefix(downstream);
- if (target == null) continue;
- if (isConflictPrefix(prefix, target)) return true;
+ if (isConflictPrefix(prefix, target)) return target;
}
- return false;
+ return null;
}
+ @NonNull
private IpPrefix getDownstreamPrefix(final IpServer downstream) {
final LinkAddress address = downstream.getAddress();
- if (address == null) return null;
return asIpPrefix(address);
}
void dump(final IndentingPrintWriter pw) {
+ pw.println("mTetheringPrefixes:");
+ pw.increaseIndent();
+ for (IpPrefix prefix : mTetheringPrefixes) {
+ pw.println(prefix);
+ }
+ pw.decreaseIndent();
+
pw.println("mUpstreamPrefixMap:");
pw.increaseIndent();
for (int i = 0; i < mUpstreamPrefixMap.size(); i++) {
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 474f4e8..5a0c5b0 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -326,7 +326,7 @@
// It is OK for the configuration to be passed to the PrivateAddressCoordinator at
// construction time because the only part of the configuration it uses is
// shouldEnableWifiP2pDedicatedIp(), and currently do not support changing that.
- mPrivateAddressCoordinator = new PrivateAddressCoordinator(mContext, mConfig);
+ mPrivateAddressCoordinator = mDeps.getPrivateAddressCoordinator(mContext, mConfig);
// Must be initialized after tethering configuration is loaded because BpfCoordinator
// constructor needs to use the configuration.
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
index 131a5fb..45b9141 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
@@ -156,4 +156,12 @@
public boolean isTetheringDenied() {
return TextUtils.equals(SystemProperties.get("ro.tether.denied"), "true");
}
+
+ /**
+ * Get a reference to PrivateAddressCoordinator to be used by Tethering.
+ */
+ public PrivateAddressCoordinator getPrivateAddressCoordinator(Context ctx,
+ TetheringConfiguration cfg) {
+ return new PrivateAddressCoordinator(ctx, cfg);
+ }
}
diff --git a/packages/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java b/packages/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java
index 95e36fa..42a91aa 100644
--- a/packages/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java
+++ b/packages/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java
@@ -17,9 +17,9 @@
package android.net.ip;
import static android.system.OsConstants.IPPROTO_ICMPV6;
-import static android.system.OsConstants.IPPROTO_TCP;
-import static com.android.internal.util.BitUtils.uint16;
+import static com.android.net.module.util.IpUtils.icmpv6Checksum;
+import static com.android.net.module.util.NetworkStackConstants.ETHER_SRC_ADDR_OFFSET;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -30,34 +30,29 @@
import android.net.INetd;
import android.net.InetAddresses;
import android.net.MacAddress;
-import android.net.TestNetworkInterface;
-import android.net.TestNetworkManager;
import android.net.util.InterfaceParams;
import android.net.util.TetheringUtils;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
-import android.system.ErrnoException;
-import android.system.Os;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.net.module.util.IpUtils;
import com.android.testutils.TapPacketReader;
+import com.android.testutils.TapPacketReaderRule;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
-import java.io.FileDescriptor;
import java.nio.ByteBuffer;
-import java.util.concurrent.atomic.AtomicReference;
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -65,16 +60,18 @@
private static final int DATA_BUFFER_LEN = 4096;
private static final int PACKET_TIMEOUT_MS = 5_000;
- // TODO: make NetworkStackConstants accessible to this test and use the constant from there.
- private static final int ETHER_SRC_ADDR_OFFSET = 6;
+ // Start the readers manually on a common handler shared with DadProxy, for simplicity
+ @Rule
+ public final TapPacketReaderRule mUpstreamReader = new TapPacketReaderRule(
+ DATA_BUFFER_LEN, false /* autoStart */);
+ @Rule
+ public final TapPacketReaderRule mTetheredReader = new TapPacketReaderRule(
+ DATA_BUFFER_LEN, false /* autoStart */);
- private DadProxy mProxy;
- TestNetworkInterface mUpstreamTestIface, mTetheredTestIface;
private InterfaceParams mUpstreamParams, mTetheredParams;
private HandlerThread mHandlerThread;
private Handler mHandler;
private TapPacketReader mUpstreamPacketReader, mTetheredPacketReader;
- private FileDescriptor mUpstreamTapFd, mTetheredTapFd;
private static INetd sNetd;
@@ -106,12 +103,12 @@
@After
public void tearDown() throws Exception {
+ mUpstreamReader.stop();
+ mTetheredReader.stop();
+
if (mHandlerThread != null) {
- mHandler.post(mUpstreamPacketReader::stop); // Also closes the socket
- mHandler.post(mTetheredPacketReader::stop); // Also closes the socket
- mUpstreamTapFd = null;
- mTetheredTapFd = null;
mHandlerThread.quitSafely();
+ mHandlerThread.join(PACKET_TIMEOUT_MS);
}
if (mTetheredParams != null) {
@@ -120,54 +117,20 @@
if (mUpstreamParams != null) {
sNetd.networkRemoveInterface(INetd.LOCAL_NET_ID, mUpstreamParams.name);
}
-
- if (mUpstreamTestIface != null) {
- try {
- Os.close(mUpstreamTestIface.getFileDescriptor().getFileDescriptor());
- } catch (ErrnoException e) { }
- }
-
- if (mTetheredTestIface != null) {
- try {
- Os.close(mTetheredTestIface.getFileDescriptor().getFileDescriptor());
- } catch (ErrnoException e) { }
- }
- }
-
- private TestNetworkInterface setupTapInterface() {
- final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
- AtomicReference<TestNetworkInterface> iface = new AtomicReference<>();
-
- inst.getUiAutomation().adoptShellPermissionIdentity();
- try {
- final TestNetworkManager tnm = (TestNetworkManager) inst.getContext().getSystemService(
- Context.TEST_NETWORK_SERVICE);
- iface.set(tnm.createTapInterface());
- } finally {
- inst.getUiAutomation().dropShellPermissionIdentity();
- }
-
- return iface.get();
}
private void setupTapInterfaces() {
// Create upstream test iface.
- mUpstreamTestIface = setupTapInterface();
- mUpstreamParams = InterfaceParams.getByName(mUpstreamTestIface.getInterfaceName());
+ mUpstreamReader.start(mHandler);
+ mUpstreamParams = InterfaceParams.getByName(mUpstreamReader.iface.getInterfaceName());
assertNotNull(mUpstreamParams);
- mUpstreamTapFd = mUpstreamTestIface.getFileDescriptor().getFileDescriptor();
- mUpstreamPacketReader = new TapPacketReader(mHandler, mUpstreamTapFd,
- DATA_BUFFER_LEN);
- mHandler.post(mUpstreamPacketReader::start);
+ mUpstreamPacketReader = mUpstreamReader.getReader();
// Create tethered test iface.
- mTetheredTestIface = setupTapInterface();
- mTetheredParams = InterfaceParams.getByName(mTetheredTestIface.getInterfaceName());
+ mTetheredReader.start(mHandler);
+ mTetheredParams = InterfaceParams.getByName(mTetheredReader.getIface().getInterfaceName());
assertNotNull(mTetheredParams);
- mTetheredTapFd = mTetheredTestIface.getFileDescriptor().getFileDescriptor();
- mTetheredPacketReader = new TapPacketReader(mHandler, mTetheredTapFd,
- DATA_BUFFER_LEN);
- mHandler.post(mTetheredPacketReader::start);
+ mTetheredPacketReader = mTetheredReader.getReader();
}
private static final int IPV6_HEADER_LEN = 40;
@@ -177,31 +140,6 @@
private static final int ICMPV6_CHECKSUM_OFFSET = 2;
private static final int ETHER_TYPE_IPV6 = 0x86dd;
- // TODO: move the IpUtils code to frameworks/lib/net and link it statically.
- private static int checksumFold(int sum) {
- while (sum > 0xffff) {
- sum = (sum >> 16) + (sum & 0xffff);
- }
- return sum;
- }
-
- // TODO: move the IpUtils code to frameworks/lib/net and link it statically.
- private static short checksumAdjust(short checksum, short oldWord, short newWord) {
- checksum = (short) ~checksum;
- int tempSum = checksumFold(uint16(checksum) + uint16(newWord) + 0xffff - uint16(oldWord));
- return (short) ~tempSum;
- }
-
- // TODO: move the IpUtils code to frameworks/lib/net and link it statically.
- private static short icmpv6Checksum(ByteBuffer buf, int ipOffset, int transportOffset,
- int transportLen) {
- // The ICMPv6 checksum is the same as the TCP checksum, except the pseudo-header uses
- // 58 (ICMPv6) instead of 6 (TCP). Calculate the TCP checksum, and then do an incremental
- // checksum adjustment for the change in the next header byte.
- short checksum = IpUtils.tcpChecksum(buf, ipOffset, transportOffset, transportLen);
- return checksumAdjust(checksum, (short) IPPROTO_TCP, (short) IPPROTO_ICMPV6);
- }
-
private static ByteBuffer createDadPacket(int type) {
// Refer to buildArpPacket()
int icmpLen = ICMPV6_NA_NS_LEN
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
index 191eb6e..8cb80ba 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
@@ -51,6 +51,9 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+import java.util.Arrays;
+
@RunWith(AndroidJUnit4.class)
@SmallTest
public final class PrivateAddressCoordinatorTest {
@@ -70,7 +73,17 @@
private final Network mWifiNetwork = new Network(1);
private final Network mMobileNetwork = new Network(2);
private final Network mVpnNetwork = new Network(3);
- private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork, mVpnNetwork};
+ private final Network mMobileNetwork2 = new Network(4);
+ private final Network mMobileNetwork3 = new Network(5);
+ private final Network mMobileNetwork4 = new Network(6);
+ private final Network mMobileNetwork5 = new Network(7);
+ private final Network mMobileNetwork6 = new Network(8);
+ private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork, mVpnNetwork,
+ mMobileNetwork2, mMobileNetwork3, mMobileNetwork4, mMobileNetwork5, mMobileNetwork6};
+ private final ArrayList<IpPrefix> mTetheringPrefixes = new ArrayList<>(Arrays.asList(
+ new IpPrefix("192.168.0.0/16"),
+ new IpPrefix("172.16.0.0/12"),
+ new IpPrefix("10.0.0.0/8")));
private void setUpIpServers() throws Exception {
when(mUsbIpServer.interfaceType()).thenReturn(TETHERING_USB);
@@ -87,27 +100,34 @@
when(mConnectivityMgr.getAllNetworks()).thenReturn(mAllNetworks);
when(mConfig.shouldEnableWifiP2pDedicatedIp()).thenReturn(false);
setUpIpServers();
- mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext, mConfig));
+ mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext, mConfig,
+ mTetheringPrefixes));
+ }
+
+ private LinkAddress requestDownstreamAddress(final IpServer ipServer, boolean useLastAddress) {
+ final LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
+ ipServer, useLastAddress);
+ when(ipServer.getAddress()).thenReturn(address);
+ return address;
}
@Test
public void testRequestDownstreamAddressWithoutUsingLastAddress() throws Exception {
final IpPrefix bluetoothPrefix = asIpPrefix(mBluetoothAddress);
- final LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer, false /* useLastAddress */);
+ final LinkAddress address = requestDownstreamAddress(mHotspotIpServer,
+ false /* useLastAddress */);
final IpPrefix hotspotPrefix = asIpPrefix(address);
assertNotEquals(hotspotPrefix, bluetoothPrefix);
- when(mHotspotIpServer.getAddress()).thenReturn(address);
- final LinkAddress newAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer, false /* useLastAddress */);
+ final LinkAddress newAddress = requestDownstreamAddress(mHotspotIpServer,
+ false /* useLastAddress */);
final IpPrefix testDupRequest = asIpPrefix(newAddress);
assertNotEquals(hotspotPrefix, testDupRequest);
assertNotEquals(bluetoothPrefix, testDupRequest);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
- final LinkAddress usbAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
- mUsbIpServer, false /* useLastAddress */);
+ final LinkAddress usbAddress = requestDownstreamAddress(mUsbIpServer,
+ false /* useLastAddress */);
final IpPrefix usbPrefix = asIpPrefix(usbAddress);
assertNotEquals(usbPrefix, bluetoothPrefix);
assertNotEquals(usbPrefix, hotspotPrefix);
@@ -117,30 +137,27 @@
@Test
public void testSanitizedAddress() throws Exception {
int fakeSubAddr = 0x2b00; // 43.0.
- when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr);
- LinkAddress actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer, false /* useLastAddress */);
- assertEquals(new LinkAddress("192.168.43.42/24"), actualAddress);
+ when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr);
+ LinkAddress actualAddress = requestDownstreamAddress(mHotspotIpServer,
+ false /* useLastAddress */);
+ assertEquals(new LinkAddress("192.168.43.2/24"), actualAddress);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
fakeSubAddr = 0x2d01; // 45.1.
- when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr);
- actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer, false /* useLastAddress */);
- assertEquals(new LinkAddress("192.168.45.42/24"), actualAddress);
+ when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr);
+ actualAddress = requestDownstreamAddress(mHotspotIpServer, false /* useLastAddress */);
+ assertEquals(new LinkAddress("192.168.45.2/24"), actualAddress);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
fakeSubAddr = 0x2eff; // 46.255.
- when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr);
- actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer, false /* useLastAddress */);
- assertEquals(new LinkAddress("192.168.46.42/24"), actualAddress);
+ when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr);
+ actualAddress = requestDownstreamAddress(mHotspotIpServer, false /* useLastAddress */);
+ assertEquals(new LinkAddress("192.168.46.254/24"), actualAddress);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
fakeSubAddr = 0x2f05; // 47.5.
- when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr);
- actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer, false /* useLastAddress */);
+ when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr);
+ actualAddress = requestDownstreamAddress(mHotspotIpServer, false /* useLastAddress */);
assertEquals(new LinkAddress("192.168.47.5/24"), actualAddress);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
}
@@ -148,29 +165,29 @@
@Test
public void testReservedPrefix() throws Exception {
// - Test bluetooth prefix is reserved.
- when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(
+ when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(
getSubAddress(mBluetoothAddress.getAddress().getAddress()));
- final LinkAddress hotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer, false /* useLastAddress */);
+ final LinkAddress hotspotAddress = requestDownstreamAddress(mHotspotIpServer,
+ false /* useLastAddress */);
final IpPrefix hotspotPrefix = asIpPrefix(hotspotAddress);
assertNotEquals(asIpPrefix(mBluetoothAddress), hotspotPrefix);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
// - Test previous enabled hotspot prefix(cached prefix) is reserved.
- when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(
+ when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(
getSubAddress(hotspotAddress.getAddress().getAddress()));
- final LinkAddress usbAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
- mUsbIpServer, false /* useLastAddress */);
+ final LinkAddress usbAddress = requestDownstreamAddress(mUsbIpServer,
+ false /* useLastAddress */);
final IpPrefix usbPrefix = asIpPrefix(usbAddress);
assertNotEquals(asIpPrefix(mBluetoothAddress), usbPrefix);
assertNotEquals(hotspotPrefix, usbPrefix);
mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer);
// - Test wifi p2p prefix is reserved.
- when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(
+ when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(
getSubAddress(mLegacyWifiP2pAddress.getAddress().getAddress()));
- final LinkAddress etherAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
- mEthernetIpServer, false /* useLastAddress */);
+ final LinkAddress etherAddress = requestDownstreamAddress(mEthernetIpServer,
+ false /* useLastAddress */);
final IpPrefix etherPrefix = asIpPrefix(etherAddress);
assertNotEquals(asIpPrefix(mLegacyWifiP2pAddress), etherPrefix);
assertNotEquals(asIpPrefix(mBluetoothAddress), etherPrefix);
@@ -180,30 +197,35 @@
@Test
public void testRequestLastDownstreamAddress() throws Exception {
- final int fakeHotspotSubAddr = 0x2b05;
- final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24");
- when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr);
- final LinkAddress hotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer, true /* useLastAddress */);
- assertEquals("Wrong wifi prefix: ", predefinedPrefix, asIpPrefix(hotspotAddress));
- when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddress);
+ final int fakeHotspotSubAddr = 0x2b05; // 43.5
+ when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr);
+ final LinkAddress hotspotAddress = requestDownstreamAddress(mHotspotIpServer,
+ true /* useLastAddress */);
+ assertEquals("Wrong wifi prefix: ", new LinkAddress("192.168.43.5/24"), hotspotAddress);
- final LinkAddress usbAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
- mUsbIpServer, true /* useLastAddress */);
- assertNotEquals(predefinedPrefix, asIpPrefix(usbAddress));
+ final LinkAddress usbAddress = requestDownstreamAddress(mUsbIpServer,
+ true /* useLastAddress */);
+ assertEquals("Wrong wifi prefix: ", new LinkAddress("192.168.45.5/24"), usbAddress);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer);
final int newFakeSubAddr = 0x3c05;
- when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr);
+ when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr);
- final LinkAddress newHotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer, true /* useLastAddress */);
+ final LinkAddress newHotspotAddress = requestDownstreamAddress(mHotspotIpServer,
+ true /* useLastAddress */);
assertEquals(hotspotAddress, newHotspotAddress);
- final LinkAddress newUsbAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
- mUsbIpServer, true /* useLastAddress */);
+ final LinkAddress newUsbAddress = requestDownstreamAddress(mUsbIpServer,
+ true /* useLastAddress */);
assertEquals(usbAddress, newUsbAddress);
+
+ final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork,
+ new LinkAddress("192.168.88.23/16"), null,
+ makeNetworkCapabilities(TRANSPORT_WIFI));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(wifiUpstream);
+ verify(mHotspotIpServer).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
+ verify(mUsbIpServer).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
}
private UpstreamNetworkState buildUpstreamNetworkState(final Network network,
@@ -229,17 +251,15 @@
@Test
public void testNoConflictUpstreamPrefix() throws Exception {
- final int fakeHotspotSubId = 43;
- final int fakeHotspotSubAddr = 0x2b05;
+ final int fakeHotspotSubAddr = 0x2b05; // 43.5
final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24");
// Force always get subAddress "43.5" for conflict testing.
- when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr);
+ when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr);
// - Enable hotspot with prefix 192.168.43.0/24
- final LinkAddress hotspotAddr = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer, true /* useLastAddress */);
+ final LinkAddress hotspotAddr = requestDownstreamAddress(mHotspotIpServer,
+ true /* useLastAddress */);
final IpPrefix hotspotPrefix = asIpPrefix(hotspotAddr);
assertEquals("Wrong wifi prefix: ", predefinedPrefix, hotspotPrefix);
- when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr);
// - test mobile network with null NetworkCapabilities. Ideally this should not happen
// because NetworkCapabilities update should always happen before LinkProperties update
// and the UpstreamNetworkState update, just make sure no crash in this case.
@@ -290,28 +310,211 @@
reset(mHotspotIpServer);
// - Restart hotspot again and its prefix is different previous.
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
- final LinkAddress hotspotAddr2 = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer, true /* useLastAddress */);
+ final LinkAddress hotspotAddr2 = requestDownstreamAddress(mHotspotIpServer,
+ true /* useLastAddress */);
final IpPrefix hotspotPrefix2 = asIpPrefix(hotspotAddr2);
assertNotEquals(hotspotPrefix, hotspotPrefix2);
- when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr2);
mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyWifi);
verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
// - Usb tethering can be enabled and its prefix is different with conflict one.
- final LinkAddress usbAddr = mPrivateAddressCoordinator.requestDownstreamAddress(
- mUsbIpServer, true /* useLastAddress */);
+ final LinkAddress usbAddr = requestDownstreamAddress(mUsbIpServer,
+ true /* useLastAddress */);
final IpPrefix usbPrefix = asIpPrefix(usbAddr);
assertNotEquals(predefinedPrefix, usbPrefix);
assertNotEquals(hotspotPrefix2, usbPrefix);
- when(mUsbIpServer.getAddress()).thenReturn(usbAddr);
// - Disable wifi upstream, then wifi's prefix can be selected again.
mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork);
- final LinkAddress ethAddr = mPrivateAddressCoordinator.requestDownstreamAddress(
- mEthernetIpServer, true /* useLastAddress */);
+ final LinkAddress ethAddr = requestDownstreamAddress(mEthernetIpServer,
+ true /* useLastAddress */);
final IpPrefix ethPrefix = asIpPrefix(ethAddr);
assertEquals(predefinedPrefix, ethPrefix);
}
+ @Test
+ public void testChooseAvailablePrefix() throws Exception {
+ final int randomAddress = 0x8605; // 134.5
+ when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(randomAddress);
+ final LinkAddress addr0 = requestDownstreamAddress(mHotspotIpServer,
+ true /* useLastAddress */);
+ // Check whether return address is prefix 192.168.0.0/16 + subAddress 0.0.134.5.
+ assertEquals("Wrong prefix: ", new LinkAddress("192.168.134.5/24"), addr0);
+ final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork,
+ new LinkAddress("192.168.134.13/26"), null,
+ makeNetworkCapabilities(TRANSPORT_WIFI));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(wifiUpstream);
+
+ // Check whether return address is next prefix of 192.168.134.0/24.
+ final LinkAddress addr1 = requestDownstreamAddress(mHotspotIpServer,
+ true /* useLastAddress */);
+ assertEquals("Wrong prefix: ", new LinkAddress("192.168.135.5/24"), addr1);
+ final UpstreamNetworkState wifiUpstream2 = buildUpstreamNetworkState(mWifiNetwork,
+ new LinkAddress("192.168.149.16/19"), null,
+ makeNetworkCapabilities(TRANSPORT_WIFI));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(wifiUpstream2);
+
+
+ // The conflict range is 128 ~ 159, so the address is 192.168.160.5/24.
+ final LinkAddress addr2 = requestDownstreamAddress(mHotspotIpServer,
+ true /* useLastAddress */);
+ assertEquals("Wrong prefix: ", new LinkAddress("192.168.160.5/24"), addr2);
+ final UpstreamNetworkState mobileUpstream = buildUpstreamNetworkState(mMobileNetwork,
+ new LinkAddress("192.168.129.53/18"), null,
+ makeNetworkCapabilities(TRANSPORT_CELLULAR));
+ // Update another conflict upstream which is covered by the previous one (but not the first
+ // one) and verify whether this would affect the result.
+ final UpstreamNetworkState mobileUpstream2 = buildUpstreamNetworkState(mMobileNetwork2,
+ new LinkAddress("192.168.170.7/19"), null,
+ makeNetworkCapabilities(TRANSPORT_CELLULAR));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream);
+ mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream2);
+
+ // The conflict range are 128 ~ 159 and 159 ~ 191, so the address is 192.168.192.5/24.
+ final LinkAddress addr3 = requestDownstreamAddress(mHotspotIpServer,
+ true /* useLastAddress */);
+ assertEquals("Wrong prefix: ", new LinkAddress("192.168.192.5/24"), addr3);
+ final UpstreamNetworkState mobileUpstream3 = buildUpstreamNetworkState(mMobileNetwork3,
+ new LinkAddress("192.168.188.133/17"), null,
+ makeNetworkCapabilities(TRANSPORT_CELLULAR));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream3);
+
+ // Conflict range: 128 ~ 255. The next available address is 192.168.0.5 because
+ // 192.168.134/24 ~ 192.168.255.255/24 is not available.
+ final LinkAddress addr4 = requestDownstreamAddress(mHotspotIpServer,
+ true /* useLastAddress */);
+ assertEquals("Wrong prefix: ", new LinkAddress("192.168.0.5/24"), addr4);
+ final UpstreamNetworkState mobileUpstream4 = buildUpstreamNetworkState(mMobileNetwork4,
+ new LinkAddress("192.168.3.59/21"), null,
+ makeNetworkCapabilities(TRANSPORT_CELLULAR));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream4);
+
+ // Conflict ranges: 128 ~ 255 and 0 ~ 7, so the address is 192.168.8.5/24.
+ final LinkAddress addr5 = requestDownstreamAddress(mHotspotIpServer,
+ true /* useLastAddress */);
+ assertEquals("Wrong prefix: ", new LinkAddress("192.168.8.5/24"), addr5);
+ final UpstreamNetworkState mobileUpstream5 = buildUpstreamNetworkState(mMobileNetwork5,
+ new LinkAddress("192.168.68.43/21"), null,
+ makeNetworkCapabilities(TRANSPORT_CELLULAR));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream5);
+
+ // Update an upstream that does *not* conflict, check whether return the same address
+ // 192.168.5/24.
+ final LinkAddress addr6 = requestDownstreamAddress(mHotspotIpServer,
+ true /* useLastAddress */);
+ assertEquals("Wrong prefix: ", new LinkAddress("192.168.8.5/24"), addr6);
+ final UpstreamNetworkState mobileUpstream6 = buildUpstreamNetworkState(mMobileNetwork6,
+ new LinkAddress("192.168.10.97/21"), null,
+ makeNetworkCapabilities(TRANSPORT_CELLULAR));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream6);
+
+ // Conflict ranges: 0 ~ 15 and 128 ~ 255, so the address is 192.168.16.5/24.
+ final LinkAddress addr7 = requestDownstreamAddress(mHotspotIpServer,
+ true /* useLastAddress */);
+ assertEquals("Wrong prefix: ", new LinkAddress("192.168.16.5/24"), addr7);
+ final UpstreamNetworkState mobileUpstream7 = buildUpstreamNetworkState(mMobileNetwork6,
+ new LinkAddress("192.168.0.0/17"), null,
+ makeNetworkCapabilities(TRANSPORT_CELLULAR));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream7);
+
+ // Choose prefix from next range(172.16.0.0/12) when no available prefix in 192.168.0.0/16.
+ final LinkAddress addr8 = requestDownstreamAddress(mHotspotIpServer,
+ true /* useLastAddress */);
+ assertEquals("Wrong prefix: ", new LinkAddress("172.16.134.5/24"), addr8);
+ }
+
+ @Test
+ public void testChoosePrefixFromDifferentRanges() throws Exception {
+ final int randomAddress = 0x1f2b2a; // 31.43.42
+ when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(randomAddress);
+ final LinkAddress classC1 = requestDownstreamAddress(mHotspotIpServer,
+ true /* useLastAddress */);
+ // Check whether return address is prefix 192.168.0.0/16 + subAddress 0.0.43.42.
+ assertEquals("Wrong prefix: ", new LinkAddress("192.168.43.42/24"), classC1);
+ final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork,
+ new LinkAddress("192.168.88.23/17"), null,
+ makeNetworkCapabilities(TRANSPORT_WIFI));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(wifiUpstream);
+ verifyNotifyConflictAndRelease(mHotspotIpServer);
+
+ // Check whether return address is next address of prefix 192.168.128.0/17.
+ final LinkAddress classC2 = requestDownstreamAddress(mHotspotIpServer,
+ true /* useLastAddress */);
+ assertEquals("Wrong prefix: ", new LinkAddress("192.168.128.42/24"), classC2);
+ final UpstreamNetworkState mobileUpstream = buildUpstreamNetworkState(mMobileNetwork,
+ new LinkAddress("192.1.2.3/8"), null,
+ makeNetworkCapabilities(TRANSPORT_CELLULAR));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream);
+ verifyNotifyConflictAndRelease(mHotspotIpServer);
+
+ // Check whether return address is under prefix 172.16.0.0/12.
+ final LinkAddress classB1 = requestDownstreamAddress(mHotspotIpServer,
+ true /* useLastAddress */);
+ assertEquals("Wrong prefix: ", new LinkAddress("172.31.43.42/24"), classB1);
+ final UpstreamNetworkState mobileUpstream2 = buildUpstreamNetworkState(mMobileNetwork2,
+ new LinkAddress("172.28.123.100/14"), null,
+ makeNetworkCapabilities(TRANSPORT_CELLULAR));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream2);
+ verifyNotifyConflictAndRelease(mHotspotIpServer);
+
+ // 172.28.0.0 ~ 172.31.255.255 is not available.
+ // Check whether return address is next address of prefix 172.16.0.0/14.
+ final LinkAddress classB2 = requestDownstreamAddress(mHotspotIpServer,
+ true /* useLastAddress */);
+ assertEquals("Wrong prefix: ", new LinkAddress("172.16.0.42/24"), classB2);
+
+ // Check whether new downstream is next address of address 172.16.0.42/24.
+ final LinkAddress classB3 = requestDownstreamAddress(mUsbIpServer,
+ true /* useLastAddress */);
+ assertEquals("Wrong prefix: ", new LinkAddress("172.16.1.42/24"), classB3);
+ final UpstreamNetworkState mobileUpstream3 = buildUpstreamNetworkState(mMobileNetwork3,
+ new LinkAddress("172.16.0.1/24"), null,
+ makeNetworkCapabilities(TRANSPORT_CELLULAR));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream3);
+ verifyNotifyConflictAndRelease(mHotspotIpServer);
+ verify(mUsbIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
+
+ // Check whether return address is next address of prefix 172.16.1.42/24.
+ final LinkAddress classB4 = requestDownstreamAddress(mHotspotIpServer,
+ true /* useLastAddress */);
+ assertEquals("Wrong prefix: ", new LinkAddress("172.16.2.42/24"), classB4);
+ final UpstreamNetworkState mobileUpstream4 = buildUpstreamNetworkState(mMobileNetwork4,
+ new LinkAddress("172.16.0.1/13"), null,
+ makeNetworkCapabilities(TRANSPORT_CELLULAR));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream4);
+ verifyNotifyConflictAndRelease(mHotspotIpServer);
+ verifyNotifyConflictAndRelease(mUsbIpServer);
+
+ // Check whether return address is next address of prefix 172.16.0.1/13.
+ final LinkAddress classB5 = requestDownstreamAddress(mHotspotIpServer,
+ true /* useLastAddress */);
+ assertEquals("Wrong prefix: ", new LinkAddress("172.24.0.42/24"), classB5);
+ // Check whether return address is next address of prefix 172.24.0.42/24.
+ final LinkAddress classB6 = requestDownstreamAddress(mUsbIpServer,
+ true /* useLastAddress */);
+ assertEquals("Wrong prefix: ", new LinkAddress("172.24.1.42/24"), classB6);
+ final UpstreamNetworkState mobileUpstream5 = buildUpstreamNetworkState(mMobileNetwork5,
+ new LinkAddress("172.24.0.1/12"), null,
+ makeNetworkCapabilities(TRANSPORT_CELLULAR));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream5);
+ verifyNotifyConflictAndRelease(mHotspotIpServer);
+ verifyNotifyConflictAndRelease(mUsbIpServer);
+
+ // Check whether return address is prefix 10.0.0.0/8 + subAddress 0.31.43.42.
+ final LinkAddress classA1 = requestDownstreamAddress(mHotspotIpServer,
+ true /* useLastAddress */);
+ assertEquals("Wrong prefix: ", new LinkAddress("10.31.43.42/24"), classA1);
+ // Check whether new downstream is next address of address 10.31.43.42/24.
+ final LinkAddress classA2 = requestDownstreamAddress(mUsbIpServer,
+ true /* useLastAddress */);
+ assertEquals("Wrong prefix: ", new LinkAddress("10.31.44.42/24"), classA2);
+ }
+
+ private void verifyNotifyConflictAndRelease(final IpServer ipServer) throws Exception {
+ verify(ipServer).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
+ mPrivateAddressCoordinator.releaseDownstream(ipServer);
+ reset(ipServer);
+ setUpIpServers();
+ }
+
private int getSubAddress(final byte... ipv4Address) {
assertEquals(4, ipv4Address.length);
@@ -320,8 +523,8 @@
}
private void assertReseveredWifiP2pPrefix() throws Exception {
- LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer, true /* useLastAddress */);
+ LinkAddress address = requestDownstreamAddress(mHotspotIpServer,
+ true /* useLastAddress */);
final IpPrefix hotspotPrefix = asIpPrefix(address);
final IpPrefix legacyWifiP2pPrefix = asIpPrefix(mLegacyWifiP2pAddress);
assertNotEquals(legacyWifiP2pPrefix, hotspotPrefix);
@@ -330,7 +533,7 @@
@Test
public void testEnableLegacyWifiP2PAddress() throws Exception {
- when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(
+ when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(
getSubAddress(mLegacyWifiP2pAddress.getAddress().getAddress()));
// No matter #shouldEnableWifiP2pDedicatedIp() is enabled or not, legacy wifi p2p prefix
// is resevered.
@@ -340,8 +543,8 @@
assertReseveredWifiP2pPrefix();
// If #shouldEnableWifiP2pDedicatedIp() is enabled, wifi P2P gets the configured address.
- LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
- mWifiP2pIpServer, true /* useLastAddress */);
+ LinkAddress address = requestDownstreamAddress(mWifiP2pIpServer,
+ true /* useLastAddress */);
assertEquals(mLegacyWifiP2pAddress, address);
mPrivateAddressCoordinator.releaseDownstream(mWifiP2pIpServer);
}
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index df57020..20e94b2 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -24,6 +24,9 @@
import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
+import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.RouteInfo.RTN_UNICAST;
import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
@@ -179,6 +182,7 @@
private static final String TEST_P2P_IFNAME = "test_p2p-p2p0-0";
private static final String TEST_NCM_IFNAME = "test_ncm0";
private static final String TEST_ETH_IFNAME = "test_eth0";
+ private static final String TEST_BT_IFNAME = "test_pan0";
private static final String TETHERING_NAME = "Tethering";
private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app";
@@ -230,6 +234,7 @@
private TetheringConfiguration mConfig;
private EntitlementManager mEntitleMgr;
private OffloadController mOffloadCtrl;
+ private PrivateAddressCoordinator mPrivateAddressCoordinator;
private class TestContext extends BroadcastInterceptingContext {
TestContext(Context base) {
@@ -446,6 +451,18 @@
public boolean isTetheringDenied() {
return false;
}
+
+
+ @Override
+ public PrivateAddressCoordinator getPrivateAddressCoordinator(Context ctx,
+ TetheringConfiguration cfg) {
+ final ArrayList<IpPrefix> prefixPool = new ArrayList<>(Arrays.asList(
+ new IpPrefix("192.168.0.0/16"),
+ new IpPrefix("172.16.0.0/12"),
+ new IpPrefix("10.0.0.0/8")));
+ mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(ctx, cfg, prefixPool));
+ return mPrivateAddressCoordinator;
+ }
}
private static UpstreamNetworkState buildMobileUpstreamState(boolean withIPv4,
@@ -1875,27 +1892,36 @@
sendConfigurationChanged();
}
- private static UpstreamNetworkState buildV4WifiUpstreamState(final String ipv4Address,
- final int prefixLength, final Network network) {
+ private static UpstreamNetworkState buildV4UpstreamState(final LinkAddress address,
+ final Network network, final String iface, final int transportType) {
final LinkProperties prop = new LinkProperties();
- prop.setInterfaceName(TEST_WIFI_IFNAME);
+ prop.setInterfaceName(iface);
- prop.addLinkAddress(
- new LinkAddress(InetAddresses.parseNumericAddress(ipv4Address),
- prefixLength));
+ prop.addLinkAddress(address);
final NetworkCapabilities capabilities = new NetworkCapabilities()
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+ .addTransportType(transportType);
return new UpstreamNetworkState(prop, capabilities, network);
}
+ private void updateV4Upstream(final LinkAddress ipv4Address, final Network network,
+ final String iface, final int transportType) {
+ final UpstreamNetworkState upstream = buildV4UpstreamState(ipv4Address, network, iface,
+ transportType);
+ mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage(
+ Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK,
+ UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES,
+ 0,
+ upstream);
+ mLooper.dispatchAll();
+ }
+
@Test
public void testHandleIpConflict() throws Exception {
final Network wifiNetwork = new Network(200);
final Network[] allNetworks = { wifiNetwork };
when(mCm.getAllNetworks()).thenReturn(allNetworks);
- UpstreamNetworkState upstreamNetwork = null;
- runUsbTethering(upstreamNetwork);
+ runUsbTethering(null);
final ArgumentCaptor<InterfaceConfigurationParcel> ifaceConfigCaptor =
ArgumentCaptor.forClass(InterfaceConfigurationParcel.class);
verify(mNetd).interfaceSetCfg(ifaceConfigCaptor.capture());
@@ -1903,13 +1929,10 @@
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks(
any(), any());
reset(mNetd, mUsbManager);
- upstreamNetwork = buildV4WifiUpstreamState(ipv4Address, 30, wifiNetwork);
- mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage(
- Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK,
- UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES,
- 0,
- upstreamNetwork);
- mLooper.dispatchAll();
+
+ // Cause a prefix conflict by assigning a /30 out of the downstream's /24 to the upstream.
+ updateV4Upstream(new LinkAddress(InetAddresses.parseNumericAddress(ipv4Address), 30),
+ wifiNetwork, TEST_WIFI_IFNAME, TRANSPORT_WIFI);
// verify turn off usb tethering
verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_NONE);
mTethering.interfaceRemoved(TEST_USB_IFNAME);
@@ -1921,9 +1944,10 @@
@Test
public void testNoAddressAvailable() throws Exception {
final Network wifiNetwork = new Network(200);
- final Network[] allNetworks = { wifiNetwork };
+ final Network btNetwork = new Network(201);
+ final Network mobileNetwork = new Network(202);
+ final Network[] allNetworks = { wifiNetwork, btNetwork, mobileNetwork };
when(mCm.getAllNetworks()).thenReturn(allNetworks);
- final String upstreamAddress = "192.168.0.100";
runUsbTethering(null);
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks(
any(), any());
@@ -1940,13 +1964,13 @@
mLooper.dispatchAll();
reset(mUsbManager, mEm);
- final UpstreamNetworkState upstreamNetwork = buildV4WifiUpstreamState(
- upstreamAddress, 16, wifiNetwork);
- mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage(
- Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK,
- UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES,
- 0,
- upstreamNetwork);
+ updateV4Upstream(new LinkAddress("192.168.0.100/16"), wifiNetwork, TEST_WIFI_IFNAME,
+ TRANSPORT_WIFI);
+ updateV4Upstream(new LinkAddress("172.16.0.0/12"), btNetwork, TEST_BT_IFNAME,
+ TRANSPORT_BLUETOOTH);
+ updateV4Upstream(new LinkAddress("10.0.0.0/8"), mobileNetwork, TEST_MOBILE_IFNAME,
+ TRANSPORT_CELLULAR);
+
mLooper.dispatchAll();
// verify turn off usb tethering
verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_NONE);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 9ddf7a4..e1c4993 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -941,10 +941,19 @@
if (resolvedUserId != mCurrentUserId) {
return null;
}
- if (mA11yWindowManager.findA11yWindowInfoByIdLocked(windowId) == null) {
+ final AccessibilityWindowInfo accessibilityWindowInfo = mA11yWindowManager
+ .findA11yWindowInfoByIdLocked(windowId);
+ if (accessibilityWindowInfo == null) {
return null;
}
- return mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(userId, windowId);
+ // We use AccessibilityWindowInfo#getId instead of windowId. When the windowId comes
+ // from an embedded hierarchy, the system can't find correct window token because
+ // embedded hierarchy doesn't have windowInfo. Calling
+ // AccessibilityWindowManager#findA11yWindowInfoByIdLocked can look for its parent's
+ // windowInfo, so it is safer to use AccessibilityWindowInfo#getId
+ // to get window token to find real window.
+ return mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(userId,
+ accessibilityWindowInfo.getId());
}
}
@@ -2624,6 +2633,7 @@
}
@Override
+ @SuppressWarnings("AndroidFrameworkPendingIntentMutability")
public PendingIntent getPendingIntentActivity(Context context, int requestCode, Intent intent,
int flags) {
return PendingIntent.getActivity(context, requestCode, intent, flags);
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
index a860db3..14af8c6 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
@@ -19,6 +19,7 @@
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_DOUBLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SINGLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SINGLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_DOWN;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_LEFT;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_RIGHT;
@@ -27,11 +28,13 @@
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_DOUBLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SINGLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_DOWN;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_LEFT;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_RIGHT;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_UP;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_TRIPLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_DOUBLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SINGLE_TAP;
@@ -140,6 +143,9 @@
mMultiFingerGestures.add(
new MultiFingerMultiTap(mContext, 2, 1, GESTURE_2_FINGER_SINGLE_TAP, this));
mMultiFingerGestures.add(
+ new MultiFingerMultiTapAndHold(
+ mContext, 2, 1, GESTURE_2_FINGER_SINGLE_TAP_AND_HOLD, this));
+ mMultiFingerGestures.add(
new MultiFingerMultiTap(mContext, 2, 2, GESTURE_2_FINGER_DOUBLE_TAP, this));
mMultiFingerGestures.add(
new MultiFingerMultiTapAndHold(
@@ -153,9 +159,17 @@
new MultiFingerMultiTap(mContext, 3, 2, GESTURE_3_FINGER_DOUBLE_TAP, this));
mMultiFingerGestures.add(
new MultiFingerMultiTapAndHold(
+ mContext, 3, 1, GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD, this));
+ mMultiFingerGestures.add(
+ new MultiFingerMultiTapAndHold(
mContext, 3, 2, GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD, this));
mMultiFingerGestures.add(
new MultiFingerMultiTap(mContext, 3, 3, GESTURE_3_FINGER_TRIPLE_TAP, this));
+ mMultiFingerGestures.add(
+ new MultiFingerMultiTapAndHold(
+ mContext, 3, 3, GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD, this));
+ mMultiFingerGestures.add(
+ new MultiFingerMultiTap(mContext, 3, 3, GESTURE_3_FINGER_TRIPLE_TAP, this));
// Four-finger taps.
mMultiFingerGestures.add(
new MultiFingerMultiTap(mContext, 4, 1, GESTURE_4_FINGER_SINGLE_TAP, this));
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTap.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTap.java
index e15c495..46b4628 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTap.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTap.java
@@ -162,6 +162,7 @@
// Accept down only before target number of fingers are down
// or the finger count is not more than target.
if ((currentFingerCount > mTargetFingerCount) || mIsTargetFingerCountReached) {
+ mIsTargetFingerCountReached = false;
cancelGesture(event, rawEvent, policyFlags);
return;
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 6157004..032820d 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -391,7 +391,10 @@
checkArgument(getCallingUserId() == userId,
"Must be called by either same user or system");
- mAppOpsManager.checkPackage(Binder.getCallingUid(), pkg);
+ int callingUid = Binder.getCallingUid();
+ if (mAppOpsManager.checkPackage(callingUid, pkg) != AppOpsManager.MODE_ALLOWED) {
+ throw new SecurityException(pkg + " doesn't belong to uid " + callingUid);
+ }
}
@Override
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 26c28d5..4b10ab7 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -122,6 +122,7 @@
"netd_aidl_interfaces-platform-java",
"overlayable_policy_aidl-java",
"SurfaceFlingerProperties",
+ "com.android.sysprop.watchdog",
],
}
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 43c54b4..72a2152 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -1106,4 +1106,17 @@
}
}
+ /**
+ * Retrieve all of the information we know about a particular activity class including its
+ * package states.
+ *
+ * @param packageName a specific package
+ * @param filterCallingUid The results will be filtered in the context of this UID instead
+ * of the calling UID.
+ * @param userId The user for whom the package is installed
+ * @return IncrementalStatesInfo that contains information about package states.
+ */
+ public abstract IncrementalStatesInfo getIncrementalStatesInfo(String packageName,
+ int filterCallingUid, int userId);
+
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index b59f7645..bb9f6d2 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -140,6 +140,7 @@
import android.net.util.LinkPropertiesUtils.CompareResult;
import android.net.util.MultinetworkPolicyTracker;
import android.net.util.NetdService;
+import android.os.BasicShellCommandHandler;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -156,11 +157,8 @@
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
-import android.os.ShellCallback;
-import android.os.ShellCommand;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -7658,14 +7656,14 @@
}
@Override
- public void onShellCommand(@NonNull FileDescriptor in, @NonNull FileDescriptor out,
- FileDescriptor err, @NonNull String[] args, ShellCallback callback,
- @NonNull ResultReceiver resultReceiver) {
- (new ShellCmd()).exec(this, in, out, err, args, callback, resultReceiver);
+ public int handleShellCommand(@NonNull ParcelFileDescriptor in,
+ @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
+ @NonNull String[] args) {
+ return new ShellCmd().exec(this, in.getFileDescriptor(), out.getFileDescriptor(),
+ err.getFileDescriptor(), args);
}
- private class ShellCmd extends ShellCommand {
-
+ private class ShellCmd extends BasicShellCommandHandler {
@Override
public int onCommand(String cmd) {
if (cmd == null) {
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index b3d4085..95a7a22 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -38,7 +38,6 @@
import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
-import android.telecom.TelecomManager;
import android.util.MutableBoolean;
import android.util.Slog;
import android.view.KeyEvent;
@@ -46,7 +45,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.server.LocalServices;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.wm.WindowManagerInternal;
@@ -529,15 +527,9 @@
"userSetupComplete = %s, performing panic gesture.",
userSetupComplete));
}
- // TODO(b/160006048): Not all devices have telephony. Check system feature first.
- TelecomManager telecomManager = (TelecomManager) mContext.getSystemService(
- Context.TELECOM_SERVICE);
- mContext.startActivity(telecomManager.createLaunchEmergencyDialerIntent(null).addFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
- | Intent.FLAG_ACTIVITY_SINGLE_TOP).putExtra(
- "com.android.phone.EmergencyDialer.extra.ENTRY_TYPE",
- 2)); // 2 maps to power button, forcing into fast emergency dialer experience.
+ StatusBarManagerInternal service = LocalServices.getService(
+ StatusBarManagerInternal.class);
+ service.onEmergencyActionLaunchGestureDetected();
return true;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 0c34744..afddd65 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -33,7 +33,6 @@
import android.hardware.input.InputManager;
import android.hardware.vibrator.IVibrator;
import android.hardware.vibrator.V1_0.EffectStrength;
-import android.icu.text.DateFormat;
import android.media.AudioManager;
import android.os.BatteryStats;
import android.os.Binder;
@@ -80,6 +79,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
@@ -90,6 +90,8 @@
public class VibratorService extends IVibratorService.Stub
implements InputManager.InputDeviceListener {
private static final String TAG = "VibratorService";
+ private static final SimpleDateFormat DEBUG_DATE_FORMAT =
+ new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
private static final boolean DEBUG = false;
private static final String EXTERNAL_VIBRATOR_SERVICE = "external_vibrator_service";
@@ -126,7 +128,7 @@
private final LinkedList<VibrationInfo> mPreviousRingVibrations;
private final LinkedList<VibrationInfo> mPreviousNotificationVibrations;
private final LinkedList<VibrationInfo> mPreviousAlarmVibrations;
- private final LinkedList<ExternalVibration> mPreviousExternalVibrations;
+ private final LinkedList<VibrationInfo> mPreviousExternalVibrations;
private final LinkedList<VibrationInfo> mPreviousVibrations;
private final int mPreviousVibrationsLimit;
private final boolean mAllowPriorityVibrationsInLowPowerMode;
@@ -162,7 +164,7 @@
@GuardedBy("mLock")
private Vibration mCurrentVibration;
private int mCurVibUid = -1;
- private ExternalVibration mCurrentExternalVibration;
+ private ExternalVibrationHolder mCurrentExternalVibration;
private boolean mVibratorUnderExternalControl;
private boolean mLowPowerMode;
@GuardedBy("mLock")
@@ -231,19 +233,12 @@
void onComplete(long vibrationId);
}
- /**
- * Holder for a vibration to be played. This class can be shared with native methods for
- * hardware callback support.
- */
+ /** Holder for a {@link VibrationEffect}. */
private final class Vibration implements IBinder.DeathRecipient {
public final IBinder token;
// Start time in CLOCK_BOOTTIME base.
public final long startTime;
- // Start time in unix epoch time. Only to be used for debugging purposes and to correlate
- // with other system events, any duration calculations should be done use startTime so as
- // not to be affected by discontinuities created by RTC adjustments.
- public final long startTimeDebug;
public final VibrationAttributes attrs;
public final long id;
public final int uid;
@@ -255,18 +250,28 @@
// The original effect that was requested. Typically these two things differ because
// the effect was scaled based on the users vibration intensity settings.
public VibrationEffect originalEffect;
+ // The scale applied to the original effect.
+ public float scale;
+
+ // Start/end times in unix epoch time. Only to be used for debugging purposes and to
+ // correlate with other system events, any duration calculations should be done use
+ // startTime so as not to be affected by discontinuities created by RTC adjustments.
+ private final long mStartTimeDebug;
+ private long mEndTimeDebug;
+ private VibrationInfo.Status mStatus;
private Vibration(IBinder token, VibrationEffect effect,
VibrationAttributes attrs, int uid, String opPkg, String reason) {
this.token = token;
- this.id = mNextVibrationId.getAndIncrement();
this.effect = effect;
+ this.id = mNextVibrationId.getAndIncrement();
this.startTime = SystemClock.elapsedRealtime();
- this.startTimeDebug = System.currentTimeMillis();
this.attrs = attrs;
this.uid = uid;
this.opPkg = opPkg;
this.reason = reason;
+ mStartTimeDebug = System.currentTimeMillis();
+ mStatus = VibrationInfo.Status.RUNNING;
}
@Override
@@ -276,11 +281,24 @@
if (DEBUG) {
Slog.d(TAG, "Vibration finished because binder died, cleaning up");
}
- doCancelVibrateLocked();
+ doCancelVibrateLocked(VibrationInfo.Status.CANCELLED);
}
}
}
+ public void end(VibrationInfo.Status status) {
+ if (hasEnded()) {
+ // Vibration already ended, keep first ending status set and ignore this one.
+ return;
+ }
+ mStatus = status;
+ mEndTimeDebug = System.currentTimeMillis();
+ }
+
+ public boolean hasEnded() {
+ return mStatus != VibrationInfo.Status.RUNNING;
+ }
+
public boolean hasTimeoutLongerThan(long millis) {
final long duration = effect.getDuration();
return duration >= 0 && duration > millis;
@@ -308,40 +326,109 @@
public VibrationInfo toInfo() {
return new VibrationInfo(
- startTimeDebug, effect, originalEffect, attrs, uid, opPkg, reason);
+ mStartTimeDebug, mEndTimeDebug, effect, originalEffect, scale, attrs,
+ uid, opPkg, reason, mStatus);
}
}
- private static class VibrationInfo {
+ /** Holder for a {@link ExternalVibration}. */
+ private final class ExternalVibrationHolder {
+
+ public final ExternalVibration externalVibration;
+ public int scale;
+
private final long mStartTimeDebug;
+ private long mEndTimeDebug;
+ private VibrationInfo.Status mStatus;
+
+ private ExternalVibrationHolder(ExternalVibration externalVibration) {
+ this.externalVibration = externalVibration;
+ this.scale = SCALE_NONE;
+ mStartTimeDebug = System.currentTimeMillis();
+ mStatus = VibrationInfo.Status.RUNNING;
+ }
+
+ public void end(VibrationInfo.Status status) {
+ if (mStatus != VibrationInfo.Status.RUNNING) {
+ // Vibration already ended, keep first ending status set and ignore this one.
+ return;
+ }
+ mStatus = status;
+ mEndTimeDebug = System.currentTimeMillis();
+ }
+
+ public VibrationInfo toInfo() {
+ return new VibrationInfo(
+ mStartTimeDebug, mEndTimeDebug, /* effect= */ null, /* originalEffect= */ null,
+ scale, externalVibration.getVibrationAttributes(),
+ externalVibration.getUid(), externalVibration.getPackage(),
+ /* reason= */ null, mStatus);
+ }
+ }
+
+ /** Debug information about vibrations. */
+ private static class VibrationInfo {
+
+ public enum Status {
+ RUNNING,
+ FINISHED,
+ CANCELLED,
+ ERROR_APP_OPS,
+ IGNORED,
+ IGNORED_APP_OPS,
+ IGNORED_BACKGROUND,
+ IGNORED_RINGTONE,
+ IGNORED_UNKNOWN_VIBRATION,
+ IGNORED_UNSUPPORTED,
+ IGNORED_FOR_ALARM,
+ IGNORED_FOR_EXTERNAL,
+ IGNORED_FOR_ONGOING,
+ IGNORED_FOR_POWER,
+ IGNORED_FOR_SETTINGS,
+ }
+
+ private final long mStartTimeDebug;
+ private final long mEndTimeDebug;
private final VibrationEffect mEffect;
private final VibrationEffect mOriginalEffect;
+ private final float mScale;
private final VibrationAttributes mAttrs;
private final int mUid;
private final String mOpPkg;
private final String mReason;
+ private final VibrationInfo.Status mStatus;
- VibrationInfo(long startTimeDebug, VibrationEffect effect,
- VibrationEffect originalEffect, VibrationAttributes attrs, int uid,
- String opPkg, String reason) {
+ VibrationInfo(long startTimeDebug, long endTimeDebug, VibrationEffect effect,
+ VibrationEffect originalEffect, float scale, VibrationAttributes attrs,
+ int uid, String opPkg, String reason, VibrationInfo.Status status) {
mStartTimeDebug = startTimeDebug;
+ mEndTimeDebug = endTimeDebug;
mEffect = effect;
mOriginalEffect = originalEffect;
+ mScale = scale;
mAttrs = attrs;
mUid = uid;
mOpPkg = opPkg;
mReason = reason;
+ mStatus = status;
}
@Override
public String toString() {
return new StringBuilder()
.append("startTime: ")
- .append(DateFormat.getDateTimeInstance().format(new Date(mStartTimeDebug)))
+ .append(DEBUG_DATE_FORMAT.format(new Date(mStartTimeDebug)))
+ .append(", endTime: ")
+ .append(mEndTimeDebug == 0 ? null
+ : DEBUG_DATE_FORMAT.format(new Date(mEndTimeDebug)))
+ .append(", status: ")
+ .append(mStatus.name().toLowerCase())
.append(", effect: ")
.append(mEffect)
.append(", originalEffect: ")
.append(mOriginalEffect)
+ .append(", scale: ")
+ .append(String.format("%.2f", mScale))
.append(", attrs: ")
.append(mAttrs)
.append(", uid: ")
@@ -354,11 +441,80 @@
}
void dumpProto(ProtoOutputStream proto, long fieldId) {
- synchronized (this) {
- final long token = proto.start(fieldId);
- proto.write(VibrationProto.START_TIME, mStartTimeDebug);
- proto.end(token);
+ final long token = proto.start(fieldId);
+ proto.write(VibrationProto.START_TIME, mStartTimeDebug);
+ proto.write(VibrationProto.END_TIME, mEndTimeDebug);
+ proto.write(VibrationProto.STATUS, mStatus.ordinal());
+
+ final long attrsToken = proto.start(VibrationProto.ATTRIBUTES);
+ proto.write(VibrationAttributesProto.USAGE, mAttrs.getUsage());
+ proto.write(VibrationAttributesProto.AUDIO_USAGE, mAttrs.getAudioUsage());
+ proto.write(VibrationAttributesProto.FLAGS, mAttrs.getFlags());
+ proto.end(attrsToken);
+
+ if (mEffect != null) {
+ dumpEffect(proto, VibrationProto.EFFECT, mEffect);
}
+ if (mOriginalEffect != null) {
+ dumpEffect(proto, VibrationProto.ORIGINAL_EFFECT, mOriginalEffect);
+ }
+
+ proto.end(token);
+ }
+
+ private void dumpEffect(ProtoOutputStream proto, long fieldId, VibrationEffect effect) {
+ final long token = proto.start(fieldId);
+ if (effect instanceof VibrationEffect.OneShot) {
+ dumpEffect(proto, VibrationEffectProto.ONESHOT, (VibrationEffect.OneShot) effect);
+ } else if (effect instanceof VibrationEffect.Waveform) {
+ dumpEffect(proto, VibrationEffectProto.WAVEFORM, (VibrationEffect.Waveform) effect);
+ } else if (effect instanceof VibrationEffect.Prebaked) {
+ dumpEffect(proto, VibrationEffectProto.PREBAKED, (VibrationEffect.Prebaked) effect);
+ } else if (effect instanceof VibrationEffect.Composed) {
+ dumpEffect(proto, VibrationEffectProto.COMPOSED, (VibrationEffect.Composed) effect);
+ }
+ proto.end(token);
+ }
+
+ private void dumpEffect(ProtoOutputStream proto, long fieldId,
+ VibrationEffect.OneShot effect) {
+ final long token = proto.start(fieldId);
+ proto.write(OneShotProto.DURATION, (int) effect.getDuration());
+ proto.write(OneShotProto.AMPLITUDE, effect.getAmplitude());
+ proto.end(token);
+ }
+
+ private void dumpEffect(ProtoOutputStream proto, long fieldId,
+ VibrationEffect.Waveform effect) {
+ final long token = proto.start(fieldId);
+ for (long timing : effect.getTimings()) {
+ proto.write(WaveformProto.TIMINGS, (int) timing);
+ }
+ for (int amplitude : effect.getAmplitudes()) {
+ proto.write(WaveformProto.AMPLITUDES, amplitude);
+ }
+ proto.write(WaveformProto.REPEAT, effect.getRepeatIndex() >= 0);
+ proto.end(token);
+ }
+
+ private void dumpEffect(ProtoOutputStream proto, long fieldId,
+ VibrationEffect.Prebaked effect) {
+ final long token = proto.start(fieldId);
+ proto.write(PrebakedProto.EFFECT_ID, effect.getId());
+ proto.write(PrebakedProto.EFFECT_STRENGTH, effect.getEffectStrength());
+ proto.write(PrebakedProto.FALLBACK, effect.shouldFallback());
+ proto.end(token);
+ }
+
+ private void dumpEffect(ProtoOutputStream proto, long fieldId,
+ VibrationEffect.Composed effect) {
+ final long token = proto.start(fieldId);
+ for (PrimitiveEffect primitive : effect.getPrimitiveEffects()) {
+ proto.write(ComposedProto.EFFECT_IDS, primitive.id);
+ proto.write(ComposedProto.EFFECT_SCALES, primitive.scale);
+ proto.write(ComposedProto.DELAYS, primitive.delay);
+ }
+ proto.end(token);
}
}
@@ -549,7 +705,7 @@
if (DEBUG) {
Slog.d(TAG, "Vibration finished by callback, cleaning up");
}
- doCancelVibrateLocked();
+ doCancelVibrateLocked(VibrationInfo.Status.FINISHED);
}
}
}
@@ -792,6 +948,7 @@
}
attrs = fixupVibrationAttributes(attrs);
+ Vibration vib = new Vibration(token, effect, attrs, uid, opPkg, reason);
// If our current vibration is longer than the new vibration and is the same amplitude,
// then just let the current one finish.
@@ -808,6 +965,7 @@
Slog.d(TAG,
"Ignoring incoming vibration in favor of current vibration");
}
+ endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_ONGOING);
return;
}
}
@@ -819,6 +977,7 @@
if (DEBUG) {
Slog.d(TAG, "Ignoring incoming vibration for current external vibration");
}
+ endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_EXTERNAL);
return;
}
@@ -832,24 +991,29 @@
if (DEBUG) {
Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration");
}
+ endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_ALARM);
return;
}
- Vibration vib = new Vibration(token, effect, attrs, uid, opPkg, reason);
if (mProcStatesCache.get(uid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)
> ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
&& !vib.isNotification() && !vib.isRingtone() && !vib.isAlarm()) {
Slog.e(TAG, "Ignoring incoming vibration as process with"
+ " uid= " + uid + " is background,"
+ " attrs= " + vib.attrs);
+ endVibrationLocked(vib, VibrationInfo.Status.IGNORED_BACKGROUND);
return;
}
linkVibration(vib);
final long ident = Binder.clearCallingIdentity();
try {
- doCancelVibrateLocked();
+ doCancelVibrateLocked(VibrationInfo.Status.CANCELLED);
startVibrationLocked(vib);
- addToPreviousVibrationsLocked(vib);
+
+ if (!vib.hasEnded() && mCurrentVibration.id != vib.id) {
+ // Vibration was unexpectedly ignored: add to list for debugging
+ endVibrationLocked(vib, VibrationInfo.Status.IGNORED);
+ }
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -868,7 +1032,7 @@
return effect.getDuration() == Long.MAX_VALUE;
}
- private void addToPreviousVibrationsLocked(Vibration vib) {
+ private void endVibrationLocked(Vibration vib, VibrationInfo.Status status) {
final LinkedList<VibrationInfo> previousVibrations;
if (vib.isRingtone()) {
previousVibrations = mPreviousRingVibrations;
@@ -883,9 +1047,18 @@
if (previousVibrations.size() > mPreviousVibrationsLimit) {
previousVibrations.removeFirst();
}
+ vib.end(status);
previousVibrations.addLast(vib.toInfo());
}
+ private void endVibrationLocked(ExternalVibrationHolder vib, VibrationInfo.Status status) {
+ if (mPreviousExternalVibrations.size() > mPreviousVibrationsLimit) {
+ mPreviousExternalVibrations.removeFirst();
+ }
+ vib.end(status);
+ mPreviousExternalVibrations.addLast(vib.toInfo());
+ }
+
@Override // Binder call
public void cancelVibrate(IBinder token) {
mContext.enforceCallingOrSelfPermission(
@@ -899,7 +1072,7 @@
}
final long ident = Binder.clearCallingIdentity();
try {
- doCancelVibrateLocked();
+ doCancelVibrateLocked(VibrationInfo.Status.CANCELLED);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -908,7 +1081,7 @@
}
@GuardedBy("mLock")
- private void doCancelVibrateLocked() {
+ private void doCancelVibrateLocked(VibrationInfo.Status status) {
Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doCancelVibrateLocked");
try {
@@ -917,12 +1090,13 @@
mThread = null;
}
if (mCurrentExternalVibration != null) {
- mCurrentExternalVibration.mute();
+ endVibrationLocked(mCurrentExternalVibration, status);
+ mCurrentExternalVibration.externalVibration.mute();
mCurrentExternalVibration = null;
setVibratorUnderExternalControl(false);
}
doVibratorOff();
- reportFinishVibrationLocked();
+ reportFinishVibrationLocked(status);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
@@ -936,7 +1110,7 @@
synchronized (mLock) {
// Make sure the vibration is really done. This also reports that the vibration is
// finished.
- doCancelVibrateLocked();
+ doCancelVibrateLocked(VibrationInfo.Status.FINISHED);
}
}
@@ -944,7 +1118,7 @@
private void startVibrationLocked(final Vibration vib) {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked");
try {
- final int intensity = getCurrentIntensityLocked(vib);
+ final int intensity = getCurrentIntensityLocked(vib.attrs.getUsage());
if (!shouldVibrate(vib, intensity)) {
return;
}
@@ -959,6 +1133,7 @@
private void startVibrationInnerLocked(Vibration vib) {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationInnerLocked");
try {
+ // Set current vibration before starting it, so callback will work.
mCurrentVibration = vib;
if (vib.effect instanceof VibrationEffect.OneShot) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
@@ -971,18 +1146,21 @@
} else if (vib.effect instanceof VibrationEffect.Prebaked) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
doVibratorPrebakedEffectLocked(vib);
- } else if (vib.effect instanceof VibrationEffect.Composed) {
+ } else if (vib.effect instanceof VibrationEffect.Composed) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
doVibratorComposedEffectLocked(vib);
} else {
Slog.e(TAG, "Unknown vibration type, ignoring");
+ endVibrationLocked(vib, VibrationInfo.Status.IGNORED_UNKNOWN_VIBRATION);
+ // The set current vibration is not actually playing, so drop it.
+ mCurrentVibration = null;
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
- private boolean isAllowedToVibrateLocked(Vibration vib) {
+ private boolean shouldVibrateForPowerModeLocked(Vibration vib) {
if (!mLowPowerMode) {
return true;
}
@@ -993,14 +1171,28 @@
|| usage == VibrationAttributes.USAGE_COMMUNICATION_REQUEST;
}
- private int getCurrentIntensityLocked(Vibration vib) {
- if (vib.isRingtone()) {
+ private int getCurrentIntensityLocked(int usageHint) {
+ if (isRingtone(usageHint)) {
return mRingIntensity;
- } else if (vib.isNotification()) {
+ } else if (isNotification(usageHint)) {
return mNotificationIntensity;
- } else if (vib.isHapticFeedback()) {
+ } else if (isHapticFeedback(usageHint)) {
return mHapticFeedbackIntensity;
- } else if (vib.isAlarm()) {
+ } else if (isAlarm(usageHint)) {
+ return Vibrator.VIBRATION_INTENSITY_HIGH;
+ } else {
+ return Vibrator.VIBRATION_INTENSITY_MEDIUM;
+ }
+ }
+
+ private int getDefaultIntensity(int usageHint) {
+ if (isRingtone(usageHint)) {
+ return mVibrator.getDefaultRingVibrationIntensity();
+ } else if (isNotification(usageHint)) {
+ return mVibrator.getDefaultNotificationVibrationIntensity();
+ } else if (isHapticFeedback(usageHint)) {
+ return mVibrator.getDefaultHapticFeedbackIntensity();
+ } else if (isAlarm(usageHint)) {
return Vibrator.VIBRATION_INTENSITY_HIGH;
} else {
return Vibrator.VIBRATION_INTENSITY_MEDIUM;
@@ -1019,21 +1211,7 @@
return;
}
- final int defaultIntensity;
- if (vib.isRingtone()) {
- defaultIntensity = mVibrator.getDefaultRingVibrationIntensity();
- } else if (vib.isNotification()) {
- defaultIntensity = mVibrator.getDefaultNotificationVibrationIntensity();
- } else if (vib.isHapticFeedback()) {
- defaultIntensity = mVibrator.getDefaultHapticFeedbackIntensity();
- } else if (vib.isAlarm()) {
- defaultIntensity = Vibrator.VIBRATION_INTENSITY_HIGH;
- } else {
- // If we don't know what kind of vibration we're playing then just skip scaling for
- // now.
- return;
- }
-
+ final int defaultIntensity = getDefaultIntensity(vib.attrs.getUsage());
final ScaleLevel scale = mScaleLevels.get(intensity - defaultIntensity);
if (scale == null) {
// We should have scaling levels for all cases, so not being able to scale because of a
@@ -1045,6 +1223,7 @@
vib.originalEffect = vib.effect;
vib.effect = vib.effect.resolve(mDefaultVibrationAmplitude).scale(scale.factor);
+ vib.scale = scale.factor;
}
private boolean shouldVibrateForRingtone() {
@@ -1084,11 +1263,13 @@
}
private boolean shouldVibrate(Vibration vib, int intensity) {
- if (!isAllowedToVibrateLocked(vib)) {
+ if (!shouldVibrateForPowerModeLocked(vib)) {
+ endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_POWER);
return false;
}
if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
+ endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_SETTINGS);
return false;
}
@@ -1096,6 +1277,7 @@
if (DEBUG) {
Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
}
+ endVibrationLocked(vib, VibrationInfo.Status.IGNORED_RINGTONE);
return false;
}
@@ -1105,6 +1287,9 @@
// We might be getting calls from within system_server, so we don't actually
// want to throw a SecurityException here.
Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid);
+ endVibrationLocked(vib, VibrationInfo.Status.ERROR_APP_OPS);
+ } else {
+ endVibrationLocked(vib, VibrationInfo.Status.IGNORED_APP_OPS);
}
return false;
}
@@ -1113,10 +1298,11 @@
}
@GuardedBy("mLock")
- private void reportFinishVibrationLocked() {
+ private void reportFinishVibrationLocked(VibrationInfo.Status status) {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked");
try {
if (mCurrentVibration != null) {
+ endVibrationLocked(mCurrentVibration, status);
mAppOps.finishOp(AppOpsManager.OP_VIBRATE, mCurrentVibration.uid,
mCurrentVibration.opPkg);
unlinkVibration(mCurrentVibration);
@@ -1153,7 +1339,7 @@
if (devicesUpdated || lowPowerModeUpdated) {
// If the state changes out from under us then just reset.
- doCancelVibrateLocked();
+ doCancelVibrateLocked(VibrationInfo.Status.CANCELLED);
}
updateAlwaysOnLocked();
@@ -1224,7 +1410,7 @@
}
private void updateAlwaysOnLocked(int id, Vibration vib) {
- final int intensity = getCurrentIntensityLocked(vib);
+ final int intensity = getCurrentIntensityLocked(vib.attrs.getUsage());
if (!shouldVibrate(vib, intensity)) {
mNativeWrapper.vibratorAlwaysOnDisable(id);
} else {
@@ -1345,6 +1531,10 @@
return;
}
}
+ endVibrationLocked(vib, VibrationInfo.Status.IGNORED_UNSUPPORTED);
+ // The set current vibration is not actually playing, so drop it.
+ mCurrentVibration = null;
+
if (!prebaked.shouldFallback()) {
return;
}
@@ -1355,11 +1545,12 @@
}
Vibration fallbackVib = new Vibration(vib.token, effect, vib.attrs, vib.uid,
vib.opPkg, vib.reason + " (fallback)");
- final int intensity = getCurrentIntensityLocked(fallbackVib);
+ // Set current vibration before starting it, so callback will work.
+ mCurrentVibration = fallbackVib;
+ final int intensity = getCurrentIntensityLocked(fallbackVib.attrs.getUsage());
linkVibration(fallbackVib);
applyVibrationIntensityScalingLocked(fallbackVib, intensity);
startVibrationInnerLocked(fallbackVib);
- return;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
@@ -1376,11 +1567,10 @@
usingInputDeviceVibrators = !mInputDeviceVibrators.isEmpty();
}
// Input devices don't support composed effect, so skip trying it with them.
- if (usingInputDeviceVibrators) {
- return;
- }
-
- if (!hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
+ if (usingInputDeviceVibrators || !hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
+ endVibrationLocked(vib, VibrationInfo.Status.IGNORED_UNSUPPORTED);
+ // The set current vibration is not actually playing, so drop it.
+ mCurrentVibration = null;
return;
}
@@ -1489,15 +1679,25 @@
} else {
pw.println("null");
}
- pw.print(" mCurrentExternalVibration=" + mCurrentExternalVibration);
+ pw.print(" mCurrentExternalVibration=");
+ if (mCurrentExternalVibration != null) {
+ pw.println(mCurrentExternalVibration.toInfo().toString());
+ } else {
+ pw.println("null");
+ }
pw.println(" mVibratorUnderExternalControl=" + mVibratorUnderExternalControl);
pw.println(" mIsVibrating=" + mIsVibrating);
- pw.println(" mVibratorStateListeners Count=" +
- mVibratorStateListeners.getRegisteredCallbackCount());
+ pw.println(" mVibratorStateListeners Count="
+ + mVibratorStateListeners.getRegisteredCallbackCount());
pw.println(" mLowPowerMode=" + mLowPowerMode);
pw.println(" mHapticFeedbackIntensity=" + mHapticFeedbackIntensity);
+ pw.println(" mHapticFeedbackDefaultIntensity="
+ + mVibrator.getDefaultHapticFeedbackIntensity());
pw.println(" mNotificationIntensity=" + mNotificationIntensity);
+ pw.println(" mNotificationDefaultIntensity="
+ + mVibrator.getDefaultNotificationVibrationIntensity());
pw.println(" mRingIntensity=" + mRingIntensity);
+ pw.println(" mRingDefaultIntensity=" + mVibrator.getDefaultRingVibrationIntensity());
pw.println(" mSupportedEffects=" + mSupportedEffects);
pw.println(" mSupportedPrimitives=" + mSupportedPrimitives);
pw.println();
@@ -1523,8 +1723,8 @@
}
pw.println(" Previous external vibrations:");
- for (ExternalVibration vib : mPreviousExternalVibrations) {
- pw.println(" " + vib);
+ for (VibrationInfo info : mPreviousExternalVibrations) {
+ pw.println(" " + info);
}
}
}
@@ -1535,36 +1735,45 @@
synchronized (mLock) {
if (mCurrentVibration != null) {
mCurrentVibration.toInfo().dumpProto(proto,
- VibratorServiceDumpProto.CURRENT_VIBRATION);
+ VibratorServiceDumpProto.CURRENT_VIBRATION);
+ }
+ if (mCurrentExternalVibration != null) {
+ mCurrentExternalVibration.toInfo().dumpProto(proto,
+ VibratorServiceDumpProto.CURRENT_EXTERNAL_VIBRATION);
}
proto.write(VibratorServiceDumpProto.IS_VIBRATING, mIsVibrating);
proto.write(VibratorServiceDumpProto.VIBRATOR_UNDER_EXTERNAL_CONTROL,
- mVibratorUnderExternalControl);
+ mVibratorUnderExternalControl);
proto.write(VibratorServiceDumpProto.LOW_POWER_MODE, mLowPowerMode);
proto.write(VibratorServiceDumpProto.HAPTIC_FEEDBACK_INTENSITY,
- mHapticFeedbackIntensity);
- proto.write(VibratorServiceDumpProto.NOTIFICATION_INTENSITY,
- mNotificationIntensity);
+ mHapticFeedbackIntensity);
+ proto.write(VibratorServiceDumpProto.HAPTIC_FEEDBACK_DEFAULT_INTENSITY,
+ mVibrator.getDefaultHapticFeedbackIntensity());
+ proto.write(VibratorServiceDumpProto.NOTIFICATION_INTENSITY, mNotificationIntensity);
+ proto.write(VibratorServiceDumpProto.NOTIFICATION_DEFAULT_INTENSITY,
+ mVibrator.getDefaultNotificationVibrationIntensity());
proto.write(VibratorServiceDumpProto.RING_INTENSITY, mRingIntensity);
+ proto.write(VibratorServiceDumpProto.RING_DEFAULT_INTENSITY,
+ mVibrator.getDefaultRingVibrationIntensity());
for (VibrationInfo info : mPreviousRingVibrations) {
- info.dumpProto(proto,
- VibratorServiceDumpProto.PREVIOUS_RING_VIBRATIONS);
+ info.dumpProto(proto, VibratorServiceDumpProto.PREVIOUS_RING_VIBRATIONS);
}
for (VibrationInfo info : mPreviousNotificationVibrations) {
- info.dumpProto(proto,
- VibratorServiceDumpProto.PREVIOUS_NOTIFICATION_VIBRATIONS);
+ info.dumpProto(proto, VibratorServiceDumpProto.PREVIOUS_NOTIFICATION_VIBRATIONS);
}
for (VibrationInfo info : mPreviousAlarmVibrations) {
- info.dumpProto(proto,
- VibratorServiceDumpProto.PREVIOUS_ALARM_VIBRATIONS);
+ info.dumpProto(proto, VibratorServiceDumpProto.PREVIOUS_ALARM_VIBRATIONS);
}
for (VibrationInfo info : mPreviousVibrations) {
- info.dumpProto(proto,
- VibratorServiceDumpProto.PREVIOUS_VIBRATIONS);
+ info.dumpProto(proto, VibratorServiceDumpProto.PREVIOUS_VIBRATIONS);
+ }
+
+ for (VibrationInfo info : mPreviousExternalVibrations) {
+ info.dumpProto(proto, VibratorServiceDumpProto.PREVIOUS_EXTERNAL_VIBRATIONS);
}
}
proto.flush();
@@ -1579,8 +1788,8 @@
VibrateWaveformThread(Vibration vib) {
mWaveform = (VibrationEffect.Waveform) vib.effect;
- mVibration = new Vibration(vib.token, /* effect= */ null, vib.attrs, vib.uid, vib.opPkg,
- vib.reason);
+ mVibration = new Vibration(vib.token, /* effect= */ null, vib.attrs, vib.uid,
+ vib.opPkg, vib.reason);
mTmpWorkSource.set(vib.uid);
mWakeLock.setWorkSource(mTmpWorkSource);
}
@@ -1655,8 +1864,8 @@
// appropriate intervals.
onDuration = getTotalOnDuration(timings, amplitudes, index - 1,
repeat);
- mVibration.effect =
- VibrationEffect.createOneShot(onDuration, amplitude);
+ mVibration.effect = VibrationEffect.createOneShot(
+ onDuration, amplitude);
doVibratorOn(mVibration);
} else {
doVibratorSetAmplitude(amplitude);
@@ -1827,7 +2036,7 @@
if (mCurrentVibration != null
&& !(mCurrentVibration.isHapticFeedback()
&& mCurrentVibration.isFromSystem())) {
- doCancelVibrateLocked();
+ doCancelVibrateLocked(VibrationInfo.Status.CANCELLED);
}
}
}
@@ -1882,63 +2091,54 @@
int mode = getAppOpMode(vib.getUid(), vib.getPackage(), vib.getVibrationAttributes());
if (mode != AppOpsManager.MODE_ALLOWED) {
+ ExternalVibrationHolder vibHolder = new ExternalVibrationHolder(vib);
+ vibHolder.scale = SCALE_MUTE;
if (mode == AppOpsManager.MODE_ERRORED) {
Slog.w(TAG, "Would be an error: external vibrate from uid " + vib.getUid());
+ endVibrationLocked(vibHolder, VibrationInfo.Status.ERROR_APP_OPS);
+ } else {
+ endVibrationLocked(vibHolder, VibrationInfo.Status.IGNORED_APP_OPS);
}
return SCALE_MUTE;
}
final int scaleLevel;
synchronized (mLock) {
- if (!vib.equals(mCurrentExternalVibration)) {
- if (mCurrentExternalVibration == null) {
- // If we're not under external control right now, then cancel any normal
- // vibration that may be playing and ready the vibrator for external
- // control.
- doCancelVibrateLocked();
- setVibratorUnderExternalControl(true);
- }
- // At this point we either have an externally controlled vibration playing, or
- // no vibration playing. Since the interface defines that only one externally
- // controlled vibration can play at a time, by returning something other than
- // SCALE_MUTE from this function we can be assured that if we are currently
- // playing vibration, it will be muted in favor of the new vibration.
- //
- // Note that this doesn't support multiple concurrent external controls, as we
- // would need to mute the old one still if it came from a different controller.
- mCurrentExternalVibration = vib;
- mCurrentExternalDeathRecipient = new ExternalVibrationDeathRecipient();
- mCurrentExternalVibration.linkToDeath(mCurrentExternalDeathRecipient);
- if (mPreviousExternalVibrations.size() > mPreviousVibrationsLimit) {
- mPreviousExternalVibrations.removeFirst();
- }
- mPreviousExternalVibrations.addLast(vib);
- if (DEBUG) {
- Slog.e(TAG, "Playing external vibration: " + vib);
- }
+ if (mCurrentExternalVibration != null
+ && mCurrentExternalVibration.externalVibration.equals(vib)) {
+ // We are already playing this external vibration, so we can return the same
+ // scale calculated in the previous call to this method.
+ return mCurrentExternalVibration.scale;
}
- final int usage = vib.getVibrationAttributes().getUsage();
- final int defaultIntensity;
- final int currentIntensity;
- if (isRingtone(usage)) {
- defaultIntensity = mVibrator.getDefaultRingVibrationIntensity();
- currentIntensity = mRingIntensity;
- } else if (isNotification(usage)) {
- defaultIntensity = mVibrator.getDefaultNotificationVibrationIntensity();
- currentIntensity = mNotificationIntensity;
- } else if (isHapticFeedback(usage)) {
- defaultIntensity = mVibrator.getDefaultHapticFeedbackIntensity();
- currentIntensity = mHapticFeedbackIntensity;
- } else if (isAlarm(usage)) {
- defaultIntensity = Vibrator.VIBRATION_INTENSITY_HIGH;
- currentIntensity = Vibrator.VIBRATION_INTENSITY_HIGH;
+ if (mCurrentExternalVibration == null) {
+ // If we're not under external control right now, then cancel any normal
+ // vibration that may be playing and ready the vibrator for external control.
+ doCancelVibrateLocked(VibrationInfo.Status.CANCELLED);
+ setVibratorUnderExternalControl(true);
} else {
- defaultIntensity = 0;
- currentIntensity = 0;
+ endVibrationLocked(mCurrentExternalVibration, VibrationInfo.Status.CANCELLED);
}
+ // At this point we either have an externally controlled vibration playing, or
+ // no vibration playing. Since the interface defines that only one externally
+ // controlled vibration can play at a time, by returning something other than
+ // SCALE_MUTE from this function we can be assured that if we are currently
+ // playing vibration, it will be muted in favor of the new vibration.
+ //
+ // Note that this doesn't support multiple concurrent external controls, as we
+ // would need to mute the old one still if it came from a different controller.
+ mCurrentExternalVibration = new ExternalVibrationHolder(vib);
+ mCurrentExternalDeathRecipient = new ExternalVibrationDeathRecipient();
+ vib.linkToDeath(mCurrentExternalDeathRecipient);
+ if (DEBUG) {
+ Slog.e(TAG, "Playing external vibration: " + vib);
+ }
+ int usage = vib.getVibrationAttributes().getUsage();
+ int defaultIntensity = getDefaultIntensity(usage);
+ int currentIntensity = getCurrentIntensityLocked(usage);
scaleLevel = currentIntensity - defaultIntensity;
}
if (scaleLevel >= SCALE_VERY_LOW && scaleLevel <= SCALE_VERY_HIGH) {
+ mCurrentExternalVibration.scale = scaleLevel;
return scaleLevel;
} else {
// Presumably we want to play this but something about our scaling has gone
@@ -1952,22 +2152,42 @@
@Override
public void onExternalVibrationStop(ExternalVibration vib) {
synchronized (mLock) {
- if (vib.equals(mCurrentExternalVibration)) {
- mCurrentExternalVibration.unlinkToDeath(mCurrentExternalDeathRecipient);
- mCurrentExternalDeathRecipient = null;
- mCurrentExternalVibration = null;
- setVibratorUnderExternalControl(false);
+ if (mCurrentExternalVibration != null
+ && mCurrentExternalVibration.externalVibration.equals(vib)) {
if (DEBUG) {
Slog.e(TAG, "Stopping external vibration" + vib);
}
+ doCancelExternalVibrateLocked(VibrationInfo.Status.FINISHED);
}
}
}
+ private void doCancelExternalVibrateLocked(VibrationInfo.Status status) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doCancelExternalVibrateLocked");
+ try {
+ if (mCurrentExternalVibration == null) {
+ return;
+ }
+ endVibrationLocked(mCurrentExternalVibration, status);
+ mCurrentExternalVibration.externalVibration.unlinkToDeath(
+ mCurrentExternalDeathRecipient);
+ mCurrentExternalDeathRecipient = null;
+ mCurrentExternalVibration = null;
+ setVibratorUnderExternalControl(false);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
+ }
+
private class ExternalVibrationDeathRecipient implements IBinder.DeathRecipient {
public void binderDied() {
synchronized (mLock) {
- onExternalVibrationStop(mCurrentExternalVibration);
+ if (mCurrentExternalVibration != null) {
+ if (DEBUG) {
+ Slog.d(TAG, "External vibration finished because binder died");
+ }
+ doCancelExternalVibrateLocked(VibrationInfo.Status.CANCELLED);
+ }
}
}
}
@@ -2229,5 +2449,4 @@
}
}
}
-
}
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 990a547..49444834 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -23,7 +23,9 @@
import android.content.IntentFilter;
import android.hidl.manager.V1_0.IServiceManager;
import android.os.Binder;
+import android.os.Build;
import android.os.Debug;
+import android.os.FileUtils;
import android.os.Handler;
import android.os.IPowerManager;
import android.os.Looper;
@@ -31,10 +33,12 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+import android.sysprop.WatchdogProperties;
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.ZygoteConnectionConstants;
@@ -42,12 +46,16 @@
import com.android.server.am.ActivityManagerService;
import com.android.server.wm.SurfaceAnimationThread;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
import java.util.HashSet;
import java.util.List;
@@ -75,6 +83,12 @@
private static final int WAITED_HALF = 2;
private static final int OVERDUE = 3;
+ // Track watchdog timeout history and break the crash loop if there is.
+ private static final String TIMEOUT_HISTORY_FILE = "/data/system/watchdog-timeout-history.txt";
+ private static final String PROP_FATAL_LOOP_COUNT = "framework_watchdog.fatal_count";
+ private static final String PROP_FATAL_LOOP_WINDOWS_SECS =
+ "framework_watchdog.fatal_window.second";
+
// Which native processes to dump into dropbox's stack traces
public static final String[] NATIVE_STACKS_OF_INTEREST = new String[] {
"/system/bin/audioserver",
@@ -699,6 +713,10 @@
Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + subject);
WatchdogDiagnostics.diagnoseCheckers(blockedCheckers);
Slog.w(TAG, "*** GOODBYE!");
+ if (!Build.IS_USER && isCrashLoopFound()
+ && !WatchdogProperties.is_fatal_ignore().orElse(false)) {
+ breakCrashLoop();
+ }
Process.killProcess(Process.myPid());
System.exit(10);
}
@@ -716,4 +734,107 @@
Slog.w(TAG, "Failed to write to /proc/sysrq-trigger", e);
}
}
+
+ private void resetTimeoutHistory() {
+ writeTimeoutHistory(new ArrayList<String>());
+ }
+
+ private void writeTimeoutHistory(Iterable<String> crashHistory) {
+ String data = String.join(",", crashHistory);
+
+ try (FileWriter writer = new FileWriter(TIMEOUT_HISTORY_FILE)) {
+ writer.write(SystemProperties.get("ro.boottime.zygote"));
+ writer.write(":");
+ writer.write(data);
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to write file " + TIMEOUT_HISTORY_FILE, e);
+ }
+ }
+
+ private String[] readTimeoutHistory() {
+ final String[] emptyStringArray = {};
+
+ try (BufferedReader reader = new BufferedReader(new FileReader(TIMEOUT_HISTORY_FILE))) {
+ String line = reader.readLine();
+ if (line == null) {
+ return emptyStringArray;
+ }
+
+ String[] data = line.trim().split(":");
+ String boottime = data.length >= 1 ? data[0] : "";
+ String history = data.length >= 2 ? data[1] : "";
+ if (SystemProperties.get("ro.boottime.zygote").equals(boottime) && !history.isEmpty()) {
+ return history.split(",");
+ } else {
+ return emptyStringArray;
+ }
+ } catch (FileNotFoundException e) {
+ return emptyStringArray;
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to read file " + TIMEOUT_HISTORY_FILE, e);
+ return emptyStringArray;
+ }
+ }
+
+ private boolean hasActiveUsbConnection() {
+ try {
+ final String state = FileUtils.readTextFile(
+ new File("/sys/class/android_usb/android0/state"),
+ 128 /*max*/, null /*ellipsis*/).trim();
+ if ("CONFIGURED".equals(state)) {
+ return true;
+ }
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to determine if device was on USB", e);
+ }
+ return false;
+ }
+
+ private boolean isCrashLoopFound() {
+ int fatalCount = WatchdogProperties.fatal_count().orElse(0);
+ long fatalWindowMs = TimeUnit.SECONDS.toMillis(
+ WatchdogProperties.fatal_window_second().orElse(0));
+ if (fatalCount == 0 || fatalWindowMs == 0) {
+ if (fatalCount != fatalWindowMs) {
+ Slog.w(TAG, String.format("sysprops '%s' and '%s' should be set or unset together",
+ PROP_FATAL_LOOP_COUNT, PROP_FATAL_LOOP_WINDOWS_SECS));
+ }
+ return false;
+ }
+
+ // new-history = [last (fatalCount - 1) items in old-history] + [nowMs].
+ long nowMs = SystemClock.elapsedRealtime(); // Time since boot including deep sleep.
+ String[] rawCrashHistory = readTimeoutHistory();
+ ArrayList<String> crashHistory = new ArrayList<String>(Arrays.asList(Arrays.copyOfRange(
+ rawCrashHistory,
+ Math.max(0, rawCrashHistory.length - fatalCount - 1),
+ rawCrashHistory.length)));
+ // Something wrong here.
+ crashHistory.add(String.valueOf(nowMs));
+ writeTimeoutHistory(crashHistory);
+
+ // Returns false if the device has an active USB connection.
+ if (hasActiveUsbConnection()) {
+ return false;
+ }
+
+ long firstCrashMs;
+ try {
+ firstCrashMs = Long.parseLong(crashHistory.get(0));
+ } catch (NumberFormatException t) {
+ Slog.w(TAG, "Failed to parseLong " + crashHistory.get(0), t);
+ resetTimeoutHistory();
+ return false;
+ }
+ return crashHistory.size() >= fatalCount && nowMs - firstCrashMs < fatalWindowMs;
+ }
+
+ private void breakCrashLoop() {
+ try (FileWriter kmsg = new FileWriter("/dev/kmsg_debug", /* append= */ true)) {
+ kmsg.append("Fatal reset to escape the system_server crashing loop\n");
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to append to kmsg", e);
+ }
+ doSysRq('c');
+ }
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index b2e021f..31712be 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -56,6 +56,8 @@
import android.app.ServiceStartArgs;
import android.app.admin.DevicePolicyEventLogger;
import android.appwidget.AppWidgetManagerInternal;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.Disabled;
import android.content.ComponentName;
import android.content.ComponentName.WithComponentName;
import android.content.Context;
@@ -79,6 +81,7 @@
import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.TransactionTooLargeException;
@@ -100,6 +103,7 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.procstats.ServiceState;
+import com.android.internal.compat.IPlatformCompat;
import com.android.internal.messages.nano.SystemMessageProto;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BatteryStatsImpl;
@@ -234,6 +238,16 @@
private static final SimpleDateFormat DATE_FORMATTER =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ private final IPlatformCompat mPlatformCompat;
+
+ /**
+ * The BG-launch FGS restriction feature is going to be allowed only for apps targetSdkVersion
+ * is higher than R.
+ */
+ @ChangeId
+ @Disabled
+ static final long FGS_BG_START_RESTRICTION_CHANGE_ID = 170668199L;
+
final Runnable mLastAnrDumpClearer = new Runnable() {
@Override public void run() {
synchronized (mAm) {
@@ -430,6 +444,9 @@
}
mMaxStartingBackground = maxBg > 0
? maxBg : ActivityManager.isLowRamDeviceStatic() ? 1 : 8;
+
+ final IBinder b = ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
+ mPlatformCompat = IPlatformCompat.Stub.asInterface(b);
}
void systemServicesReady() {
@@ -557,12 +574,20 @@
r.mLoggedInfoAllowStartForeground = true;
}
if (r.mAllowStartForeground == FGS_FEATURE_DENIED
- && mAm.mConstants.mFlagFgsStartRestrictionEnabled) {
- Slog.w(TAG, "startForegroundService() not allowed due to "
- + "mAllowStartForeground false: service "
- + r.shortInstanceName);
- showFgsBgRestrictedNotificationLocked(r);
- forcedStandby = true;
+ && (mAm.mConstants.mFlagFgsStartRestrictionEnabled
+ || isChangeEnabled(FGS_BG_START_RESTRICTION_CHANGE_ID, r))) {
+ if (mAm.mConstants.mFlagFgsStartTempAllowListEnabled
+ && mAm.isOnDeviceIdleWhitelistLocked(r.appInfo.uid, false)) {
+ // uid is on DeviceIdleController's allowlist.
+ Slog.d(TAG, "startForegroundService() mAllowStartForeground false "
+ + "but allowlist true: service " + r.shortInstanceName);
+ } else {
+ Slog.w(TAG, "startForegroundService() not allowed due to "
+ + "mAllowStartForeground false: service "
+ + r.shortInstanceName);
+ showFgsBgRestrictedNotificationLocked(r);
+ return null;
+ }
}
}
}
@@ -1461,14 +1486,22 @@
r.mLoggedInfoAllowStartForeground = true;
}
if (r.mAllowStartForeground == FGS_FEATURE_DENIED
- && mAm.mConstants.mFlagFgsStartRestrictionEnabled) {
- Slog.w(TAG,
- "Service.startForeground() not allowed due to "
- + "mAllowStartForeground false: service "
- + r.shortInstanceName);
- showFgsBgRestrictedNotificationLocked(r);
- updateServiceForegroundLocked(r.app, true);
- ignoreForeground = true;
+ && (mAm.mConstants.mFlagFgsStartRestrictionEnabled
+ || isChangeEnabled(FGS_BG_START_RESTRICTION_CHANGE_ID, r))) {
+ if (mAm.mConstants.mFlagFgsStartTempAllowListEnabled
+ && mAm.isOnDeviceIdleWhitelistLocked(r.appInfo.uid, false)) {
+ // uid is on DeviceIdleController's allowlist.
+ Slog.d(TAG, "Service.startForeground() "
+ + "mAllowStartForeground false but allowlist true: service "
+ + r.shortInstanceName);
+ } else {
+ Slog.w(TAG, "Service.startForeground() not allowed due to "
+ + "mAllowStartForeground false: service "
+ + r.shortInstanceName);
+ showFgsBgRestrictedNotificationLocked(r);
+ updateServiceForegroundLocked(r.app, true);
+ ignoreForeground = true;
+ }
}
}
}
@@ -5087,4 +5120,12 @@
context.getSystemService(NotificationManager.class).notifyAsUser(Long.toString(now),
NOTE_FOREGROUND_SERVICE_BG_LAUNCH, n.build(), UserHandle.ALL);
}
+
+ private boolean isChangeEnabled(long changeId, ServiceRecord r) {
+ boolean enabled = false;
+ try {
+ enabled = mPlatformCompat.isChangeEnabled(changeId, r.appInfo);
+ } catch (RemoteException e) { }
+ return enabled;
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 48055b5..b54a917e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -161,6 +161,13 @@
private static final String KEY_DEFAULT_FGS_STARTS_RESTRICTION_ENABLED =
"default_fgs_starts_restriction_enabled";
+ /**
+ * Default value for mFlagFgsStartTempAllowListEnabled if not explicitly set in
+ * Settings.Global.
+ */
+ private static final String KEY_DEFAULT_FGS_STARTS_TEMP_ALLOWLIST_ENABLED =
+ "default_fgs_starts_temp_allowlist_enabled";
+
// Maximum number of cached processes we will allow.
public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
@@ -321,6 +328,10 @@
// at all.
volatile boolean mFlagFgsStartRestrictionEnabled = false;
+ // When the foreground service background start restriction is enabled, if the app in
+ // DeviceIdleController's Temp AllowList is allowed to bypass the restriction.
+ volatile boolean mFlagFgsStartTempAllowListEnabled = false;
+
private final ActivityManagerService mService;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -472,6 +483,9 @@
case KEY_DEFAULT_FGS_STARTS_RESTRICTION_ENABLED:
updateFgsStartsRestriction();
break;
+ case KEY_DEFAULT_FGS_STARTS_TEMP_ALLOWLIST_ENABLED:
+ updateFgsStartsTempAllowList();
+ break;
case KEY_OOMADJ_UPDATE_POLICY:
updateOomAdjUpdatePolicy();
break;
@@ -724,6 +738,13 @@
/*defaultValue*/ false);
}
+ private void updateFgsStartsTempAllowList() {
+ mFlagFgsStartTempAllowListEnabled = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_DEFAULT_FGS_STARTS_TEMP_ALLOWLIST_ENABLED,
+ /*defaultValue*/ false);
+ }
+
private void updateOomAdjUpdatePolicy() {
OOMADJ_UPDATE_QUICK = DeviceConfig.getInt(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index 0d077c6..68cfc23 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -26,6 +26,7 @@
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityThread;
import android.attention.AttentionManagerInternal;
import android.attention.AttentionManagerInternal.AttentionCallbackInternal;
import android.content.BroadcastReceiver;
@@ -68,6 +69,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Objects;
+import java.util.Set;
/**
* An attention service implementation that runs in System Server process.
@@ -81,21 +83,15 @@
/** Service will unbind if connection is not used for that amount of time. */
private static final long CONNECTION_TTL_MILLIS = 60_000;
- /**
- * We cache the DeviceConfig values to avoid frequent ashmem-related checks; if the cached
- * values are stale for more than this duration we will update the cache.
- */
- @VisibleForTesting static final long DEVICE_CONFIG_MAX_STALENESS_MILLIS = 4 * 60 * 60 * 1000L;
-
- @VisibleForTesting long mLastReadDeviceConfigMillis = Long.MIN_VALUE;
-
/** DeviceConfig flag name, if {@code true}, enables AttentionManagerService features. */
- private static final String KEY_SERVICE_ENABLED = "service_enabled";
+ @VisibleForTesting
+ static final String KEY_SERVICE_ENABLED = "service_enabled";
/** Default value in absence of {@link DeviceConfig} override. */
private static final boolean DEFAULT_SERVICE_ENABLED = true;
- private boolean mIsServiceEnabledCached;
+ @VisibleForTesting
+ boolean mIsServiceEnabled;
/**
* DeviceConfig flag name, describes how much time we consider a result fresh; if the check
@@ -108,7 +104,8 @@
@VisibleForTesting
static final long DEFAULT_STALE_AFTER_MILLIS = 1_000;
- private long mStaleAfterMillisCached;
+ @VisibleForTesting
+ long mStaleAfterMillis;
/** The size of the buffer that stores recent attention check results. */
@VisibleForTesting
@@ -156,6 +153,11 @@
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
mContext.registerReceiver(new ScreenStateReceiver(),
new IntentFilter(Intent.ACTION_SCREEN_OFF));
+
+ readValuesFromDeviceConfig();
+ DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+ ActivityThread.currentApplication().getMainExecutor(),
+ (properties) -> onDeviceConfigChange(properties.getKeyset()));
}
}
@@ -179,17 +181,9 @@
return mComponentName != null;
}
- /**
- * Returns {@code true} if attention service is supported on this device.
- */
- @VisibleForTesting
- protected boolean isAttentionServiceSupported() {
- return isServiceEnabled();
- }
-
- private boolean isServiceEnabled() {
- ensureDeviceConfigCachedValuesFreshness();
- return mIsServiceEnabledCached;
+ private boolean getIsServiceEnabled() {
+ return DeviceConfig.getBoolean(NAMESPACE_ATTENTION_MANAGER_SERVICE, KEY_SERVICE_ENABLED,
+ DEFAULT_SERVICE_ENABLED);
}
/**
@@ -198,39 +192,38 @@
*/
@VisibleForTesting
protected long getStaleAfterMillis() {
- ensureDeviceConfigCachedValuesFreshness();
- return mStaleAfterMillisCached;
- }
-
- @VisibleForTesting
- protected void ensureDeviceConfigCachedValuesFreshness() {
- final long now = SystemClock.elapsedRealtime();
- final long whenBecomesStale =
- mLastReadDeviceConfigMillis + DEVICE_CONFIG_MAX_STALENESS_MILLIS;
- if (now < whenBecomesStale) {
- if (DEBUG) {
- Slog.d(LOG_TAG,
- "Cached values are still fresh. Refreshed at=" + mLastReadDeviceConfigMillis
- + ", now=" + now);
- }
- return;
- }
-
- mIsServiceEnabledCached = DeviceConfig.getBoolean(NAMESPACE_ATTENTION_MANAGER_SERVICE,
- KEY_SERVICE_ENABLED,
- DEFAULT_SERVICE_ENABLED);
-
final long millis = DeviceConfig.getLong(NAMESPACE_ATTENTION_MANAGER_SERVICE,
KEY_STALE_AFTER_MILLIS,
DEFAULT_STALE_AFTER_MILLIS);
+
if (millis < 0 || millis > 10_000) {
Slog.w(LOG_TAG, "Bad flag value supplied for: " + KEY_STALE_AFTER_MILLIS);
- mStaleAfterMillisCached = DEFAULT_STALE_AFTER_MILLIS;
- } else {
- mStaleAfterMillisCached = millis;
+ return DEFAULT_STALE_AFTER_MILLIS;
}
- mLastReadDeviceConfigMillis = now;
+ return millis;
+ }
+
+ private void onDeviceConfigChange(@NonNull Set<String> keys) {
+ for (String key : keys) {
+ switch (key) {
+ case KEY_SERVICE_ENABLED:
+ case KEY_STALE_AFTER_MILLIS:
+ readValuesFromDeviceConfig();
+ return;
+ default:
+ Slog.i(LOG_TAG, "Ignoring change on " + key);
+ }
+ }
+ }
+
+ private void readValuesFromDeviceConfig() {
+ mIsServiceEnabled = getIsServiceEnabled();
+ mStaleAfterMillis = getStaleAfterMillis();
+
+ Slog.i(LOG_TAG, "readValuesFromDeviceConfig():"
+ + "\nmIsServiceEnabled=" + mIsServiceEnabled
+ + "\nmStaleAfterMillis=" + mStaleAfterMillis);
}
/**
@@ -246,7 +239,7 @@
boolean checkAttention(long timeout, AttentionCallbackInternal callbackInternal) {
Objects.requireNonNull(callbackInternal);
- if (!isAttentionServiceSupported()) {
+ if (!mIsServiceEnabled) {
Slog.w(LOG_TAG, "Trying to call checkAttention() on an unsupported device.");
return false;
}
@@ -272,7 +265,7 @@
// throttle frequent requests
final AttentionCheckCache cache = mAttentionCheckCacheBuffer == null ? null
: mAttentionCheckCacheBuffer.getLast();
- if (cache != null && now < cache.mLastComputed + getStaleAfterMillis()) {
+ if (cache != null && now < cache.mLastComputed + mStaleAfterMillis) {
callbackInternal.onSuccess(cache.mResult, cache.mTimestamp);
return true;
}
@@ -379,7 +372,8 @@
private void dumpInternal(IndentingPrintWriter ipw) {
ipw.println("Attention Manager Service (dumpsys attention) state:\n");
- ipw.println("isServiceEnabled=" + isServiceEnabled());
+ ipw.println("isServiceEnabled=" + mIsServiceEnabled);
+ ipw.println("mStaleAfterMillis=" + mStaleAfterMillis);
ipw.println("AttentionServicePackageName=" + getServiceConfigPackage(mContext));
ipw.println("Resolved component:");
if (mComponentName != null) {
@@ -403,7 +397,7 @@
private final class LocalService extends AttentionManagerInternal {
@Override
public boolean isAttentionServiceSupported() {
- return AttentionManagerService.this.isAttentionServiceSupported();
+ return AttentionManagerService.this.mIsServiceEnabled;
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
index cb7db92..c87f62f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
+++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
@@ -89,7 +89,8 @@
}
}
- void onError(int sensorId, int cookie, int error, int vendorCode) throws RemoteException {
+ public void onError(int sensorId, int cookie, int error, int vendorCode)
+ throws RemoteException {
if (mSensorReceiver != null) {
mSensorReceiver.onError(sensorId, cookie, error, vendorCode);
} else if (mFaceServiceReceiver != null) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/LockoutConsumer.java b/services/core/java/com/android/server/biometrics/sensors/LockoutConsumer.java
new file mode 100644
index 0000000..153bd46
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/LockoutConsumer.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020 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.biometrics.sensors;
+
+/**
+ * Interface that clients interested/eligible for lockout events should implement.
+ */
+public interface LockoutConsumer {
+ void onLockoutTimed(long durationMillis);
+ void onLockoutPermanent();
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java
index 42c7d16..3fdd279 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java
@@ -17,7 +17,6 @@
package com.android.server.biometrics.sensors.face;
import android.content.Context;
-import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.face.Face;
import android.util.AtomicFile;
import android.util.Slog;
@@ -41,7 +40,7 @@
* Class managing the set of faces per user across device reboots.
* @hide
*/
-public class FaceUserState extends BiometricUserState {
+public class FaceUserState extends BiometricUserState<Face> {
private static final String TAG = "FaceState";
private static final String FACE_FILE = "settings_face.xml";
@@ -72,19 +71,9 @@
}
@Override
- public void addBiometric(BiometricAuthenticator.Identifier identifier) {
- if (identifier instanceof Face) {
- super.addBiometric(identifier);
- } else {
- Slog.w(TAG, "Attempted to add non-face identifier");
- }
- }
-
- @Override
- protected ArrayList getCopy(ArrayList array) {
- ArrayList<Face> result = new ArrayList<>(array.size());
- for (int i = 0; i < array.size(); i++) {
- Face f = (Face) array.get(i);
+ protected ArrayList<Face> getCopy(ArrayList<Face> array) {
+ final ArrayList<Face> result = new ArrayList<>();
+ for (Face f : array) {
result.add(new Face(f.getName(), f.getBiometricId(), f.getDeviceId()));
}
return result;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceUtils.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceUtils.java
index 0197028..f47b228 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceUtils.java
@@ -30,7 +30,7 @@
/**
* Utility class for dealing with faces and face settings.
*/
-public class FaceUtils implements BiometricUtils {
+public class FaceUtils implements BiometricUtils<Face> {
private static final Object sInstanceLock = new Object();
private static FaceUtils sInstance;
@@ -56,9 +56,8 @@
}
@Override
- public void addBiometricForUser(Context ctx, int userId,
- BiometricAuthenticator.Identifier identifier) {
- getStateForUser(ctx, userId).addBiometric(identifier);
+ public void addBiometricForUser(Context ctx, int userId, Face face) {
+ getStateForUser(ctx, userId).addBiometric(face);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 105fcec..dc22970 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -33,10 +33,9 @@
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.fingerprint.IFingerprint;
import android.hardware.biometrics.fingerprint.SensorProps;
-import android.hardware.biometrics.ITestService;
-import android.hardware.biometrics.SensorPropertiesInternal;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintClientActiveCallback;
@@ -53,6 +52,8 @@
import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.EventLog;
import android.util.Pair;
import android.util.Slog;
@@ -91,54 +92,52 @@
private final GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
private final LockPatternUtils mLockPatternUtils;
@NonNull private List<ServiceProvider> mServiceProviders;
- @Nullable private TestService mTestService;
+ @NonNull private final ArrayMap<Integer, TestSession> mTestSessions;
- private final class TestService extends ITestService.Stub {
+ private final class TestSession extends ITestSession.Stub {
+ private final int mSensorId;
- @Override
- public List<SensorPropertiesInternal> getSensorPropertiesInternal(
- String opPackageName) {
- Utils.checkPermission(getContext(), TEST_BIOMETRIC);
- return null;
+ TestSession(int sensorId) {
+ mSensorId = sensorId;
}
@Override
- public void enableTestHal(int sensorId, boolean enableTestHal) {
+ public void enableTestHal(boolean enableTestHal) {
Utils.checkPermission(getContext(), TEST_BIOMETRIC);
}
@Override
- public void enrollStart(int sensorId, int userId) {
+ public void startEnroll(int userId) {
Utils.checkPermission(getContext(), TEST_BIOMETRIC);
}
@Override
- public void enrollFinish(int sensorId, int userId) {
+ public void finishEnroll(int userId) {
Utils.checkPermission(getContext(), TEST_BIOMETRIC);
}
@Override
- public void authenticateSuccess(int sensorId, int userId) {
+ public void acceptAuthentication(int userId) {
Utils.checkPermission(getContext(), TEST_BIOMETRIC);
}
@Override
- public void authenticateReject(int sensorId, int userId) {
+ public void rejectAuthentication(int userId) {
Utils.checkPermission(getContext(), TEST_BIOMETRIC);
}
@Override
- public void notifyAcquired(int sensorId, int userId) {
+ public void notifyAcquired(int userId) {
Utils.checkPermission(getContext(), TEST_BIOMETRIC);
}
@Override
- public void notifyError(int sensorId, int userId) {
+ public void notifyError(int userId) {
Utils.checkPermission(getContext(), TEST_BIOMETRIC);
}
@Override
- public void internalCleanup(int sensorId, int userId) {
+ public void cleanupInternalState(int userId) {
Utils.checkPermission(getContext(), TEST_BIOMETRIC);
}
}
@@ -148,15 +147,17 @@
*/
private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
@Override
- public ITestService getTestService(String opPackageName) {
+ public ITestSession createTestSession(int sensorId, String opPackageName) {
Utils.checkPermission(getContext(), TEST_BIOMETRIC);
- synchronized (this) {
- if (mTestService == null) {
- mTestService = new TestService();
+ final TestSession session;
+ synchronized (mTestSessions) {
+ if (!mTestSessions.containsKey(sensorId)) {
+ mTestSessions.put(sensorId, new TestSession(sensorId));
}
+ session = mTestSessions.get(sensorId);
}
- return mTestService;
+ return session;
}
@Override // Binder call
@@ -187,7 +188,7 @@
}
@Override // Binder call
- public void revokeChallenge(IBinder token, String opPackageName) {
+ public void revokeChallenge(IBinder token, String opPackageName, long challenge) {
Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
@@ -196,7 +197,8 @@
return;
}
- provider.second.scheduleRevokeChallenge(provider.first, token, opPackageName);
+ provider.second.scheduleRevokeChallenge(provider.first, token, opPackageName,
+ challenge);
}
@Override // Binder call
@@ -619,6 +621,7 @@
mLockoutResetDispatcher = new LockoutResetDispatcher(context);
mLockPatternUtils = new LockPatternUtils(context);
mServiceProviders = new ArrayList<>();
+ mTestSessions = new ArrayMap<>();
initializeAidlHals();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUserState.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUserState.java
index 56312bc..f32d28c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUserState.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUserState.java
@@ -17,7 +17,6 @@
package com.android.server.biometrics.sensors.fingerprint;
import android.content.Context;
-import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.fingerprint.Fingerprint;
import android.util.AtomicFile;
import android.util.Slog;
@@ -40,7 +39,7 @@
* Class managing the set of fingerprint per user across device reboots.
* @hide
*/
-public class FingerprintUserState extends BiometricUserState {
+public class FingerprintUserState extends BiometricUserState<Fingerprint> {
private static final String TAG = "FingerprintState";
private static final String FINGERPRINT_FILE = "settings_fingerprint.xml";
@@ -72,19 +71,9 @@
}
@Override
- public void addBiometric(BiometricAuthenticator.Identifier identifier) {
- if (identifier instanceof Fingerprint) {
- super.addBiometric(identifier);
- } else {
- Slog.w(TAG, "Attempted to add non-fingerprint identifier");
- }
- }
-
- @Override
- protected ArrayList getCopy(ArrayList array) {
- ArrayList<Fingerprint> result = new ArrayList<>();
- for (int i = 0; i < array.size(); i++) {
- Fingerprint fp = (Fingerprint) array.get(i);
+ protected ArrayList<Fingerprint> getCopy(ArrayList<Fingerprint> array) {
+ final ArrayList<Fingerprint> result = new ArrayList<>();
+ for (Fingerprint fp : array) {
result.add(new Fingerprint(fp.getName(), fp.getGroupId(), fp.getBiometricId(),
fp.getDeviceId()));
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUtils.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUtils.java
index f0bfe12..3bf3a5b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUtils.java
@@ -30,7 +30,7 @@
/**
* Utility class for dealing with fingerprints and fingerprint settings.
*/
-public class FingerprintUtils implements BiometricUtils {
+public class FingerprintUtils implements BiometricUtils<Fingerprint> {
private static final Object sInstanceLock = new Object();
private static FingerprintUtils sInstance;
@@ -56,9 +56,8 @@
}
@Override
- public void addBiometricForUser(Context context, int userId,
- BiometricAuthenticator.Identifier identifier) {
- getStateForUser(context, userId).addBiometric(identifier);
+ public void addBiometricForUser(Context context, int userId, Fingerprint fingerprint) {
+ getStateForUser(context, userId).addBiometric(fingerprint);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index 1162c9c..35d0188 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -68,7 +68,7 @@
@NonNull IFingerprintServiceReceiver receiver, String opPackageName);
void scheduleRevokeChallenge(int sensorId, @NonNull IBinder token,
- @NonNull String opPackageName);
+ @NonNull String opPackageName, long challenge);
void scheduleEnroll(int sensorId, @NonNull IBinder token, byte[] hardwareAuthToken, int userId,
@NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
new file mode 100644
index 0000000..e923943
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2020 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.biometrics.sensors.fingerprint.aidl;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.TaskStackListener;
+import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricFingerprintConstants;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.common.ICancellationSignal;
+import android.hardware.biometrics.fingerprint.ISession;
+import android.hardware.fingerprint.IUdfpsOverlayController;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.AuthenticationClient;
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.LockoutConsumer;
+import com.android.server.biometrics.sensors.LockoutTracker;
+import com.android.server.biometrics.sensors.fingerprint.Udfps;
+import com.android.server.biometrics.sensors.fingerprint.UdfpsHelper;
+
+import java.util.ArrayList;
+
+/**
+ * Fingerprint-specific authentication client supporting the
+ * {@link android.hardware.biometrics.fingerprint.IFingerprint} AIDL interface.
+ */
+public class FingerprintAuthenticationClient extends AuthenticationClient<ISession> implements
+ Udfps, LockoutConsumer {
+ private static final String TAG = "FingerprintAuthenticationClient";
+
+ @NonNull private final LockoutCache mLockoutCache;
+ @Nullable private final IUdfpsOverlayController mUdfpsOverlayController;
+ @Nullable private ICancellationSignal mCancellationSignal;
+
+ public FingerprintAuthenticationClient(@NonNull Context context,
+ @NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token,
+ @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
+ boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation,
+ int sensorId, boolean isStrongBiometric, int statsClient,
+ @Nullable TaskStackListener taskStackListener, @NonNull LockoutCache lockoutCache,
+ @Nullable IUdfpsOverlayController udfpsOverlayController) {
+ super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted, owner,
+ cookie, requireConfirmation, sensorId, isStrongBiometric,
+ BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener,
+ lockoutCache);
+ mLockoutCache = lockoutCache;
+ mUdfpsOverlayController = udfpsOverlayController;
+ }
+
+ @Override
+ public void onAuthenticated(BiometricAuthenticator.Identifier identifier,
+ boolean authenticated, ArrayList<Byte> token) {
+ super.onAuthenticated(identifier, authenticated, token);
+
+ if (authenticated) {
+ UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
+ mCallback.onClientFinished(this, true /* success */);
+ }
+ }
+
+ @Override
+ protected void startHalOperation() {
+ UdfpsHelper.showUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
+ try {
+ mCancellationSignal = getFreshDaemon().authenticate(mSequentialId, mOperationId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */);
+ UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
+ mCallback.onClientFinished(this, false /* success */);
+ }
+ }
+
+ @Override
+ protected void stopHalOperation() {
+ UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
+ try {
+ mCancellationSignal.cancel();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */);
+ mCallback.onClientFinished(this, false /* success */);
+ }
+ }
+
+ @Override
+ public void onPointerDown(int x, int y, float minor, float major) {
+ try {
+ getFreshDaemon().onPointerDown(0 /* pointerId */, x, y, minor, major);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+
+ @Override
+ public void onPointerUp() {
+ try {
+ getFreshDaemon().onPointerUp(0 /* pointerId */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+
+ @Override
+ public void onLockoutTimed(long durationMillis) {
+ mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_TIMED);
+ // Lockout metrics are logged as an error code.
+ final int error = BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT;
+ logOnError(getContext(), error, 0 /* vendorCode */, getTargetUserId());
+
+ try {
+ getListener().onError(getSensorId(), getCookie(), error, 0 /* vendorCode */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+
+ @Override
+ public void onLockoutPermanent() {
+ mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_PERMANENT);
+ // Lockout metrics are logged as an error code.
+ final int error = BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
+ logOnError(getContext(), error, 0 /* vendorCode */, getTargetUserId());
+
+ try {
+ getListener().onError(getSensorId(), getCookie(), error, 0 /* vendorCode */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index 33f5418..c96bef1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.hardware.biometrics.BiometricFaceConstants;
import android.hardware.biometrics.BiometricFingerprintConstants;
+import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.common.ICancellationSignal;
import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.fingerprint.IUdfpsOverlayController;
@@ -48,11 +49,12 @@
public FingerprintEnrollClient(@NonNull Context context,
@NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, int userId,
- @NonNull byte[] hardwareAuthToken, @NonNull String owner, @NonNull BiometricUtils utils,
- int statsModality, int sensorId,
+ @NonNull byte[] hardwareAuthToken, @NonNull String owner,
+ @NonNull FingerprintUtils utils, int sensorId,
@Nullable IUdfpsOverlayController udfpsOvelayController, int maxTemplatesPerUser) {
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
- 0 /* timeoutSec */, statsModality, sensorId, true /* shouldVibrate */);
+ 0 /* timeoutSec */, BiometricsProtoEnums.MODALITY_FINGERPRINT, sensorId,
+ true /* shouldVibrate */);
mUdfpsOverlayController = udfpsOvelayController;
mMaxTemplatesPerUser = maxTemplatesPerUser;
}
@@ -83,7 +85,7 @@
protected void startHalOperation() {
UdfpsHelper.showUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
try {
- getFreshDaemon().enroll(mSequentialId,
+ mCancellationSignal = getFreshDaemon().enroll(mSequentialId,
HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken));
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting enroll", e);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGenerateChallengeClient.java
index 3a6b113..7db01ee 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGenerateChallengeClient.java
@@ -34,7 +34,7 @@
private static final String TAG = "FingerprintGenerateChallengeClient";
private static final int CHALLENGE_TIMEOUT_SEC = 600; // 10 minutes
- private IGenerateChallengeCallback mGenerateChallengeCallback =
+ private final IGenerateChallengeCallback mGenerateChallengeCallback =
new IGenerateChallengeCallback.Stub() {
@Override
public void onChallengeGenerated(int sensorId, int userId, long challenge) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 44a23cf..bac83b9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -19,6 +19,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.IActivityTaskManager;
+import android.app.TaskStackListener;
import android.content.Context;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.fingerprint.IFingerprint;
@@ -36,12 +39,15 @@
import android.util.SparseArray;
import android.view.Surface;
+import com.android.server.biometrics.Utils;
+import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.ClientMonitor;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import com.android.server.biometrics.sensors.fingerprint.ServiceProvider;
+import com.android.server.biometrics.sensors.fingerprint.Udfps;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -51,6 +57,7 @@
/**
* Provider for a single instance of the {@link IFingerprint} HAL.
*/
+@SuppressWarnings("deprecation")
public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvider {
@NonNull private final Context mContext;
@@ -58,9 +65,49 @@
@NonNull private final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports
@NonNull private final ClientMonitor.LazyDaemon<IFingerprint> mLazyDaemon;
@NonNull private final Handler mHandler;
+ @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
+ @NonNull private final IActivityTaskManager mActivityTaskManager;
+ @NonNull private final BiometricTaskStackListener mTaskStackListener;
@Nullable private IUdfpsOverlayController mUdfpsOverlayController;
+ private final class BiometricTaskStackListener extends TaskStackListener {
+ @Override
+ public void onTaskStackChanged() {
+ mHandler.post(() -> {
+ for (int i = 0; i < mSensors.size(); i++) {
+ final ClientMonitor<?> client = mSensors.get(i).getScheduler()
+ .getCurrentClient();
+ if (!(client instanceof AuthenticationClient)) {
+ Slog.e(getTag(), "Task stack changed for client: " + client);
+ continue;
+ }
+ if (Utils.isKeyguard(mContext, client.getOwnerString())) {
+ continue; // Keyguard is always allowed
+ }
+
+ try {
+ final List<ActivityManager.RunningTaskInfo> runningTasks =
+ mActivityTaskManager.getTasks(1);
+ if (!runningTasks.isEmpty()) {
+ final String topPackage =
+ runningTasks.get(0).topActivity.getPackageName();
+ if (!topPackage.contentEquals(client.getOwnerString())
+ && !client.isAlreadyDone()) {
+ Slog.e(getTag(), "Stopping background authentication, top: "
+ + topPackage + " currentClient: " + client);
+ mSensors.get(i).getScheduler()
+ .cancelAuthentication(client.getToken());
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Unable to get running tasks", e);
+ }
+ }
+ });
+ }
+ }
+
public FingerprintProvider(@NonNull Context context, @NonNull SensorProps[] props,
@NonNull String halInstanceName, @NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
@@ -69,6 +116,9 @@
mSensors = new SparseArray<>();
mLazyDaemon = this::getHalInstance;
mHandler = new Handler(Looper.getMainLooper());
+ mLockoutResetDispatcher = lockoutResetDispatcher;
+ mActivityTaskManager = ActivityTaskManager.getService();
+ mTaskStackListener = new BiometricTaskStackListener();
for (SensorProps prop : props) {
final int sensorId = prop.commonProps.sensorId;
@@ -132,7 +182,7 @@
mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client, callback);
}
- private void scheduleCreateSessionWithoutHandler(@NonNull IFingerprint daemon, int sensorId,
+ private void createNewSessionWithoutHandler(@NonNull IFingerprint daemon, int sensorId,
int userId) throws RemoteException {
// Note that per IFingerprint createSession contract, this method will block until all
// existing operations are canceled/finished. However, also note that this is fine, since
@@ -157,7 +207,7 @@
@NonNull
@Override
public List<FingerprintSensorPropertiesInternal> getSensorProperties() {
- List<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
+ final List<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
for (int i = 0; i < mSensors.size(); i++) {
props.add(mSensors.valueAt(i).getSensorProperties());
}
@@ -166,7 +216,27 @@
@Override
public void scheduleResetLockout(int sensorId, int userId, @Nullable byte[] hardwareAuthToken) {
+ mHandler.post(() -> {
+ final IFingerprint daemon = getHalInstance();
+ if (daemon == null) {
+ Slog.e(getTag(), "Null daemon during resetLockout, sensorId: " + sensorId);
+ return;
+ }
+ try {
+ if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
+ createNewSessionWithoutHandler(daemon, sensorId, userId);
+ }
+
+ final FingerprintResetLockoutClient client = new FingerprintResetLockoutClient(
+ mContext, mSensors.get(sensorId).getLazySession(), userId,
+ mContext.getOpPackageName(), sensorId, hardwareAuthToken,
+ mSensors.get(sensorId).getLockoutCache(), mLockoutResetDispatcher);
+ scheduleForSensor(sensorId, client);
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Remote exception when scheduling resetLockout", e);
+ }
+ });
}
@Override
@@ -176,14 +246,19 @@
final FingerprintGenerateChallengeClient client =
new FingerprintGenerateChallengeClient(mContext, mLazyDaemon, token,
new ClientMonitorCallbackConverter(receiver), opPackageName, sensorId);
- mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
+ scheduleForSensor(sensorId, client);
});
}
@Override
public void scheduleRevokeChallenge(int sensorId, @NonNull IBinder token,
- @NonNull String opPackageName) {
-
+ @NonNull String opPackageName, long challenge) {
+ mHandler.post(() -> {
+ final FingerprintRevokeChallengeClient client =
+ new FingerprintRevokeChallengeClient(mContext, mLazyDaemon, token,
+ opPackageName, sensorId, challenge);
+ scheduleForSensor(sensorId, client);
+ });
}
@Override
@@ -194,12 +269,15 @@
final IFingerprint daemon = getHalInstance();
if (daemon == null) {
Slog.e(getTag(), "Null daemon during enroll, sensorId: " + sensorId);
+ // If this happens, we need to send HW_UNAVAILABLE after the scheduler gets to
+ // this operation. We should not send the callback yet, since the scheduler may
+ // be processing something else.
return;
}
try {
if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
- scheduleCreateSessionWithoutHandler(daemon, sensorId, userId);
+ createNewSessionWithoutHandler(daemon, sensorId, userId);
}
final int maxTemplatesPerUser = mSensors.get(sensorId).getSensorProperties()
@@ -207,8 +285,7 @@
final FingerprintEnrollClient client = new FingerprintEnrollClient(mContext,
mSensors.get(sensorId).getLazySession(), token,
new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
- opPackageName, FingerprintUtils.getInstance(),
- BiometricsProtoEnums.MODALITY_FINGERPRINT, sensorId,
+ opPackageName, FingerprintUtils.getInstance(), sensorId,
mUdfpsOverlayController, maxTemplatesPerUser);
scheduleForSensor(sensorId, client, new ClientMonitor.Callback() {
@Override
@@ -227,7 +304,7 @@
@Override
public void cancelEnrollment(int sensorId, @NonNull IBinder token) {
-
+ mHandler.post(() -> mSensors.get(sensorId).getScheduler().cancelEnrollment(token));
}
@Override
@@ -242,24 +319,74 @@
int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient,
boolean isKeyguard) {
+ mHandler.post(() -> {
+ final IFingerprint daemon = getHalInstance();
+ if (daemon == null) {
+ Slog.e(getTag(), "Null daemon during authenticate, sensorId: " + sensorId);
+ // If this happens, we need to send HW_UNAVAILABLE after the scheduler gets to
+ // this operation. We should not send the callback yet, since the scheduler may
+ // be processing something else.
+ return;
+ }
+ try {
+ if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
+ createNewSessionWithoutHandler(daemon, sensorId, userId);
+ }
+
+ final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
+ final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient(
+ mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId,
+ operationId, restricted, opPackageName, cookie,
+ false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
+ mTaskStackListener, mSensors.get(sensorId).getLockoutCache(),
+ mUdfpsOverlayController);
+ mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Remote exception when scheduling authenticate", e);
+ }
+ });
}
@Override
public void startPreparedClient(int sensorId, int cookie) {
-
+ mHandler.post(() -> mSensors.get(sensorId).getScheduler().startPreparedClient(cookie));
}
@Override
public void cancelAuthentication(int sensorId, @NonNull IBinder token) {
-
+ mHandler.post(() -> mSensors.get(sensorId).getScheduler().cancelAuthentication(token));
}
@Override
public void scheduleRemove(int sensorId, @NonNull IBinder token,
@NonNull IFingerprintServiceReceiver receiver, int fingerId, int userId,
@NonNull String opPackageName) {
+ mHandler.post(() -> {
+ final IFingerprint daemon = getHalInstance();
+ if (daemon == null) {
+ Slog.e(getTag(), "Null daemon during remove, sensorId: " + sensorId);
+ // If this happens, we need to send HW_UNAVAILABLE after the scheduler gets to
+ // this operation. We should not send the callback yet, since the scheduler may
+ // be processing something else.
+ return;
+ }
+ try {
+ if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
+ createNewSessionWithoutHandler(daemon, sensorId, userId);
+ }
+
+ final FingerprintRemovalClient client = new FingerprintRemovalClient(mContext,
+ mSensors.get(sensorId).getLazySession(), token,
+ new ClientMonitorCallbackConverter(receiver), fingerId, userId,
+ opPackageName, FingerprintUtils.getInstance(), sensorId,
+ mSensors.get(sensorId).getAuthenticatorIds());
+ mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Remote exception when scheduling remove", e);
+ }
+ });
}
@Override
@@ -285,7 +412,7 @@
@Override
public int getLockoutModeForUser(int sensorId, int userId) {
- return 0;
+ return mSensors.get(sensorId).getLockoutCache().getLockoutModeForUser(userId);
}
@Override
@@ -295,12 +422,24 @@
@Override
public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
-
+ final ClientMonitor<?> client = mSensors.get(sensorId).getScheduler().getCurrentClient();
+ if (!(client instanceof Udfps)) {
+ Slog.e(getTag(), "onPointerDown received during client: " + client);
+ return;
+ }
+ final Udfps udfps = (Udfps) client;
+ udfps.onPointerDown(x, y, minor, major);
}
@Override
public void onPointerUp(int sensorId) {
-
+ final ClientMonitor<?> client = mSensors.get(sensorId).getScheduler().getCurrentClient();
+ if (!(client instanceof Udfps)) {
+ Slog.e(getTag(), "onPointerUp received during client: " + client);
+ return;
+ }
+ final Udfps udfps = (Udfps) client;
+ udfps.onPointerUp();
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintRemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintRemovalClient.java
new file mode 100644
index 0000000..df063dc
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintRemovalClient.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2020 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.biometrics.sensors.fingerprint.aidl;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.fingerprint.ISession;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.RemovalClient;
+import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
+
+import java.util.Map;
+
+/**
+ * Fingerprint-specific removal client supporting the
+ * {@link android.hardware.biometrics.fingerprint.IFingerprint} interface.
+ */
+public class FingerprintRemovalClient extends RemovalClient<ISession> {
+ private static final String TAG = "FingerprintRemovalClient";
+
+ public FingerprintRemovalClient(@NonNull Context context,
+ @NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token,
+ @NonNull ClientMonitorCallbackConverter listener, int biometricId, int userId,
+ @NonNull String owner, @NonNull FingerprintUtils utils, int sensorId,
+ @NonNull Map<Integer, Long> authenticatorIds) {
+ super(context, lazyDaemon, token, listener, biometricId, userId, owner, utils, sensorId,
+ authenticatorIds, BiometricsProtoEnums.MODALITY_FINGERPRINT);
+ }
+
+ @Override
+ protected void startHalOperation() {
+ try {
+ final int[] ids = new int[] {mBiometricId};
+ getFreshDaemon().removeEnrollments(mSequentialId, ids);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when requesting remove", e);
+ mCallback.onClientFinished(this, false /* success */);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
new file mode 100644
index 0000000..bc35ad4
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 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.biometrics.sensors.fingerprint.aidl;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.fingerprint.IFingerprint;
+import android.hardware.biometrics.fingerprint.ISession;
+import android.hardware.keymaster.HardwareAuthToken;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.HardwareAuthTokenUtils;
+import com.android.server.biometrics.sensors.ClientMonitor;
+import com.android.server.biometrics.sensors.LockoutResetDispatcher;
+import com.android.server.biometrics.sensors.LockoutTracker;
+
+/**
+ * Fingerprint-specific resetLockout client for the {@link IFingerprint} AIDL HAL interface.
+ * Updates the framework's lockout cache and notifies clients such as Keyguard when lockout is
+ * cleared.
+ */
+public class FingerprintResetLockoutClient extends ClientMonitor<ISession> {
+
+ private static final String TAG = "FingerprintResetLockoutClient";
+
+ private final HardwareAuthToken mHardwareAuthToken;
+ private final LockoutCache mLockoutCache;
+ private final LockoutResetDispatcher mLockoutResetDispatcher;
+
+ public FingerprintResetLockoutClient(@NonNull Context context,
+ @NonNull LazyDaemon<ISession> lazyDaemon, int userId, String owner, int sensorId,
+ @NonNull byte[] hardwareAuthToken, @NonNull LockoutCache lockoutTracker,
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher) {
+ super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
+ 0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
+ BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
+ mHardwareAuthToken = HardwareAuthTokenUtils.toHardwareAuthToken(hardwareAuthToken);
+ mLockoutCache = lockoutTracker;
+ mLockoutResetDispatcher = lockoutResetDispatcher;
+ }
+
+ @Override
+ public void unableToStart() {
+ // Nothing to do here
+ }
+
+ @Override
+ protected void startHalOperation() {
+ try {
+ getFreshDaemon().resetLockout(mSequentialId, mHardwareAuthToken);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to reset lockout", e);
+ mCallback.onClientFinished(this, false /* success */);
+ }
+ }
+
+ void onLockoutCleared() {
+ mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_NONE);
+ mLockoutResetDispatcher.notifyLockoutResetCallbacks(getSensorId());
+ mCallback.onClientFinished(this, true /* success */);
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintRevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintRevokeChallengeClient.java
new file mode 100644
index 0000000..e97dbe7
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintRevokeChallengeClient.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2020 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.biometrics.sensors.fingerprint.aidl;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.fingerprint.IFingerprint;
+import android.hardware.biometrics.fingerprint.IRevokeChallengeCallback;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.RevokeChallengeClient;
+
+/**
+ * Fingerprint-specific revokeChallenge client for the {@link IFingerprint} AIDL HAL interface.
+ */
+public class FingerprintRevokeChallengeClient extends RevokeChallengeClient<IFingerprint> {
+
+ private static final String TAG = "FingerpirntRevokeChallengeClient";
+
+ private final long mChallenge;
+
+ private final IRevokeChallengeCallback mRevokeChallengeCallback =
+ new IRevokeChallengeCallback.Stub() {
+ @Override
+ public void onChallengeRevoked(int sensorId, int userId, long challenge) {
+ final boolean success = challenge == mChallenge;
+ mCallback.onClientFinished(FingerprintRevokeChallengeClient.this, success);
+ }
+ };
+
+ public FingerprintRevokeChallengeClient(
+ @NonNull Context context,
+ @NonNull LazyDaemon<IFingerprint> lazyDaemon,
+ @NonNull IBinder token,
+ @NonNull String owner, int sensorId, long challenge) {
+ super(context, lazyDaemon, token, owner, sensorId);
+ mChallenge = challenge;
+ }
+
+ @Override
+ protected void startHalOperation() {
+ try {
+ getFreshDaemon().revokeChallenge(getSensorId(), getTargetUserId(), mChallenge,
+ mRevokeChallengeCallback);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to revokeChallenge", e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/LockoutCache.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/LockoutCache.java
new file mode 100644
index 0000000..2abbcb0
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/LockoutCache.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 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.biometrics.sensors.fingerprint.aidl;
+
+import android.util.SparseIntArray;
+
+import com.android.server.biometrics.sensors.LockoutTracker;
+
+/**
+ * For a single sensor, caches lockout states for all users.
+ */
+public class LockoutCache implements LockoutTracker {
+
+ // Map of userId to LockoutMode
+ private final SparseIntArray mUserLockoutStates;
+
+ LockoutCache() {
+ mUserLockoutStates = new SparseIntArray();
+ }
+
+ public void setLockoutModeForUser(int userId, @LockoutMode int mode) {
+ synchronized (this) {
+ mUserLockoutStates.put(userId, mode);
+ }
+ }
+
+ @Override
+ public int getLockoutModeForUser(int userId) {
+ synchronized (this) {
+ return mUserLockoutStates.get(userId, LOCKOUT_NONE);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
index 3c27f9c..b7aa2d5 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
@@ -37,12 +37,15 @@
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.ClientMonitor;
import com.android.server.biometrics.sensors.Interruptable;
+import com.android.server.biometrics.sensors.LockoutConsumer;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* Maintains the state of a single sensor within an instance of the
@@ -54,6 +57,8 @@
@NonNull private final Handler mHandler;
@NonNull private final FingerprintSensorPropertiesInternal mSensorProperties;
@NonNull private final BiometricScheduler mScheduler;
+ @NonNull private final LockoutCache mLockoutCache;
+ @NonNull private final Map<Integer, Long> mAuthenticatorIds;
@Nullable private Session mCurrentSession; // TODO: Death recipient
@NonNull private final ClientMonitor.LazyDaemon<ISession> mLazySession;
@@ -82,6 +87,8 @@
mHandler = handler;
mSensorProperties = sensorProperties;
mScheduler = new BiometricScheduler(tag, gestureAvailabilityDispatcher);
+ mLockoutCache = new LockoutCache();
+ mAuthenticatorIds = new HashMap<>();
mLazySession = () -> mCurrentSession != null ? mCurrentSession.mSession : null;
}
@@ -207,17 +214,48 @@
@Override
public void onLockoutTimed(long durationMillis) {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof LockoutConsumer)) {
+ Slog.e(mTag, "onLockoutTimed for non-lockout consumer: "
+ + Utils.getClientName(client));
+ return;
+ }
+ final LockoutConsumer lockoutConsumer = (LockoutConsumer) client;
+ lockoutConsumer.onLockoutTimed(durationMillis);
+ });
}
@Override
public void onLockoutPermanent() {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof LockoutConsumer)) {
+ Slog.e(mTag, "onLockoutPermanent for non-lockout consumer: "
+ + Utils.getClientName(client));
+ return;
+ }
+ final LockoutConsumer lockoutConsumer = (LockoutConsumer) client;
+ lockoutConsumer.onLockoutPermanent();
+ });
}
@Override
public void onLockoutCleared() {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof FingerprintResetLockoutClient)) {
+ Slog.e(mTag, "onLockoutCleared for non-resetLockout client: "
+ + Utils.getClientName(client));
+ return;
+ }
+ final FingerprintResetLockoutClient resetLockoutClient =
+ (FingerprintResetLockoutClient) client;
+ resetLockoutClient.onLockoutCleared();
+ });
}
@Override
@@ -253,4 +291,12 @@
@NonNull BiometricScheduler getScheduler() {
return mScheduler;
}
+
+ @NonNull LockoutCache getLockoutCache() {
+ return mLockoutCache;
+ }
+
+ @NonNull Map<Integer, Long> getAuthenticatorIds() {
+ return mAuthenticatorIds;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 8ce99f4..da68bc8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -518,7 +518,7 @@
@Override
public void scheduleRevokeChallenge(int sensorId, @NonNull IBinder token,
- @NonNull String opPackageName) {
+ @NonNull String opPackageName, long challenge) {
mHandler.post(() -> {
final FingerprintRevokeChallengeClient client = new FingerprintRevokeChallengeClient(
mContext, mLazyDaemon, token, opPackageName, mSensorProperties.sensorId);
@@ -594,16 +594,12 @@
@Override
public void startPreparedClient(int sensorId, int cookie) {
- mHandler.post(() -> {
- mScheduler.startPreparedClient(cookie);
- });
+ mHandler.post(() -> mScheduler.startPreparedClient(cookie));
}
@Override
public void cancelAuthentication(int sensorId, @NonNull IBinder token) {
- mHandler.post(() -> {
- mScheduler.cancelAuthentication(token);
- });
+ mHandler.post(() -> mScheduler.cancelAuthentication(token));
}
@Override
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
index 4cff5c0..7e3c1ab 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -16,8 +16,11 @@
package com.android.server.devicestate;
+import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
+
import android.annotation.NonNull;
import android.content.Context;
+import android.hardware.devicestate.IDeviceStateManager;
import android.util.IntArray;
import android.util.Slog;
@@ -49,9 +52,6 @@
* @see DeviceStatePolicy
*/
public final class DeviceStateManagerService extends SystemService {
- /** Invalid device state. */
- public static final int INVALID_DEVICE_STATE = -1;
-
private static final String TAG = "DeviceStateManagerService";
private static final boolean DEBUG = false;
@@ -88,6 +88,7 @@
@Override
public void onStart() {
mDeviceStatePolicy.getDeviceStateProvider().setListener(new DeviceStateProviderListener());
+ publishBinderService(Context.DEVICE_STATE_SERVICE, new BinderService());
}
/**
@@ -267,4 +268,9 @@
requestState(state);
}
}
+
+ /** Implementation of {@link IDeviceStateManager} published as a binder service. */
+ private final class BinderService extends IDeviceStateManager.Stub {
+
+ }
}
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index eb2c7e6..93cada7 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -208,7 +208,6 @@
private PackageManager mPackageManager;
private Context mContext;
- private DisplayDeviceConfig mDisplayDeviceConfig;
private final Injector mInjector;
AutomaticBrightnessController(Callbacks callbacks, Looper looper,
@@ -217,14 +216,13 @@
float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate,
long brighteningLightDebounceConfig, long darkeningLightDebounceConfig,
boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds,
- HysteresisLevels screenBrightnessThresholds, Context context, DisplayDeviceConfig
- displayDeviceConfig) {
+ HysteresisLevels screenBrightnessThresholds, Context context) {
this(new Injector(), callbacks, looper, sensorManager, lightSensor, mapper,
lightSensorWarmUpTime, brightnessMin, brightnessMax, dozeScaleFactor,
lightSensorRate, initialLightSensorRate, brighteningLightDebounceConfig,
darkeningLightDebounceConfig, resetAmbientLuxAfterWarmUpConfig,
- ambientBrightnessThresholds, screenBrightnessThresholds, context,
- displayDeviceConfig);
+ ambientBrightnessThresholds, screenBrightnessThresholds, context
+ );
}
@VisibleForTesting
@@ -234,8 +232,7 @@
float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate,
long brighteningLightDebounceConfig, long darkeningLightDebounceConfig,
boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds,
- HysteresisLevels screenBrightnessThresholds, Context context, DisplayDeviceConfig
- displayDeviceConfig) {
+ HysteresisLevels screenBrightnessThresholds, Context context) {
mInjector = injector;
mContext = context;
mCallbacks = callbacks;
@@ -257,7 +254,6 @@
mScreenBrightnessThresholds = screenBrightnessThresholds;
mShortTermModelValid = true;
mShortTermModelAnchor = -1;
- mDisplayDeviceConfig = displayDeviceConfig;
mHandler = new AutomaticBrightnessHandler(looper);
mAmbientLightRingBuffer =
new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon);
diff --git a/services/core/java/com/android/server/display/DisplayBlanker.java b/services/core/java/com/android/server/display/DisplayBlanker.java
index d294898..e2129ba 100644
--- a/services/core/java/com/android/server/display/DisplayBlanker.java
+++ b/services/core/java/com/android/server/display/DisplayBlanker.java
@@ -20,5 +20,5 @@
* Interface used to update the actual display state.
*/
public interface DisplayBlanker {
- void requestDisplayState(int state, float brightness);
+ void requestDisplayState(int displayId, int state, float brightness);
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index ca94efc..ffce3be 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -2382,7 +2382,7 @@
synchronized (mSyncRoot) {
DisplayBlanker blanker = new DisplayBlanker() {
@Override
- public void requestDisplayState(int state, float brightness) {
+ public void requestDisplayState(int displayId, int state, float brightness) {
// The order of operations is important for legacy reasons.
if (state == Display.STATE_OFF) {
requestGlobalDisplayStateInternal(state, brightness);
@@ -2395,11 +2395,9 @@
}
}
};
- LogicalDisplay defaultDisplay =
- mLogicalDisplayMapper.getLocked(Display.DEFAULT_DISPLAY);
- DisplayDevice defaultDevice = defaultDisplay.getPrimaryDisplayDeviceLocked();
mDisplayPowerController = new DisplayPowerController(
- mContext, callbacks, handler, sensorManager, blanker, defaultDevice);
+ mContext, callbacks, handler, sensorManager, blanker,
+ Display.DEFAULT_DISPLAY);
mSensorManager = sensorManager;
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 58ef9d1..0211876 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -163,8 +163,8 @@
// The display blanker.
private final DisplayBlanker mBlanker;
- // The display device.
- private final DisplayDevice mDisplayDevice;
+ // The ID of the LogicalDisplay tied to this DisplayPowerController.
+ private final int mDisplayId;
// Tracker for brightness changes.
private final BrightnessTracker mBrightnessTracker;
@@ -406,7 +406,7 @@
*/
public DisplayPowerController(Context context,
DisplayPowerCallbacks callbacks, Handler handler,
- SensorManager sensorManager, DisplayBlanker blanker, DisplayDevice displayDevice) {
+ SensorManager sensorManager, DisplayBlanker blanker, int displayId) {
mHandler = new DisplayControllerHandler(handler.getLooper());
mBrightnessTracker = new BrightnessTracker(context, null);
mSettingsObserver = new SettingsObserver(mHandler);
@@ -417,10 +417,9 @@
mBlanker = blanker;
mContext = context;
mBrightnessSynchronizer = new BrightnessSynchronizer(context);
- mDisplayDevice = displayDevice;
+ mDisplayId = displayId;
PowerManager pm = context.getSystemService(PowerManager.class);
- DisplayDeviceConfig displayDeviceConfig = mDisplayDevice.getDisplayDeviceConfig();
final Resources resources = context.getResources();
@@ -515,7 +514,7 @@
mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
autoBrightnessResetAmbientLuxAfterWarmUp, ambientBrightnessThresholds,
- screenBrightnessThresholds, context, displayDeviceConfig);
+ screenBrightnessThresholds, context);
} else {
mUseSoftwareAutoBrightnessConfig = false;
}
@@ -684,7 +683,7 @@
// Initialize the power state object for the default display.
// In the future, we might manage multiple displays independently.
mPowerState = new DisplayPowerState(mBlanker,
- mColorFadeEnabled ? new ColorFade(Display.DEFAULT_DISPLAY) : null);
+ mColorFadeEnabled ? new ColorFade(mDisplayId) : null, mDisplayId);
if (mColorFadeEnabled) {
mColorFadeOnAnimator = ObjectAnimator.ofFloat(
@@ -1153,7 +1152,7 @@
if (ready && state != Display.STATE_OFF
&& mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_TURNING_ON) {
setReportedScreenState(REPORTED_TO_POLICY_SCREEN_ON);
- mWindowManagerPolicy.screenTurnedOn();
+ mWindowManagerPolicy.screenTurnedOn(mDisplayId);
}
// Grab a wake lock if we have unfinished business.
@@ -1277,7 +1276,7 @@
if (mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_ON) {
setReportedScreenState(REPORTED_TO_POLICY_SCREEN_TURNING_OFF);
blockScreenOff();
- mWindowManagerPolicy.screenTurningOff(mPendingScreenOffUnblocker);
+ mWindowManagerPolicy.screenTurningOff(mDisplayId, mPendingScreenOffUnblocker);
unblockScreenOff();
} else if (mPendingScreenOffUnblocker != null) {
// Abort doing the state change until screen off is unblocked.
@@ -1309,14 +1308,14 @@
&& !mScreenOffBecauseOfProximity) {
setReportedScreenState(REPORTED_TO_POLICY_SCREEN_OFF);
unblockScreenOn();
- mWindowManagerPolicy.screenTurnedOff();
+ mWindowManagerPolicy.screenTurnedOff(mDisplayId);
} else if (!isOff
&& mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_TURNING_OFF) {
// We told policy already that screen was turning off, but now we changed our minds.
// Complete the full state transition on -> turningOff -> off.
unblockScreenOff();
- mWindowManagerPolicy.screenTurnedOff();
+ mWindowManagerPolicy.screenTurnedOff(mDisplayId);
setReportedScreenState(REPORTED_TO_POLICY_SCREEN_OFF);
}
if (!isOff && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_OFF) {
@@ -1326,7 +1325,7 @@
} else {
unblockScreenOn();
}
- mWindowManagerPolicy.screenTurningOn(mPendingScreenOnUnblocker);
+ mWindowManagerPolicy.screenTurningOn(mDisplayId, mPendingScreenOnUnblocker);
}
// Return true if the screen isn't blocked.
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index 4b6430d..54f30a9 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -58,6 +58,7 @@
private final DisplayBlanker mBlanker;
private final ColorFade mColorFade;
private final PhotonicModulator mPhotonicModulator;
+ private final int mDisplayId;
private int mScreenState;
private float mScreenBrightness;
@@ -71,13 +72,14 @@
private Runnable mCleanListener;
- public DisplayPowerState(DisplayBlanker blanker, ColorFade colorFade) {
+ public DisplayPowerState(DisplayBlanker blanker, ColorFade colorFade, int displayId) {
mHandler = new Handler(true /*async*/);
mChoreographer = Choreographer.getInstance();
mBlanker = blanker;
mColorFade = colorFade;
mPhotonicModulator = new PhotonicModulator();
mPhotonicModulator.start();
+ mDisplayId = displayId;
// At boot time, we know that the screen is on and the electron beam
// animation is not playing. We don't know the screen's brightness though,
@@ -434,10 +436,10 @@
// Apply pending change.
if (DEBUG) {
- Slog.d(TAG, "Updating screen state: state="
+ Slog.d(TAG, "Updating screen state: id=" + mDisplayId + ", state="
+ Display.stateToString(state) + ", backlight=" + brightnessState);
}
- mBlanker.requestDisplayState(state, brightnessState);
+ mBlanker.requestDisplayState(mDisplayId, state, brightnessState);
}
}
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 507a265..858cce4 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -969,6 +969,10 @@
}
private int findMatchingModeIdLocked(int configId) {
+ if (configId < 0 || configId >= mDisplayConfigs.length) {
+ Slog.e(TAG, "Invalid display config index " + configId);
+ return NO_DISPLAY_MODE_ID;
+ }
SurfaceControl.DisplayConfig config = mDisplayConfigs[configId];
for (int i = 0; i < mSupportedModes.size(); i++) {
DisplayModeRecord record = mSupportedModes.valueAt(i);
diff --git a/services/core/java/com/android/server/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java
index 5206571..179fb7d 100644
--- a/services/core/java/com/android/server/location/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/LocationProviderManager.java
@@ -23,15 +23,12 @@
import static android.location.LocationManager.KEY_LOCATION_CHANGED;
import static android.location.LocationManager.KEY_PROVIDER_ENABLED;
import static android.location.LocationManager.PASSIVE_PROVIDER;
-import static android.location.LocationRequest.PASSIVE_INTERVAL;
import static android.os.IPowerManager.LOCATION_MODE_NO_CHANGE;
import static android.os.PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF;
import static android.os.PowerManager.LOCATION_MODE_FOREGROUND_ONLY;
import static android.os.PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF;
import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF;
-import static com.android.internal.location.ProviderRequest.EMPTY_REQUEST;
-import static com.android.internal.location.ProviderRequest.INTERVAL_DISABLED;
import static com.android.server.location.LocationManagerService.D;
import static com.android.server.location.LocationManagerService.TAG;
import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
@@ -503,14 +500,7 @@
LocationRequest.Builder builder = new LocationRequest.Builder(baseRequest);
if (mPermissionLevel < PERMISSION_FINE) {
- switch (baseRequest.getQuality()) {
- case LocationRequest.ACCURACY_FINE:
- builder.setQuality(LocationRequest.ACCURACY_BLOCK);
- break;
- case LocationRequest.POWER_HIGH:
- builder.setQuality(LocationRequest.POWER_LOW);
- break;
- }
+ builder.setQuality(LocationRequest.QUALITY_LOW_POWER);
if (baseRequest.getIntervalMillis() < MIN_COARSE_INTERVAL_MS) {
builder.setIntervalMillis(MIN_COARSE_INTERVAL_MS);
}
@@ -1709,7 +1699,7 @@
@Override
protected boolean registerWithService(ProviderRequest request,
Collection<Registration> registrations) {
- return reregisterWithService(EMPTY_REQUEST, request, registrations);
+ return reregisterWithService(ProviderRequest.EMPTY_REQUEST, request, registrations);
}
@GuardedBy("mLock")
@@ -1778,8 +1768,8 @@
Preconditions.checkState(Thread.holdsLock(mLock));
}
- mLocationEventLog.logProviderUpdateRequest(mName, EMPTY_REQUEST);
- mProvider.setRequest(EMPTY_REQUEST);
+ mLocationEventLog.logProviderUpdateRequest(mName, ProviderRequest.EMPTY_REQUEST);
+ mProvider.setRequest(ProviderRequest.EMPTY_REQUEST);
}
@GuardedBy("mLock")
@@ -1839,27 +1829,27 @@
Preconditions.checkState(Thread.holdsLock(mLock));
}
- long intervalMs = INTERVAL_DISABLED;
+ long intervalMs = ProviderRequest.INTERVAL_DISABLED;
+ int quality = LocationRequest.QUALITY_LOW_POWER;
boolean locationSettingsIgnored = false;
boolean lowPower = true;
- ArrayList<LocationRequest> locationRequests = new ArrayList<>(registrations.size());
for (Registration registration : registrations) {
LocationRequest request = registration.getRequest();
// passive requests do not contribute to the provider request
- if (request.getIntervalMillis() == PASSIVE_INTERVAL) {
+ if (request.getIntervalMillis() == LocationRequest.PASSIVE_INTERVAL) {
continue;
}
intervalMs = min(request.getIntervalMillis(), intervalMs);
+ quality = min(request.getQuality(), quality);
locationSettingsIgnored |= request.isLocationSettingsIgnored();
lowPower &= request.isLowPower();
- locationRequests.add(request);
}
- if (intervalMs == INTERVAL_DISABLED) {
- return EMPTY_REQUEST;
+ if (intervalMs == ProviderRequest.INTERVAL_DISABLED) {
+ return ProviderRequest.EMPTY_REQUEST;
}
// calculate who to blame for power in a somewhat arbitrary fashion. we pick a threshold
@@ -1872,7 +1862,7 @@
} catch (ArithmeticException e) {
// check for and handle overflow by setting to one below the passive interval so passive
// requests are automatically skipped
- thresholdIntervalMs = PASSIVE_INTERVAL - 1;
+ thresholdIntervalMs = LocationRequest.PASSIVE_INTERVAL - 1;
}
WorkSource workSource = new WorkSource();
@@ -1884,9 +1874,9 @@
return new ProviderRequest.Builder()
.setIntervalMillis(intervalMs)
+ .setQuality(quality)
.setLocationSettingsIgnored(locationSettingsIgnored)
.setLowPower(lowPower)
- .setLocationRequests(locationRequests)
.setWorkSource(workSource)
.build();
}
diff --git a/services/core/java/com/android/server/location/PassiveLocationProviderManager.java b/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
index fc10d5f..b771861 100644
--- a/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
+++ b/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
@@ -63,15 +63,7 @@
@Override
protected ProviderRequest mergeRegistrations(Collection<Registration> registrations) {
- boolean locationSettingsIgnored = false;
- for (Registration registration : registrations) {
- locationSettingsIgnored |= registration.getRequest().isLocationSettingsIgnored();
- }
-
- return new ProviderRequest.Builder()
- .setIntervalMillis(0)
- .setLocationSettingsIgnored(locationSettingsIgnored)
- .build();
+ return new ProviderRequest.Builder().setIntervalMillis(0).build();
}
@Override
@@ -79,4 +71,9 @@
Collection<Registration> registrations) {
return 0;
}
+
+ @Override
+ protected String getServiceState() {
+ return mProvider.getCurrentRequest().isActive() ? "registered" : "unregistered";
+ }
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index e144b40..e25e605 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -708,12 +708,12 @@
// For fast GNSS TTFF
provider = LocationManager.NETWORK_PROVIDER;
locationListener = mNetworkLocationListener;
- locationRequest.setQuality(LocationRequest.POWER_LOW);
+ locationRequest.setQuality(LocationRequest.QUALITY_LOW_POWER);
} else {
// For Device-Based Hybrid (E911)
provider = LocationManager.FUSED_PROVIDER;
locationListener = mFusedLocationListener;
- locationRequest.setQuality(LocationRequest.ACCURACY_FINE);
+ locationRequest.setQuality(LocationRequest.QUALITY_HIGH_ACCURACY);
}
// Ignore location settings if in emergency mode. This is only allowed for
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index dcfd3f2..35d3621 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -3900,7 +3900,7 @@
// quick check: if this uid doesn't have INTERNET permission, it
// doesn't have network access anyway, so it is a waste to mess
// with it here.
- if (hasInternetPermissionUL(uid)) {
+ if (hasInternetPermissionUL(uid) && !isUidForegroundOnRestrictPowerUL(uid)) {
uidRules.put(uid, FIREWALL_RULE_DENY);
}
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java
index 5a8fbf3..7cdc4cc 100644
--- a/services/core/java/com/android/server/net/NetworkStatsAccess.java
+++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java
@@ -27,6 +27,7 @@
import android.app.admin.DevicePolicyManagerInternal;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.os.Process;
import android.os.UserHandle;
import android.telephony.TelephonyManager;
@@ -110,11 +111,12 @@
boolean hasCarrierPrivileges = tm != null &&
tm.checkCarrierPrivilegesForPackageAnyPhone(callingPackage) ==
TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
- boolean isDeviceOwner = dpmi != null && dpmi.isActiveDeviceOwner(callingUid);
+ final boolean isDeviceOwner = dpmi != null && dpmi.isActiveDeviceOwner(callingUid);
+ final int appId = UserHandle.getAppId(callingUid);
if (hasCarrierPrivileges || isDeviceOwner
- || UserHandle.getAppId(callingUid) == android.os.Process.SYSTEM_UID) {
- // Carrier-privileged apps and device owners, and the system can access data usage for
- // all apps on the device.
+ || appId == Process.SYSTEM_UID || appId == Process.NETWORK_STACK_UID) {
+ // Carrier-privileged apps and device owners, and the system (including the
+ // network stack) can access data usage for all apps on the device.
return NetworkStatsAccess.Level.DEVICE;
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
index d202a2a..5646c75 100644
--- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
+++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
@@ -30,6 +30,7 @@
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.CollectionUtils;
@@ -94,39 +95,41 @@
// also needed to track CBRS.
final List<Integer> newSubs = getActiveSubIdList(mSubscriptionManager);
- for (final int subId : newSubs) {
- final RatTypeListener match = CollectionUtils.find(mRatListeners,
- it -> it.mSubId == subId);
- if (match != null) continue;
+ // IMSI is needed for every newly added sub. Listener stores subscriberId into it to
+ // prevent binder call to telephony when querying RAT. Keep listener registration with empty
+ // IMSI is meaningless since the RAT type changed is ambiguous for multi-SIM if reported
+ // with empty IMSI. So filter the subs w/o a valid IMSI to prevent such registration.
+ final List<Pair<Integer, String>> filteredNewSubs =
+ CollectionUtils.mapNotNull(newSubs, subId -> {
+ final String subscriberId = mTeleManager.getSubscriberId(subId);
+ return TextUtils.isEmpty(subscriberId) ? null : new Pair(subId, subscriberId);
+ });
- // Create listener for every newly added sub. Also store subscriberId into it to
- // prevent binder call to telephony when querying RAT. If the subscriberId is empty
- // for any reason, such as SIM PIN locked, skip registration.
- // SubscriberId will be unavailable again if 1. modem crashed 2. reboot
- // 3. re-insert SIM. If that happens, the listeners will be eventually synchronized
- // with active sub list once all subscriberIds are ready.
- final String subscriberId = mTeleManager.getSubscriberId(subId);
- if (TextUtils.isEmpty(subscriberId)) {
- Log.d(NetworkStatsService.TAG, "Empty subscriberId for newly added sub "
- + subId + ", skip listener registration");
+ for (final Pair<Integer, String> sub : filteredNewSubs) {
+ // Fully match listener with subId and IMSI, since in some rare cases, IMSI might be
+ // suddenly change regardless of subId, such as switch IMSI feature in modem side.
+ // If that happens, register new listener with new IMSI and remove old one later.
+ if (CollectionUtils.find(mRatListeners,
+ it -> it.equalsKey(sub.first, sub.second)) != null) {
continue;
}
+
final RatTypeListener listener =
- new RatTypeListener(mExecutor, this, subId, subscriberId);
+ new RatTypeListener(mExecutor, this, sub.first, sub.second);
mRatListeners.add(listener);
// Register listener to the telephony manager that associated with specific sub.
- mTeleManager.createForSubscriptionId(subId)
+ mTeleManager.createForSubscriptionId(sub.first)
.listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE);
- Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + subId);
+ Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + sub.first);
}
for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) {
- // If the new list contains the subId of the listener, keeps it.
- final Integer match = CollectionUtils.find(newSubs, it -> it == listener.mSubId);
- if (match != null) continue;
-
- handleRemoveRatTypeListener(listener);
+ // If there is no subId and IMSI matched the listener, removes it.
+ if (CollectionUtils.find(filteredNewSubs,
+ it -> listener.equalsKey(it.first, it.second)) == null) {
+ handleRemoveRatTypeListener(listener);
+ }
}
}
@@ -232,5 +235,9 @@
public int getSubId() {
return mSubId;
}
+
+ boolean equalsKey(int subId, @NonNull String subscriberId) {
+ return mSubId == subId && TextUtils.equals(mSubscriberId, subscriberId);
+ }
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 269bd20..03bf74f 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -421,6 +421,7 @@
private IActivityManager mAm;
private ActivityTaskManagerInternal mAtm;
private ActivityManager mActivityManager;
+ private ActivityManagerInternal mAmi;
private IPackageManager mPackageManager;
private PackageManager mPackageManagerClient;
AudioManager mAudioManager;
@@ -1897,7 +1898,7 @@
DevicePolicyManagerInternal dpm, IUriGrantsManager ugm,
UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, UserManager userManager,
NotificationHistoryManager historyManager, StatsManager statsManager,
- TelephonyManager telephonyManager) {
+ TelephonyManager telephonyManager, ActivityManagerInternal ami) {
mHandler = handler;
Resources resources = getContext().getResources();
mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
@@ -1919,6 +1920,7 @@
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
mCompanionManager = companionManager;
mActivityManager = activityManager;
+ mAmi = ami;
mDeviceIdleManager = getContext().getSystemService(DeviceIdleManager.class);
mDpm = dpm;
mUm = userManager;
@@ -2197,7 +2199,8 @@
new NotificationHistoryManager(getContext(), handler),
mStatsManager = (StatsManager) getContext().getSystemService(
Context.STATS_MANAGER),
- getContext().getSystemService(TelephonyManager.class));
+ getContext().getSystemService(TelephonyManager.class),
+ LocalServices.getService(ActivityManagerInternal.class));
publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
@@ -4766,7 +4769,7 @@
@Override
public List<ComponentName> getEnabledNotificationListeners(int userId) {
- checkCallerIsSystem();
+ checkNotificationListenerAccess();
return mListeners.getAllowedComponents(userId);
}
@@ -4835,7 +4838,7 @@
public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
boolean granted) {
Objects.requireNonNull(listener);
- checkCallerIsSystemOrShell();
+ checkNotificationListenerAccess();
final long identity = Binder.clearCallingIdentity();
try {
if (mAllowedManagedServicePackages.test(
@@ -5108,6 +5111,14 @@
}
};
+ protected void checkNotificationListenerAccess() {
+ if (!isCallerSystemOrPhone()) {
+ getContext().enforceCallingPermission(
+ permission.MANAGE_NOTIFICATION_LISTENERS,
+ "Caller must hold " + permission.MANAGE_NOTIFICATION_LISTENERS);
+ }
+ }
+
@VisibleForTesting
protected void setNotificationAssistantAccessGrantedForUserInternal(
ComponentName assistant, int baseUserId, boolean granted) {
@@ -5239,8 +5250,8 @@
if (!summaries.containsKey(pkg)) {
// Add summary
final ApplicationInfo appInfo =
- adjustedSbn.getNotification().extras.getParcelable(
- Notification.EXTRA_BUILDER_APPLICATION_INFO);
+ adjustedSbn.getNotification().extras.getParcelable(
+ Notification.EXTRA_BUILDER_APPLICATION_INFO);
final Bundle extras = new Bundle();
extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
final String channelId = notificationRecord.getChannel().getId();
@@ -5276,11 +5287,11 @@
notificationRecord.getIsAppImportanceLocked());
summaries.put(pkg, summarySbn.getKey());
}
- }
- if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
- summaryRecord.getSbn().getId(), summaryRecord.getSbn().getTag(), summaryRecord,
- true)) {
- mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord, isAppForeground));
+ if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
+ summaryRecord.getSbn().getId(), summaryRecord.getSbn().getTag(), summaryRecord,
+ true)) {
+ mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord, isAppForeground));
+ }
}
}
@@ -6019,13 +6030,17 @@
+ " cannot post for pkg " + targetPkg + " in user " + userId);
}
+ public boolean hasFlag(final int flags, final int flag) {
+ return (flags & flag) != 0;
+ }
/**
* Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
*
* Has side effects.
*/
- private boolean checkDisqualifyingFeatures(int userId, int uid, int id, String tag,
+ boolean checkDisqualifyingFeatures(int userId, int uid, int id, String tag,
NotificationRecord r, boolean isAutogroup) {
+ Notification n = r.getNotification();
final String pkg = r.getSbn().getPackageName();
final boolean isSystemNotification =
isUidSystemOrPhone(uid) || ("android".equals(pkg));
@@ -6034,71 +6049,101 @@
// Limit the number of notifications that any given package except the android
// package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
if (!isSystemNotification && !isNotificationFromListener) {
- synchronized (mNotificationLock) {
- final int callingUid = Binder.getCallingUid();
- if (mNotificationsByKey.get(r.getSbn().getKey()) == null
- && isCallerInstantApp(callingUid, userId)) {
- // Ephemeral apps have some special constraints for notifications.
- // They are not allowed to create new notifications however they are allowed to
- // update notifications created by the system (e.g. a foreground service
- // notification).
- throw new SecurityException("Instant app " + pkg
- + " cannot create notifications");
- }
+ final int callingUid = Binder.getCallingUid();
+ if (mNotificationsByKey.get(r.getSbn().getKey()) == null
+ && isCallerInstantApp(callingUid, userId)) {
+ // Ephemeral apps have some special constraints for notifications.
+ // They are not allowed to create new notifications however they are allowed to
+ // update notifications created by the system (e.g. a foreground service
+ // notification).
+ throw new SecurityException("Instant app " + pkg
+ + " cannot create notifications");
+ }
- // rate limit updates that aren't completed progress notifications
- if (mNotificationsByKey.get(r.getSbn().getKey()) != null
- && !r.getNotification().hasCompletedProgress()
- && !isAutogroup) {
+ // rate limit updates that aren't completed progress notifications
+ if (mNotificationsByKey.get(r.getSbn().getKey()) != null
+ && !r.getNotification().hasCompletedProgress()
+ && !isAutogroup) {
- final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
- if (appEnqueueRate > mMaxPackageEnqueueRate) {
- mUsageStats.registerOverRateQuota(pkg);
- final long now = SystemClock.elapsedRealtime();
- if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
- Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
- + ". Shedding " + r.getSbn().getKey() + ". package=" + pkg);
- mLastOverRateLogTime = now;
- }
- return false;
+ final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
+ if (appEnqueueRate > mMaxPackageEnqueueRate) {
+ mUsageStats.registerOverRateQuota(pkg);
+ final long now = SystemClock.elapsedRealtime();
+ if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
+ Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
+ + ". Shedding " + r.getSbn().getKey() + ". package=" + pkg);
+ mLastOverRateLogTime = now;
}
+ return false;
}
+ }
- // limit the number of non-fgs outstanding notificationrecords an app can have
- if (!r.getNotification().isForegroundService()) {
- int count = getNotificationCountLocked(pkg, userId, id, tag);
- if (count >= MAX_PACKAGE_NOTIFICATIONS) {
- mUsageStats.registerOverCountQuota(pkg);
- Slog.e(TAG, "Package has already posted or enqueued " + count
- + " notifications. Not showing more. package=" + pkg);
- return false;
- }
+ // limit the number of non-fgs outstanding notificationrecords an app can have
+ if (!n.isForegroundService()) {
+ int count = getNotificationCountLocked(pkg, userId, id, tag);
+ if (count >= MAX_PACKAGE_NOTIFICATIONS) {
+ mUsageStats.registerOverCountQuota(pkg);
+ Slog.e(TAG, "Package has already posted or enqueued " + count
+ + " notifications. Not showing more. package=" + pkg);
+ return false;
}
}
}
- synchronized (mNotificationLock) {
- // snoozed apps
- if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
- MetricsLogger.action(r.getLogMaker()
- .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
- .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
- mNotificationRecordLogger.log(
- NotificationRecordLogger.NotificationEvent.NOTIFICATION_NOT_POSTED_SNOOZED,
- r);
- if (DBG) {
- Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
+ // bubble or inline reply that's immutable?
+ if (n.getBubbleMetadata() != null
+ && n.getBubbleMetadata().getIntent() != null
+ && hasFlag(mAmi.getPendingIntentFlags(
+ n.getBubbleMetadata().getIntent().getTarget()),
+ PendingIntent.FLAG_IMMUTABLE)) {
+ throw new IllegalArgumentException(r.getKey() + " Not posted."
+ + " PendingIntents attached to bubbles must be mutable");
+ }
+
+ if (n.actions != null) {
+ for (Notification.Action action : n.actions) {
+ if ((action.getRemoteInputs() != null || action.getDataOnlyRemoteInputs() != null)
+ && hasFlag(mAmi.getPendingIntentFlags(action.actionIntent.getTarget()),
+ PendingIntent.FLAG_IMMUTABLE)) {
+ throw new IllegalArgumentException(r.getKey() + " Not posted."
+ + " PendingIntents attached to actions with remote"
+ + " inputs must be mutable");
}
- mSnoozeHelper.update(userId, r);
- handleSavePolicyFile();
- return false;
}
+ }
+
+ if (r.getSystemGeneratedSmartActions() != null) {
+ for (Notification.Action action : r.getSystemGeneratedSmartActions()) {
+ if ((action.getRemoteInputs() != null || action.getDataOnlyRemoteInputs() != null)
+ && hasFlag(mAmi.getPendingIntentFlags(action.actionIntent.getTarget()),
+ PendingIntent.FLAG_IMMUTABLE)) {
+ throw new IllegalArgumentException(r.getKey() + " Not posted."
+ + " PendingIntents attached to contextual actions with remote inputs"
+ + " must be mutable");
+ }
+ }
+ }
+
+ // snoozed apps
+ if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
+ MetricsLogger.action(r.getLogMaker()
+ .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
+ .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
+ mNotificationRecordLogger.log(
+ NotificationRecordLogger.NotificationEvent.NOTIFICATION_NOT_POSTED_SNOOZED,
+ r);
+ if (DBG) {
+ Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
+ }
+ mSnoozeHelper.update(userId, r);
+ handleSavePolicyFile();
+ return false;
+ }
- // blocked apps
- if (isBlocked(r, mUsageStats)) {
- return false;
- }
+ // blocked apps
+ if (isBlocked(r, mUsageStats)) {
+ return false;
}
return true;
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index ad022c7..7992fea 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -777,12 +777,15 @@
void registerApkInApex(AndroidPackage pkg) {
synchronized (mLock) {
for (ActiveApexInfo aai : mActiveApexInfosCache) {
- if (pkg.getBaseApkPath().startsWith(aai.apexDirectory.getAbsolutePath())) {
+ if (pkg.getBaseApkPath().startsWith(
+ aai.apexDirectory.getAbsolutePath() + File.separator)) {
List<String> apks = mApksInApex.get(aai.apexModuleName);
if (apks == null) {
apks = Lists.newArrayList();
mApksInApex.put(aai.apexModuleName, apks);
}
+ Slog.i(TAG, "Registering " + pkg.getPackageName() + " as apk-in-apex of "
+ + aai.apexModuleName);
apks.add(pkg.getPackageName());
}
}
diff --git a/services/core/java/com/android/server/pm/IncrementalStates.java b/services/core/java/com/android/server/pm/IncrementalStates.java
index dda5faf..ababb83 100644
--- a/services/core/java/com/android/server/pm/IncrementalStates.java
+++ b/services/core/java/com/android/server/pm/IncrementalStates.java
@@ -376,10 +376,10 @@
case IDataLoaderStatusListener.STREAM_INTEGRITY_ERROR:
// fall through
case IDataLoaderStatusListener.STREAM_SOURCE_ERROR: {
- return PackageManager.UNSTARTABLE_REASON_DATALOADER_TRANSPORT;
+ return PackageManager.UNSTARTABLE_REASON_CONNECTION_ERROR;
}
case IDataLoaderStatusListener.STREAM_STORAGE_ERROR: {
- return PackageManager.UNSTARTABLE_REASON_DATALOADER_STORAGE;
+ return PackageManager.UNSTARTABLE_REASON_INSUFFICIENT_STORAGE;
}
default:
return PackageManager.UNSTARTABLE_REASON_UNKNOWN;
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 9bb6f78..66ae50e 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -44,6 +44,8 @@
import android.content.pm.IPackageInstallerCallback;
import android.content.pm.IPackageManager;
import android.content.pm.IShortcutChangeCallback;
+import android.content.pm.IncrementalStatesInfo;
+import android.content.pm.LauncherActivityInfoInternal;
import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.ShortcutQuery;
import android.content.pm.PackageInfo;
@@ -369,18 +371,13 @@
}
}
- private ResolveInfo getHiddenAppActivityInfo(String packageName, int callingUid,
- UserHandle user) {
+ private LauncherActivityInfoInternal getHiddenAppActivityInfo(String packageName,
+ int callingUid, UserHandle user) {
Intent intent = new Intent();
intent.setComponent(new ComponentName(packageName,
PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME));
- final PackageManagerInternal pmInt =
- LocalServices.getService(PackageManagerInternal.class);
- List<ResolveInfo> apps = pmInt.queryIntentActivities(intent,
- intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- callingUid, user.getIdentifier());
+ final List<LauncherActivityInfoInternal> apps = queryIntentLauncherActivities(intent,
+ callingUid, user);
if (apps.size() > 0) {
return apps.get(0);
}
@@ -399,14 +396,14 @@
}
@Override
- public ParceledListSlice<ResolveInfo> getLauncherActivities(String callingPackage,
- String packageName, UserHandle user) throws RemoteException {
- ParceledListSlice<ResolveInfo> launcherActivities = queryActivitiesForUser(
- callingPackage,
- new Intent(Intent.ACTION_MAIN)
- .addCategory(Intent.CATEGORY_LAUNCHER)
- .setPackage(packageName),
- user);
+ public ParceledListSlice<LauncherActivityInfoInternal> getLauncherActivities(
+ String callingPackage, String packageName, UserHandle user) throws RemoteException {
+ ParceledListSlice<LauncherActivityInfoInternal> launcherActivities =
+ queryActivitiesForUser(callingPackage,
+ new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_LAUNCHER)
+ .setPackage(packageName),
+ user);
if (Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED, 1) == 0) {
return launcherActivities;
@@ -428,7 +425,8 @@
return launcherActivities;
}
- final ArrayList<ResolveInfo> result = new ArrayList<>(launcherActivities.getList());
+ final ArrayList<LauncherActivityInfoInternal> result = new ArrayList<>(
+ launcherActivities.getList());
final PackageManagerInternal pmInt =
LocalServices.getService(PackageManagerInternal.class);
if (packageName != null) {
@@ -440,7 +438,8 @@
ApplicationInfo appInfo = pmInt.getApplicationInfo(packageName, /*flags*/ 0,
callingUid, user.getIdentifier());
if (shouldShowSyntheticActivity(user, appInfo)) {
- ResolveInfo info = getHiddenAppActivityInfo(packageName, callingUid, user);
+ LauncherActivityInfoInternal info = getHiddenAppActivityInfo(packageName,
+ callingUid, user);
if (info != null) {
result.add(info);
}
@@ -448,8 +447,8 @@
return new ParceledListSlice<>(result);
}
final HashSet<String> visiblePackages = new HashSet<>();
- for (ResolveInfo info : result) {
- visiblePackages.add(info.activityInfo.packageName);
+ for (LauncherActivityInfoInternal info : result) {
+ visiblePackages.add(info.getActivityInfo().packageName);
}
List<ApplicationInfo> installedPackages = pmInt.getInstalledApplications(0,
user.getIdentifier(), callingUid);
@@ -458,8 +457,8 @@
if (!shouldShowSyntheticActivity(user, applicationInfo)) {
continue;
}
- ResolveInfo info = getHiddenAppActivityInfo(applicationInfo.packageName,
- callingUid, user);
+ LauncherActivityInfoInternal info = getHiddenAppActivityInfo(
+ applicationInfo.packageName, callingUid, user);
if (info != null) {
result.add(info);
}
@@ -533,7 +532,7 @@
}
@Override
- public ActivityInfo resolveActivity(
+ public LauncherActivityInfoInternal resolveLauncherActivityInternal(
String callingPackage, ComponentName component, UserHandle user)
throws RemoteException {
if (!canAccessProfile(user.getIdentifier(), "Cannot resolve activity")) {
@@ -545,10 +544,13 @@
try {
final PackageManagerInternal pmInt =
LocalServices.getService(PackageManagerInternal.class);
- return pmInt.getActivityInfo(component,
+ final ActivityInfo activityInfo = pmInt.getActivityInfo(component,
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
callingUid, user.getIdentifier());
+ final IncrementalStatesInfo incrementalStatesInfo = pmInt.getIncrementalStatesInfo(
+ component.getPackageName(), callingUid, user.getIdentifier());
+ return new LauncherActivityInfoInternal(activityInfo, incrementalStatesInfo);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -562,28 +564,46 @@
new Intent(Intent.ACTION_CREATE_SHORTCUT).setPackage(packageName), user);
}
- private ParceledListSlice<ResolveInfo> queryActivitiesForUser(String callingPackage,
- Intent intent, UserHandle user) {
+ private ParceledListSlice<LauncherActivityInfoInternal> queryActivitiesForUser(
+ String callingPackage, Intent intent, UserHandle user) {
if (!canAccessProfile(user.getIdentifier(), "Cannot retrieve activities")) {
return null;
}
-
final int callingUid = injectBinderCallingUid();
long ident = injectClearCallingIdentity();
try {
- final PackageManagerInternal pmInt =
- LocalServices.getService(PackageManagerInternal.class);
- List<ResolveInfo> apps = pmInt.queryIntentActivities(intent,
- intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- callingUid, user.getIdentifier());
- return new ParceledListSlice<>(apps);
+ return new ParceledListSlice<>(queryIntentLauncherActivities(intent, callingUid,
+ user));
} finally {
injectRestoreCallingIdentity(ident);
}
}
+ private List<LauncherActivityInfoInternal> queryIntentLauncherActivities(
+ Intent intent, int callingUid, UserHandle user) {
+ final PackageManagerInternal pmInt =
+ LocalServices.getService(PackageManagerInternal.class);
+ List<ResolveInfo> apps = pmInt.queryIntentActivities(intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+ callingUid, user.getIdentifier());
+ final int numResolveInfos = apps.size();
+ List<LauncherActivityInfoInternal> results = new ArrayList<>();
+ for (int i = 0; i < numResolveInfos; i++) {
+ final ResolveInfo ri = apps.get(i);
+ final IncrementalStatesInfo incrementalStatesInfo =
+ pmInt.getIncrementalStatesInfo(ri.resolvePackageName, callingUid,
+ user.getIdentifier());
+ if (incrementalStatesInfo == null) {
+ continue;
+ }
+ results.add(new LauncherActivityInfoInternal(ri.activityInfo,
+ incrementalStatesInfo));
+ }
+ return results;
+ }
+
@Override
public IntentSender getShortcutConfigActivityIntent(String callingPackage,
ComponentName component, UserHandle user) throws RemoteException {
@@ -1238,7 +1258,10 @@
} finally {
mListeners.finishBroadcast();
}
-
+ PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+ pmi.registerInstalledLoadingProgressCallback(packageName,
+ new PackageLoadingProgressCallback(packageName, user),
+ user.getIdentifier());
super.onPackageAdded(packageName, uid);
}
@@ -1266,6 +1289,11 @@
@Override
public void onPackageModified(String packageName) {
+ onPackageChanged(packageName);
+ super.onPackageModified(packageName);
+ }
+
+ private void onPackageChanged(String packageName) {
UserHandle user = new UserHandle(getChangingUserId());
final int n = mListeners.beginBroadcast();
try {
@@ -1282,8 +1310,6 @@
} finally {
mListeners.finishBroadcast();
}
-
- super.onPackageModified(packageName);
}
@Override
@@ -1435,6 +1461,7 @@
} catch (RemoteException re) {
Slog.d(TAG, "Callback failed ", re);
}
+
}
} catch (RuntimeException e) {
// When the user is locked we get IllegalState, so just catch all.
@@ -1443,6 +1470,12 @@
mListeners.finishBroadcast();
}
}
+
+ @Override
+ public void onPackageStateChanged(String packageName, int uid) {
+ onPackageChanged(packageName);
+ super.onPackageStateChanged(packageName, uid);
+ }
}
class PackageCallbackList<T extends IInterface> extends RemoteCallbackList<T> {
@@ -1451,5 +1484,38 @@
checkCallbackCount();
}
}
+
+ class PackageLoadingProgressCallback extends
+ PackageManagerInternal.InstalledLoadingProgressCallback {
+ private String mPackageName;
+ private UserHandle mUser;
+
+ PackageLoadingProgressCallback(String packageName, UserHandle user) {
+ super(mCallbackHandler);
+ mPackageName = packageName;
+ mUser = user;
+ }
+
+ @Override
+ public void onLoadingProgressChanged(float progress) {
+ final int n = mListeners.beginBroadcast();
+ try {
+ for (int i = 0; i < n; i++) {
+ IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+ BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
+ if (!isEnabledProfileOf(cookie.user, mUser, "onLoadingProgressChanged")) {
+ continue;
+ }
+ try {
+ listener.onPackageProgressChanged(mUser, mPackageName, progress);
+ } catch (RemoteException re) {
+ Slog.d(TAG, "Callback failed ", re);
+ }
+ }
+ } finally {
+ mListeners.finishBroadcast();
+ }
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9caa91b..5b42440 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -180,6 +180,7 @@
import android.content.pm.IPackageManagerNative;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
+import android.content.pm.IncrementalStatesInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.InstantAppInfo;
import android.content.pm.InstantAppRequest;
@@ -17269,13 +17270,13 @@
private final PackageSetting mPackageSetting;
private final String mPackageName;
private final String mPathString;
- private final int mUserId;
+ private final int mUid;
private final int[] mInstalledUserIds;
IncrementalStatesCallback(PackageSetting packageSetting, int userId) {
mPackageSetting = packageSetting;
mPackageName = packageSetting.name;
- mUserId = userId;
+ mUid = UserHandle.getUid(userId, packageSetting.appId);
mPathString = packageSetting.getPathString();
final int[] allUserIds = resolveUserIds(userId);
final ArrayList<Integer> installedUserIds = new ArrayList<>();
@@ -17311,7 +17312,7 @@
ps, mInstalledUserIds, mSettings.mPackages);
}
Bundle extras = new Bundle();
- extras.putInt(Intent.EXTRA_UID, mUserId);
+ extras.putInt(Intent.EXTRA_UID, mUid);
extras.putString(Intent.EXTRA_PACKAGE_NAME, mPackageName);
sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_LOADED, mPackageName,
extras, 0 /*flags*/,
@@ -17331,9 +17332,9 @@
ps, mInstalledUserIds, mSettings.mPackages);
}
Bundle extras = new Bundle();
- extras.putInt(Intent.EXTRA_UID, mUserId);
+ extras.putInt(Intent.EXTRA_UID, mUid);
extras.putString(Intent.EXTRA_PACKAGE_NAME, mPackageName);
- extras.putInt(Intent.EXTRA_REASON, reason);
+ extras.putInt(Intent.EXTRA_UNSTARTABLE_REASON, reason);
// send broadcast to users with this app installed
sendPackageBroadcast(Intent.ACTION_PACKAGE_UNSTARTABLE, mPackageName,
extras, 0 /*flags*/,
@@ -17353,7 +17354,7 @@
ps, mInstalledUserIds, mSettings.mPackages);
}
Bundle extras = new Bundle();
- extras.putInt(Intent.EXTRA_UID, mUserId);
+ extras.putInt(Intent.EXTRA_UID, mUid);
extras.putString(Intent.EXTRA_PACKAGE_NAME, mPackageName);
// send broadcast to users with this app installed
sendPackageBroadcast(Intent.ACTION_PACKAGE_STARTABLE, mPackageName,
@@ -25658,8 +25659,22 @@
return mIncrementalManager.unregisterCallback(ps.getPathString(),
(IPackageLoadingProgressCallback) callback.getBinder());
}
+
+ @Override
+ public IncrementalStatesInfo getIncrementalStatesInfo(
+ String packageName, int filterCallingUid, int userId) {
+ final PackageSetting ps = getPackageSettingForUser(packageName, filterCallingUid,
+ userId);
+ if (ps == null) {
+ Slog.w(TAG, "Failed getting incremental state. Package " + packageName
+ + " is not available");
+ return null;
+ }
+ return ps.getIncrementalStates();
+ }
}
+
@GuardedBy("mLock")
private SparseArray<String> getAppsWithSharedUserIdsLocked() {
final SparseArray<String> sharedUserIds = new SparseArray<>();
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index c086017..fedbed2 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -32,6 +32,7 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.PermissionInfo;
import android.content.pm.parsing.component.ParsedPermission;
+import android.os.Build;
import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;
@@ -445,36 +446,38 @@
return null;
}
- public @Nullable PermissionInfo generatePermissionInfo(@NonNull String groupName, int flags) {
- if (groupName == null) {
- if (perm == null || perm.getGroup() == null) {
- return generatePermissionInfo(protectionLevel, flags);
- }
- } else {
- if (perm != null && groupName.equals(perm.getGroup())) {
- return PackageInfoUtils.generatePermissionInfo(perm, flags);
- }
- }
- return null;
+ @Nullable
+ public String getGroup() {
+ return perm != null ? perm.getGroup() : null;
}
- public @NonNull PermissionInfo generatePermissionInfo(int adjustedProtectionLevel, int flags) {
+ @NonNull
+ public PermissionInfo generatePermissionInfo(int flags) {
+ return generatePermissionInfo(flags, Build.VERSION_CODES.CUR_DEVELOPMENT);
+ }
+
+ @NonNull
+ public PermissionInfo generatePermissionInfo(int flags, int targetSdkVersion) {
PermissionInfo permissionInfo;
if (perm != null) {
- final boolean protectionLevelChanged = protectionLevel != adjustedProtectionLevel;
permissionInfo = PackageInfoUtils.generatePermissionInfo(perm, flags);
- if (protectionLevelChanged) {
- // if we return different protection level, don't use the cached info
- permissionInfo = new PermissionInfo(permissionInfo);
- permissionInfo.protectionLevel = adjustedProtectionLevel;
- }
- return permissionInfo;
+ } else {
+ permissionInfo = new PermissionInfo();
+ permissionInfo.name = name;
+ permissionInfo.packageName = sourcePackageName;
+ permissionInfo.nonLocalizedLabel = name;
}
- permissionInfo = new PermissionInfo();
- permissionInfo.name = name;
- permissionInfo.packageName = sourcePackageName;
- permissionInfo.nonLocalizedLabel = name;
- permissionInfo.protectionLevel = protectionLevel;
+ if (targetSdkVersion >= Build.VERSION_CODES.O) {
+ permissionInfo.protectionLevel = protectionLevel;
+ } else {
+ final int protection = protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
+ if (protection == PermissionInfo.PROTECTION_SIGNATURE) {
+ // Signature permission's protection flags are always reported.
+ permissionInfo.protectionLevel = protectionLevel;
+ } else {
+ permissionInfo.protectionLevel = protection;
+ }
+ }
return permissionInfo;
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 25e1848..e1f129e 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -378,8 +378,9 @@
@NonNull Injector injector) {
mInjector = injector;
// The package info cache is the cache for package and permission information.
+ // Disable the package info and package permission caches locally but leave the
+ // checkPermission cache active.
mInjector.invalidatePackageInfoCache();
- mInjector.disablePermissionCache();
mInjector.disablePackageNamePermissionCache();
mContext = context;
@@ -544,24 +545,37 @@
@Override
@Nullable
- public PermissionInfo getPermissionInfo(String permName, String packageName,
+ public PermissionInfo getPermissionInfo(@NonNull String permName, @NonNull String opPackageName,
@PermissionInfoFlags int flags) {
final int callingUid = getCallingUid();
if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
return null;
}
- final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
+ final AndroidPackage opPackage = mPackageManagerInt.getPackage(opPackageName);
+ final int targetSdkVersion = getPermissionInfoCallingTargetSdkVersion(opPackage,
+ callingUid);
synchronized (mLock) {
final BasePermission bp = mSettings.getPermissionLocked(permName);
if (bp == null) {
return null;
}
- final int adjustedProtectionLevel = adjustPermissionProtectionFlagsLocked(
- bp.getProtectionLevel(), pkg, callingUid);
- return bp.generatePermissionInfo(adjustedProtectionLevel, flags);
+ return bp.generatePermissionInfo(flags, targetSdkVersion);
}
}
+ private int getPermissionInfoCallingTargetSdkVersion(@Nullable AndroidPackage pkg, int uid) {
+ final int appId = UserHandle.getAppId(uid);
+ if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID
+ || appId == Process.SHELL_UID) {
+ // System sees all flags.
+ return Build.VERSION_CODES.CUR_DEVELOPMENT;
+ }
+ if (pkg == null) {
+ return Build.VERSION_CODES.CUR_DEVELOPMENT;
+ }
+ return pkg.getTargetSdkVersion();
+ }
+
@Override
@Nullable
public ParceledListSlice<PermissionInfo> queryPermissionsByGroup(String groupName,
@@ -576,9 +590,8 @@
}
final ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10);
for (BasePermission bp : mSettings.mPermissions.values()) {
- final PermissionInfo pi = bp.generatePermissionInfo(groupName, flags);
- if (pi != null) {
- out.add(pi);
+ if (Objects.equals(bp.getGroup(), groupName)) {
+ out.add(bp.generatePermissionInfo(flags));
}
}
return new ParceledListSlice<>(out);
@@ -2235,32 +2248,6 @@
}
}
- private int adjustPermissionProtectionFlagsLocked(int protectionLevel,
- @Nullable AndroidPackage pkg, int uid) {
- // Signature permission flags area always reported
- final int protectionLevelMasked = protectionLevel
- & (PermissionInfo.PROTECTION_NORMAL
- | PermissionInfo.PROTECTION_DANGEROUS
- | PermissionInfo.PROTECTION_SIGNATURE);
- if (protectionLevelMasked == PermissionInfo.PROTECTION_SIGNATURE) {
- return protectionLevel;
- }
- // System sees all flags.
- final int appId = UserHandle.getAppId(uid);
- if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID
- || appId == Process.SHELL_UID) {
- return protectionLevel;
- }
- if (pkg == null) {
- return protectionLevel;
- }
- if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.O) {
- return protectionLevelMasked;
- }
- // Apps that target O see flags for all protection levels.
- return protectionLevel;
- }
-
/**
* We might auto-grant permissions if any permission of the group is already granted. Hence if
* the group of a granted permission changes we need to revoke it to avoid having permissions of
@@ -4903,8 +4890,7 @@
BasePermission bp = mSettings.mPermissions.valueAt(i);
if (bp.perm != null && bp.perm.getProtection() == protection) {
- matchingPermissions.add(
- PackageInfoUtils.generatePermissionInfo(bp.perm, 0));
+ matchingPermissions.add(bp.generatePermissionInfo(0));
}
}
}
@@ -4925,8 +4911,7 @@
if (bp.perm != null && (bp.perm.getProtectionFlags() & protectionFlags)
== protectionFlags) {
- matchingPermissions.add(
- PackageInfoUtils.generatePermissionInfo(bp.perm, 0));
+ matchingPermissions.add(bp.generatePermissionInfo(0));
}
}
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index df283e2..0313aae 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4506,7 +4506,11 @@
// Called on the DisplayManager's DisplayPowerController thread.
@Override
- public void screenTurnedOff() {
+ public void screenTurnedOff(int displayId) {
+ if (displayId != DEFAULT_DISPLAY) {
+ return;
+ }
+
if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turned off...");
updateScreenOffSleepToken(true);
@@ -4529,7 +4533,11 @@
// Called on the DisplayManager's DisplayPowerController thread.
@Override
- public void screenTurningOn(final ScreenOnListener screenOnListener) {
+ public void screenTurningOn(int displayId, final ScreenOnListener screenOnListener) {
+ if (displayId != DEFAULT_DISPLAY) {
+ return;
+ }
+
if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on...");
Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn", 0 /* cookie */);
@@ -4552,7 +4560,11 @@
// Called on the DisplayManager's DisplayPowerController thread.
@Override
- public void screenTurnedOn() {
+ public void screenTurnedOn(int displayId) {
+ if (displayId != DEFAULT_DISPLAY) {
+ return;
+ }
+
synchronized (mLock) {
if (mKeyguardDelegate != null) {
mKeyguardDelegate.onScreenTurnedOn();
@@ -4562,7 +4574,11 @@
}
@Override
- public void screenTurningOff(ScreenOffListener screenOffListener) {
+ public void screenTurningOff(int displayId, ScreenOffListener screenOffListener) {
+ if (displayId != DEFAULT_DISPLAY) {
+ return;
+ }
+
mWindowManagerFuncs.screenTurningOff(screenOffListener);
synchronized (mLock) {
if (mKeyguardDelegate != null) {
@@ -4824,8 +4840,8 @@
}
startedWakingUp(ON_BECAUSE_OF_UNKNOWN);
finishedWakingUp(ON_BECAUSE_OF_UNKNOWN);
- screenTurningOn(null);
- screenTurnedOn();
+ screenTurningOn(DEFAULT_DISPLAY, null);
+ screenTurnedOn(DEFAULT_DISPLAY);
}
@Override
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index b96d65c..0d8d347 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -831,7 +831,7 @@
public void finishedGoingToSleep(int why);
/**
- * Called when the device is about to turn on the screen to show content.
+ * Called when the display is about to turn on to show content.
* When waking up, this method will be called once after the call to wakingUp().
* When dozing, the method will be called sometime after the call to goingToSleep() and
* may be called repeatedly in the case where the screen is pulsing on and off.
@@ -839,13 +839,13 @@
* Must call back on the listener to tell it when the higher-level system
* is ready for the screen to go on (i.e. the lock screen is shown).
*/
- public void screenTurningOn(ScreenOnListener screenOnListener);
+ public void screenTurningOn(int displayId, ScreenOnListener screenOnListener);
/**
- * Called when the device has actually turned on the screen, i.e. the display power state has
- * been set to ON and the screen is unblocked.
+ * Called when the display has actually turned on, i.e. the display power state has been set to
+ * ON and the screen is unblocked.
*/
- public void screenTurnedOn();
+ public void screenTurnedOn(int displayId);
/**
* Called when the display would like to be turned off. This gives policy a chance to do some
@@ -854,12 +854,12 @@
* @param screenOffListener Must be called to tell that the display power state can actually be
* changed now after policy has done its work.
*/
- public void screenTurningOff(ScreenOffListener screenOffListener);
+ public void screenTurningOff(int displayId, ScreenOffListener screenOffListener);
/**
- * Called when the device has turned the screen off.
+ * Called when the display has turned off.
*/
- public void screenTurnedOff();
+ public void screenTurnedOff(int displayId);
public interface ScreenOnListener {
void onScreenOn();
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index a4fa745..44a6336 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -25,6 +25,7 @@
import android.content.rollback.PackageRollbackInfo.RestoreInfo;
import android.content.rollback.RollbackInfo;
import android.os.UserHandle;
+import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseIntArray;
@@ -37,6 +38,7 @@
import org.json.JSONObject;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
@@ -66,8 +68,6 @@
//
// * XXX, YYY are the rollbackIds for the corresponding rollbacks.
// * rollback.json contains all relevant metadata for the rollback.
- //
- // TODO: Use AtomicFile for all the .json files?
private final File mRollbackDataDir;
RollbackStore(File rollbackDataDir) {
@@ -259,6 +259,8 @@
* Saves the given rollback to persistent storage.
*/
static void saveRollback(Rollback rollback) {
+ FileOutputStream fos = null;
+ AtomicFile file = new AtomicFile(new File(rollback.getBackupDir(), "rollback.json"));
try {
JSONObject dataJson = new JSONObject();
dataJson.put("info", rollbackInfoToJson(rollback.info));
@@ -272,11 +274,16 @@
dataJson.putOpt(
"extensionVersions", extensionVersionsToJson(rollback.getExtensionVersions()));
- PrintWriter pw = new PrintWriter(new File(rollback.getBackupDir(), "rollback.json"));
+ fos = file.startWrite();
+ PrintWriter pw = new PrintWriter(fos);
pw.println(dataJson.toString());
pw.close();
+ file.finishWrite(fos);
} catch (JSONException | IOException e) {
Slog.e(TAG, "Unable to save rollback for: " + rollback.info.getRollbackId(), e);
+ if (fos != null) {
+ file.failWrite(fos);
+ }
}
}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index e0b671f..f43a4ce 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -1630,13 +1630,14 @@
if (modemInfo == null) {
return StatsManager.PULL_SKIP;
}
- pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, modemInfo.getTimestamp(),
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,
+ modemInfo.getTimestampMillis(),
modemInfo.getSleepTimeMillis(), modemInfo.getIdleTimeMillis(),
- modemInfo.getTransmitPowerInfo().get(0).getTimeInMillis(),
- modemInfo.getTransmitPowerInfo().get(1).getTimeInMillis(),
- modemInfo.getTransmitPowerInfo().get(2).getTimeInMillis(),
- modemInfo.getTransmitPowerInfo().get(3).getTimeInMillis(),
- modemInfo.getTransmitPowerInfo().get(4).getTimeInMillis(),
+ modemInfo.getTransmitDurationMillisAtPowerLevel(0),
+ modemInfo.getTransmitDurationMillisAtPowerLevel(1),
+ modemInfo.getTransmitDurationMillisAtPowerLevel(2),
+ modemInfo.getTransmitDurationMillisAtPowerLevel(3),
+ modemInfo.getTransmitDurationMillisAtPowerLevel(4),
modemInfo.getReceiveTimeMillis(),
-1 /*`energy_used` field name deprecated, use -1 to indicate as unused.*/));
} finally {
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index e9215f9..ebfffec 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -86,6 +86,13 @@
void toggleSplitScreen();
void appTransitionFinished(int displayId);
+ /**
+ * Notifies the status bar that a Emergency Action launch gesture has been detected.
+ *
+ * TODO (b/169175022) Update method name and docs when feature name is locked.
+ */
+ void onEmergencyActionLaunchGestureDetected();
+
void toggleRecentApps();
void setCurrentUser(int newUserId);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 6a68dc1..55cb7f3 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -264,6 +264,23 @@
}
}
+ /**
+ * Notifies the status bar that a Emergency Action launch gesture has been detected.
+ *
+ * TODO (b/169175022) Update method name and docs when feature name is locked.
+ */
+ @Override
+ public void onEmergencyActionLaunchGestureDetected() {
+ if (SPEW) Slog.d(TAG, "Launching emergency action");
+ if (mBar != null) {
+ try {
+ mBar.onEmergencyActionLaunchGestureDetected();
+ } catch (RemoteException e) {
+ if (SPEW) Slog.d(TAG, "Failed to launch emergency action");
+ }
+ }
+ }
+
@Override
public void topAppWindowChanged(int displayId, boolean isFullscreen, boolean isImmersive) {
StatusBarManagerService.this.topAppWindowChanged(displayId, isFullscreen, isImmersive);
diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
index 08eaa29..1f73977 100644
--- a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
@@ -28,6 +28,8 @@
import android.app.time.TimeZoneConfiguration;
import android.os.UserHandle;
+import com.android.internal.util.Preconditions;
+
import java.util.Objects;
/**
@@ -40,6 +42,7 @@
private final @UserIdInt int mUserId;
private final boolean mUserConfigAllowed;
private final boolean mAutoDetectionSupported;
+ private final boolean mGeoDetectionSupported;
private final boolean mAutoDetectionEnabled;
private final boolean mLocationEnabled;
private final boolean mGeoDetectionEnabled;
@@ -48,9 +51,13 @@
mUserId = builder.mUserId;
mUserConfigAllowed = builder.mUserConfigAllowed;
mAutoDetectionSupported = builder.mAutoDetectionSupported;
+ mGeoDetectionSupported = builder.mGeoDetectionSupported;
mAutoDetectionEnabled = builder.mAutoDetectionEnabled;
mLocationEnabled = builder.mLocationEnabled;
mGeoDetectionEnabled = builder.mGeoDetectionEnabled;
+ // if mGeoDetectionSupported then mAutoDetectionSupported, i.e. mGeoDetectionSupported
+ // cannot be true if mAutoDetectionSupported == false
+ Preconditions.checkState(mAutoDetectionSupported || !mGeoDetectionSupported);
}
/** Returns the ID of the user this configuration is associated with. */
@@ -69,11 +76,16 @@
return mUserConfigAllowed;
}
- /** Returns true if the device supports some form of auto time zone detection. */
+ /** Returns true if the device supports any form of auto time zone detection. */
public boolean isAutoDetectionSupported() {
return mAutoDetectionSupported;
}
+ /** Returns true if the device supports geolocation time zone detection. */
+ public boolean isGeoDetectionSupported() {
+ return mGeoDetectionSupported;
+ }
+
/** Returns the value of the auto time zone detection enabled setting. */
public boolean getAutoDetectionEnabledSetting() {
return mAutoDetectionEnabled;
@@ -101,10 +113,10 @@
* distinct from the raw setting value.
*/
public boolean getGeoDetectionEnabledBehavior() {
- if (getAutoDetectionEnabledBehavior()) {
- return mLocationEnabled && mGeoDetectionEnabled;
- }
- return false;
+ return getAutoDetectionEnabledBehavior()
+ && isGeoDetectionSupported()
+ && isLocationEnabled()
+ && getGeoDetectionEnabledSetting();
}
/** Creates a {@link TimeZoneCapabilitiesAndConfig} object using the configuration values. */
@@ -121,10 +133,10 @@
// Automatic time zone detection is only supported on devices if there is a telephony
// network available or geolocation time zone detection is possible.
- boolean deviceHasTimeZoneDetection = isAutoDetectionSupported();
+ boolean deviceHasAutoTimeZoneDetection = isAutoDetectionSupported();
final int configureAutoDetectionEnabledCapability;
- if (!deviceHasTimeZoneDetection) {
+ if (!deviceHasAutoTimeZoneDetection) {
configureAutoDetectionEnabledCapability = CAPABILITY_NOT_SUPPORTED;
} else if (!allowConfigDateTime) {
configureAutoDetectionEnabledCapability = CAPABILITY_NOT_ALLOWED;
@@ -133,8 +145,9 @@
}
builder.setConfigureAutoDetectionEnabledCapability(configureAutoDetectionEnabledCapability);
+ boolean deviceHasLocationTimeZoneDetection = isGeoDetectionSupported();
final int configureGeolocationDetectionEnabledCapability;
- if (!deviceHasTimeZoneDetection) {
+ if (!deviceHasLocationTimeZoneDetection) {
configureGeolocationDetectionEnabledCapability = CAPABILITY_NOT_SUPPORTED;
} else if (!allowConfigDateTime) {
configureGeolocationDetectionEnabledCapability = CAPABILITY_NOT_ALLOWED;
@@ -199,6 +212,7 @@
return mUserId == that.mUserId
&& mUserConfigAllowed == that.mUserConfigAllowed
&& mAutoDetectionSupported == that.mAutoDetectionSupported
+ && mGeoDetectionSupported == that.mGeoDetectionSupported
&& mAutoDetectionEnabled == that.mAutoDetectionEnabled
&& mLocationEnabled == that.mLocationEnabled
&& mGeoDetectionEnabled == that.mGeoDetectionEnabled;
@@ -207,7 +221,8 @@
@Override
public int hashCode() {
return Objects.hash(mUserId, mUserConfigAllowed, mAutoDetectionSupported,
- mAutoDetectionEnabled, mLocationEnabled, mGeoDetectionEnabled);
+ mGeoDetectionSupported, mAutoDetectionEnabled, mLocationEnabled,
+ mGeoDetectionEnabled);
}
@Override
@@ -216,6 +231,7 @@
+ "mUserId=" + mUserId
+ ", mUserConfigAllowed=" + mUserConfigAllowed
+ ", mAutoDetectionSupported=" + mAutoDetectionSupported
+ + ", mGeoDetectionSupported=" + mGeoDetectionSupported
+ ", mAutoDetectionEnabled=" + mAutoDetectionEnabled
+ ", mLocationEnabled=" + mLocationEnabled
+ ", mGeoDetectionEnabled=" + mGeoDetectionEnabled
@@ -228,8 +244,10 @@
public static class Builder {
private final @UserIdInt int mUserId;
+
private boolean mUserConfigAllowed;
private boolean mAutoDetectionSupported;
+ private boolean mGeoDetectionSupported;
private boolean mAutoDetectionEnabled;
private boolean mLocationEnabled;
private boolean mGeoDetectionEnabled;
@@ -248,6 +266,7 @@
this.mUserId = toCopy.mUserId;
this.mUserConfigAllowed = toCopy.mUserConfigAllowed;
this.mAutoDetectionSupported = toCopy.mAutoDetectionSupported;
+ this.mGeoDetectionSupported = toCopy.mGeoDetectionSupported;
this.mAutoDetectionEnabled = toCopy.mAutoDetectionEnabled;
this.mLocationEnabled = toCopy.mLocationEnabled;
this.mGeoDetectionEnabled = toCopy.mGeoDetectionEnabled;
@@ -262,7 +281,7 @@
}
/**
- * Sets whether automatic time zone detection is supported on this device.
+ * Sets whether any form of automatic time zone detection is supported on this device.
*/
public Builder setAutoDetectionSupported(boolean supported) {
mAutoDetectionSupported = supported;
@@ -270,6 +289,14 @@
}
/**
+ * Sets whether geolocation time zone detection is supported on this device.
+ */
+ public Builder setGeoDetectionSupported(boolean supported) {
+ mGeoDetectionSupported = supported;
+ return this;
+ }
+
+ /**
* Sets the value of the automatic time zone detection enabled setting for this device.
*/
public Builder setAutoDetectionEnabled(boolean enabled) {
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
index 964dbec..941be0e 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
@@ -119,13 +119,13 @@
@Override
public ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) {
- boolean geoDetectionEnabled = mGeoDetectionFeatureEnabled && isGeoDetectionEnabled(userId);
return new ConfigurationInternal.Builder(userId)
.setUserConfigAllowed(isUserConfigAllowed(userId))
.setAutoDetectionSupported(isAutoDetectionSupported())
+ .setGeoDetectionSupported(isGeoDetectionSupported())
.setAutoDetectionEnabled(isAutoDetectionEnabled())
.setLocationEnabled(isLocationEnabled(userId))
- .setGeoDetectionEnabled(geoDetectionEnabled)
+ .setGeoDetectionEnabled(isGeoDetectionEnabled(userId))
.build();
}
@@ -170,7 +170,11 @@
final boolean autoDetectionEnabled = configuration.isAutoDetectionEnabled();
setAutoDetectionEnabled(autoDetectionEnabled);
- if (mGeoDetectionFeatureEnabled) {
+ // Avoid writing the geo detection enabled setting for devices that do not support geo
+ // time zone detection: if we wrote it down then we'd set the value explicitly, which
+ // would prevent detecting "default" later. That might influence what happens on later
+ // releases that support geo detection on the same hardware.
+ if (isGeoDetectionSupported()) {
final boolean geoTzDetectionEnabled = configuration.isGeoDetectionEnabled();
setGeoDetectionEnabled(userId, geoTzDetectionEnabled);
}
@@ -183,7 +187,11 @@
}
private boolean isAutoDetectionSupported() {
- return deviceHasTelephonyNetwork() || mGeoDetectionFeatureEnabled;
+ return deviceHasTelephonyNetwork() || isGeoDetectionSupported();
+ }
+
+ private boolean isGeoDetectionSupported() {
+ return mGeoDetectionFeatureEnabled;
}
private boolean isAutoDetectionEnabled() {
@@ -199,10 +207,10 @@
}
private boolean isGeoDetectionEnabled(@UserIdInt int userId) {
- final boolean locationEnabled = isLocationEnabled(userId);
+ final boolean geoDetectionEnabledByDefault = false;
return Settings.Secure.getIntForUser(mCr,
Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED,
- locationEnabled ? 1 : 0 /* defaultValue */, userId) != 0;
+ (geoDetectionEnabledByDefault ? 1 : 0) /* defaultValue */, userId) != 0;
}
private void setGeoDetectionEnabled(@UserIdInt int userId, boolean enabled) {
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index fb06a9c..9d08b1b 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -397,6 +397,13 @@
return -1;
}
}
+
+ PackageOptimizationInfo getPackageOptimizationInfo(ArtManagerInternal artManagerInternal) {
+ return artManagerInternal == null || launchedActivityAppRecordRequiredAbi == null
+ ? PackageOptimizationInfo.createWithNoInfo()
+ : artManagerInternal.getPackageOptimizationInfo(applicationInfo,
+ launchedActivityAppRecordRequiredAbi, launchedActivityName);
+ }
}
ActivityMetricsLogger(ActivityStackSupervisor supervisor, Looper looper) {
@@ -857,14 +864,8 @@
info.bindApplicationDelayMs);
}
builder.addTaggedData(APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS, info.windowsDrawnDelayMs);
- final ArtManagerInternal artManagerInternal = getArtManagerInternal();
final PackageOptimizationInfo packageOptimizationInfo =
- (artManagerInternal == null) || (info.launchedActivityAppRecordRequiredAbi == null)
- ? PackageOptimizationInfo.createWithNoInfo()
- : artManagerInternal.getPackageOptimizationInfo(
- info.applicationInfo,
- info.launchedActivityAppRecordRequiredAbi,
- info.launchedActivityName);
+ info.getPackageOptimizationInfo(getArtManagerInternal());
builder.addTaggedData(PACKAGE_OPTIMIZATION_COMPILATION_REASON,
packageOptimizationInfo.getCompilationReason());
builder.addTaggedData(PACKAGE_OPTIMIZATION_COMPILATION_FILTER,
@@ -985,6 +986,8 @@
builder.addTaggedData(APP_TRANSITION_PROCESS_RUNNING,
info.mProcessRunning ? 1 : 0);
mMetricsLogger.write(builder);
+ final PackageOptimizationInfo packageOptimizationInfo =
+ infoSnapshot.getPackageOptimizationInfo(getArtManagerInternal());
FrameworkStatsLog.write(
FrameworkStatsLog.APP_START_FULLY_DRAWN,
info.mLastLaunchedActivity.info.applicationInfo.uid,
@@ -995,6 +998,8 @@
info.mLastLaunchedActivity.info.name,
info.mProcessRunning,
startupTimeMs,
+ packageOptimizationInfo.getCompilationReason(),
+ packageOptimizationInfo.getCompilationFilter(),
info.mSourceType,
info.mSourceEventDelayMs);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 9868fc1..746bc0e 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -3222,6 +3222,7 @@
getDisplayContent().mUnknownAppVisibilityController.appRemovedOrHidden(this);
mWmService.mTaskSnapshotController.onAppRemoved(this);
mStackSupervisor.getActivityMetricsLogger().notifyActivityRemoved(this);
+ mStackSupervisor.mStoppingActivities.remove(this);
waitingToShow = false;
// TODO(b/169035022): move to a more-appropriate place.
@@ -4760,14 +4761,15 @@
supportsEnterPipOnTaskSwitch = false;
break;
case RESUMED:
- // If the app is capable of entering PIP, we should try pausing it now
- // so it can PIP correctly.
- if (deferHidingClient) {
- getRootTask().startPausingLocked(
- mStackSupervisor.mUserLeaving /* userLeaving */,
- false /* uiSleeping */, null /* resuming */, "makeInvisible");
+ // Do nothing if currently in the process of resuming the activity. Otherwise,
+ // starting to pause it since it is not visible.
+ if (task.mInResumeTopActivity
+ && task.topRunningActivity(true /* focusableOnly */) == this) {
break;
}
+ getRootTask().startPausingLocked(mStackSupervisor.mUserLeaving,
+ false /* uiSleeping */, null /* resuming */, "makeInvisible");
+ // fall through
case INITIALIZING:
case PAUSING:
case PAUSED:
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 8bd42f0..94b3d8d 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -41,6 +41,7 @@
import com.android.internal.protolog.common.ProtoLog;
import com.android.server.policy.WindowManagerPolicy;
+import java.io.PrintWriter;
import java.util.Comparator;
import java.util.function.BiFunction;
import java.util.function.Consumer;
@@ -71,6 +72,13 @@
IDisplayAreaOrganizer mOrganizer;
private final Configuration mTmpConfiguration = new Configuration();
+ /**
+ * Whether this {@link DisplayArea} should ignore fixed-orientation request. If {@code true}, it
+ * can never specify orientation, but shows the fixed-orientation apps below it in the
+ * letterbox; otherwise, it rotates based on the fixed-orientation request.
+ */
+ protected boolean mIgnoreOrientationRequest;
+
DisplayArea(WindowManagerService wms, Type type, String name) {
this(wms, type, name, FEATURE_UNDEFINED);
}
@@ -127,6 +135,56 @@
}
}
+ @Override
+ int getOrientation(int candidate) {
+ mLastOrientationSource = null;
+ if (mIgnoreOrientationRequest) {
+ return SCREEN_ORIENTATION_UNSET;
+ }
+
+ return super.getOrientation(candidate);
+ }
+
+ /**
+ * Sets whether this {@link DisplayArea} should ignore fixed-orientation request from apps and
+ * windows below it.
+ *
+ * @return Whether the display orientation changed after calling this method.
+ */
+ boolean setIgnoreOrientationRequest(boolean ignoreOrientationRequest) {
+ if (mIgnoreOrientationRequest == ignoreOrientationRequest) {
+ return false;
+ }
+ mIgnoreOrientationRequest = ignoreOrientationRequest;
+
+ // Check whether we should notify Display to update orientation.
+ if (mDisplayContent == null) {
+ return false;
+ }
+
+ // The orientation request from this DA may now be respected.
+ if (!ignoreOrientationRequest) {
+ return mDisplayContent.updateOrientation();
+ }
+
+ final int lastOrientation = mDisplayContent.getLastOrientation();
+ final WindowContainer lastOrientationSource = mDisplayContent.getLastOrientationSource();
+ if (lastOrientation == SCREEN_ORIENTATION_UNSET
+ || lastOrientation == SCREEN_ORIENTATION_UNSPECIFIED) {
+ // Orientation won't be changed.
+ return false;
+ }
+ if (lastOrientationSource == null || lastOrientationSource.isDescendantOf(this)) {
+ // Try update if the orientation may be affected.
+ return mDisplayContent.updateOrientation();
+ }
+ return false;
+ }
+
+ boolean getIgnoreOrientationRequest() {
+ return mIgnoreOrientationRequest;
+ }
+
/**
* When a {@link DisplayArea} is repositioned, it should only be moved among its siblings of the
* same {@link Type}.
@@ -200,6 +258,14 @@
}
@Override
+ void dump(PrintWriter pw, String prefix, boolean dumpAll) {
+ super.dump(pw, prefix, dumpAll);
+ if (mIgnoreOrientationRequest) {
+ pw.println(prefix + "mIgnoreOrientationRequest=true");
+ }
+ }
+
+ @Override
long getProtoFieldId() {
return DISPLAY_AREA;
}
@@ -370,6 +436,9 @@
Comparator.comparingInt(WindowToken::getWindowLayerFromType);
private final Predicate<WindowState> mGetOrientingWindow = w -> {
+ if (!w.isVisible() || !w.mLegacyPolicyVisibilityAfterAnim) {
+ return false;
+ }
final WindowManagerPolicy policy = mWmService.mPolicy;
if (policy.isKeyguardHostWindow(w.mAttrs)) {
if (mWmService.mKeyguardGoingAway) {
@@ -405,6 +474,11 @@
@Override
int getOrientation(int candidate) {
+ mLastOrientationSource = null;
+ if (mIgnoreOrientationRequest) {
+ return SCREEN_ORIENTATION_UNSET;
+ }
+
// Find a window requesting orientation.
final WindowState win = getWindow(mGetOrientingWindow);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e7f0e3e..be03e91 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -28,8 +28,8 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
@@ -2347,6 +2347,13 @@
@Override
int getOrientation() {
mLastOrientationSource = null;
+ if (mIgnoreOrientationRequest) {
+ // Return SCREEN_ORIENTATION_UNSPECIFIED so that Display respect sensor rotation
+ ProtoLog.v(WM_DEBUG_ORIENTATION,
+ "Display id=%d is ignoring all orientation requests, return %d",
+ mDisplayId, SCREEN_ORIENTATION_UNSPECIFIED);
+ return SCREEN_ORIENTATION_UNSPECIFIED;
+ }
if (mWmService.mDisplayFrozen) {
if (mWmService.mPolicy.isKeyguardLocked()) {
@@ -2363,19 +2370,15 @@
}
final int orientation = super.getOrientation();
- if (orientation != SCREEN_ORIENTATION_UNSET && orientation != SCREEN_ORIENTATION_BEHIND) {
+ if (orientation == SCREEN_ORIENTATION_UNSET) {
+ // Return SCREEN_ORIENTATION_UNSPECIFIED so that Display respect sensor rotation
ProtoLog.v(WM_DEBUG_ORIENTATION,
- "App is requesting an orientation, return %d for display id=%d",
- orientation, mDisplayId);
- return orientation;
+ "No app or window is requesting an orientation, return %d for display id=%d",
+ SCREEN_ORIENTATION_UNSPECIFIED, mDisplayId);
+ return SCREEN_ORIENTATION_UNSPECIFIED;
}
- ProtoLog.v(WM_DEBUG_ORIENTATION,
- "No app is requesting an orientation, return %d for display id=%d",
- getLastOrientation(), mDisplayId);
- // The next app has not been requested to be visible, so we keep the current orientation
- // to prevent freezing/unfreezing the display too early.
- return getLastOrientation();
+ return orientation;
}
void updateDisplayInfo() {
@@ -4243,6 +4246,10 @@
@Override
int getOrientation(int candidate) {
+ if (mIgnoreOrientationRequest) {
+ return SCREEN_ORIENTATION_UNSET;
+ }
+
// IME does not participate in orientation.
return candidate;
}
@@ -5349,8 +5356,13 @@
return mDisplayPolicy.getSystemUiContext();
}
- Point getDisplayPosition() {
- return mWmService.mDisplayManagerInternal.getDisplayPosition(getDisplayId());
+ @Override
+ boolean setIgnoreOrientationRequest(boolean ignoreOrientationRequest) {
+ if (mIgnoreOrientationRequest == ignoreOrientationRequest) return false;
+ final boolean rotationChanged = super.setIgnoreOrientationRequest(ignoreOrientationRequest);
+ mWmService.mDisplayWindowSettings.setIgnoreOrientationRequest(
+ this, mIgnoreOrientationRequest);
+ return rotationChanged;
}
/**
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 3ff369a3..4e7e0ba 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1040,9 +1040,12 @@
}
if (attrs.providesInsetsTypes != null) {
- mContext.enforcePermission(
- android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
- "DisplayPolicy");
+ // Recents component is allowed to add inset types.
+ if (!mService.mAtmInternal.isCallerRecents(callingUid)) {
+ mContext.enforcePermission(
+ android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
+ "DisplayPolicy");
+ }
enforceSingleInsetsTypeCorrespondingToWindowType(attrs.providesInsetsTypes);
for (@InternalInsetsType int insetType : attrs.providesInsetsTypes) {
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index 04e37fa..f647bea 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -112,6 +112,7 @@
private boolean mShouldShowSystemDecors = false;
private boolean mShouldShowIme = false;
private int mFixedToUserRotation = IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT;
+ private boolean mIgnoreOrientationRequest = false;
private Entry(String name) {
mName = name;
@@ -131,6 +132,7 @@
mShouldShowSystemDecors = copyFrom.mShouldShowSystemDecors;
mShouldShowIme = copyFrom.mShouldShowIme;
mFixedToUserRotation = copyFrom.mFixedToUserRotation;
+ mIgnoreOrientationRequest = copyFrom.mIgnoreOrientationRequest;
}
/** @return {@code true} if all values are default. */
@@ -144,7 +146,8 @@
&& !mShouldShowWithInsecureKeyguard
&& !mShouldShowSystemDecors
&& !mShouldShowIme
- && mFixedToUserRotation == IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT;
+ && mFixedToUserRotation == IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT
+ && !mIgnoreOrientationRequest;
}
}
@@ -248,6 +251,15 @@
writeSettingsIfNeeded(entry, displayInfo);
}
+ void setIgnoreOrientationRequest(
+ DisplayContent displayContent, boolean ignoreOrientationRequest) {
+ final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+ final Entry entry = getOrCreateEntry(displayInfo);
+ if (entry.mIgnoreOrientationRequest == ignoreOrientationRequest) return;
+ entry.mIgnoreOrientationRequest = ignoreOrientationRequest;
+ writeSettingsIfNeeded(entry, displayInfo);
+ }
+
private int getWindowingModeLocked(Entry entry, DisplayContent dc) {
int windowingMode = entry != null ? entry.mWindowingMode
: WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -389,6 +401,7 @@
final boolean hasSizeOverride = entry.mForcedWidth != 0 && entry.mForcedHeight != 0;
dc.mIsDensityForced = hasDensityOverride;
dc.mIsSizeForced = hasSizeOverride;
+ dc.setIgnoreOrientationRequest(entry.mIgnoreOrientationRequest);
final int width = hasSizeOverride ? entry.mForcedWidth : dc.mBaseDisplayWidth;
final int height = hasSizeOverride ? entry.mForcedHeight : dc.mBaseDisplayHeight;
@@ -529,6 +542,8 @@
entry.mShouldShowSystemDecors = getBooleanAttribute(parser, "shouldShowSystemDecors");
entry.mShouldShowIme = getBooleanAttribute(parser, "shouldShowIme");
entry.mFixedToUserRotation = getIntAttribute(parser, "fixedToUserRotation");
+ entry.mIgnoreOrientationRequest
+ = getBooleanAttribute(parser, "ignoreOrientationRequest");
mEntries.put(name, entry);
}
XmlUtils.skipCurrentTag(parser);
@@ -613,6 +628,10 @@
out.attribute(null, "fixedToUserRotation",
Integer.toString(entry.mFixedToUserRotation));
}
+ if (entry.mIgnoreOrientationRequest) {
+ out.attribute(null, "ignoreOrientationRequest",
+ Boolean.toString(entry.mIgnoreOrientationRequest));
+ }
out.endTag(null, "display");
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 143b657..470c2b1 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -531,7 +531,7 @@
// event. This is used to omit Surfaces from occlusion detection.
populateOverlayInputInfo(mInvalidInputWindow, w.getName(), type, isVisible);
mInputTransaction.setInputWindowInfo(
- w.mWinAnimator.mSurfaceController.getClientViewRootSurface(),
+ w.mWinAnimator.mSurfaceController.mSurfaceControl,
mInvalidInputWindow);
return;
}
@@ -600,8 +600,7 @@
if (w.mWinAnimator.hasSurface()) {
mInputTransaction.setInputWindowInfo(
- w.mWinAnimator.mSurfaceController.getClientViewRootSurface(),
- inputWindowHandle);
+ w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle);
}
}
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index dda1e2d..4ad2575 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -389,9 +389,7 @@
final int taskCount = visibleTasks.size();
for (int i = 0; i < taskCount; i++) {
final Task task = visibleTasks.get(i);
- final WindowConfiguration config = task.getWindowConfiguration();
- if (config.tasksAreFloating()
- || config.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+ if (skipAnimation(task)) {
continue;
}
addAnimation(task, !recentTaskIds.get(task.mTaskId));
@@ -434,6 +432,19 @@
}
}
+
+ /**
+ * Whether a task should be filtered from the recents animation. This can be true for tasks
+ * being displayed outside of recents.
+ */
+ private boolean skipAnimation(Task task) {
+ final WindowConfiguration config = task.getWindowConfiguration();
+ return task.isAlwaysOnTop()
+ || config.tasksAreFloating()
+ || config.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+ }
+
+
@VisibleForTesting
AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible) {
return addAnimation(task, isRecentTaskInvisible, false /* hidden */,
@@ -529,8 +540,9 @@
void addTaskToTargets(Task task, OnAnimationFinishedCallback finishedCallback) {
if (mRunner != null) {
- // No need to send task appeared when the task target already exists.
- if (isAnimatingTask(task)) {
+ // No need to send task appeared when the task target already exists, or when the
+ // task is being managed as a multi-window mode outside of recents (e.g. bubbles).
+ if (isAnimatingTask(task) || skipAnimation(task)) {
return;
}
final RemoteAnimationTarget target = createTaskRemoteAnimation(task, finishedCallback);
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 25732e7..7ed22a1 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -203,16 +203,14 @@
.setCallsite("ScreenRotationAnimation")
.build();
- // In case display bounds change, screenshot buffer and surface may mismatch so set a
- // scaling mode.
- SurfaceControl.Transaction t2 = mService.mTransactionFactory.get();
- t2.setOverrideScalingMode(mScreenshotLayer, Surface.SCALING_MODE_SCALE_TO_WINDOW);
- t2.apply(true /* sync */);
-
// Capture a screenshot into the surface we just created.
final int displayId = displayContent.getDisplayId();
final Surface surface = mService.mSurfaceFactory.get();
+ // In case display bounds change, screenshot buffer and surface may mismatch so set a
+ // scaling mode.
surface.copyFrom(mScreenshotLayer);
+ surface.setScalingMode(Surface.SCALING_MODE_SCALE_TO_WINDOW);
+
SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
mService.mDisplayManagerInternal.systemScreenshot(displayId);
if (screenshotBuffer != null) {
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 1fdb49f..02230d6 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -204,15 +204,14 @@
int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
- InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
- SurfaceControl outBLASTSurfaceControl) {
+ InsetsSourceControl[] outActiveControls, Point outSurfaceSize) {
if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
+ Binder.getCallingPid());
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
int res = mService.relayoutWindow(this, window, attrs,
requestedWidth, requestedHeight, viewFlags, flags, frameNumber,
outFrames, mergedConfiguration, outSurfaceControl, outInsetsState,
- outActiveControls, outSurfaceSize, outBLASTSurfaceControl);
+ outActiveControls, outSurfaceSize);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
+ Binder.getCallingPid());
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 249fe03..a66a2c4 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -1474,14 +1474,6 @@
// Update task bounds if needed.
adjustBoundsForDisplayChangeIfNeeded(getDisplayContent());
- if (getWindowConfiguration().windowsAreScaleable()) {
- // We force windows out of SCALING_MODE_FREEZE so that we can continue to animate them
- // while a resize is pending.
- forceWindowsScaleable(true /* force */);
- } else {
- forceWindowsScaleable(false /* force */);
- }
-
mRootWindowContainer.updateUIDsPresentOnDisplay();
// Resume next focusable stack after reparenting to another display if we aren't removing
@@ -3780,17 +3772,6 @@
positionChildAt(position, child, false /* includeParents */);
}
- void forceWindowsScaleable(boolean force) {
- mWmService.openSurfaceTransaction();
- try {
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- mChildren.get(i).forceWindowsScaleableInTransaction(force);
- }
- } finally {
- mWmService.closeSurfaceTransaction("forceWindowsScaleable");
- }
- }
-
void setTaskDescription(TaskDescription taskDescription) {
mTaskDescription = taskDescription;
}
@@ -4792,9 +4773,11 @@
// If the task is not yet visible when it is added to the task organizer, then we should
// hide it to allow the task organizer to show it when it is properly reparented. We
// skip this for tasks created by the organizer because they can synchronously update
- // the leash before new children are added to the task.
+ // the leash before new children are added to the task. Also skip this if the task
+ // has already been sent to the organizer which can happen before the first draw if
+ // an existing task is reported to the organizer when it first registers.
if (!mAtmService.getTransitionController().isShellTransitionsEnabled()
- && !mCreatedByOrganizer
+ && !mCreatedByOrganizer && !mTaskAppearedSent
&& mTaskOrganizer != null && !prevHasBeenVisible) {
getSyncTransaction().hide(getSurfaceControl());
commitPendingTransaction();
@@ -4846,6 +4829,11 @@
@VisibleForTesting
boolean setTaskOrganizer(ITaskOrganizer organizer) {
+ return setTaskOrganizer(organizer, false /* skipTaskAppeared */);
+ }
+
+ @VisibleForTesting
+ boolean setTaskOrganizer(ITaskOrganizer organizer, boolean skipTaskAppeared) {
if (mTaskOrganizer == organizer) {
return false;
}
@@ -4858,7 +4846,9 @@
sendTaskVanished(prevOrganizer);
if (mTaskOrganizer != null) {
- sendTaskAppeared();
+ if (!skipTaskAppeared) {
+ sendTaskAppeared();
+ }
} else {
// No longer managed by any organizer.
mTaskAppearedSent = false;
@@ -4871,6 +4861,10 @@
return true;
}
+ boolean updateTaskOrganizerState(boolean forceUpdate) {
+ return updateTaskOrganizerState(forceUpdate, false /* skipTaskAppeared */);
+ }
+
/**
* Called when the task state changes (ie. from windowing mode change) an the task organizer
* state should also be updated.
@@ -4878,9 +4872,10 @@
* @param forceUpdate Updates the task organizer to the one currently specified in the task
* org controller for the task's windowing mode, ignoring the cached
* windowing mode checks.
+ * @param skipTaskAppeared Skips calling taskAppeared for the new organizer if it has changed
* @return {@code true} if task organizer changed.
*/
- boolean updateTaskOrganizerState(boolean forceUpdate) {
+ boolean updateTaskOrganizerState(boolean forceUpdate, boolean skipTaskAppeared) {
if (getSurfaceControl() == null) {
// Can't call onTaskAppeared without a surfacecontrol, so defer this until after one
// is created.
@@ -4896,7 +4891,7 @@
if (!forceUpdate && mTaskOrganizer == organizer) {
return false;
}
- return setTaskOrganizer(organizer);
+ return setTaskOrganizer(organizer, skipTaskAppeared);
}
@Override
@@ -5883,7 +5878,11 @@
final TaskDisplayArea taskDisplayArea = getDisplayArea();
// If the top activity is the resumed one, nothing to do.
+ // For devices that are not in fullscreen mode (e.g. freeform windows), it's possible
+ // we still want to proceed if the visibility of other windows have changed (e.g. bringing
+ // a fullscreen window forward to cover another freeform activity.)
if (mResumedActivity == next && next.isState(RESUMED)
+ && taskDisplayArea.getWindowingMode() != WINDOWING_MODE_FREEFORM
&& taskDisplayArea.allResumedActivitiesComplete()) {
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index d69fb0b..830ad5d 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -29,10 +29,12 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.isSplitScreenWindowingMode;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK;
@@ -150,13 +152,6 @@
private boolean mRemoved;
/**
- * Whether the task display area should ignore fixed-orientation request. If {@code true}, it
- * can never specify orientation, but show the fixed-orientation apps in the letterbox;
- * otherwise, it rotates based on the fixed-orientation request when it has the focus.
- */
- private boolean mIgnoreOrientationRequest;
-
- /**
* The id of a leaf task that most recently being moved to front.
*/
private int mLastLeafTaskToFrontId;
@@ -654,28 +649,9 @@
}
}
- /**
- * Sets whether the task display area should ignore fixed-orientation request from apps.
- *
- * @return Whether the display orientation changed
- */
- boolean setIgnoreOrientationRequest(boolean ignoreOrientationRequest) {
- if (mIgnoreOrientationRequest == ignoreOrientationRequest) {
- return false;
- }
-
- mIgnoreOrientationRequest = ignoreOrientationRequest;
- if (isLastFocused()) {
- // Update orientation if this TDA is the last focused, otherwise it shouldn't affect
- // the display.
- return mDisplayContent.updateOrientation();
- }
-
- return false;
- }
-
@Override
int getOrientation(int candidate) {
+ mLastOrientationSource = null;
// Only allow to specify orientation if this TDA is not set to ignore orientation request,
// and it has the focus.
if (mIgnoreOrientationRequest || !isLastFocused()) {
@@ -708,7 +684,21 @@
return SCREEN_ORIENTATION_UNSPECIFIED;
}
- return super.getOrientation(candidate);
+ final int orientation = super.getOrientation(candidate);
+ if (orientation != SCREEN_ORIENTATION_UNSET
+ && orientation != SCREEN_ORIENTATION_BEHIND) {
+ ProtoLog.v(WM_DEBUG_ORIENTATION,
+ "App is requesting an orientation, return %d for display id=%d",
+ orientation, mDisplayContent.mDisplayId);
+ return orientation;
+ }
+
+ ProtoLog.v(WM_DEBUG_ORIENTATION,
+ "No app is requesting an orientation, return %d for display id=%d",
+ mDisplayContent.getLastOrientation(), mDisplayContent.mDisplayId);
+ // The next app has not been requested to be visible, so we keep the current orientation
+ // to prevent freezing/unfreezing the display too early.
+ return mDisplayContent.getLastOrientation();
}
@Override
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 8201d10..48550ed0 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -32,6 +32,7 @@
import android.app.WindowConfiguration;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.ParceledListSlice;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
@@ -39,6 +40,7 @@
import android.view.SurfaceControl;
import android.window.ITaskOrganizer;
import android.window.ITaskOrganizerController;
+import android.window.TaskAppearedInfo;
import android.window.WindowContainerToken;
import com.android.internal.annotations.VisibleForTesting;
@@ -76,8 +78,6 @@
WINDOWING_MODE_FREEFORM
};
- private final WindowManagerGlobalLock mGlobalLock;
-
private class DeathRecipient implements IBinder.DeathRecipient {
ITaskOrganizer mTaskOrganizer;
@@ -103,39 +103,38 @@
* transaction before they are presented to the task org.
*/
private class TaskOrganizerCallbacks {
- final WindowManagerService mService;
final ITaskOrganizer mTaskOrganizer;
final Consumer<Runnable> mDeferTaskOrgCallbacksConsumer;
- private final SurfaceControl.Transaction mTransaction;
-
- TaskOrganizerCallbacks(WindowManagerService wm, ITaskOrganizer taskOrg,
+ TaskOrganizerCallbacks(ITaskOrganizer taskOrg,
Consumer<Runnable> deferTaskOrgCallbacksConsumer) {
- mService = wm;
mDeferTaskOrgCallbacksConsumer = deferTaskOrgCallbacksConsumer;
mTaskOrganizer = taskOrg;
- mTransaction = wm.mTransactionFactory.get();
}
IBinder getBinder() {
return mTaskOrganizer.asBinder();
}
+ SurfaceControl prepareLeash(Task task, boolean visible, String reason) {
+ SurfaceControl outSurfaceControl = new SurfaceControl(task.getSurfaceControl(), reason);
+ if (!task.mCreatedByOrganizer && !visible) {
+ // To prevent flashes, we hide the task prior to sending the leash to the
+ // task org if the task has previously hidden (ie. when entering PIP)
+ mTransaction.hide(outSurfaceControl);
+ mTransaction.apply();
+ }
+ return outSurfaceControl;
+ }
+
void onTaskAppeared(Task task) {
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task appeared taskId=%d", task.mTaskId);
final boolean visible = task.isVisible();
final RunningTaskInfo taskInfo = task.getTaskInfo();
mDeferTaskOrgCallbacksConsumer.accept(() -> {
try {
- SurfaceControl outSurfaceControl = new SurfaceControl(task.getSurfaceControl(),
- "TaskOrganizerController.onTaskAppeared");
- if (!task.mCreatedByOrganizer && !visible) {
- // To prevent flashes, we hide the task prior to sending the leash to the
- // task org if the task has previously hidden (ie. when entering PIP)
- mTransaction.hide(outSurfaceControl);
- mTransaction.apply();
- }
- mTaskOrganizer.onTaskAppeared(taskInfo, outSurfaceControl);
+ mTaskOrganizer.onTaskAppeared(taskInfo, prepareLeash(task, visible,
+ "TaskOrganizerController.onTaskAppeared"));
} catch (RemoteException e) {
Slog.e(TAG, "Exception sending onTaskAppeared callback", e);
}
@@ -208,8 +207,7 @@
mDeferTaskOrgCallbacksConsumer != null
? mDeferTaskOrgCallbacksConsumer
: mService.mWindowManager.mAnimator::addAfterPrepareSurfacesRunnable;
- mOrganizer = new TaskOrganizerCallbacks(mService.mWindowManager, organizer,
- deferTaskOrgCallbacksConsumer);
+ mOrganizer = new TaskOrganizerCallbacks(organizer, deferTaskOrgCallbacksConsumer);
mDeathRecipient = new DeathRecipient(organizer);
try {
organizer.asBinder().linkToDeath(mDeathRecipient, 0);
@@ -219,6 +217,18 @@
mUid = uid;
}
+ /**
+ * Register this task with this state, but doesn't trigger the task appeared callback to
+ * the organizer.
+ */
+ SurfaceControl addTaskWithoutCallback(Task t, String reason) {
+ t.mTaskAppearedSent = true;
+ if (!mOrganizedTasks.contains(t)) {
+ mOrganizedTasks.add(t);
+ }
+ return mOrganizer.prepareLeash(t, t.isVisible(), reason);
+ }
+
void addTask(Task t) {
if (t.mTaskAppearedSent) return;
@@ -265,6 +275,9 @@
}
}
+ private final ActivityTaskManagerService mService;
+ private final WindowManagerGlobalLock mGlobalLock;
+
// List of task organizers by priority
private final LinkedList<ITaskOrganizer> mTaskOrganizers = new LinkedList<>();
private final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap<>();
@@ -273,8 +286,7 @@
// Set of organized tasks (by taskId) that dispatch back pressed to their organizers
private final HashSet<Integer> mInterceptBackPressedOnRootTasks = new HashSet();
- private final ActivityTaskManagerService mService;
-
+ private SurfaceControl.Transaction mTransaction;
private RunningTaskInfo mTmpTaskInfo;
private Consumer<Runnable> mDeferTaskOrgCallbacksConsumer;
@@ -299,7 +311,7 @@
* Register a TaskOrganizer to manage tasks as they enter the a supported windowing mode.
*/
@Override
- public void registerTaskOrganizer(ITaskOrganizer organizer) {
+ public ParceledListSlice<TaskAppearedInfo> registerTaskOrganizer(ITaskOrganizer organizer) {
enforceStackPermission("registerTaskOrganizer()");
final int uid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
@@ -307,17 +319,36 @@
synchronized (mGlobalLock) {
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register task organizer=%s uid=%d",
organizer.asBinder(), uid);
+
+ // Defer initializing the transaction since the transaction factory can be set up
+ // by the tests after construction of the controller
+ if (mTransaction == null) {
+ mTransaction = mService.mWindowManager.mTransactionFactory.get();
+ }
+
if (!mTaskOrganizerStates.containsKey(organizer.asBinder())) {
mTaskOrganizers.add(organizer);
mTaskOrganizerStates.put(organizer.asBinder(),
new TaskOrganizerState(organizer, uid));
}
+
+ final ArrayList<TaskAppearedInfo> taskInfos = new ArrayList<>();
+ final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
mService.mRootWindowContainer.forAllTasks((task) -> {
if (ArrayUtils.contains(UNSUPPORTED_WINDOWING_MODES, task.getWindowingMode())) {
return;
}
- task.updateTaskOrganizerState(true /* forceUpdate */);
+
+ boolean returnTask = !task.mCreatedByOrganizer;
+ task.updateTaskOrganizerState(true /* forceUpdate */,
+ returnTask /* skipTaskAppeared */);
+ if (returnTask) {
+ SurfaceControl outSurfaceControl = state.addTaskWithoutCallback(task,
+ "TaskOrganizerController.registerTaskOrganizer");
+ taskInfos.add(new TaskAppearedInfo(task.getTaskInfo(), outSurfaceControl));
+ }
});
+ return new ParceledListSlice<>(taskInfos);
}
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 6904740..efa0525 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -122,7 +122,6 @@
//tmp vars for unused relayout params
private static final Point sTmpSurfaceSize = new Point();
- private static final SurfaceControl sTmpSurfaceControl = new SurfaceControl();
private final Window mWindow;
private final Surface mSurface;
@@ -260,7 +259,7 @@
try {
session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0, -1,
tmpFrames, tmpMergedConfiguration, surfaceControl, mTmpInsetsState,
- mTempControls, sTmpSurfaceSize, sTmpSurfaceControl);
+ mTempControls, sTmpSurfaceSize);
} catch (RemoteException e) {
// Local call.
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 38ec924..0edaa1d 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -861,13 +861,6 @@
}
}
- void forceWindowsScaleableInTransaction(boolean force) {
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowContainer wc = mChildren.get(i);
- wc.forceWindowsScaleableInTransaction(force);
- }
- }
-
/**
* @return {@code true} when an application can override an app transition animation on this
* container.
@@ -2744,8 +2737,9 @@
pw.print(prefix); pw.println("ContainerAnimator:");
mSurfaceAnimator.dump(pw, prefix + " ");
}
- if (mLastOrientationSource != null) {
+ if (mLastOrientationSource != null && this == mDisplayContent) {
pw.println(prefix + "mLastOrientationSource=" + mLastOrientationSource);
+ pw.println(prefix + "deepestLastOrientationSource=" + getLastOrientationSource());
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 223aa1e..4be118e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2104,8 +2104,7 @@
int requestedWidth, int requestedHeight, int viewVisibility, int flags,
long frameNumber, ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
- InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
- SurfaceControl outBLASTSurfaceControl) {
+ InsetsSourceControl[] outActiveControls, Point outSurfaceSize) {
Arrays.fill(outActiveControls, null);
int result = 0;
boolean configChanged;
@@ -2280,8 +2279,7 @@
result = win.relayoutVisibleWindow(result, attrChanges);
try {
- result = createSurfaceControl(outSurfaceControl, outBLASTSurfaceControl,
- result, win, winAnimator);
+ result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
} catch (Exception e) {
displayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
@@ -2313,7 +2311,6 @@
// surface, let the client use that, but don't create new surface at this point.
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: getSurface");
winAnimator.mSurfaceController.getSurfaceControl(outSurfaceControl);
- winAnimator.mSurfaceController.getBLASTSurfaceControl(outBLASTSurfaceControl);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
} else {
if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Releasing surface in: " + win);
@@ -2501,8 +2498,7 @@
return focusMayChange;
}
- private int createSurfaceControl(SurfaceControl outSurfaceControl,
- SurfaceControl outBLASTSurfaceControl, int result,
+ private int createSurfaceControl(SurfaceControl outSurfaceControl, int result,
WindowState win, WindowStateAnimator winAnimator) {
if (!win.mHasSurface) {
result |= RELAYOUT_RES_SURFACE_CHANGED;
@@ -2517,7 +2513,6 @@
}
if (surfaceController != null) {
surfaceController.getSurfaceControl(outSurfaceControl);
- surfaceController.getBLASTSurfaceControl(outBLASTSurfaceControl);
ProtoLog.i(WM_SHOW_TRANSACTIONS, "OUT SURFACE %s: copied", outSurfaceControl);
} else {
@@ -3714,16 +3709,52 @@
@Override
public void setFixedToUserRotation(int displayId, int fixedToUserRotation) {
if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
- "freezeRotation()")) {
+ "setFixedToUserRotation()")) {
throw new SecurityException("Requires SET_ORIENTATION permission");
}
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final DisplayContent display = mRoot.getDisplayContent(displayId);
+ if (display == null) {
+ Slog.w(TAG, "Trying to set rotate for app for a missing display.");
+ return;
+ }
+ display.getDisplayRotation().setFixedToUserRotation(fixedToUserRotation);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
+ public void setIgnoreOrientationRequest(int displayId, boolean ignoreOrientationRequest) {
+ mAtmInternal.enforceCallerIsRecentsOrHasPermission(
+ android.Manifest.permission.SET_ORIENTATION, "setIgnoreOrientationRequest()");
+
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final DisplayContent display = mRoot.getDisplayContent(displayId);
+ if (display == null) {
+ Slog.w(TAG, "Trying to setIgnoreOrientationRequest() for a missing display.");
+ return;
+ }
+ display.setIgnoreOrientationRequest(ignoreOrientationRequest);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ boolean getIgnoreOrientationRequest(int displayId) {
synchronized (mGlobalLock) {
final DisplayContent display = mRoot.getDisplayContent(displayId);
if (display == null) {
- Slog.w(TAG, "Trying to set rotate for app for a missing display.");
- return;
+ Slog.w(TAG, "Trying to getIgnoreOrientationRequest() for a missing display.");
+ return false;
}
- display.getDisplayRotation().setFixedToUserRotation(fixedToUserRotation);
+ return display.getIgnoreOrientationRequest();
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 506e0dd..fa1c50f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -106,6 +106,10 @@
return runSetDisplayUserRotation(pw);
case "set-fix-to-user-rotation":
return runSetFixToUserRotation(pw);
+ case "set-ignore-orientation-request":
+ return runSetIgnoreOrientationRequest(pw);
+ case "get-ignore-orientation-request":
+ return runGetIgnoreOrientationRequest(pw);
case "dump-visible-window-views":
return runDumpVisibleWindowViews(pw);
default:
@@ -368,6 +372,47 @@
return 0;
}
+ private int runSetIgnoreOrientationRequest(PrintWriter pw) throws RemoteException {
+ int displayId = Display.DEFAULT_DISPLAY;
+ String arg = getNextArgRequired();
+ if ("-d".equals(arg)) {
+ displayId = Integer.parseInt(getNextArgRequired());
+ arg = getNextArgRequired();
+ }
+
+ final boolean ignoreOrientationRequest;
+ switch (arg) {
+ case "true":
+ case "1":
+ ignoreOrientationRequest = true;
+ break;
+ case "false":
+ case "0":
+ ignoreOrientationRequest = false;
+ break;
+ default:
+ getErrPrintWriter().println("Error: expecting true, 1, false, 0, but we "
+ + "get " + arg);
+ return -1;
+ }
+
+ mInterface.setIgnoreOrientationRequest(displayId, ignoreOrientationRequest);
+ return 0;
+ }
+
+ private int runGetIgnoreOrientationRequest(PrintWriter pw) throws RemoteException {
+ int displayId = Display.DEFAULT_DISPLAY;
+ String arg = getNextArg();
+ if ("-d".equals(arg)) {
+ displayId = Integer.parseInt(getNextArgRequired());
+ }
+
+ final boolean ignoreOrientationRequest = mInternal.getIgnoreOrientationRequest(displayId);
+ pw.println("ignoreOrientationRequest " + ignoreOrientationRequest
+ + " for displayId=" + displayId);
+ return 0;
+ }
+
private int runDumpVisibleWindowViews(PrintWriter pw) {
if (!mInternal.checkCallingPermission(android.Manifest.permission.DUMP,
"runDumpVisibleWindowViews()")) {
@@ -433,8 +478,11 @@
pw.println(" Set user rotation mode and user rotation.");
pw.println(" dump-visible-window-views");
pw.println(" Dumps the encoded view hierarchies of visible windows");
- pw.println(" set-fix-to-user-rotation [-d DISPLAY_ID] [enabled|disabled]");
+ pw.println(" set-fix-to-user-rotation [-d DISPLAY_ID] [enabled|disabled|default]");
pw.println(" Enable or disable rotating display for app requested orientation.");
+ pw.println(" set-ignore-orientation-request [-d DISPLAY_ID] [true|1|false|0]");
+ pw.println(" get-ignore-orientation-request [-d DISPLAY_ID] ");
+ pw.println(" If app requested orientation should be ignored.");
if (!IS_USER) {
pw.println(" tracing (start | stop)");
pw.println(" Start or stop window tracing.");
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 0b200e2..5e07f51 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -207,7 +207,7 @@
final Map.Entry<IBinder, WindowContainerTransaction.Change> entry =
entries.next();
final WindowContainer wc = WindowContainer.fromBinder(entry.getKey());
- if (!wc.isAttached()) {
+ if (wc == null || !wc.isAttached()) {
Slog.e(TAG, "Attempt to operate on detached container: " + wc);
continue;
}
@@ -380,24 +380,18 @@
return effects;
}
- private int applyTaskDisplayAreaChanges(TaskDisplayArea taskDisplayArea,
- WindowContainerTransaction.Change c) {
- int effects = applyDisplayAreaChanges(taskDisplayArea, c);
- if ((c.getChangeMask()
- & WindowContainerTransaction.Change.CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) {
- if (taskDisplayArea.setIgnoreOrientationRequest(c.getIgnoreOrientationRequest())) {
- effects |= TRANSACT_EFFECTS_LIFECYCLE;
- }
- }
-
- return effects;
- }
-
- private int applyDisplayAreaChanges(WindowContainer container,
+ private int applyDisplayAreaChanges(DisplayArea displayArea,
WindowContainerTransaction.Change c) {
final int[] effects = new int[1];
- container.forAllTasks(task -> {
+ if ((c.getChangeMask()
+ & WindowContainerTransaction.Change.CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) {
+ if (displayArea.setIgnoreOrientationRequest(c.getIgnoreOrientationRequest())) {
+ effects[0] |= TRANSACT_EFFECTS_LIFECYCLE;
+ }
+ }
+
+ displayArea.forAllTasks(task -> {
Task tr = (Task) task;
if ((c.getChangeMask() & WindowContainerTransaction.Change.CHANGE_HIDDEN) != 0) {
if (tr.setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, c.getHidden())) {
@@ -475,10 +469,8 @@
int effects = applyChanges(wc, c);
- if (wc instanceof TaskDisplayArea) {
- effects |= applyTaskDisplayAreaChanges((TaskDisplayArea) wc, c);
- } else if (wc instanceof DisplayArea) {
- effects |= applyDisplayAreaChanges(wc, c);
+ if (wc instanceof DisplayArea) {
+ effects |= applyDisplayAreaChanges(wc.asDisplayArea(), c);
} else if (wc instanceof Task) {
effects |= applyTaskChanges(wc.asTask(), c);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 0b53bf6..25b4828 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2172,16 +2172,7 @@
}
}
- @Override
- void forceWindowsScaleableInTransaction(boolean force) {
- if (mWinAnimator != null && mWinAnimator.hasSurface()) {
- mWinAnimator.mSurfaceController.forceScaleableInTransaction(force);
- }
-
- super.forceWindowsScaleableInTransaction(force);
- }
-
- @Override
+ @Override
void removeImmediately() {
super.removeImmediately();
@@ -5779,7 +5770,7 @@
}
SurfaceControl getClientViewRootSurface() {
- return mWinAnimator.getClientViewRootSurface();
+ return mWinAnimator.getSurfaceControl();
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index f342976..972d0d4 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -359,8 +359,8 @@
// surface before destroying it.
if (mSurfaceController != null && mPendingDestroySurface != null) {
mPostDrawTransaction.reparentChildren(
- mSurfaceController.getClientViewRootSurface(),
- mPendingDestroySurface.getClientViewRootSurface()).apply();
+ mSurfaceController.mSurfaceControl,
+ mPendingDestroySurface.mSurfaceControl).apply();
}
destroySurfaceLocked();
mSurfaceDestroyDeferred = true;
@@ -371,7 +371,7 @@
// Our SurfaceControl is always at layer 0 within the parent Surface managed by
// window-state. We want this old Surface to stay on top of the new one
// until we do the swap, so we place it at a positive layer.
- t.setLayer(mSurfaceController.getClientViewRootSurface(), PRESERVED_SURFACE_LAYER);
+ t.setLayer(mSurfaceController.mSurfaceControl, PRESERVED_SURFACE_LAYER);
}
mDestroyPreservedSurfaceUponRedraw = true;
mSurfaceDestroyDeferred = true;
@@ -393,8 +393,8 @@
&& !mPendingDestroySurface.mChildrenDetached
&& (mWin.mActivityRecord == null || !mWin.mActivityRecord.isRelaunching())) {
mPostDrawTransaction.reparentChildren(
- mPendingDestroySurface.getClientViewRootSurface(),
- mSurfaceController.getClientViewRootSurface()).apply();
+ mPendingDestroySurface.mSurfaceControl,
+ mSurfaceController.mSurfaceControl).apply();
}
destroyDeferredSurfaceLocked();
@@ -971,10 +971,6 @@
* @return Returns true if the surface was successfully shown.
*/
private boolean showSurfaceRobustlyLocked() {
- if (mWin.getWindowConfiguration().windowsAreScaleable()) {
- mSurfaceController.forceScaleableInTransaction(true);
- }
-
boolean shown = mSurfaceController.showRobustlyInTransaction();
if (!shown)
return false;
@@ -988,8 +984,8 @@
// Instead let the children get removed when the old surface is deleted.
if (!mPendingDestroySurface.mChildrenDetached) {
mPostDrawTransaction.reparentChildren(
- mPendingDestroySurface.getClientViewRootSurface(),
- mSurfaceController.getClientViewRootSurface());
+ mPendingDestroySurface.mSurfaceControl,
+ mSurfaceController.mSurfaceControl);
}
}
@@ -1205,10 +1201,10 @@
mOffsetPositionForStackResize = offsetPositionForStackResize;
}
- SurfaceControl getClientViewRootSurface() {
+ SurfaceControl getSurfaceControl() {
if (!hasSurface()) {
return null;
}
- return mSurfaceController.getClientViewRootSurface();
+ return mSurfaceController.mSurfaceControl;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index cbe0a42..feecda7 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -50,11 +50,6 @@
SurfaceControl mSurfaceControl;
- /**
- * WM only uses for deferred transactions.
- */
- SurfaceControl mBLASTSurfaceControl;
-
// Should only be set from within setShown().
private boolean mSurfaceShown = false;
private float mSurfaceX = 0;
@@ -112,22 +107,13 @@
final boolean useBLAST = mService.mUseBLAST && ((win.getAttrs().privateFlags &
WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST) != 0);
+
if (useBLAST) {
- b.setContainerLayer();
+ b.setBLASTLayer();
}
mSurfaceControl = b.build();
- if (useBLAST) {
- mBLASTSurfaceControl = win.makeSurface()
- .setParent(mSurfaceControl)
- .setName(name + "(BLAST)")
- .setHidden(false)
- .setBLASTLayer()
- .setCallsite("WindowSurfaceController")
- .build();
- }
-
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
@@ -172,9 +158,6 @@
} finally {
setShown(false);
mSurfaceControl = null;
- if (mBLASTSurfaceControl != null) {
- mBLASTSurfaceControl.release();
- }
}
}
@@ -342,11 +325,9 @@
return false;
}
- void forceScaleableInTransaction(boolean force) {
- // -1 means we don't override the default or client specified
- // scaling mode.
- int scalingMode = force ? SCALING_MODE_SCALE_TO_WINDOW : -1;
- mSurfaceControl.setOverrideScalingMode(scalingMode);
+ void deferTransactionUntil(SurfaceControl barrier, long frame) {
+ // TODO: Logging
+ mSurfaceControl.deferTransactionUntil(barrier, frame);
}
boolean clearWindowContentFrameStats() {
@@ -371,12 +352,6 @@
outSurfaceControl.copyFrom(mSurfaceControl, "WindowSurfaceController.getSurfaceControl");
}
- void getBLASTSurfaceControl(SurfaceControl outSurfaceControl) {
- if (mBLASTSurfaceControl != null) {
- outSurfaceControl.copyFrom(mBLASTSurfaceControl, "WindowSurfaceController.getBLASTSurfaceControl");
- }
- }
-
boolean getShown() {
return mSurfaceShown;
}
@@ -401,21 +376,6 @@
return mSurfaceH;
}
- /**
- * Returns the Surface which the client-framework ViewRootImpl will be using.
- * This is either the WSA SurfaceControl or it's BLAST child surface.
- * This has too main uses:
- * 1. This is the Surface the client will add children to, we use this to make
- * sure we don't reparent the BLAST surface itself when calling reparentChildren
- * 2. We use this as the barrier Surface for some deferTransaction operations.
- */
- SurfaceControl getClientViewRootSurface() {
- if (mBLASTSurfaceControl != null) {
- return mBLASTSurfaceControl;
- }
- return mSurfaceControl;
- }
-
void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
proto.write(SHOWN, mSurfaceShown);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 36ff974..177b7b4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1569,10 +1569,15 @@
}
/**
- * Creates a new {@link CallerIdentity} object to represent the caller's identity. If no
- * component name is provided, look up the component name and fill it in for the caller.
+ * Creates a new {@link CallerIdentity} object to represent the caller's identity, which should
+ * be an admin of a profile on the device. If no component name is provided, look up the
+ * component name and fill it in for the caller.
+ *
+ * Note: this method should only be called when the expected caller is an admin.
+ *
+ * @throws SecurityException if the caller is not an active admin.
*/
- private CallerIdentity getCallerIdentityOptionalAdmin(@Nullable ComponentName adminComponent) {
+ private CallerIdentity getAdminCallerIdentity(@Nullable ComponentName adminComponent) {
if (adminComponent == null) {
ActiveAdmin admin = getActiveAdminOfCaller();
if (admin != null) {
@@ -1586,24 +1591,66 @@
/**
* Creates a new {@link CallerIdentity} object to represent the caller's identity. If no
- * package name is provided, look up the package name and fill it in for the caller.
+ * component name is provided, look up the component name and fill it in for the caller.
+ *
+ * Note: this method should only be called when the caller may not be an admin. If the caller
+ * is not an admin, the ComponentName in the returned identity will be null.
*/
- private CallerIdentity getCallerIdentityOptionalPackage(@Nullable String callerPackage) {
+ private CallerIdentity getNonPrivilegedOrAdminCallerIdentity(
+ @Nullable ComponentName adminComponent) {
+ if (adminComponent == null) {
+ ActiveAdmin admin = getActiveAdminOfCaller();
+ if (admin != null) {
+ adminComponent = admin.info.getComponent();
+ } else {
+ return getCallerIdentity();
+ }
+ }
+ return getCallerIdentity(adminComponent);
+
+ }
+
+ /**
+ * Creates a new {@link CallerIdentity} object to represent the caller's identity. If no
+ * package name is provided, look up the package name and fill it in for the caller.
+ *
+ * Note: this method should only be called when the expected caller is an admin.
+ *
+ * @throws SecurityException if the caller is not an active admin.
+ */
+ private CallerIdentity getAdminCallerIdentityUsingPackage(@Nullable String callerPackage) {
if (callerPackage == null) {
ActiveAdmin admin = getActiveAdminOfCaller();
if (admin != null) {
return getCallerIdentity(admin.info.getPackageName());
}
throw new SecurityException("Caller is not an active admin");
- } else {
- return getCallerIdentity(callerPackage);
}
+ return getCallerIdentity(callerPackage);
+ }
+
+ /**
+ * Creates a new {@link CallerIdentity} object to represent the caller's identity. If no
+ * package name is provided, look up the package name and fill it in for the caller.
+ */
+ private CallerIdentity getNonPrivilegedOrAdminCallerIdentityUsingPackage(
+ @Nullable String callerPackage) {
+ if (callerPackage == null) {
+ ActiveAdmin admin = getActiveAdminOfCaller();
+ if (admin != null) {
+ callerPackage = admin.info.getPackageName();
+ } else {
+ return getCallerIdentity();
+ }
+ }
+ return getCallerIdentity(callerPackage);
}
/**
* Retrieves the active admin of the caller. This method should not be called directly and
- * should only be called by {@link #getCallerIdentityOptionalAdmin} or
- * {@link #getCallerIdentityOptionalPackage}.
+ * should only be called by {@link #getAdminCallerIdentity},
+ * {@link #getNonPrivilegedOrAdminCallerIdentity}, {@link #getAdminCallerIdentityUsingPackage}
+ * or {@link #getNonPrivilegedOrAdminCallerIdentityUsingPackage}.
*/
private ActiveAdmin getActiveAdminOfCaller() {
final int callerUid = mInjector.binderGetCallingUid();
@@ -6023,7 +6070,7 @@
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity caller = getCallerIdentityOptionalAdmin(comp);
+ final CallerIdentity caller = getAdminCallerIdentity(comp);
Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
@@ -6463,12 +6510,12 @@
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity caller = getCallerIdentityOptionalAdmin(who);
+ final CallerIdentity caller = getAdminCallerIdentity(who);
Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
// Check for permissions if a particular caller is specified
- if (who != null) {
+ if (caller.hasAdminComponent()) {
// When checking for a single caller, status is based on caller's request
ActiveAdmin ap = getActiveAdminUncheckedLocked(who, userHandle);
return ap != null ? ap.encryptionRequested : false;
@@ -6497,7 +6544,7 @@
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity caller = getCallerIdentityOptionalPackage(callerPackage);
+ final CallerIdentity caller = getAdminCallerIdentityUsingPackage(callerPackage);
Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
// It's not critical here, but let's make sure the package name is correct, in case
@@ -8614,12 +8661,12 @@
Objects.requireNonNull(agent, "agent null");
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity caller = getCallerIdentityOptionalAdmin(admin);
+ final CallerIdentity caller = getAdminCallerIdentity(admin);
Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
final String componentName = agent.flattenToString();
- if (admin != null) {
+ if (caller.hasAdminComponent()) {
final ActiveAdmin ap = getActiveAdminUncheckedLocked(admin, userHandle, parent);
if (ap == null) return null;
TrustAgentInfo trustAgentInfo = ap.trustAgentInfos.get(componentName);
diff --git a/services/net/TEST_MAPPING b/services/net/TEST_MAPPING
new file mode 100644
index 0000000..7025dd1
--- /dev/null
+++ b/services/net/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/base/core/java/android/net"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index 09e3bfe..7d17109 100644
--- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -41,6 +41,7 @@
import static com.android.server.backup.testing.Utils.transferStreamedData;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -2880,8 +2881,8 @@
}
private static IterableSubject assertDirectory(Path directory) throws IOException {
- return assertThat(oneTimeIterable(Files.newDirectoryStream(directory).iterator()))
- .named("directory " + directory);
+ return assertWithMessage("directory " + directory).that(
+ oneTimeIterable(Files.newDirectoryStream(directory).iterator()));
}
private static void assertJournalDoesNotContain(
diff --git a/services/robotests/backup/src/com/android/server/backup/testing/TestUtils.java b/services/robotests/backup/src/com/android/server/backup/testing/TestUtils.java
index 3fe1f3f..3114a75 100644
--- a/services/robotests/backup/src/com/android/server/backup/testing/TestUtils.java
+++ b/services/robotests/backup/src/com/android/server/backup/testing/TestUtils.java
@@ -17,6 +17,7 @@
package com.android.server.backup.testing;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import static org.robolectric.Shadows.shadowOf;
@@ -95,8 +96,8 @@
* logcat before that.
*/
public static void assertLogcatAtMost(String tag, int level) {
- assertThat(ShadowLog.getLogsForTag(tag).stream().allMatch(logItem -> logItem.type <= level))
- .named("All logs <= " + level)
+ assertWithMessage("All logs <= " + level).that(
+ ShadowLog.getLogsForTag(tag).stream().allMatch(logItem -> logItem.type <= level))
.isTrue();
}
@@ -105,8 +106,8 @@
* logcat before that.
*/
public static void assertLogcatAtLeast(String tag, int level) {
- assertThat(ShadowLog.getLogsForTag(tag).stream().anyMatch(logItem -> logItem.type >= level))
- .named("Any log >= " + level)
+ assertWithMessage("Any log >= " + level).that(
+ ShadowLog.getLogsForTag(tag).stream().anyMatch(logItem -> logItem.type >= level))
.isTrue();
}
@@ -121,11 +122,10 @@
* that uses logcat before that.
*/
public static void assertLogcat(String tag, int... logs) {
- assertThat(
+ assertWithMessage("Log items (specified per level)").that(
ShadowLog.getLogsForTag(tag).stream()
.map(logItem -> logItem.type)
.collect(toSet()))
- .named("Log items (specified per level)")
.containsExactly(IntStream.of(logs).boxed().toArray());
}
@@ -135,15 +135,13 @@
/** Declare shadow {@link ShadowEventLog} to use this. */
public static void assertEventLogged(int tag, Object... values) {
- assertThat(ShadowEventLog.getEntries())
- .named("Event logs")
+ assertWithMessage("Event logs").that(ShadowEventLog.getEntries())
.contains(new ShadowEventLog.Entry(tag, Arrays.asList(values)));
}
/** Declare shadow {@link ShadowEventLog} to use this. */
public static void assertEventNotLogged(int tag, Object... values) {
- assertThat(ShadowEventLog.getEntries())
- .named("Event logs")
+ assertWithMessage("Event logs").that(ShadowEventLog.getEntries())
.doesNotContain(new ShadowEventLog.Entry(tag, Arrays.asList(values)));
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index d61783e..a5f0834 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -48,10 +48,13 @@
import static com.android.server.alarm.AlarmManagerService.IS_WAKEUP_MASK;
import static com.android.server.alarm.AlarmManagerService.TIME_CHANGED_MASK;
import static com.android.server.alarm.AlarmManagerService.WORKING_INDEX;
+import static com.android.server.alarm.Constants.TEST_CALLING_PACKAGE;
+import static com.android.server.alarm.Constants.TEST_CALLING_UID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
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.anyLong;
@@ -82,6 +85,7 @@
import android.platform.test.annotations.Presubmit;
import android.provider.DeviceConfig;
import android.provider.Settings;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.SparseArray;
@@ -108,6 +112,8 @@
import org.mockito.quality.Strictness;
import org.mockito.stubbing.Answer;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.concurrent.Executor;
@@ -116,9 +122,7 @@
@RunWith(AndroidJUnit4.class)
public class AlarmManagerServiceTest {
private static final String TAG = AlarmManagerServiceTest.class.getSimpleName();
- private static final String TEST_CALLING_PACKAGE = "com.android.framework.test-package";
private static final int SYSTEM_UI_UID = 12345;
- private static final int TEST_CALLING_UID = 67890;
private static final int TEST_CALLING_USER = UserHandle.getUserId(TEST_CALLING_UID);
private long mAppStandbyWindow;
@@ -350,19 +354,31 @@
}
private void setTestAlarm(int type, long triggerTime, PendingIntent operation) {
- setTestAlarm(type, triggerTime, operation, 0, TEST_CALLING_UID);
+ setTestAlarm(type, triggerTime, operation, 0, AlarmManager.FLAG_STANDALONE,
+ TEST_CALLING_UID);
}
private void setRepeatingTestAlarm(int type, long firstTrigger, long interval,
PendingIntent pi) {
- setTestAlarm(type, firstTrigger, pi, interval, TEST_CALLING_UID);
+ setTestAlarm(type, firstTrigger, pi, interval, AlarmManager.FLAG_STANDALONE,
+ TEST_CALLING_UID);
+ }
+
+ private void setIdleUntilAlarm(int type, long triggerTime, PendingIntent pi) {
+ setTestAlarm(type, triggerTime, pi, 0, AlarmManager.FLAG_IDLE_UNTIL, TEST_CALLING_UID);
+ }
+
+ private void setWakeFromIdle(int type, long triggerTime, PendingIntent pi) {
+ // Note: Only alarm clock alarms are allowed to include this flag in the actual service.
+ // But this is a unit test so we'll only test the flag for granularity and convenience.
+ setTestAlarm(type, triggerTime, pi, 0,
+ AlarmManager.FLAG_WAKE_FROM_IDLE | AlarmManager.FLAG_STANDALONE, TEST_CALLING_UID);
}
private void setTestAlarm(int type, long triggerTime, PendingIntent operation, long interval,
- int callingUid) {
- mService.setImpl(type, triggerTime, AlarmManager.WINDOW_EXACT, interval,
- operation, null, "test", AlarmManager.FLAG_STANDALONE, null, null,
- callingUid, TEST_CALLING_PACKAGE);
+ int flags, int callingUid) {
+ mService.setImpl(type, triggerTime, AlarmManager.WINDOW_EXACT, interval, operation, null,
+ "test", flags, null, null, callingUid, TEST_CALLING_PACKAGE);
}
private void setTestAlarmWithListener(int type, long triggerTime, IAlarmListener listener) {
@@ -1002,7 +1018,7 @@
for (int i = 0; i < numAlarms; i++) {
int mockUid = UserHandle.getUid(mockUserId, 1234 + i);
setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10,
- getNewMockPendingIntent(mockUid), 0, mockUid);
+ getNewMockPendingIntent(mockUid), 0, AlarmManager.FLAG_STANDALONE, mockUid);
}
assertEquals(numAlarms, mService.mAlarmsPerUid.size());
mService.removeUserLocked(mockUserId);
@@ -1142,6 +1158,116 @@
}
}
+ @Test
+ public void singleIdleUntil() {
+ doReturn(0).when(mService).fuzzForDuration(anyLong());
+
+ final PendingIntent idleUntilPi6 = getNewMockPendingIntent();
+ setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 6, idleUntilPi6);
+
+ assertTrue(mService.mPendingIdleUntil.matches(idleUntilPi6, null));
+ assertEquals(mNowElapsedTest + 6, mTestTimer.getElapsed());
+ assertEquals(mNowElapsedTest + 6, mService.mPendingIdleUntil.getWhenElapsed());
+
+ final PendingIntent idleUntilPi2 = getNewMockPendingIntent();
+ setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 2, idleUntilPi2);
+
+ // The same mPendingIdleUntil should get updated, even with a different PendingIntent.
+ assertTrue(mService.mPendingIdleUntil.matches(idleUntilPi2, null));
+ assertEquals(mNowElapsedTest + 2, mTestTimer.getElapsed());
+ assertEquals(1, mService.mAlarmStore.size());
+
+ final PendingIntent idleUntilPi10 = getNewMockPendingIntent();
+ setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 10, idleUntilPi10);
+
+ // The same thing should happen even when the new alarm is in farther in the future.
+ assertTrue(mService.mPendingIdleUntil.matches(idleUntilPi10, null));
+ assertEquals(mNowElapsedTest + 10, mTestTimer.getElapsed());
+ assertEquals(1, mService.mAlarmStore.size());
+ }
+
+ @Test
+ public void nextWakeFromIdle() throws Exception {
+ assertNull(mService.mNextWakeFromIdle);
+
+ final PendingIntent wakeFromIdle6 = getNewMockPendingIntent();
+ final long trigger6 = mNowElapsedTest + 6;
+ setWakeFromIdle(ELAPSED_REALTIME_WAKEUP, trigger6, wakeFromIdle6);
+
+ assertTrue(mService.mNextWakeFromIdle.matches(wakeFromIdle6, null));
+ assertEquals(trigger6, mService.mNextWakeFromIdle.getWhenElapsed());
+ assertEquals(trigger6, mTestTimer.getElapsed());
+
+ final PendingIntent wakeFromIdle10 = getNewMockPendingIntent();
+ final long trigger10 = mNowElapsedTest + 10;
+ setWakeFromIdle(ELAPSED_REALTIME_WAKEUP, trigger10, wakeFromIdle10);
+
+ // mNextWakeFromIdle should not get updated.
+ assertTrue(mService.mNextWakeFromIdle.matches(wakeFromIdle6, null));
+ assertEquals(trigger6, mTestTimer.getElapsed());
+ assertEquals(trigger6, mService.mNextWakeFromIdle.getWhenElapsed());
+
+ final PendingIntent wakeFromIdle3 = getNewMockPendingIntent();
+ final long trigger3 = mNowElapsedTest + 3;
+ setWakeFromIdle(ELAPSED_REALTIME_WAKEUP, trigger3, wakeFromIdle3);
+
+ // mNextWakeFromIdle should always reflect the next earliest wake_from_idle alarm.
+ assertTrue(mService.mNextWakeFromIdle.matches(wakeFromIdle3, null));
+ assertEquals(trigger3, mTestTimer.getElapsed());
+ assertEquals(trigger3, mService.mNextWakeFromIdle.getWhenElapsed());
+
+ mNowElapsedTest = trigger3;
+ mTestTimer.expire();
+
+ assertTrue(mService.mNextWakeFromIdle.matches(wakeFromIdle6, null));
+ assertEquals(trigger6, mTestTimer.getElapsed());
+ assertEquals(trigger6, mService.mNextWakeFromIdle.getWhenElapsed());
+
+ mService.removeLocked(wakeFromIdle6, null);
+
+ assertTrue(mService.mNextWakeFromIdle.matches(wakeFromIdle10, null));
+ assertEquals(trigger10, mTestTimer.getElapsed());
+ assertEquals(trigger10, mService.mNextWakeFromIdle.getWhenElapsed());
+
+ mService.removeLocked(wakeFromIdle10, null);
+ assertNull(mService.mNextWakeFromIdle);
+ }
+
+ @Test
+ public void idleUntilBeforeWakeFromIdle() {
+ doReturn(0).when(mService).fuzzForDuration(anyLong());
+
+ final PendingIntent idleUntilPi = getNewMockPendingIntent();
+ final long requestedIdleUntil = mNowElapsedTest + 10;
+ setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, requestedIdleUntil, idleUntilPi);
+
+ assertEquals(requestedIdleUntil, mService.mPendingIdleUntil.getWhenElapsed());
+
+ final PendingIntent wakeFromIdle5 = getNewMockPendingIntent();
+ setWakeFromIdle(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 5, wakeFromIdle5);
+ assertEquals(mNowElapsedTest + 5, mService.mPendingIdleUntil.getWhenElapsed());
+
+ final PendingIntent wakeFromIdle8 = getNewMockPendingIntent();
+ setWakeFromIdle(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 8, wakeFromIdle8);
+ assertEquals(mNowElapsedTest + 5, mService.mPendingIdleUntil.getWhenElapsed());
+
+ final PendingIntent wakeFromIdle12 = getNewMockPendingIntent();
+ setWakeFromIdle(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 12, wakeFromIdle12);
+ assertEquals(mNowElapsedTest + 5, mService.mPendingIdleUntil.getWhenElapsed());
+
+ mService.removeLocked(wakeFromIdle5, null);
+ assertEquals(mNowElapsedTest + 8, mService.mPendingIdleUntil.getWhenElapsed());
+
+ mService.removeLocked(wakeFromIdle8, null);
+ assertEquals(requestedIdleUntil, mService.mPendingIdleUntil.getWhenElapsed());
+
+ mService.removeLocked(idleUntilPi, null);
+ assertNull(mService.mPendingIdleUntil);
+
+ setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 15, idleUntilPi);
+ assertEquals(mNowElapsedTest + 12, mService.mPendingIdleUntil.getWhenElapsed());
+ }
+
@After
public void tearDown() {
if (mMockingSession != null) {
@@ -1149,4 +1275,12 @@
}
LocalServices.removeServiceForTest(AlarmManagerInternal.class);
}
+
+ private void dumpAllAlarms(String tag, ArrayList<Alarm> alarms) {
+ System.out.println(tag + ": ");
+ IndentingPrintWriter ipw = new IndentingPrintWriter(new PrintWriter(System.out));
+ AlarmManagerService.dumpAlarmList(ipw, alarms, mNowElapsedTest,
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"));
+ ipw.close();
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java
index 9e43b4a..f0490ce 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java
@@ -16,6 +16,9 @@
package com.android.server.alarm;
+import static com.android.server.alarm.Constants.TEST_CALLING_PACKAGE;
+import static com.android.server.alarm.Constants.TEST_CALLING_UID;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
@@ -35,9 +38,6 @@
@Presubmit
@RunWith(AndroidJUnit4.class)
public class AlarmStoreTest {
- private static final int TEST_CALLING_UID = 12345;
- private static final String TEST_CALLING_PACKAGE = "android.alarm.unit.test";
-
private AlarmStore mAlarmStore;
@Before
@@ -45,22 +45,22 @@
mAlarmStore = new BatchingAlarmStore(null);
}
- private static Alarm createAlarm(long whenElapsed, long windowLength, PendingIntent mockPi,
+ private static Alarm createAlarm(long whenElapsed, long windowLength,
AlarmManager.AlarmClockInfo alarmClock) {
- return createAlarm(AlarmManager.ELAPSED_REALTIME, whenElapsed, windowLength, mockPi,
+ return createAlarm(AlarmManager.ELAPSED_REALTIME, whenElapsed, windowLength,
alarmClock);
}
private static Alarm createWakeupAlarm(long whenElapsed, long windowLength,
- PendingIntent mockPi, AlarmManager.AlarmClockInfo alarmClock) {
- return createAlarm(AlarmManager.ELAPSED_REALTIME_WAKEUP, whenElapsed, windowLength, mockPi,
+ AlarmManager.AlarmClockInfo alarmClock) {
+ return createAlarm(AlarmManager.ELAPSED_REALTIME_WAKEUP, whenElapsed, windowLength,
alarmClock);
}
private static Alarm createAlarm(int type, long whenElapsed, long windowLength,
- PendingIntent mockPi, AlarmManager.AlarmClockInfo alarmClock) {
- return new Alarm(type, whenElapsed, whenElapsed, windowLength, whenElapsed + windowLength,
- 0, mockPi, null, null, null, 0, alarmClock, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
+ AlarmManager.AlarmClockInfo alarmClock) {
+ return new Alarm(type, whenElapsed, whenElapsed, windowLength, 0, mock(PendingIntent.class),
+ null, null, null, 0, alarmClock, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
}
private void addAlarmsToStore(Alarm... alarms) {
@@ -71,11 +71,11 @@
@Test
public void add() {
- final Alarm a1 = createAlarm(1, 0, mock(PendingIntent.class), null);
+ final Alarm a1 = createAlarm(1, 0, null);
mAlarmStore.add(a1);
assertEquals(1, mAlarmStore.size());
- final Alarm a2 = createAlarm(2, 0, mock(PendingIntent.class), null);
+ final Alarm a2 = createAlarm(2, 0, null);
mAlarmStore.add(a2);
assertEquals(2, mAlarmStore.size());
@@ -86,17 +86,17 @@
@Test
public void remove() {
- final Alarm a1 = createAlarm(1, 0, mock(PendingIntent.class), null);
- final Alarm a2 = createAlarm(2, 0, mock(PendingIntent.class), null);
- final Alarm a5 = createAlarm(5, 0, mock(PendingIntent.class), null);
+ final Alarm a1 = createAlarm(1, 0, null);
+ final Alarm a2 = createAlarm(2, 0, null);
+ final Alarm a5 = createAlarm(5, 0, null);
addAlarmsToStore(a1, a2, a5);
- ArrayList<Alarm> removed = mAlarmStore.remove(a -> (a.whenElapsed < 4));
+ ArrayList<Alarm> removed = mAlarmStore.remove(a -> (a.getWhenElapsed() < 4));
assertEquals(2, removed.size());
assertEquals(1, mAlarmStore.size());
assertTrue(removed.contains(a1) && removed.contains(a2));
- final Alarm a8 = createAlarm(8, 0, mock(PendingIntent.class), null);
+ final Alarm a8 = createAlarm(8, 0, null);
addAlarmsToStore(a8, a2, a1);
removed = mAlarmStore.remove(unused -> false);
@@ -110,10 +110,10 @@
@Test
public void removePendingAlarms() {
- final Alarm a1_11 = createAlarm(1, 10, mock(PendingIntent.class), null);
- final Alarm a2_5 = createAlarm(2, 3, mock(PendingIntent.class), null);
- final Alarm a6_9 = createAlarm(6, 3, mock(PendingIntent.class), null);
- addAlarmsToStore(a2_5, a6_9, a1_11);
+ final Alarm a1to11 = createAlarm(1, 10, null);
+ final Alarm a2to5 = createAlarm(2, 3, null);
+ final Alarm a6to9 = createAlarm(6, 3, null);
+ addAlarmsToStore(a2to5, a6to9, a1to11);
final ArrayList<Alarm> pendingAt0 = mAlarmStore.removePendingAlarms(0);
assertEquals(0, pendingAt0.size());
@@ -121,24 +121,24 @@
final ArrayList<Alarm> pendingAt3 = mAlarmStore.removePendingAlarms(3);
assertEquals(2, pendingAt3.size());
- assertTrue(pendingAt3.contains(a1_11) && pendingAt3.contains(a2_5));
+ assertTrue(pendingAt3.contains(a1to11) && pendingAt3.contains(a2to5));
assertEquals(1, mAlarmStore.size());
- addAlarmsToStore(a2_5, a1_11);
+ addAlarmsToStore(a2to5, a1to11);
final ArrayList<Alarm> pendingAt7 = mAlarmStore.removePendingAlarms(7);
assertEquals(3, pendingAt7.size());
- assertTrue(pendingAt7.contains(a1_11) && pendingAt7.contains(a2_5) && pendingAt7.contains(
- a6_9));
+ assertTrue(pendingAt7.contains(a1to11) && pendingAt7.contains(a2to5) && pendingAt7.contains(
+ a6to9));
assertEquals(0, mAlarmStore.size());
}
@Test
public void getNextWakeupDeliveryTime() {
- final Alarm a1_10 = createAlarm(1, 9, mock(PendingIntent.class), null);
- final Alarm a3_8_wakeup = createWakeupAlarm(3, 5, mock(PendingIntent.class), null);
- final Alarm a6_wakeup = createWakeupAlarm(6, 0, mock(PendingIntent.class), null);
- final Alarm a5 = createAlarm(5, 0, mock(PendingIntent.class), null);
- addAlarmsToStore(a5, a6_wakeup, a3_8_wakeup, a1_10);
+ final Alarm a1to10 = createAlarm(1, 9, null);
+ final Alarm a3to8wakeup = createWakeupAlarm(3, 5, null);
+ final Alarm a6wakeup = createWakeupAlarm(6, 0, null);
+ final Alarm a5 = createAlarm(5, 0, null);
+ addAlarmsToStore(a5, a6wakeup, a3to8wakeup, a1to10);
// The wakeup alarms are [6] and [3, 8], hence 6 is the latest time till when we can
// defer delivering any wakeup alarm.
@@ -155,11 +155,11 @@
@Test
public void getNextDeliveryTime() {
- final Alarm a1_10 = createAlarm(1, 9, mock(PendingIntent.class), null);
- final Alarm a3_8_wakeup = createWakeupAlarm(3, 5, mock(PendingIntent.class), null);
- final Alarm a6_wakeup = createWakeupAlarm(6, 0, mock(PendingIntent.class), null);
- final Alarm a5 = createAlarm(5, 0, mock(PendingIntent.class), null);
- addAlarmsToStore(a5, a6_wakeup, a3_8_wakeup, a1_10);
+ final Alarm a1to10 = createAlarm(1, 9, null);
+ final Alarm a3to8wakeup = createWakeupAlarm(3, 5, null);
+ final Alarm a6wakeup = createWakeupAlarm(6, 0, null);
+ final Alarm a5 = createAlarm(5, 0, null);
+ addAlarmsToStore(a5, a6wakeup, a3to8wakeup, a1to10);
assertTrue(mAlarmStore.getNextDeliveryTime() <= 5);
@@ -168,24 +168,22 @@
}
@Test
- public void recalculateAlarmDeliveries() {
- final Alarm a5 = createAlarm(5, 0, mock(PendingIntent.class), null);
- final Alarm a8 = createAlarm(8, 0, mock(PendingIntent.class), null);
- final Alarm a10 = createAlarm(10, 0, mock(PendingIntent.class), null);
+ public void updateAlarmDeliveries() {
+ final Alarm a5 = createAlarm(5, 0, null);
+ final Alarm a8 = createAlarm(8, 0, null);
+ final Alarm a10 = createAlarm(10, 0, null);
addAlarmsToStore(a8, a10, a5);
assertEquals(5, mAlarmStore.getNextDeliveryTime());
- mAlarmStore.recalculateAlarmDeliveries(a -> {
- a.whenElapsed += 3;
- a.maxWhenElapsed = a.whenElapsed;
+ mAlarmStore.updateAlarmDeliveries(a -> {
+ a.setPolicyElapsed(Alarm.REQUESTER_POLICY_INDEX, a.getWhenElapsed() + 3);
return true;
});
assertEquals(8, mAlarmStore.getNextDeliveryTime());
- mAlarmStore.recalculateAlarmDeliveries(a -> {
- a.whenElapsed = 20 - a.whenElapsed;
- a.maxWhenElapsed = a.whenElapsed;
+ mAlarmStore.updateAlarmDeliveries(a -> {
+ a.setPolicyElapsed(Alarm.REQUESTER_POLICY_INDEX, 20 - a.getWhenElapsed());
return true;
});
assertEquals(7, mAlarmStore.getNextDeliveryTime());
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java
new file mode 100644
index 0000000..efcfae3
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2020 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.alarm;
+
+import static android.app.AlarmManager.ELAPSED_REALTIME;
+
+import static com.android.server.alarm.Alarm.APP_STANDBY_POLICY_INDEX;
+import static com.android.server.alarm.Alarm.REQUESTER_POLICY_INDEX;
+import static com.android.server.alarm.Constants.TEST_CALLING_PACKAGE;
+import static com.android.server.alarm.Constants.TEST_CALLING_UID;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import android.app.PendingIntent;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class AlarmTest {
+
+ private Alarm createDefaultAlarm(long requestedElapsed, long windowLength) {
+ return new Alarm(ELAPSED_REALTIME, 0, requestedElapsed, windowLength, 0,
+ mock(PendingIntent.class), null, null, null, 0, null, TEST_CALLING_UID,
+ TEST_CALLING_PACKAGE);
+ }
+
+ @Test
+ public void initSetsOnlyRequesterPolicy() {
+ final Alarm a = createDefaultAlarm(4567, 2);
+ assertEquals(4567, a.getPolicyElapsed(REQUESTER_POLICY_INDEX));
+ assertEquals(0, a.getPolicyElapsed(APP_STANDBY_POLICY_INDEX));
+ }
+
+ @Test
+ public void whenElapsed() {
+ final Alarm a = createDefaultAlarm(0, 0);
+
+ a.setPolicyElapsed(REQUESTER_POLICY_INDEX, 4);
+ a.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 10);
+ assertEquals(10, a.getWhenElapsed());
+
+ a.setPolicyElapsed(REQUESTER_POLICY_INDEX, 12);
+ assertEquals(12, a.getWhenElapsed());
+
+ a.setPolicyElapsed(REQUESTER_POLICY_INDEX, 7);
+ assertEquals(10, a.getWhenElapsed());
+
+ a.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 2);
+ assertEquals(7, a.getWhenElapsed());
+
+ a.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 7);
+ assertEquals(7, a.getWhenElapsed());
+ }
+
+ @Test
+ public void maxWhenElapsed() {
+ final Alarm a = createDefaultAlarm(10, 12);
+ assertEquals(22, a.getMaxWhenElapsed());
+
+ a.setPolicyElapsed(REQUESTER_POLICY_INDEX, 15);
+ assertEquals(27, a.getMaxWhenElapsed());
+
+ a.setPolicyElapsed(REQUESTER_POLICY_INDEX, 2);
+ assertEquals(14, a.getMaxWhenElapsed());
+
+ a.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 5);
+ assertEquals(14, a.getMaxWhenElapsed());
+
+ a.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 16);
+ assertEquals(16, a.getMaxWhenElapsed());
+
+ a.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 12);
+ assertEquals(14, a.getMaxWhenElapsed());
+ }
+
+ @Test
+ public void setPolicyElapsed() {
+ final Alarm exactAlarm = createDefaultAlarm(10, 0);
+
+ assertTrue(exactAlarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, 4));
+ assertTrue(exactAlarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 10));
+
+ assertFalse(exactAlarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, 8));
+ assertFalse(exactAlarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, 10));
+ assertFalse(exactAlarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 8));
+
+ assertTrue(exactAlarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, 7));
+
+ final Alarm inexactAlarm = createDefaultAlarm(10, 5);
+
+ assertTrue(inexactAlarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, 4));
+ assertTrue(inexactAlarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 10));
+
+ // whenElapsed won't change, but maxWhenElapsed will.
+ assertTrue(inexactAlarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, 8));
+ assertTrue(inexactAlarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, 10));
+
+ assertFalse(inexactAlarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 8));
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java
index 6465739..5bb6a42 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java
@@ -45,7 +45,7 @@
}
uidAlarms.add(new Alarm(
removeIt ? RTC : RTC_WAKEUP,
- 0, 0, 0, 0, 0, null, null, null, null, 0, null, uid, name));
+ 0, 0, 0, 0, null, null, null, null, 0, null, uid, name));
return all;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/Constants.java b/services/tests/mockingservicestests/src/com/android/server/alarm/Constants.java
new file mode 100644
index 0000000..2552db8
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/Constants.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2020 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.alarm;
+
+public interface Constants {
+ String TEST_CALLING_PACKAGE = "com.android.framework.test-package";
+ int TEST_CALLING_UID = 67890;
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationFudgerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationFudgerTest.java
index a0f48c6..d67eddd 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/LocationFudgerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationFudgerTest.java
@@ -79,7 +79,7 @@
Location coarse = mFudger.createCoarse(fine);
assertThat(coarse).isNotNull();
- assertThat(coarse).isNotSameAs(fine);
+ assertThat(coarse).isNotSameInstanceAs(fine);
assertThat(coarse.hasBearing()).isFalse();
assertThat(coarse.hasSpeed()).isFalse();
assertThat(coarse.hasAltitude()).isFalse();
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
index 31ec4a5..3aedd3c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
@@ -710,7 +710,6 @@
@Test
public void testProviderRequest() {
assertThat(mProvider.getRequest().isActive()).isFalse();
- assertThat(mProvider.getRequest().getLocationRequests()).isEmpty();
ILocationListener listener1 = createMockLocationListener();
LocationRequest request1 = new LocationRequest.Builder(5).setWorkSource(
@@ -718,7 +717,6 @@
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
assertThat(mProvider.getRequest().isActive()).isTrue();
- assertThat(mProvider.getRequest().getLocationRequests()).containsExactly(request1);
assertThat(mProvider.getRequest().isLocationSettingsIgnored()).isFalse();
assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(5);
assertThat(mProvider.getRequest().isLowPower()).isFalse();
@@ -732,8 +730,6 @@
mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
assertThat(mProvider.getRequest().isActive()).isTrue();
- assertThat(mProvider.getRequest().getLocationRequests()).containsExactly(request1,
- request2);
assertThat(mProvider.getRequest().isLocationSettingsIgnored()).isFalse();
assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(1);
assertThat(mProvider.getRequest().isLowPower()).isFalse();
@@ -742,7 +738,6 @@
mManager.unregisterLocationRequest(listener1);
assertThat(mProvider.getRequest().isActive()).isTrue();
- assertThat(mProvider.getRequest().getLocationRequests()).containsExactly(request2);
assertThat(mProvider.getRequest().isLocationSettingsIgnored()).isFalse();
assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(1);
assertThat(mProvider.getRequest().isLowPower()).isTrue();
@@ -751,7 +746,6 @@
mManager.unregisterLocationRequest(listener2);
assertThat(mProvider.getRequest().isActive()).isFalse();
- assertThat(mProvider.getRequest().getLocationRequests()).isEmpty();
}
@Test
@@ -855,7 +849,6 @@
mInjector.getSettingsHelper().setLocationEnabled(false, IDENTITY.getUserId());
assertThat(mProvider.getRequest().isActive()).isTrue();
- assertThat(mProvider.getRequest().getLocationRequests()).containsExactly(request2);
assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(5);
assertThat(mProvider.getRequest().isLocationSettingsIgnored()).isTrue();
}
diff --git a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
index c91bb93..9a2ce3c 100644
--- a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
@@ -223,6 +223,25 @@
}
@Test
+ public void testInterceptPowerKeyDown_firstPowerDown_panicGestureNotLaunched() {
+ withPanicGestureEnabledSettingValue(true);
+ mGestureLauncherService.updatePanicButtonGestureEnabled();
+
+ long eventTime = INITIAL_EVENT_TIME_MILLIS
+ + GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS - 1;
+ KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
+ IGNORED_REPEAT);
+ boolean interactive = true;
+ MutableBoolean outLaunched = new MutableBoolean(true);
+ boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
+ outLaunched);
+
+ assertFalse(intercepted);
+ assertFalse(outLaunched.value);
+ verify(mMetricsLogger).histogram("power_double_tap_interval", (int) eventTime);
+ }
+
+ @Test
public void testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOffInteractive() {
withCameraDoubleTapPowerEnableConfigValue(false);
withCameraDoubleTapPowerDisableSettingValue(1);
@@ -405,6 +424,146 @@
}
@Test
+ public void
+ testInterceptPowerKeyDown_fiveInboundPresses_cameraAndPanicEnabled_bothLaunch() {
+ withCameraDoubleTapPowerEnableConfigValue(true);
+ withCameraDoubleTapPowerDisableSettingValue(0);
+ withPanicGestureEnabledSettingValue(true);
+ mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
+ mGestureLauncherService.updatePanicButtonGestureEnabled();
+ withUserSetupCompleteValue(true);
+
+ // First button press does nothing
+ long eventTime = INITIAL_EVENT_TIME_MILLIS;
+ KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
+ IGNORED_REPEAT);
+ boolean interactive = true;
+ MutableBoolean outLaunched = new MutableBoolean(true);
+ boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
+ outLaunched);
+ assertFalse(intercepted);
+ assertFalse(outLaunched.value);
+
+ final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
+
+ // 2nd button triggers camera
+ eventTime += interval;
+ keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
+ IGNORED_REPEAT);
+ outLaunched.value = false;
+ intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
+ outLaunched);
+ assertTrue(intercepted);
+ assertTrue(outLaunched.value);
+
+ // Camera checks
+ verify(mStatusBarManagerInternal).onCameraLaunchGestureDetected(
+ StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
+ verify(mMetricsLogger)
+ .action(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE, (int) interval);
+
+ final ArgumentCaptor<Integer> cameraIntervalCaptor = ArgumentCaptor.forClass(Integer.class);
+ verify(mMetricsLogger, times(2)).histogram(
+ eq("power_double_tap_interval"), cameraIntervalCaptor.capture());
+ List<Integer> cameraIntervals = cameraIntervalCaptor.getAllValues();
+ assertEquals((int) INITIAL_EVENT_TIME_MILLIS, cameraIntervals.get(0).intValue());
+ assertEquals((int) interval, cameraIntervals.get(1).intValue());
+
+ final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
+ verify(mMetricsLogger, times(2)).histogram(
+ eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
+ List<Integer> tapCounts = tapCountCaptor.getAllValues();
+ assertEquals(1, tapCounts.get(0).intValue());
+ assertEquals(2, tapCounts.get(1).intValue());
+
+ // Continue the button presses for the panic gesture.
+
+ // Presses 3 and 4 should not trigger any gesture
+ for (int i = 0; i < 2; i++) {
+ eventTime += interval;
+ keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
+ IGNORED_REPEAT);
+ outLaunched.value = false;
+ intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
+ outLaunched);
+ assertFalse(intercepted);
+ assertFalse(outLaunched.value);
+ }
+
+ // Fifth button press should trigger the panic flow
+ eventTime += interval;
+ keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
+ IGNORED_REPEAT);
+ outLaunched.value = false;
+ intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
+ outLaunched);
+ assertTrue(intercepted);
+ assertTrue(outLaunched.value);
+
+ // TODO (b/169960245) Verify metric event equiv. to ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE
+ verify(mStatusBarManagerInternal).onEmergencyActionLaunchGestureDetected();
+
+ final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
+ verify(mMetricsLogger, times(5)).histogram(
+ eq("power_double_tap_interval"), intervalCaptor.capture());
+ List<Integer> intervals = intervalCaptor.getAllValues();
+ assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
+ assertEquals((int) interval, intervals.get(1).intValue());
+ }
+
+ @Test
+ public void
+ testInterceptPowerKeyDown_fiveInboundPresses_panicGestureEnabled_launchesPanicFlow() {
+ withPanicGestureEnabledSettingValue(true);
+ mGestureLauncherService.updatePanicButtonGestureEnabled();
+ withUserSetupCompleteValue(true);
+
+ // First button press does nothing
+ long eventTime = INITIAL_EVENT_TIME_MILLIS;
+ KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
+ IGNORED_REPEAT);
+ boolean interactive = true;
+ MutableBoolean outLaunched = new MutableBoolean(true);
+ boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
+ outLaunched);
+ assertFalse(intercepted);
+ assertFalse(outLaunched.value);
+
+ final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
+ // 3 more button presses which should not trigger any gesture (camera gesture disabled)
+ for (int i = 0; i < 3; i++) {
+ eventTime += interval;
+ keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
+ IGNORED_REPEAT);
+ outLaunched.value = false;
+ intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
+ outLaunched);
+ assertFalse(intercepted);
+ assertFalse(outLaunched.value);
+ }
+
+ // Fifth button press should trigger the panic flow
+ eventTime += interval;
+ keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
+ IGNORED_REPEAT);
+ outLaunched.value = false;
+ intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
+ outLaunched);
+ assertTrue(outLaunched.value);
+ assertTrue(intercepted);
+
+ // TODO (b/169960245) Verify metric event equiv. to ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE
+ verify(mStatusBarManagerInternal).onEmergencyActionLaunchGestureDetected();
+
+ final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
+ verify(mMetricsLogger, times(5)).histogram(
+ eq("power_double_tap_interval"), intervalCaptor.capture());
+ List<Integer> intervals = intervalCaptor.getAllValues();
+ assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
+ assertEquals((int) interval, intervals.get(1).intValue());
+ }
+
+ @Test
public void testInterceptPowerKeyDown_longpress() {
withCameraDoubleTapPowerEnableConfigValue(true);
withCameraDoubleTapPowerDisableSettingValue(0);
diff --git a/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
index dbaa482..9ee1205 100644
--- a/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
@@ -20,7 +20,6 @@
import static com.android.server.attention.AttentionManagerService.ATTENTION_CACHE_BUFFER_SIZE;
import static com.android.server.attention.AttentionManagerService.DEFAULT_STALE_AFTER_MILLIS;
-import static com.android.server.attention.AttentionManagerService.DEVICE_CONFIG_MAX_STALENESS_MILLIS;
import static com.android.server.attention.AttentionManagerService.KEY_STALE_AFTER_MILLIS;
import static com.google.common.truth.Truth.assertThat;
@@ -40,7 +39,6 @@
import android.os.IThermalService;
import android.os.PowerManager;
import android.os.RemoteException;
-import android.os.SystemClock;
import android.provider.DeviceConfig;
import android.service.attention.IAttentionCallback;
import android.service.attention.IAttentionService;
@@ -118,7 +116,7 @@
@Test
public void testCheckAttention_returnFalseWhenPowerManagerNotInteract() throws RemoteException {
- doReturn(true).when(mSpyAttentionManager).isAttentionServiceSupported();
+ mSpyAttentionManager.mIsServiceEnabled = true;
doReturn(false).when(mMockIPowerManager).isInteractive();
AttentionCallbackInternal callback = Mockito.mock(AttentionCallbackInternal.class);
assertThat(mSpyAttentionManager.checkAttention(mTimeout, callback)).isFalse();
@@ -126,7 +124,7 @@
@Test
public void testCheckAttention_callOnSuccess() throws RemoteException {
- doReturn(true).when(mSpyAttentionManager).isAttentionServiceSupported();
+ mSpyAttentionManager.mIsServiceEnabled = true;
doReturn(true).when(mSpyAttentionManager).isServiceAvailable();
doReturn(true).when(mMockIPowerManager).isInteractive();
doNothing().when(mSpyAttentionManager).freeIfInactiveLocked();
@@ -207,38 +205,6 @@
DEFAULT_STALE_AFTER_MILLIS);
}
- @Test
- public void testEnsureDeviceConfigCachedValuesFreshness_doesNotCallDeviceConfigTooFrequently() {
- DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
- KEY_STALE_AFTER_MILLIS, String.valueOf(DEFAULT_STALE_AFTER_MILLIS), false);
- assertThat(mSpyAttentionManager.getStaleAfterMillis()).isEqualTo(
- DEFAULT_STALE_AFTER_MILLIS);
-
- DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
- KEY_STALE_AFTER_MILLIS, "123", false);
-
- // New value is ignored
- assertThat(mSpyAttentionManager.getStaleAfterMillis()).isEqualTo(
- DEFAULT_STALE_AFTER_MILLIS);
- }
-
-
- @Test
- public void testEnsureDeviceConfigCachedValuesFreshness_refreshesWhenStale() {
- DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
- KEY_STALE_AFTER_MILLIS, String.valueOf(DEFAULT_STALE_AFTER_MILLIS), false);
- assertThat(mSpyAttentionManager.getStaleAfterMillis()).isEqualTo(
- DEFAULT_STALE_AFTER_MILLIS);
-
- DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
- KEY_STALE_AFTER_MILLIS, "123", false);
- mSpyAttentionManager.mLastReadDeviceConfigMillis =
- SystemClock.elapsedRealtime() - (DEVICE_CONFIG_MAX_STALENESS_MILLIS + 1);
-
- // Values are refreshed
- assertThat(mSpyAttentionManager.getStaleAfterMillis()).isEqualTo(123);
- }
-
private class MockIAttentionService implements IAttentionService {
public void checkAttention(IAttentionCallback callback) throws RemoteException {
callback.onSuccess(0, 0);
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
index 59d4e2a..058794a 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
@@ -16,7 +16,7 @@
package com.android.server.devicestate;
-import static com.android.server.devicestate.DeviceStateManagerService.INVALID_DEVICE_STATE;
+import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertThrows;
diff --git a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index b69cc47..ec747ac 100644
--- a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -83,8 +83,8 @@
BRIGHTNESS_MAX_FLOAT, DOZE_SCALE_FACTOR, LIGHT_SENSOR_RATE,
INITIAL_LIGHT_SENSOR_RATE, BRIGHTENING_LIGHT_DEBOUNCE_CONFIG,
DARKENING_LIGHT_DEBOUNCE_CONFIG, RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG,
- mAmbientBrightnessThresholds, mScreenBrightnessThresholds, mContext,
- mDisplayDeviceConfig);
+ mAmbientBrightnessThresholds, mScreenBrightnessThresholds, mContext
+ );
controller.setLoggingEnabled(true);
// Configure the brightness controller and grab an instance of the sensor listener,
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 7cbf571..ef98b98 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -814,7 +814,7 @@
mTestLooper.dispatchAll();
assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
- assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
+ assertThat(mNativeWrapper.getResultMessages()).containsAtLeast(pressed, released);
}
@Test
@@ -834,7 +834,7 @@
mTestLooper.dispatchAll();
assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
- assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
+ assertThat(mNativeWrapper.getResultMessages()).containsAtLeast(pressed, released);
}
@Test
@@ -853,7 +853,7 @@
mTestLooper.dispatchAll();
assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
- assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
+ assertThat(mNativeWrapper.getResultMessages()).containsAtLeast(pressed, released);
}
@Test
@@ -872,7 +872,7 @@
mTestLooper.dispatchAll();
assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
- assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
+ assertThat(mNativeWrapper.getResultMessages()).containsAtLeast(pressed, released);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/inputmethod/MultiClientInputMethodManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/inputmethod/MultiClientInputMethodManagerServiceTest.java
index cdff97b..9ab762a 100644
--- a/services/tests/servicestests/src/com/android/server/inputmethod/MultiClientInputMethodManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/inputmethod/MultiClientInputMethodManagerServiceTest.java
@@ -76,7 +76,7 @@
// Act and assert
assertThat(MultiClientInputMethodManagerService.resolveMultiClientImeService(
- asList(imeService))).isSameAs(imeService);
+ asList(imeService))).isSameInstanceAs(imeService);
}
private ResolveInfo buildResolveInfo(String permission, int flags) {
diff --git a/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java b/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java
index 41be54a..f26e094 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java
@@ -194,7 +194,7 @@
assertThat(rulesFetched.size())
.isEqualTo(INDEXING_BLOCK_SIZE * 2 + unindexedRuleCount);
assertThat(rulesFetched)
- .containsAllOf(
+ .containsAtLeast(
getPackageNameIndexedRule(installedPackageName),
getAppCertificateIndexedRule(installedAppCertificate));
}
diff --git a/services/tests/servicestests/src/com/android/server/location/timezone/TestSupport.java b/services/tests/servicestests/src/com/android/server/location/timezone/TestSupport.java
index 192ade7..4810563 100644
--- a/services/tests/servicestests/src/com/android/server/location/timezone/TestSupport.java
+++ b/services/tests/servicestests/src/com/android/server/location/timezone/TestSupport.java
@@ -45,6 +45,7 @@
return new ConfigurationInternal.Builder(userId)
.setUserConfigAllowed(true)
.setAutoDetectionSupported(true)
+ .setGeoDetectionSupported(true)
.setAutoDetectionEnabled(true)
.setLocationEnabled(true)
.setGeoDetectionEnabled(geoDetectionEnabled)
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java
index 6921bb2..8d5687c 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java
@@ -71,7 +71,7 @@
Map<String, Pair<SecretKey, byte[]>> filteredKeys =
mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys);
assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet());
- assertThat(filteredKeys.entrySet()).containsAllIn(rawKeys.entrySet());
+ assertThat(filteredKeys.entrySet()).containsAtLeastElementsIn(rawKeys.entrySet());
}
@Test
@@ -85,7 +85,7 @@
Map<String, Pair<SecretKey, byte[]>> filteredKeys =
mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys);
assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet());
- assertThat(rawKeys.entrySet()).containsAllIn(filteredKeys.entrySet());
+ assertThat(rawKeys.entrySet()).containsAtLeastElementsIn(filteredKeys.entrySet());
}
@Test
@@ -100,7 +100,7 @@
Map<String, Pair<SecretKey, byte[]>> filteredKeys =
mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys);
assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet());
- assertThat(rawKeys.entrySet()).containsAllIn(filteredKeys.entrySet());
+ assertThat(rawKeys.entrySet()).containsAtLeastElementsIn(filteredKeys.entrySet());
}
@Test
@@ -122,7 +122,7 @@
Map<String, Pair<SecretKey, byte[]>> filteredKeys =
mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys);
assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet());
- assertThat(rawKeys.entrySet()).containsAllIn(filteredKeys.entrySet());
+ assertThat(rawKeys.entrySet()).containsAtLeastElementsIn(filteredKeys.entrySet());
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertXmlTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertXmlTest.java
index 9836c64..b0cb2ea 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertXmlTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertXmlTest.java
@@ -70,7 +70,7 @@
CertXml certXml = CertXml.parse(certXmlBytes);
List<X509Certificate> endpointCerts = certXml.getAllEndpointCerts();
assertThat(endpointCerts).hasSize(3);
- assertThat(endpointCerts).containsAllOf(TestData.LEAF_CERT_1, TestData.LEAF_CERT_2);
+ assertThat(endpointCerts).containsAtLeast(TestData.LEAF_CERT_1, TestData.LEAF_CERT_2);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
index 154d42c..3a292de 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
@@ -72,7 +72,8 @@
@JvmStatic
fun checkAllCasesHandled() {
// Assert that all states have been tested at least once.
- assertThat(CASES.map { it.state }.distinct()).containsAllIn(ActorState.values())
+ assertThat(CASES.map { it.state }.distinct())
+ .containsAtLeastElementsIn(ActorState.values())
}
@BeforeClass
diff --git a/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java b/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java
index 62e135b..c4c2f68 100644
--- a/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java
@@ -146,7 +146,7 @@
// Test that package is now unstartable
assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
assertFalse(mIncrementalStates.isStartable());
- assertEquals(PackageManager.UNSTARTABLE_REASON_DATALOADER_TRANSPORT,
+ assertEquals(PackageManager.UNSTARTABLE_REASON_CONNECTION_ERROR,
mUnstartableReason.get());
}
@@ -160,7 +160,7 @@
// Test that package is now unstartable
assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
assertFalse(mIncrementalStates.isStartable());
- assertEquals(PackageManager.UNSTARTABLE_REASON_DATALOADER_TRANSPORT,
+ assertEquals(PackageManager.UNSTARTABLE_REASON_CONNECTION_ERROR,
mUnstartableReason.get());
}
@@ -181,7 +181,7 @@
// Test that package is now unstartable
assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
assertFalse(mIncrementalStates.isStartable());
- assertEquals(PackageManager.UNSTARTABLE_REASON_DATALOADER_STORAGE,
+ assertEquals(PackageManager.UNSTARTABLE_REASON_INSUFFICIENT_STORAGE,
mUnstartableReason.get());
}
@@ -202,7 +202,7 @@
// Test that package is now unstartable
assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
assertFalse(mIncrementalStates.isStartable());
- assertEquals(PackageManager.UNSTARTABLE_REASON_DATALOADER_STORAGE,
+ assertEquals(PackageManager.UNSTARTABLE_REASON_INSUFFICIENT_STORAGE,
mUnstartableReason.get());
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 44bb58f..22b0715 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -639,7 +639,7 @@
UserInfo user1 = createUser("User 1", 0);
UserInfo user2 = createUser("User 2", 0);
long[] serialNumbersOfUsers = mUserManager.getSerialNumbersOfUsers(false);
- assertThat(serialNumbersOfUsers).asList().containsAllOf(
+ assertThat(serialNumbersOfUsers).asList().containsAtLeast(
(long) user1.serialNumber, (long) user2.serialNumber);
}
diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java
index b6a0979..eedc978 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java
@@ -46,41 +46,25 @@
private static final String INSTALLER = "some.installer";
private static final Correspondence<VersionedPackage, VersionedPackage> VER_PKG_CORR =
- new Correspondence<VersionedPackage, VersionedPackage>() {
- @Override
- public boolean compare(VersionedPackage a, VersionedPackage b) {
- if (a == null || b == null) {
- return a == b;
- }
- return a.equals(b);
+ Correspondence.from((VersionedPackage a, VersionedPackage b) -> {
+ if (a == null || b == null) {
+ return a == b;
}
-
- @Override
- public String toString() {
- return "is the same as";
- }
- };
+ return a.equals(b);
+ }, "is the same as");
private static final Correspondence<PackageRollbackInfo.RestoreInfo,
PackageRollbackInfo.RestoreInfo>
RESTORE_INFO_CORR =
- new Correspondence<PackageRollbackInfo.RestoreInfo, PackageRollbackInfo.RestoreInfo>() {
- @Override
- public boolean compare(PackageRollbackInfo.RestoreInfo a,
- PackageRollbackInfo.RestoreInfo b) {
- if (a == null || b == null) {
- return a == b;
- }
- return a.userId == b.userId
- && a.appId == b.appId
- && Objects.equals(a.seInfo, b.seInfo);
+ Correspondence.from((PackageRollbackInfo.RestoreInfo a,
+ PackageRollbackInfo.RestoreInfo b) -> {
+ if (a == null || b == null) {
+ return a == b;
}
-
- @Override
- public String toString() {
- return "is the same as";
- }
- };
+ return a.userId == b.userId
+ && a.appId == b.appId
+ && Objects.equals(a.seInfo, b.seInfo);
+ }, "is the same as");
private static final String JSON_ROLLBACK_NO_EXT = "{'info':{'rollbackId':123,'packages':"
+ "[{'versionRolledBackFrom':{'packageName':'blah','longVersionCode':55},"
diff --git a/services/tests/servicestests/src/com/android/server/storage/DiskStatsFileLoggerTest.java b/services/tests/servicestests/src/com/android/server/storage/DiskStatsFileLoggerTest.java
index 46224cb..8fb2e68 100644
--- a/services/tests/servicestests/src/com/android/server/storage/DiskStatsFileLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/storage/DiskStatsFileLoggerTest.java
@@ -132,7 +132,7 @@
appSizes.getLong(i), cacheSizes.getLong(i));
apps.add(app);
}
- assertThat(apps).containsAllOf(new AppSizeGrouping("com.test.app", 1100, 20),
+ assertThat(apps).containsAtLeast(new AppSizeGrouping("com.test.app", 1100, 20),
new AppSizeGrouping("com.test.app2", 11, 2));
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
index 3fc294d..682a80c 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
@@ -47,6 +47,7 @@
ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
.setUserConfigAllowed(true)
.setAutoDetectionSupported(true)
+ .setGeoDetectionSupported(true)
.setAutoDetectionEnabled(true)
.setLocationEnabled(true)
.setGeoDetectionEnabled(true)
@@ -108,6 +109,7 @@
ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
.setUserConfigAllowed(false)
.setAutoDetectionSupported(true)
+ .setGeoDetectionSupported(true)
.setAutoDetectionEnabled(true)
.setLocationEnabled(true)
.setGeoDetectionEnabled(true)
@@ -169,6 +171,7 @@
ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
.setUserConfigAllowed(true)
.setAutoDetectionSupported(false)
+ .setGeoDetectionSupported(false)
.setAutoDetectionEnabled(true)
.setLocationEnabled(true)
.setGeoDetectionEnabled(true)
@@ -220,4 +223,67 @@
assertTrue(configuration.isGeoDetectionEnabled());
}
}
+
+ /**
+ * Tests when {@link ConfigurationInternal#isAutoDetectionSupported()} is true, but
+ * {@link ConfigurationInternal#isGeoDetectionSupported()} is false.
+ */
+ @Test
+ public void test_geoDetectNotSupported() {
+ ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
+ .setUserConfigAllowed(true)
+ .setAutoDetectionSupported(true)
+ .setGeoDetectionSupported(false)
+ .setAutoDetectionEnabled(true)
+ .setLocationEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+ {
+ ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
+ .setAutoDetectionEnabled(true)
+ .build();
+ assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
+ assertTrue(autoOnConfig.getGeoDetectionEnabledSetting());
+ assertTrue(autoOnConfig.getAutoDetectionEnabledBehavior());
+ assertFalse(autoOnConfig.getGeoDetectionEnabledBehavior());
+
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
+ autoOnConfig.createCapabilitiesAndConfig();
+
+ TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
+ assertEquals(CAPABILITY_POSSESSED,
+ capabilities.getConfigureAutoDetectionEnabledCapability());
+ assertEquals(CAPABILITY_NOT_SUPPORTED,
+ capabilities.getConfigureGeoDetectionEnabledCapability());
+ assertEquals(CAPABILITY_NOT_APPLICABLE,
+ capabilities.getSuggestManualTimeZoneCapability());
+
+ TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration();
+ assertTrue(configuration.isAutoDetectionEnabled());
+ assertTrue(configuration.isGeoDetectionEnabled());
+ }
+ {
+ ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
+ .setAutoDetectionEnabled(false)
+ .build();
+ assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
+ assertTrue(autoOffConfig.getGeoDetectionEnabledSetting());
+ assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
+ assertFalse(autoOffConfig.getGeoDetectionEnabledBehavior());
+
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
+ autoOffConfig.createCapabilitiesAndConfig();
+
+ TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
+ assertEquals(CAPABILITY_POSSESSED,
+ capabilities.getConfigureAutoDetectionEnabledCapability());
+ assertEquals(CAPABILITY_NOT_SUPPORTED,
+ capabilities.getConfigureGeoDetectionEnabledCapability());
+ assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZoneCapability());
+
+ TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration();
+ assertFalse(configuration.isAutoDetectionEnabled());
+ assertTrue(configuration.isGeoDetectionEnabled());
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
index cb27657..d2452ea 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
@@ -365,6 +365,7 @@
final boolean geoDetectionEnabled = autoDetectionEnabled;
return new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
.setAutoDetectionSupported(true)
+ .setGeoDetectionSupported(true)
.setUserConfigAllowed(true)
.setAutoDetectionEnabled(autoDetectionEnabled)
.setLocationEnabled(geoDetectionEnabled)
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
index 296aa73..a6ffd20 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
@@ -91,6 +91,7 @@
new ConfigurationInternal.Builder(USER_ID)
.setUserConfigAllowed(false)
.setAutoDetectionSupported(true)
+ .setGeoDetectionSupported(true)
.setAutoDetectionEnabled(false)
.setLocationEnabled(true)
.setGeoDetectionEnabled(false)
@@ -100,6 +101,7 @@
new ConfigurationInternal.Builder(USER_ID)
.setUserConfigAllowed(false)
.setAutoDetectionSupported(true)
+ .setGeoDetectionSupported(true)
.setAutoDetectionEnabled(true)
.setLocationEnabled(true)
.setGeoDetectionEnabled(true)
@@ -109,32 +111,36 @@
new ConfigurationInternal.Builder(USER_ID)
.setUserConfigAllowed(true)
.setAutoDetectionSupported(false)
+ .setGeoDetectionSupported(false)
.setAutoDetectionEnabled(false)
.setLocationEnabled(true)
.setGeoDetectionEnabled(false)
.build();
+ private static final ConfigurationInternal CONFIG_INT_AUTO_SUPPORTED_GEO_NOT_SUPPORTED =
+ new ConfigurationInternal.Builder(USER_ID)
+ .setUserConfigAllowed(true)
+ .setAutoDetectionSupported(true)
+ .setGeoDetectionSupported(false)
+ .setAutoDetectionEnabled(true)
+ .setLocationEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+
private static final ConfigurationInternal CONFIG_INT_AUTO_DISABLED_GEO_DISABLED =
new ConfigurationInternal.Builder(USER_ID)
.setUserConfigAllowed(true)
.setAutoDetectionSupported(true)
+ .setGeoDetectionSupported(true)
.setAutoDetectionEnabled(false)
.setLocationEnabled(true)
.setGeoDetectionEnabled(false)
.build();
- private static final ConfigurationInternal CONFIG_INT_AUTO_DISABLED_GEO_ENABLED =
- new ConfigurationInternal.Builder(USER_ID)
- .setUserConfigAllowed(true)
- .setAutoDetectionSupported(true)
- .setAutoDetectionEnabled(false)
- .setLocationEnabled(true)
- .setGeoDetectionEnabled(true)
- .build();
-
private static final ConfigurationInternal CONFIG_INT_AUTO_ENABLED_GEO_DISABLED =
new ConfigurationInternal.Builder(USER_ID)
.setAutoDetectionSupported(true)
+ .setGeoDetectionSupported(true)
.setUserConfigAllowed(true)
.setAutoDetectionEnabled(true)
.setLocationEnabled(true)
@@ -144,6 +150,7 @@
private static final ConfigurationInternal CONFIG_INT_AUTO_ENABLED_GEO_ENABLED =
new ConfigurationInternal.Builder(USER_ID)
.setAutoDetectionSupported(true)
+ .setGeoDetectionSupported(true)
.setUserConfigAllowed(true)
.setAutoDetectionEnabled(true)
.setLocationEnabled(true)
@@ -223,14 +230,14 @@
// The settings should not have been changed: user shouldn't have the capabilities.
script.verifyConfigurationNotChanged();
- // Update the configuration with auto detection enabled.
+ // Try to update the configuration with auto detection enabled.
script.simulateUpdateConfiguration(
USER_ID, CONFIG_AUTO_ENABLED, false /* expectedResult */);
// The settings should not have been changed: user shouldn't have the capabilities.
script.verifyConfigurationNotChanged();
- // Try to update the configuration to enable geolocation time zone detection.
+ // Try to update the configuration to enable geolocation time zone detection.
script.simulateUpdateConfiguration(
USER_ID, CONFIG_GEO_DETECTION_ENABLED, false /* expectedResult */);
@@ -249,7 +256,7 @@
// The settings should not have been changed: user shouldn't have the capabilities.
script.verifyConfigurationNotChanged();
- // Update the configuration with auto detection enabled.
+ // Try to update the configuration with auto detection enabled.
script.simulateUpdateConfiguration(
USER_ID, CONFIG_AUTO_ENABLED, false /* expectedResult */);
@@ -258,6 +265,38 @@
}
@Test
+ public void testUpdateConfiguration_autoDetectSupportedGeoNotSupported() {
+ Script script = new Script().initializeConfig(CONFIG_INT_AUTO_SUPPORTED_GEO_NOT_SUPPORTED);
+
+ // Update the configuration with auto detection disabled.
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */);
+
+ // The settings should have been changed and the StrategyListener onChange() called.
+ ConfigurationInternal expectedConfig =
+ new ConfigurationInternal.Builder(CONFIG_INT_AUTO_SUPPORTED_GEO_NOT_SUPPORTED)
+ .setAutoDetectionEnabled(false)
+ .build();
+ script.verifyConfigurationChangedAndReset(expectedConfig);
+
+ // Try to update the configuration with geo detection disabled.
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_GEO_DETECTION_DISABLED, false /* expectedResult */);
+
+ // The settings should not have been changed: user shouldn't have the capability to modify
+ // the setting when the feature is disabled.
+ script.verifyConfigurationNotChanged();
+
+ // Try to update the configuration with geo detection enabled.
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_GEO_DETECTION_ENABLED, false /* expectedResult */);
+
+ // The settings should not have been changed: user shouldn't have the capability to modify
+ // the setting when the feature is disabled.
+ script.verifyConfigurationNotChanged();
+ }
+
+ @Test
public void testEmptyTelephonySuggestions() {
TelephonyTimeZoneSuggestion slotIndex1TimeZoneSuggestion =
createEmptySlotIndex1Suggestion();
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
index 7b07102..1055069 100644
--- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
@@ -81,9 +81,7 @@
// A correspondence to compare a FrontendResource and a TunerFrontendInfo.
private static final Correspondence<FrontendResource, TunerFrontendInfo> FR_TFI_COMPARE =
- new Correspondence<FrontendResource, TunerFrontendInfo>() {
- @Override
- public boolean compare(FrontendResource actual, TunerFrontendInfo expected) {
+ Correspondence.from((FrontendResource actual, TunerFrontendInfo expected) -> {
if (actual == null || expected == null) {
return (actual == null) && (expected == null);
}
@@ -91,13 +89,7 @@
return actual.getId() == expected.getId()
&& actual.getType() == expected.getFrontendType()
&& actual.getExclusiveGroupId() == expected.getExclusiveGroupId();
- }
-
- @Override
- public String toString() {
- return "is correctly configured from ";
- }
- };
+ }, "is correctly configured from ");
@Before
public void setUp() throws Exception {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index ed6a20b..6ee5831 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -43,6 +43,9 @@
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+import static android.app.PendingIntent.FLAG_IMMUTABLE;
+import static android.app.PendingIntent.FLAG_MUTABLE;
+import static android.app.PendingIntent.FLAG_ONE_SHOT;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.PackageManager.FEATURE_WATCH;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
@@ -110,6 +113,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.IIntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
@@ -248,6 +252,11 @@
Resources mResources;
@Mock
RankingHandler mRankingHandler;
+ @Mock
+ ActivityManagerInternal mAmi;
+
+ @Mock
+ IIntentSender pi1;
private static final int MAX_POST_DELAY = 1000;
@@ -392,7 +401,6 @@
DeviceIdleInternal deviceIdleInternal = mock(DeviceIdleInternal.class);
when(deviceIdleInternal.getNotificationAllowlistDuration()).thenReturn(3000L);
- ActivityManagerInternal activityManagerInternal = mock(ActivityManagerInternal.class);
LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
LocalServices.addService(UriGrantsManagerInternal.class, mUgmInternal);
@@ -403,7 +411,7 @@
LocalServices.removeServiceForTest(DeviceIdleInternal.class);
LocalServices.addService(DeviceIdleInternal.class, deviceIdleInternal);
LocalServices.removeServiceForTest(ActivityManagerInternal.class);
- LocalServices.addService(ActivityManagerInternal.class, activityManagerInternal);
+ LocalServices.addService(ActivityManagerInternal.class, mAmi);
doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any());
@@ -477,7 +485,7 @@
mGroupHelper, mAm, mAtm, mAppUsageStats,
mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,
mAppOpsManager, mUm, mHistoryManager, mStatsManager,
- mock(TelephonyManager.class));
+ mock(TelephonyManager.class), mAmi);
mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
mService.setAudioManager(mAudioManager);
@@ -674,7 +682,8 @@
}
Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
.setContentTitle("foo")
- .setSmallIcon(android.R.drawable.sym_def_app_icon);
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .addAction(new Notification.Action.Builder(null, "test", null).build());
if (extender != null) {
nb.extend(extender);
}
@@ -810,6 +819,7 @@
PendingIntent pendingIntent = mock(PendingIntent.class);
Intent intent = mock(Intent.class);
when(pendingIntent.getIntent()).thenReturn(intent);
+ when(pendingIntent.getTarget()).thenReturn(pi1);
ActivityInfo info = new ActivityInfo();
info.resizeMode = RESIZE_MODE_RESIZEABLE;
@@ -7134,4 +7144,159 @@
inOrder.verify(parent).recordDismissalSentiment(anyInt());
inOrder.verify(child).recordDismissalSentiment(anyInt());
}
+
+ @Test
+ public void testImmutableBubbleIntent() throws Exception {
+ when(mAmi.getPendingIntentFlags(pi1))
+ .thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT);
+ NotificationRecord r = generateMessageBubbleNotifRecord(true,
+ mTestNotificationChannel, 7, "testImmutableBubbleIntent", null, false);
+ try {
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, r.getSbn().getTag(),
+ r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId());
+
+ waitForIdle();
+ fail("Allowed a bubble with an immutable intent to be posted");
+ } catch (IllegalArgumentException e) {
+ // good
+ }
+ }
+
+ @Test
+ public void testMutableBubbleIntent() throws Exception {
+ when(mAmi.getPendingIntentFlags(pi1))
+ .thenReturn(FLAG_MUTABLE | FLAG_ONE_SHOT);
+ NotificationRecord r = generateMessageBubbleNotifRecord(true,
+ mTestNotificationChannel, 7, "testMutableBubbleIntent", null, false);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, r.getSbn().getTag(),
+ r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId());
+
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(r.getSbn().getPackageName());
+ assertEquals(1, notifs.length);
+ }
+
+ @Test
+ public void testImmutableDirectReplyActionIntent() throws Exception {
+ when(mAmi.getPendingIntentFlags(any(IIntentSender.class)))
+ .thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT);
+ NotificationRecord r = generateMessageBubbleNotifRecord(false,
+ mTestNotificationChannel, 7, "testImmutableDirectReplyActionIntent", null, false);
+ try {
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, r.getSbn().getTag(),
+ r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId());
+
+ waitForIdle();
+ fail("Allowed a direct reply with an immutable intent to be posted");
+ } catch (IllegalArgumentException e) {
+ // good
+ }
+ }
+
+ @Test
+ public void testMutableDirectReplyActionIntent() throws Exception {
+ when(mAmi.getPendingIntentFlags(any(IIntentSender.class)))
+ .thenReturn(FLAG_MUTABLE | FLAG_ONE_SHOT);
+ NotificationRecord r = generateMessageBubbleNotifRecord(false,
+ mTestNotificationChannel, 7, "testMutableDirectReplyActionIntent", null, false);
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, r.getSbn().getTag(),
+ r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId());
+
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(r.getSbn().getPackageName());
+ assertEquals(1, notifs.length);
+ }
+
+ @Test
+ public void testImmutableDirectReplyContextualActionIntent() throws Exception {
+ when(mAmi.getPendingIntentFlags(any(IIntentSender.class)))
+ .thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT);
+ when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
+
+ NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
+ ArrayList<Notification.Action> extraAction = new ArrayList<>();
+ RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build();
+ PendingIntent inputIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+ Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon);
+ Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply",
+ inputIntent).addRemoteInput(remoteInput)
+ .build();
+ extraAction.add(replyAction);
+ Bundle signals = new Bundle();
+ signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, extraAction);
+ Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "",
+ r.getUser());
+ r.addAdjustment(adjustment);
+ r.applyAdjustments();
+
+ try {
+ mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(),
+ r.getSbn().getTag(), r,false);
+ fail("Allowed a contextual direct reply with an immutable intent to be posted");
+ } catch (IllegalArgumentException e) {
+ // good
+ }
+ }
+
+ @Test
+ public void testMutableDirectReplyContextualActionIntent() throws Exception {
+ when(mAmi.getPendingIntentFlags(any(IIntentSender.class)))
+ .thenReturn(FLAG_MUTABLE | FLAG_ONE_SHOT);
+ when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
+ NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
+ ArrayList<Notification.Action> extraAction = new ArrayList<>();
+ RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build();
+ PendingIntent inputIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+ Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon);
+ Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply",
+ inputIntent).addRemoteInput(remoteInput)
+ .build();
+ extraAction.add(replyAction);
+ Bundle signals = new Bundle();
+ signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, extraAction);
+ Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "",
+ r.getUser());
+ r.addAdjustment(adjustment);
+ r.applyAdjustments();
+
+ mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(),
+ r.getSbn().getTag(), r,false);
+ }
+
+ @Test
+ public void testImmutableActionIntent() throws Exception {
+ when(mAmi.getPendingIntentFlags(any(IIntentSender.class)))
+ .thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT);
+ NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, r.getSbn().getTag(),
+ r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId());
+
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(r.getSbn().getPackageName());
+ assertEquals(1, notifs.length);
+ }
+
+ @Test
+ public void testImmutableContextualActionIntent() throws Exception {
+ when(mAmi.getPendingIntentFlags(any(IIntentSender.class)))
+ .thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT);
+ when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
+ NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
+ ArrayList<Notification.Action> extraAction = new ArrayList<>();
+ extraAction.add(new Notification.Action(0, "hello", null));
+ Bundle signals = new Bundle();
+ signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, extraAction);
+ Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "",
+ r.getUser());
+ r.addAdjustment(adjustment);
+ r.applyAdjustments();
+
+ mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(),
+ r.getSbn().getTag(), r,false);
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
index 3281c3f..a80f62a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
@@ -32,6 +32,7 @@
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.IUriGrantsManager;
@@ -154,7 +155,8 @@
mock(DevicePolicyManagerInternal.class), mock(IUriGrantsManager.class),
mock(UriGrantsManagerInternal.class),
mock(AppOpsManager.class), mUm, mock(NotificationHistoryManager.class),
- mock(StatsManager.class), mock(TelephonyManager.class));
+ mock(StatsManager.class), mock(TelephonyManager.class),
+ mock(ActivityManagerInternal.class));
} catch (SecurityException e) {
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
throw e;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
index eca71b6..e5ae2d3 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
@@ -305,6 +305,7 @@
//when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
// anyString(), anyInt(), any())).thenReturn(true);
- assertThat(mShortcutHelper.getValidShortcutInfo("a", "p", UserHandle.SYSTEM)).isSameAs(si);
+ assertThat(mShortcutHelper.getValidShortcutInfo("a", "p", UserHandle.SYSTEM))
+ .isSameInstanceAs(si);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
index e17601e..01c1f1f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
@@ -23,6 +23,8 @@
import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS;
import static com.android.server.wm.DisplayArea.Type.ANY;
@@ -37,14 +39,18 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
+import android.content.pm.ActivityInfo;
import android.graphics.Rect;
import android.os.Binder;
import android.platform.test.annotations.Presubmit;
import android.view.SurfaceControl;
+import android.view.View;
+import android.view.WindowManager;
import com.google.android.collect.Lists;
@@ -405,6 +411,55 @@
childBounds1, windowToken.getMaxBounds());
}
+ @Test
+ public void testGetOrientation() {
+ final DisplayArea.Tokens area = new DisplayArea.Tokens(mWms, ABOVE_TASKS, "test");
+ final WindowToken token = createWindowToken(TYPE_APPLICATION_OVERLAY);
+ spyOn(token);
+ doReturn(mock(DisplayContent.class)).when(token).getDisplayContent();
+ doNothing().when(token).setParent(any());
+ final WindowState win = createWindowState(token);
+ spyOn(win);
+ doNothing().when(win).setParent(any());
+ win.mAttrs.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+ token.addChild(win, 0);
+ area.addChild(token);
+
+ doReturn(true).when(win).isVisible();
+
+ assertEquals("Visible window can request orientation",
+ ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE,
+ area.getOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR));
+
+ doReturn(false).when(win).isVisible();
+
+ assertEquals("Invisible window cannot request orientation",
+ ActivityInfo.SCREEN_ORIENTATION_NOSENSOR,
+ area.getOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR));
+ }
+
+ @Test
+ public void testSetIgnoreOrientationRequest() {
+ final DisplayArea.Tokens area = new DisplayArea.Tokens(mWms, ABOVE_TASKS, "test");
+ final WindowToken token = createWindowToken(TYPE_APPLICATION_OVERLAY);
+ spyOn(token);
+ doReturn(mock(DisplayContent.class)).when(token).getDisplayContent();
+ doNothing().when(token).setParent(any());
+ final WindowState win = createWindowState(token);
+ spyOn(win);
+ doNothing().when(win).setParent(any());
+ win.mAttrs.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+ token.addChild(win, 0);
+ area.addChild(token);
+ doReturn(true).when(win).isVisible();
+
+ assertEquals(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, area.getOrientation());
+
+ area.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+ assertEquals(ActivityInfo.SCREEN_ORIENTATION_UNSET, area.getOrientation());
+ }
+
private static class TestDisplayArea<T extends WindowContainer> extends DisplayArea<T> {
private TestDisplayArea(WindowManagerService wms, Rect bounds) {
super(wms, ANY, "half display area");
@@ -417,6 +472,13 @@
}
}
+ private WindowState createWindowState(WindowToken token) {
+ return new WindowState(mWms, mock(Session.class), new TestIWindow(), token,
+ null /* parentWindow */, 0 /* appOp */, new WindowManager.LayoutParams(),
+ View.VISIBLE, 0 /* ownerId */, 0 /* showUserId */,
+ false /* ownerCanAddInternalSystemWindow */);
+ }
+
private WindowToken createWindowToken(int type) {
return new WindowToken(mWmsRule.getWindowManagerService(), new Binder(),
type, false /* persist */, null /* displayContent */,
diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
index d0a5644..ecbfac8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
+++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
@@ -163,12 +163,6 @@
}
@Override
- public SurfaceControl.Transaction setOverrideScalingMode(SurfaceControl sc,
- int overrideScalingMode) {
- return this;
- }
-
- @Override
public SurfaceControl.Transaction setColor(SurfaceControl sc, float[] color) {
return this;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index d2b7ac4..7975899 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -1002,14 +1002,18 @@
public void testNotSpecifyOrientationByFloatingTask() {
final Task task = getTestTask();
final ActivityRecord activity = task.getTopMostActivity();
+ final WindowContainer<?> parentContainer = task.getParent();
final TaskDisplayArea taskDisplayArea = task.getDisplayArea();
activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+ assertEquals(SCREEN_ORIENTATION_LANDSCAPE, parentContainer.getOrientation());
assertEquals(SCREEN_ORIENTATION_LANDSCAPE, taskDisplayArea.getOrientation());
task.setWindowingMode(WINDOWING_MODE_PINNED);
- assertEquals(SCREEN_ORIENTATION_UNSET, taskDisplayArea.getOrientation());
+ // TDA returns the last orientation when child returns UNSET
+ assertEquals(SCREEN_ORIENTATION_UNSET, parentContainer.getOrientation());
+ assertEquals(SCREEN_ORIENTATION_LANDSCAPE, taskDisplayArea.getOrientation());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index dc85904..db5c796 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -197,19 +197,19 @@
}
@Override
- public void screenTurningOn(ScreenOnListener screenOnListener) {
+ public void screenTurningOn(int displayId, ScreenOnListener screenOnListener) {
}
@Override
- public void screenTurnedOn() {
+ public void screenTurnedOn(int displayId) {
}
@Override
- public void screenTurningOff(ScreenOffListener screenOffListener) {
+ public void screenTurningOff(int displayId, ScreenOffListener screenOffListener) {
}
@Override
- public void screenTurnedOff() {
+ public void screenTurnedOff(int displayId) {
}
@Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 0152fc6..aac8397 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -54,12 +54,14 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager.RootTaskInfo;
import android.app.PictureInPictureParams;
import android.content.pm.ActivityInfo;
+import android.content.pm.ParceledListSlice;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
@@ -72,6 +74,7 @@
import android.view.SurfaceControl;
import android.window.ITaskOrganizer;
import android.window.IWindowContainerTransactionCallback;
+import android.window.TaskAppearedInfo;
import android.window.WindowContainerTransaction;
import androidx.test.filters.SmallTest;
@@ -79,8 +82,10 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
/**
@@ -93,14 +98,27 @@
@Presubmit
@RunWith(WindowTestRunner.class)
public class WindowOrganizerTests extends WindowTestsBase {
- private ITaskOrganizer registerMockOrganizer() {
+
+ private ITaskOrganizer createMockOrganizer() {
final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
when(organizer.asBinder()).thenReturn(new Binder());
-
- mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(organizer);
return organizer;
}
+ private ITaskOrganizer registerMockOrganizer(ArrayList<TaskAppearedInfo> existingTasks) {
+ final ITaskOrganizer organizer = createMockOrganizer();
+ ParceledListSlice<TaskAppearedInfo> tasks =
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(organizer);
+ if (existingTasks != null) {
+ existingTasks.addAll(tasks.getList());
+ }
+ return organizer;
+ }
+
+ private ITaskOrganizer registerMockOrganizer() {
+ return registerMockOrganizer(null);
+ }
+
Task createTask(Task stack, boolean fakeDraw) {
final Task task = createTaskInStack(stack, 0);
@@ -128,27 +146,21 @@
@Test
public void testAppearVanish() throws RemoteException {
+ final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack);
- final ITaskOrganizer organizer = registerMockOrganizer();
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
- stack.setTaskOrganizer(organizer);
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
-
stack.removeImmediately();
verify(organizer).onTaskVanished(any());
}
@Test
public void testAppearWaitsForVisibility() throws RemoteException {
+ final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack, false);
- final ITaskOrganizer organizer = registerMockOrganizer();
-
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
- stack.setTaskOrganizer(organizer);
verify(organizer, never())
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
@@ -163,9 +175,9 @@
@Test
public void testNoVanishedIfNoAppear() throws RemoteException {
+ final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack, false /* hasBeenVisible */);
- final ITaskOrganizer organizer = registerMockOrganizer();
// In this test we skip making the Task visible, and verify
// that even though a TaskOrganizer is set remove doesn't emit
@@ -179,28 +191,25 @@
@Test
public void testTaskNoDraw() throws RemoteException {
+ final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack, false /* fakeDraw */);
- final ITaskOrganizer organizer = registerMockOrganizer();
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
verify(organizer, never())
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
assertTrue(stack.isOrganized());
mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer);
- verify(organizer, never()).onTaskVanished(any());
+ assertTaskVanished(organizer, false /* expectVanished */, stack);
assertFalse(stack.isOrganized());
}
@Test
public void testClearOrganizer() throws RemoteException {
+ final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack);
- final ITaskOrganizer organizer = registerMockOrganizer();
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
- stack.setTaskOrganizer(organizer);
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
assertTrue(stack.isOrganized());
@@ -211,16 +220,15 @@
@Test
public void testUnregisterOrganizer() throws RemoteException {
+ final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack);
- final ITaskOrganizer organizer = registerMockOrganizer();
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
assertTrue(stack.isOrganized());
mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer);
- verify(organizer).onTaskVanished(any());
+ assertTaskVanished(organizer, true /* expectVanished */, stack);
assertFalse(stack.isOrganized());
}
@@ -232,37 +240,47 @@
final Task task2 = createTask(stack2);
final Task stack3 = createStack();
final Task task3 = createTask(stack3);
- final ITaskOrganizer organizer = registerMockOrganizer();
+ final ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>();
+ final ITaskOrganizer organizer = registerMockOrganizer(existingTasks);
- // verify that tasks are appeared on registration
- verify(organizer, times(3))
- .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
+ // verify that tasks are returned and taskAppeared is not called
+ assertContainsTasks(existingTasks, stack, stack2, stack3);
+ verify(organizer, times(0)).onTaskAppeared(any(RunningTaskInfo.class),
+ any(SurfaceControl.class));
+ verify(organizer, times(0)).onTaskVanished(any());
assertTrue(stack.isOrganized());
- // Now we replace the registration and1 verify the new organizer receives tasks
- final ITaskOrganizer organizer2 = registerMockOrganizer();
- verify(organizer2, times(3))
- .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
+ // Now we replace the registration and verify the new organizer receives existing tasks
+ final ArrayList<TaskAppearedInfo> existingTasks2 = new ArrayList<>();
+ final ITaskOrganizer organizer2 = registerMockOrganizer(existingTasks2);
+ assertContainsTasks(existingTasks2, stack, stack2, stack3);
+ verify(organizer2, times(0)).onTaskAppeared(any(RunningTaskInfo.class),
+ any(SurfaceControl.class));
verify(organizer2, times(0)).onTaskVanished(any());
- // One for task
- verify(organizer, times(3)).onTaskVanished(any());
+ // Removed tasks from the original organizer
+ assertTaskVanished(organizer, true /* expectVanished */, stack, stack2, stack3);
assertTrue(stack2.isOrganized());
// Now we unregister the second one, the first one should automatically be reregistered
// so we verify that it's now seeing changes.
mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer2);
- verify(organizer, times(6))
+ verify(organizer, times(3))
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- verify(organizer2, times(3)).onTaskVanished(any());
+ assertTaskVanished(organizer2, true /* expectVanished */, stack, stack2, stack3);
}
@Test
public void testRegisterTaskOrganizerWithExistingTasks() throws RemoteException {
final Task stack = createStack();
final Task task = createTask(stack);
+ final Task stack2 = createStack();
+ final Task task2 = createTask(stack2);
+ ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>();
+ final ITaskOrganizer organizer = registerMockOrganizer(existingTasks);
+ assertContainsTasks(existingTasks, stack, stack2);
- final ITaskOrganizer organizer = registerMockOrganizer();
- verify(organizer, times(1))
+ // Verify we don't get onTaskAppeared if we are returned the tasks
+ verify(organizer, never())
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
}
@@ -366,7 +384,7 @@
}
@Test
- public void testSetIgnoreOrientationRequest() {
+ public void testSetIgnoreOrientationRequest_taskDisplayArea() {
removeGlobalMinSizeRestriction();
final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
final Task stack = taskDisplayArea.createStack(
@@ -378,7 +396,7 @@
activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
// TDA returns UNSET when ignoreOrientationRequest == true
- // DC is UNSPECIFIED because it is using the previous (default) when TDA returns UNSET.
+ // DC is UNSPECIFIED when child returns UNSET
assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSET);
assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSPECIFIED);
@@ -399,8 +417,40 @@
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
// TDA returns UNSET when ignoreOrientationRequest == true
- // DC is LANDSCAPE because it is using the previous when TDA returns UNSET.
+ // DC is UNSPECIFIED when child returns UNSET
assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSET);
+ assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSPECIFIED);
+ }
+
+ @Test
+ public void testSetIgnoreOrientationRequest_displayContent() {
+ removeGlobalMinSizeRestriction();
+ final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
+ final Task stack = taskDisplayArea.createStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true)
+ .setStack(stack).build();
+ mDisplayContent.setFocusedApp(activity);
+ activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+
+ // DC uses the orientation request from app
+ assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE);
+
+ WindowContainerTransaction t = new WindowContainerTransaction();
+ t.setIgnoreOrientationRequest(
+ mDisplayContent.mRemoteToken.toWindowContainerToken(),
+ true /* ignoreOrientationRequest */);
+ mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
+
+ // DC returns UNSPECIFIED when ignoreOrientationRequest == true
+ assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSPECIFIED);
+
+ t.setIgnoreOrientationRequest(
+ mDisplayContent.mRemoteToken.toWindowContainerToken(),
+ false /* ignoreOrientationRequest */);
+ mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
+
+ // DC uses the orientation request from app after mIgnoreOrientationRequest is set to false
assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE);
}
@@ -922,9 +972,9 @@
@Test
public void testPreventDuplicateAppear() throws RemoteException {
+ final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack, false /* fakeDraw */);
- final ITaskOrganizer organizer = registerMockOrganizer();
stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
stack.setTaskOrganizer(organizer);
@@ -945,17 +995,14 @@
@Test
public void testInterceptBackPressedOnTaskRoot() throws RemoteException {
+ final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack);
final ActivityRecord activity = createActivityRecordInTask(stack.mDisplayContent, task);
final Task stack2 = createStack();
final Task task2 = createTask(stack2);
final ActivityRecord activity2 = createActivityRecordInTask(stack.mDisplayContent, task2);
- final ITaskOrganizer organizer = registerMockOrganizer();
- // Setup the task to be controlled by the MW mode organizer
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
- stack2.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
assertTrue(stack.isOrganized());
assertTrue(stack2.isOrganized());
@@ -982,9 +1029,9 @@
@Test
public void testBLASTCallbackWithMultipleWindows() throws Exception {
+ final ITaskOrganizer organizer = registerMockOrganizer();
final Task stackController = createStack();
final Task task = createTask(stackController);
- final ITaskOrganizer organizer = registerMockOrganizer();
final WindowState w1 = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window 1");
final WindowState w2 = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window 2");
makeWindowVisible(w1);
@@ -1035,4 +1082,37 @@
assertFalse(daTask.isForceHidden());
});
}
+
+ /**
+ * Verifies that task vanished is called for a specific task.
+ */
+ private void assertTaskVanished(ITaskOrganizer organizer, boolean expectVanished, Task... tasks)
+ throws RemoteException {
+ ArgumentCaptor<RunningTaskInfo> arg = ArgumentCaptor.forClass(RunningTaskInfo.class);
+ verify(organizer, atLeastOnce()).onTaskVanished(arg.capture());
+ List<RunningTaskInfo> taskInfos = arg.getAllValues();
+
+ HashSet<Integer> vanishedTaskIds = new HashSet<>();
+ for (int i = 0; i < taskInfos.size(); i++) {
+ vanishedTaskIds.add(taskInfos.get(i).taskId);
+ }
+ HashSet<Integer> taskIds = new HashSet<>();
+ for (int i = 0; i < tasks.length; i++) {
+ taskIds.add(tasks[i].mTaskId);
+ }
+
+ assertTrue(expectVanished
+ ? vanishedTaskIds.containsAll(taskIds)
+ : !vanishedTaskIds.removeAll(taskIds));
+ }
+
+ private void assertContainsTasks(List<TaskAppearedInfo> taskInfos, Task... expectedTasks) {
+ HashSet<Integer> taskIds = new HashSet<>();
+ for (int i = 0; i < taskInfos.size(); i++) {
+ taskIds.add(taskInfos.get(i).getTaskInfo().taskId);
+ }
+ for (int i = 0; i < expectedTasks.length; i++) {
+ assertTrue(taskIds.contains(expectedTasks[i].mTaskId));
+ }
+ }
}
diff --git a/services/usb/java/com/android/server/usb/MtpNotificationManager.java b/services/usb/java/com/android/server/usb/MtpNotificationManager.java
index 462ee19..39f2f29 100644
--- a/services/usb/java/com/android/server/usb/MtpNotificationManager.java
+++ b/services/usb/java/com/android/server/usb/MtpNotificationManager.java
@@ -64,12 +64,13 @@
private final Context mContext;
private final OnOpenInAppListener mListener;
+ private final Receiver mReceiver;
MtpNotificationManager(Context context, OnOpenInAppListener listener) {
mContext = context;
mListener = listener;
- final Receiver receiver = new Receiver();
- context.registerReceiver(receiver, new IntentFilter(ACTION_OPEN_IN_APPS));
+ mReceiver = new Receiver();
+ context.registerReceiver(mReceiver, new IntentFilter(ACTION_OPEN_IN_APPS));
}
void showNotification(UsbDevice device) {
@@ -154,4 +155,8 @@
static interface OnOpenInAppListener {
void onOpenInApp(UsbDevice device);
}
+
+ public void unregister() {
+ mContext.unregisterReceiver(mReceiver);
+ }
}
diff --git a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
index d7b6b5d..26ee03c 100644
--- a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
@@ -261,6 +261,15 @@
}
/**
+ * Unregister all broadcast receivers. Must be called explicitly before
+ * object deletion.
+ */
+ public void unregisterReceivers() {
+ mPackageMonitor.unregister();
+ mMtpNotificationManager.unregister();
+ }
+
+ /**
* Remove all defaults and denied packages for a user.
*
* @param userToRemove The user
diff --git a/services/usb/java/com/android/server/usb/UsbSettingsManager.java b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
index 7b677ee..8e53ff4 100644
--- a/services/usb/java/com/android/server/usb/UsbSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
@@ -124,6 +124,7 @@
if (mSettingsByProfileGroup.indexOfKey(userToRemove.getIdentifier()) >= 0) {
// The user to remove is the parent user of the group. The parent is the last user
// that gets removed. All state will be removed with the user
+ mSettingsByProfileGroup.get(userToRemove.getIdentifier()).unregisterReceivers();
mSettingsByProfileGroup.remove(userToRemove.getIdentifier());
} else {
// We cannot find the parent user of the user that is removed, hence try to remove
diff --git a/startop/iorap/tests/src/com/google/android/startop/iorap/ParcelablesTest.kt b/startop/iorap/tests/src/com/google/android/startop/iorap/ParcelablesTest.kt
index 8fa0cde..150577a 100644
--- a/startop/iorap/tests/src/com/google/android/startop/iorap/ParcelablesTest.kt
+++ b/startop/iorap/tests/src/com/google/android/startop/iorap/ParcelablesTest.kt
@@ -124,7 +124,7 @@
data class InputData<T : Parcelable>(val valid: T, val validCopy: T, val validOther: T) {
val kls = valid.javaClass
init {
- assertThat(valid).isNotSameAs(validCopy)
+ assertThat(valid).isNotSameInstanceAs(validCopy)
// Don't use isInstanceOf because of phantom warnings in intellij about Class!
assertThat(validCopy.javaClass).isEqualTo(valid.javaClass)
assertThat(validOther.javaClass).isEqualTo(valid.javaClass)
diff --git a/telecomm/java/android/telecom/CallerInfo.java b/telecomm/java/android/telecom/CallerInfo.java
index fb6f994..aff2f01 100644
--- a/telecomm/java/android/telecom/CallerInfo.java
+++ b/telecomm/java/android/telecom/CallerInfo.java
@@ -405,7 +405,8 @@
// Change the callerInfo number ONLY if it is an emergency number
// or if it is the voicemail number. If it is either, take a
// shortcut and skip the query.
- if (PhoneNumberUtils.isLocalEmergencyNumber(context, number)) {
+ TelephonyManager tm = context.getSystemService(TelephonyManager.class);
+ if (tm.isEmergencyNumber(number)) {
return new CallerInfo().markAsEmergency(context);
} else if (PhoneNumberUtils.isVoiceMailNumber(null, subId, number)) {
return new CallerInfo().markAsVoiceMail(context, subId);
diff --git a/telecomm/java/android/telecom/CallerInfoAsyncQuery.java b/telecomm/java/android/telecom/CallerInfoAsyncQuery.java
index 4a81a8e..a9e1a8f 100644
--- a/telecomm/java/android/telecom/CallerInfoAsyncQuery.java
+++ b/telecomm/java/android/telecom/CallerInfoAsyncQuery.java
@@ -34,6 +34,7 @@
import android.provider.ContactsContract.PhoneLookup;
import android.telephony.PhoneNumberUtils;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
import java.util.ArrayList;
@@ -481,7 +482,8 @@
cw.subId = subId;
// check to see if these are recognized numbers, and use shortcuts if we can.
- if (PhoneNumberUtils.isLocalEmergencyNumber(context, number)) {
+ TelephonyManager tm = context.getSystemService(TelephonyManager.class);
+ if (tm.isEmergencyNumber(number)) {
cw.event = EVENT_EMERGENCY_NUMBER;
} else if (PhoneNumberUtils.isVoiceMailNumber(context, subId, number)) {
cw.event = EVENT_VOICEMAIL_NUMBER;
diff --git a/telephony/api/system-current.txt b/telephony/api/system-current.txt
index 11fae0c..a67273c 100644
--- a/telephony/api/system-current.txt
+++ b/telephony/api/system-current.txt
@@ -227,6 +227,25 @@
field public static final String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming";
}
+ public final class ModemActivityInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.telephony.ModemActivityInfo getDelta(@NonNull android.telephony.ModemActivityInfo);
+ method public long getIdleTimeMillis();
+ method public static int getNumTxPowerLevels();
+ method public long getReceiveTimeMillis();
+ method public long getSleepTimeMillis();
+ method public long getTimestampMillis();
+ method public long getTransmitDurationMillisAtPowerLevel(int);
+ method @NonNull public android.util.Range<java.lang.Integer> getTransmitPowerRange(int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ModemActivityInfo> CREATOR;
+ field public static final int TX_POWER_LEVEL_0 = 0; // 0x0
+ field public static final int TX_POWER_LEVEL_1 = 1; // 0x1
+ field public static final int TX_POWER_LEVEL_2 = 2; // 0x2
+ field public static final int TX_POWER_LEVEL_3 = 3; // 0x3
+ field public static final int TX_POWER_LEVEL_4 = 4; // 0x4
+ }
+
public final class NetworkRegistrationInfo implements android.os.Parcelable {
method @Nullable public android.telephony.DataSpecificRegistrationInfo getDataSpecificInfo();
method public int getRegistrationState();
@@ -693,7 +712,6 @@
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDeviceSoftwareVersion(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEmergencyNumberDbVersion();
- method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<java.lang.String> getEquivalentHomePlmns();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Map<java.lang.Integer,java.lang.Integer> getLogicalToPhysicalSlotMapping();
diff --git a/telephony/java/android/telephony/CellSignalStrength.java b/telephony/java/android/telephony/CellSignalStrength.java
index 2e7bde3..e089657 100644
--- a/telephony/java/android/telephony/CellSignalStrength.java
+++ b/telephony/java/android/telephony/CellSignalStrength.java
@@ -17,6 +17,7 @@
package android.telephony;
import android.annotation.IntRange;
+import android.annotation.SystemApi;
import android.os.PersistableBundle;
/**
@@ -155,11 +156,12 @@
/**
* Returns the number of signal strength levels.
- * @return Number of signal strength levels, enforced to be 5
+ * @return Number of signal strength levels, currently defined in the HAL as 5.
*
* @hide
*/
- public static final int getNumSignalStrengthLevels() {
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static int getNumSignalStrengthLevels() {
return NUM_SIGNAL_STRENGTH_BINS;
}
}
diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java
index debb119..881d85c 100644
--- a/telephony/java/android/telephony/ModemActivityInfo.java
+++ b/telephony/java/android/telephony/ModemActivityInfo.java
@@ -16,8 +16,12 @@
package android.telephony;
+import android.annotation.DurationMillisLong;
+import android.annotation.ElapsedRealtimeLong;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
@@ -25,46 +29,50 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Arrays;
+import java.util.Objects;
/**
- * Reports modem activity information.
+ * Contains information about the modem's activity. May be useful for power stats reporting.
* @hide
*/
+@SystemApi
+@TestApi
public final class ModemActivityInfo implements Parcelable {
+ private static final int TX_POWER_LEVELS = 5;
+
/**
- * Tx(transmit) power level. see power index below
- * <ul>
- * <li> index 0 = tx_power < 0dBm. </li>
- * <li> index 1 = 0dBm < tx_power < 5dBm. </li>
- * <li> index 2 = 5dBm < tx_power < 15dBm. </li>
- * <li> index 3 = 15dBm < tx_power < 20dBm. </li>
- * <li> index 4 = tx_power > 20dBm. </li>
- * </ul>
- */
- public static final int TX_POWER_LEVELS = 5;
- /**
- * Tx(transmit) power level 0: tx_power < 0dBm
+ * Corresponds to transmit power of less than 0dBm.
*/
public static final int TX_POWER_LEVEL_0 = 0;
+
/**
- * Tx(transmit) power level 1: 0dBm < tx_power < 5dBm
+ * Corresponds to transmit power between 0dBm and 5dBm.
*/
public static final int TX_POWER_LEVEL_1 = 1;
+
/**
- * Tx(transmit) power level 2: 5dBm < tx_power < 15dBm
+ * Corresponds to transmit power between 5dBm and 15dBm.
*/
public static final int TX_POWER_LEVEL_2 = 2;
+
/**
- * Tx(transmit) power level 3: 15dBm < tx_power < 20dBm.
+ * Corresponds to transmit power between 15dBm and 20dBm.
*/
public static final int TX_POWER_LEVEL_3 = 3;
+
/**
- * Tx(transmit) power level 4: tx_power > 20dBm
+ * Corresponds to transmit power above 20dBm.
*/
public static final int TX_POWER_LEVEL_4 = 4;
+ /**
+ * The number of transmit power levels. Fixed by HAL definition.
+ */
+ public static int getNumTxPowerLevels() {
+ return TX_POWER_LEVELS;
+ }
+
/** @hide */
@IntDef(prefix = {"TX_POWER_LEVEL_"}, value = {
TX_POWER_LEVEL_0,
@@ -82,34 +90,39 @@
new Range<>(5, 15),
new Range<>(15, 20),
new Range<>(20, Integer.MAX_VALUE)
-
};
private long mTimestamp;
private int mSleepTimeMs;
private int mIdleTimeMs;
- private List<TransmitPower> mTransmitPowerInfo = new ArrayList<>(TX_POWER_LEVELS);
+ private int[] mTxTimeMs;
private int mRxTimeMs;
+ /**
+ * @hide
+ */
+ @TestApi
public ModemActivityInfo(long timestamp, int sleepTimeMs, int idleTimeMs,
@NonNull int[] txTimeMs, int rxTimeMs) {
+ Objects.requireNonNull(txTimeMs);
+ if (txTimeMs.length != TX_POWER_LEVELS) {
+ throw new IllegalArgumentException("txTimeMs must have length == TX_POWER_LEVELS");
+ }
mTimestamp = timestamp;
mSleepTimeMs = sleepTimeMs;
mIdleTimeMs = idleTimeMs;
- populateTransmitPowerRange(txTimeMs);
+ mTxTimeMs = txTimeMs;
mRxTimeMs = rxTimeMs;
}
- /** helper API to populate tx power range for each bucket **/
- private void populateTransmitPowerRange(@NonNull int[] transmitPowerMs) {
- int i = 0;
- for ( ; i < Math.min(transmitPowerMs.length, TX_POWER_LEVELS); i++) {
- mTransmitPowerInfo.add(i, new TransmitPower(TX_POWER_RANGES[i], transmitPowerMs[i]));
- }
- // Make sure that mTransmitPowerInfo is fully initialized.
- for ( ; i < TX_POWER_LEVELS; i++) {
- mTransmitPowerInfo.add(i, new TransmitPower(TX_POWER_RANGES[i], 0));
- }
+ /**
+ * Provided for convenience in manipulation since the API exposes long values but internal
+ * representations are ints.
+ * @hide
+ */
+ public ModemActivityInfo(long timestamp, long sleepTimeMs, long idleTimeMs,
+ @NonNull int[] txTimeMs, long rxTimeMs) {
+ this(timestamp, (int) sleepTimeMs, (int) idleTimeMs, txTimeMs, (int) rxTimeMs);
}
@Override
@@ -118,7 +131,7 @@
+ " mTimestamp=" + mTimestamp
+ " mSleepTimeMs=" + mSleepTimeMs
+ " mIdleTimeMs=" + mIdleTimeMs
- + " mTransmitPowerInfo[]=" + mTransmitPowerInfo.toString()
+ + " mTxTimeMs[]=" + mTxTimeMs
+ " mRxTimeMs=" + mRxTimeMs
+ "}";
}
@@ -129,14 +142,12 @@
public static final @android.annotation.NonNull Parcelable.Creator<ModemActivityInfo> CREATOR =
new Parcelable.Creator<ModemActivityInfo>() {
- public ModemActivityInfo createFromParcel(Parcel in) {
+ public ModemActivityInfo createFromParcel(@NonNull Parcel in) {
long timestamp = in.readLong();
int sleepTimeMs = in.readInt();
int idleTimeMs = in.readInt();
int[] txTimeMs = new int[TX_POWER_LEVELS];
- for (int i = 0; i < TX_POWER_LEVELS; i++) {
- txTimeMs[i] = in.readInt();
- }
+ in.readIntArray(txTimeMs);
int rxTimeMs = in.readInt();
return new ModemActivityInfo(timestamp, sleepTimeMs, idleTimeMs,
txTimeMs, rxTimeMs);
@@ -147,21 +158,25 @@
}
};
- public void writeToParcel(Parcel dest, int flags) {
+ /**
+ * @param dest The Parcel in which the object should be written.
+ * @param flags Additional flags about how the object should be written.
+ */
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeLong(mTimestamp);
dest.writeInt(mSleepTimeMs);
dest.writeInt(mIdleTimeMs);
- for (int i = 0; i < TX_POWER_LEVELS; i++) {
- dest.writeInt(mTransmitPowerInfo.get(i).getTimeInMillis());
- }
+ dest.writeIntArray(mTxTimeMs);
dest.writeInt(mRxTimeMs);
}
/**
- * @return milliseconds since boot, including mTimeInMillis spent in sleep.
- * @see SystemClock#elapsedRealtime()
+ * Gets the timestamp at which this modem activity info was recorded.
+ *
+ * @return The timestamp, as returned by {@link SystemClock#elapsedRealtime()}, when this
+ * {@link ModemActivityInfo} was recorded.
*/
- public long getTimestamp() {
+ public @ElapsedRealtimeLong long getTimestampMillis() {
return mTimestamp;
}
@@ -171,35 +186,48 @@
}
/**
- * @return an arrayList of {@link TransmitPower} with each element representing the total time where
- * transmitter is awake time (in ms) for a given power range (in dbm).
+ * Gets the amount of time the modem spent transmitting at a certain power level.
*
- * @see #TX_POWER_LEVELS
+ * @param powerLevel The power level to query.
+ * @return The amount of time, in milliseconds, that the modem spent transmitting at the
+ * given power level.
*/
- @NonNull
- public List<TransmitPower> getTransmitPowerInfo() {
- return mTransmitPowerInfo;
+ public @DurationMillisLong long getTransmitDurationMillisAtPowerLevel(
+ @TxPowerLevel int powerLevel) {
+ return mTxTimeMs[powerLevel];
+ }
+
+ /**
+ * Gets the range of transmit powers corresponding to a certain power level.
+ *
+ * @param powerLevel The power level to query
+ * @return A {@link Range} object representing the range of intensities (in dBm) to which this
+ * power level corresponds.
+ */
+ public @NonNull Range<Integer> getTransmitPowerRange(@TxPowerLevel int powerLevel) {
+ return TX_POWER_RANGES[powerLevel];
}
/** @hide */
public void setTransmitTimeMillis(int[] txTimeMs) {
- populateTransmitPowerRange(txTimeMs);
- }
-
- /** @hide */
- @NonNull
- public int[] getTransmitTimeMillis() {
- int[] transmitTimeMillis = new int[TX_POWER_LEVELS];
- for (int i = 0; i < transmitTimeMillis.length; i++) {
- transmitTimeMillis[i] = mTransmitPowerInfo.get(i).getTimeInMillis();
- }
- return transmitTimeMillis;
+ mTxTimeMs = Arrays.copyOf(txTimeMs, TX_POWER_LEVELS);
}
/**
- * @return total mTimeInMillis (in ms) when modem is in a low power or sleep state.
+ * @return The raw array of transmit power durations
+ * @hide
*/
- public int getSleepTimeMillis() {
+ @NonNull
+ public int[] getTransmitTimeMillis() {
+ return mTxTimeMs;
+ }
+
+ /**
+ * Gets the amount of time (in milliseconds) when the modem is in a low power or sleep state.
+ *
+ * @return Time in milliseconds.
+ */
+ public @DurationMillisLong long getSleepTimeMillis() {
return mSleepTimeMs;
}
@@ -209,10 +237,44 @@
}
/**
- * @return total mTimeInMillis (in ms) when modem is awake but neither the transmitter nor receiver are
- * active.
+ * Provided for convenience, since the API surface needs to return longs but internal
+ * representations are ints.
+ * @hide
*/
- public int getIdleTimeMillis() {
+ public void setSleepTimeMillis(long sleepTimeMillis) {
+ mSleepTimeMs = (int) sleepTimeMillis;
+ }
+
+ /**
+ * Computes the difference between this instance of {@link ModemActivityInfo} and another
+ * instance.
+ *
+ * This method should be used to compute the amount of activity that has happened between two
+ * samples of modem activity taken at separate times. The sample passed in as an argument to
+ * this method should be the one that's taken later in time (and therefore has more activity).
+ * @param other The other instance of {@link ModemActivityInfo} to diff against.
+ * @return An instance of {@link ModemActivityInfo} representing the difference in modem
+ * activity.
+ */
+ public @NonNull ModemActivityInfo getDelta(@NonNull ModemActivityInfo other) {
+ int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
+ for (int i = 0; i < ModemActivityInfo.TX_POWER_LEVELS; i++) {
+ txTimeMs[i] = other.mTxTimeMs[i] - mTxTimeMs[i];
+ }
+ return new ModemActivityInfo(other.getTimestampMillis(),
+ other.getSleepTimeMillis() - getSleepTimeMillis(),
+ other.getIdleTimeMillis() - getIdleTimeMillis(),
+ txTimeMs,
+ other.getReceiveTimeMillis() - getReceiveTimeMillis());
+ }
+
+ /**
+ * Gets the amount of time (in milliseconds) when the modem is awake but neither transmitting
+ * nor receiving.
+ *
+ * @return Time in milliseconds.
+ */
+ public @DurationMillisLong long getIdleTimeMillis() {
return mIdleTimeMs;
}
@@ -222,9 +284,20 @@
}
/**
- * @return rx(receive) mTimeInMillis in ms.
+ * Provided for convenience, since the API surface needs to return longs but internal
+ * representations are ints.
+ * @hide
*/
- public int getReceiveTimeMillis() {
+ public void setIdleTimeMillis(long idleTimeMillis) {
+ mIdleTimeMs = (int) idleTimeMillis;
+ }
+
+ /**
+ * Gets the amount of time (in milliseconds) when the modem is awake and receiving data.
+ *
+ * @return Time in milliseconds.
+ */
+ public @DurationMillisLong long getReceiveTimeMillis() {
return mRxTimeMs;
}
@@ -234,71 +307,56 @@
}
/**
+ * Provided for convenience, since the API surface needs to return longs but internal
+ * representations are ints.
+ * @hide
+ */
+ public void setReceiveTimeMillis(long receiveTimeMillis) {
+ mRxTimeMs = (int) receiveTimeMillis;
+ }
+
+ /**
* Indicates if the modem has reported valid {@link ModemActivityInfo}.
*
* @return {@code true} if this {@link ModemActivityInfo} record is valid,
* {@code false} otherwise.
+ * TODO: remove usages of this outside Telephony by always returning a valid (or null) result
+ * from telephony.
+ * @hide
*/
+ @TestApi
public boolean isValid() {
- for (TransmitPower powerInfo : getTransmitPowerInfo()) {
- if(powerInfo.getTimeInMillis() < 0) {
- return false;
- }
- }
+ boolean isTxPowerValid = Arrays.stream(mTxTimeMs).allMatch((i) -> i >= 0);
- return ((getIdleTimeMillis() >= 0) && (getSleepTimeMillis() >= 0)
+ return isTxPowerValid && ((getIdleTimeMillis() >= 0) && (getSleepTimeMillis() >= 0)
&& (getReceiveTimeMillis() >= 0) && !isEmpty());
}
private boolean isEmpty() {
- for (TransmitPower txVal : getTransmitPowerInfo()) {
- if(txVal.getTimeInMillis() != 0) {
- return false;
- }
- }
+ boolean isTxPowerEmpty = mTxTimeMs == null || mTxTimeMs.length == 0
+ || Arrays.stream(mTxTimeMs).allMatch((i) -> i == 0);
- return ((getIdleTimeMillis() == 0) && (getSleepTimeMillis() == 0)
+ return isTxPowerEmpty && ((getIdleTimeMillis() == 0) && (getSleepTimeMillis() == 0)
&& (getReceiveTimeMillis() == 0));
}
- /**
- * Transmit power Information, including the power range in dbm and the total time (in ms) where
- * the transmitter is active/awake for this power range.
- * e.g, range: 0dbm(lower) ~ 5dbm(upper)
- * time: 5ms
- */
- public class TransmitPower {
- private int mTimeInMillis;
- private Range<Integer> mPowerRangeInDbm;
- /** @hide */
- public TransmitPower(@NonNull Range<Integer> range, int time) {
- this.mTimeInMillis = time;
- this.mPowerRangeInDbm = range;
- }
- /**
- * @return the total time in ms where the transmitter is active/wake for this power range
- * {@link #getPowerRangeInDbm()}.
- */
- public int getTimeInMillis() {
- return mTimeInMillis;
- }
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ModemActivityInfo that = (ModemActivityInfo) o;
+ return mTimestamp == that.mTimestamp
+ && mSleepTimeMs == that.mSleepTimeMs
+ && mIdleTimeMs == that.mIdleTimeMs
+ && mRxTimeMs == that.mRxTimeMs
+ && Arrays.equals(mTxTimeMs, that.mTxTimeMs);
+ }
- /**
- * @return the power range in dbm. e.g, range: 0dbm(lower) ~ 5dbm(upper)
- */
- @NonNull
- public Range<Integer> getPowerRangeInDbm() {
- return mPowerRangeInDbm;
- }
-
- @Override
- public String toString() {
- return "TransmitPower{"
- + " mTimeInMillis=" + mTimeInMillis
- + " mPowerRangeInDbm={" + mPowerRangeInDbm.getLower()
- + "," + mPowerRangeInDbm.getUpper()
- + "}}";
- }
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(mTimestamp, mSleepTimeMs, mIdleTimeMs, mRxTimeMs);
+ result = 31 * result + Arrays.hashCode(mTxTimeMs);
+ return result;
}
}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index cab6209..d3fca3e 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -2604,13 +2604,12 @@
/**
* Send an MMS message
*
- * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation
- * dialog. If this method is called on a device that has multiple active subscriptions, this
- * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
- * default subscription is defined, the subscription ID associated with this message will be
- * INVALID, which will result in the operation being completed on the subscription associated
- * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
- * operation is performed on the correct subscription.
+ * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this
+ * manager on a multi-SIM device, this operation may fail sending the MMS message because no
+ * suitable default subscription could be found. In this case, if {@code sentIntent} is
+ * non-null, then the {@link PendingIntent} will be sent with an error code
+ * {@code RESULT_NO_DEFAULT_SMS_APP}. See {@link #getDefault()} for more information on the
+ * conditions where this operation may fail.
* </p>
*
* @param context application context
@@ -2629,21 +2628,30 @@
}
MmsManager m = (MmsManager) context.getSystemService(Context.MMS_SERVICE);
if (m != null) {
- m.sendMultimediaMessage(getSubscriptionId(), contentUri, locationUrl, configOverrides,
- sentIntent, 0L /* messageId */);
+ resolveSubscriptionForOperation(new SubscriptionResolverResult() {
+ @Override
+ public void onSuccess(int subId) {
+ m.sendMultimediaMessage(subId, contentUri, locationUrl, configOverrides,
+ sentIntent, 0L /* messageId */);
+ }
+
+ @Override
+ public void onFailure() {
+ notifySmsError(sentIntent, RESULT_NO_DEFAULT_SMS_APP);
+ }
+ });
}
}
/**
* Download an MMS message from carrier by a given location URL
*
- * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation
- * dialog. If this method is called on a device that has multiple active subscriptions, this
- * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
- * default subscription is defined, the subscription ID associated with this message will be
- * INVALID, which will result in the operation being completed on the subscription associated
- * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
- * operation is performed on the correct subscription.
+ * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this
+ * manager on a multi-SIM device, this operation may fail downloading the MMS message because no
+ * suitable default subscription could be found. In this case, if {@code downloadedIntent} is
+ * non-null, then the {@link PendingIntent} will be sent with an error code
+ * {@code RESULT_NO_DEFAULT_SMS_APP}. See {@link #getDefault()} for more information on the
+ * conditions where this operation may fail.
* </p>
*
* @param context application context
@@ -2666,8 +2674,18 @@
}
MmsManager m = (MmsManager) context.getSystemService(Context.MMS_SERVICE);
if (m != null) {
- m.downloadMultimediaMessage(getSubscriptionId(), locationUrl, contentUri,
- configOverrides, downloadedIntent, 0L /* messageId */);
+ resolveSubscriptionForOperation(new SubscriptionResolverResult() {
+ @Override
+ public void onSuccess(int subId) {
+ m.downloadMultimediaMessage(subId, locationUrl, contentUri, configOverrides,
+ downloadedIntent, 0L /* messageId */);
+ }
+
+ @Override
+ public void onFailure() {
+ notifySmsError(downloadedIntent, RESULT_NO_DEFAULT_SMS_APP);
+ }
+ });
}
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ceaa425..a202644 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2835,11 +2835,13 @@
};
/**
- * Return a collection of all network types
- * @return network types
+ * Returns an array of all valid network types.
+ *
+ * @return An integer array containing all valid network types in no particular order.
*
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static @NonNull @NetworkType int[] getAllNetworkTypes() {
return NETWORK_TYPES;
}
@@ -10397,19 +10399,25 @@
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges})
* and {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.
+ *
+ * May return {@code null} when the subscription is inactive or when there was an error
+ * communicating with the phone process.
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(allOf = {
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.ACCESS_COARSE_LOCATION
})
- public ServiceState getServiceState() {
+ public @Nullable ServiceState getServiceState() {
return getServiceStateForSubscriber(getSubId());
}
/**
* Returns the service state information on specified subscription. Callers require
* either READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE to retrieve the information.
+ *
+ * May return {@code null} when the subscription is inactive or when there was an error
+ * communicating with the phone process.
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
@@ -10436,9 +10444,9 @@
* @param accountHandle The handle for the {@link PhoneAccount} for which to retrieve the
* voicemail ringtone.
* @return The URI for the ringtone to play when receiving a voicemail from a specific
- * PhoneAccount.
+ * PhoneAccount. May be {@code null} if no ringtone is set.
*/
- public Uri getVoicemailRingtoneUri(PhoneAccountHandle accountHandle) {
+ public @Nullable Uri getVoicemailRingtoneUri(PhoneAccountHandle accountHandle) {
try {
ITelephony service = getITelephony();
if (service != null) {
@@ -13682,9 +13690,7 @@
* @throws IllegalStateException if the Telephony process is not currently available.
* @throws SecurityException if the caller doesn't have the permission.
*
- * @hide
*/
- @SystemApi
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public @NonNull List<String> getEquivalentHomePlmns() {
try {
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index d430db5..3b9bec9 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -54,4 +54,18 @@
"launcher-aosp-tapl",
"platform-test-annotations",
],
+}
+
+java_library {
+ name: "wm-flicker-common-assertions",
+ platform_apis: true,
+ srcs: ["src/**/*Assertions.java", "src/**/*Assertions.kt"],
+ exclude_srcs: [
+ "**/helpers/*",
+ ],
+ static_libs: [
+ "flickerlib",
+ "truth-prebuilt",
+ "app-helpers-core"
+ ],
}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index 69b1187..8457039 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -21,13 +21,17 @@
import com.android.server.wm.flicker.dsl.WmAssertion
import com.android.server.wm.flicker.helpers.WindowUtils
+const val NAVIGATION_BAR_WINDOW_TITLE = "NavigationBar"
+const val STATUS_BAR_WINDOW_TITLE = "StatusBar"
+const val DOCKED_STACK_DIVIDER = "DockedStackDivider"
+
@JvmOverloads
fun WmAssertion.statusBarWindowIsAlwaysVisible(
bugId: Int = 0,
enabled: Boolean = bugId == 0
) {
all("statusBarWindowIsAlwaysVisible", enabled, bugId) {
- this.showsAboveAppWindow(FlickerTestBase.STATUS_BAR_WINDOW_TITLE)
+ this.showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE)
}
}
@@ -37,7 +41,7 @@
enabled: Boolean = bugId == 0
) {
all("navBarWindowIsAlwaysVisible", enabled, bugId) {
- this.showsAboveAppWindow(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE)
+ this.showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE)
}
}
@@ -77,7 +81,7 @@
enabled: Boolean = bugId == 0
) {
all("navBarLayerIsAlwaysVisible", enabled, bugId) {
- this.showsLayer(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE)
+ this.showsLayer(NAVIGATION_BAR_WINDOW_TITLE)
}
}
@@ -87,7 +91,7 @@
enabled: Boolean = bugId == 0
) {
all("statusBarLayerIsAlwaysVisible", enabled, bugId) {
- this.showsLayer(FlickerTestBase.STATUS_BAR_WINDOW_TITLE)
+ this.showsLayer(STATUS_BAR_WINDOW_TITLE)
}
}
@@ -102,15 +106,15 @@
val endingPos = WindowUtils.getNavigationBarPosition(endRotation)
start("navBarLayerRotatesAndScales_StartingPos", enabled, bugId) {
- this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, startingPos)
+ this.hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, startingPos)
}
end("navBarLayerRotatesAndScales_EndingPost", enabled, bugId) {
- this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, endingPos)
+ this.hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, endingPos)
}
if (startingPos == endingPos) {
all("navBarLayerRotatesAndScales", enabled = false, bugId = 167747321) {
- this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, startingPos)
+ this.hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, startingPos)
}
}
}
@@ -126,10 +130,10 @@
val endingPos = WindowUtils.getStatusBarPosition(endRotation)
start("statusBarLayerRotatesScales_StartingPos", enabled, bugId) {
- this.hasVisibleRegion(FlickerTestBase.STATUS_BAR_WINDOW_TITLE, startingPos)
+ this.hasVisibleRegion(STATUS_BAR_WINDOW_TITLE, startingPos)
}
end("statusBarLayerRotatesScales_EndingPos", enabled, bugId) {
- this.hasVisibleRegion(FlickerTestBase.STATUS_BAR_WINDOW_TITLE, endingPos)
+ this.hasVisibleRegion(STATUS_BAR_WINDOW_TITLE, endingPos)
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.kt
deleted file mode 100644
index abe7dbc..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.kt
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2020 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.wm.flicker
-
-import android.os.RemoteException
-import android.os.SystemClock
-import android.platform.helpers.IAppHelper
-import android.view.Surface
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.uiautomator.UiDevice
-
-/**
- * Base class of all Flicker test that performs common functions for all flicker tests:
- *
- *
- * - Caches transitions so that a transition is run once and the transition results are used by
- * tests multiple times. This is needed for parameterized tests which call the BeforeClass methods
- * multiple times.
- * - Keeps track of all test artifacts and deletes ones which do not need to be reviewed.
- * - Fails tests if results are not available for any test due to jank.
- */
-abstract class FlickerTestBase {
- val instrumentation by lazy {
- InstrumentationRegistry.getInstrumentation()
- }
- val uiDevice by lazy {
- UiDevice.getInstance(instrumentation)
- }
-
- /**
- * Build a test tag for the test
- * @param testName Name of the transition(s) being tested
- * @param app App being launcher
- * @param rotation Initial screen rotation
- *
- * @return test tag with pattern <NAME>__<APP>__<ROTATION>
- </ROTATION></APP></NAME> */
- protected fun buildTestTag(testName: String, app: IAppHelper, rotation: Int): String {
- return buildTestTag(
- testName, app, rotation, rotation, app2 = null, extraInfo = "")
- }
-
- /**
- * Build a test tag for the test
- * @param testName Name of the transition(s) being tested
- * @param app App being launcher
- * @param beginRotation Initial screen rotation
- * @param endRotation End screen rotation (if any, otherwise use same as initial)
- *
- * @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION>
- </END_ROTATION></BEGIN_ROTATION></APP></NAME> */
- protected fun buildTestTag(
- testName: String,
- app: IAppHelper,
- beginRotation: Int,
- endRotation: Int
- ): String {
- return buildTestTag(
- testName, app, beginRotation, endRotation, app2 = null, extraInfo = "")
- }
-
- /**
- * Build a test tag for the test
- * @param testName Name of the transition(s) being tested
- * @param app App being launcher
- * @param app2 Second app being launched (if any)
- * @param beginRotation Initial screen rotation
- * @param endRotation End screen rotation (if any, otherwise use same as initial)
- * @param extraInfo Additional information to append to the tag
- *
- * @return test tag with pattern <NAME>__<APP></APP>(S)>__<ROTATION></ROTATION>(S)>[__<EXTRA>]
- </EXTRA></NAME> */
- protected fun buildTestTag(
- testName: String,
- app: IAppHelper,
- beginRotation: Int,
- endRotation: Int,
- app2: IAppHelper?,
- extraInfo: String
- ): String {
- var testTag = "${testName}__${app.launcherName}"
- if (app2 != null) {
- testTag += "-${app2.launcherName}"
- }
- testTag += "__${Surface.rotationToString(beginRotation)}"
- if (endRotation != beginRotation) {
- testTag += "-${Surface.rotationToString(endRotation)}"
- }
- if (extraInfo.isNotEmpty()) {
- testTag += "__$extraInfo"
- }
- return testTag
- }
-
- protected fun Flicker.setRotation(rotation: Int) {
- try {
- when (rotation) {
- Surface.ROTATION_270 -> device.setOrientationLeft()
- Surface.ROTATION_90 -> device.setOrientationRight()
- Surface.ROTATION_0 -> device.setOrientationNatural()
- else -> device.setOrientationNatural()
- }
- // Wait for animation to complete
- SystemClock.sleep(1000)
- } catch (e: RemoteException) {
- throw RuntimeException(e)
- }
- }
-
- companion object {
- const val NAVIGATION_BAR_WINDOW_TITLE = "NavigationBar"
- const val STATUS_BAR_WINDOW_TITLE = "StatusBar"
- const val DOCKED_STACK_DIVIDER = "DockedStackDivider"
- }
-}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.kt
deleted file mode 100644
index e7d1f8e..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2020 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.wm.flicker
-
-import android.view.Surface
-import org.junit.runners.Parameterized
-
-abstract class NonRotationTestBase(
- protected val rotationName: String,
- protected val rotation: Int
-) : FlickerTestBase() {
- companion object {
- const val SCREENSHOT_LAYER = "RotationLayer"
-
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val supportedRotations = intArrayOf(Surface.ROTATION_0, Surface.ROTATION_90)
- return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
- }
- }
-}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/RotationTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/RotationTestBase.kt
deleted file mode 100644
index 3b67727..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/RotationTestBase.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2020 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.wm.flicker
-
-import android.view.Surface
-import org.junit.runners.Parameterized
-
-abstract class RotationTestBase(
- beginRotationName: String,
- endRotationName: String,
- protected val beginRotation: Int,
- protected val endRotation: Int
-) : FlickerTestBase() {
- companion object {
- @Parameterized.Parameters(name = "{0}-{1}")
- @JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val supportedRotations = intArrayOf(Surface.ROTATION_0, Surface.ROTATION_90)
- val params: MutableCollection<Array<Any>> = mutableListOf()
- for (begin in supportedRotations) {
- for (end in supportedRotations) {
- if (begin != end) {
- params.add(arrayOf(
- Surface.rotationToString(begin),
- Surface.rotationToString(end),
- begin,
- end
- ))
- }
- }
- }
- return params
- }
- }
-}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
new file mode 100644
index 0000000..742003a
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2020 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.wm.flicker.helpers
+
+import android.os.Bundle
+import android.os.RemoteException
+import android.os.SystemClock
+import android.platform.helpers.IAppHelper
+import android.view.Surface
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.startRotation
+
+fun Flicker.setRotation(rotation: Int) {
+ try {
+ when (rotation) {
+ Surface.ROTATION_270 -> device.setOrientationLeft()
+ Surface.ROTATION_90 -> device.setOrientationRight()
+ Surface.ROTATION_0 -> device.setOrientationNatural()
+ else -> device.setOrientationNatural()
+ }
+ // Wait for animation to complete
+ SystemClock.sleep(1000)
+ } catch (e: RemoteException) {
+ throw RuntimeException(e)
+ }
+}
+
+/**
+ * Build a test tag for the test
+ * @param testName Name of the transition(s) being tested
+ * @param app App being launcher
+ * @param beginRotation Initial screen rotation
+ * @param endRotation End screen rotation (if any, otherwise use same as initial)
+ *
+ * @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION>
+</END_ROTATION></BEGIN_ROTATION></APP></NAME> */
+fun buildTestTag(
+ testName: String,
+ app: IAppHelper,
+ beginRotation: Int,
+ endRotation: Int
+): String {
+ return buildTestTag(
+ testName, app.launcherName, beginRotation, endRotation, app2 = null, extraInfo = "")
+}
+
+/**
+ * Build a test tag for the test
+ * @param testName Name of the transition(s) being tested
+ * @param app App being launcher
+ * @param rotation Screen rotation configuration for the test
+ *
+ * @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION>
+</END_ROTATION></BEGIN_ROTATION></APP></NAME> */
+fun buildTestTag(
+ testName: String,
+ app: IAppHelper?,
+ configuration: Bundle
+): String {
+ return buildTestTag(testName, app?.launcherName ?: "", configuration.startRotation,
+ configuration.endRotation, app2 = null, extraInfo = "")
+}
+
+/**
+ * Build a test tag for the test
+ * @param testName Name of the transition(s) being tested
+ * @param app App being launcher
+ * @param app2 Second app being launched (if any)
+ * @param beginRotation Initial screen rotation
+ * @param endRotation End screen rotation (if any, otherwise use same as initial)
+ * @param extraInfo Additional information to append to the tag
+ *
+ * @return test tag with pattern <NAME>__<APP></APP>(S)>__<ROTATION></ROTATION>(S)>[__<EXTRA>]
+</EXTRA></NAME> */
+fun buildTestTag(
+ testName: String,
+ app: String,
+ beginRotation: Int,
+ endRotation: Int,
+ app2: String?,
+ extraInfo: String
+): String {
+ var testTag = "${testName}__$app"
+ if (app2 != null) {
+ testTag += "-$app2"
+ }
+ testTag += "__${Surface.rotationToString(beginRotation)}"
+ if (endRotation != beginRotation) {
+ testTag += "-${Surface.rotationToString(endRotation)}"
+ }
+ if (extraInfo.isNotEmpty()) {
+ testTag += "__$extraInfo"
+ }
+ return testTag
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index 404c789..a73264d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -16,21 +16,27 @@
package com.android.server.wm.flicker.ime
+import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.dsl.flicker
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
-import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.helpers.buildTestTag
+import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -39,56 +45,62 @@
* Test IME window closing back to app window transitions.
* To run this test: `atest FlickerTests:CloseImeWindowToAppTest`
*/
+@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class CloseImeAutoOpenWindowToAppTest(
- rotationName: String,
- rotation: Int
-) : CloseImeWindowToAppTest(rotationName, rotation) {
- override val testApp: ImeAppHelper
- get() = ImeAppAutoFocusHelper(instrumentation)
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
- @Test
- override fun test() {
- flicker(instrumentation) {
- withTag { buildTestTag("imeToAppAutoOpen", testApp, rotation) }
- repeat { 1 }
- setup {
- eachRun {
- device.wakeUpAndGoToHomeScreen()
- this.setRotation(rotation)
- testApp.open()
- testApp.openIME(device)
- }
- }
- teardown {
- eachRun {
- testApp.exit()
- this.setRotation(Surface.ROTATION_0)
- }
- }
- transitions {
- device.pressBack()
- device.waitForIdle()
- }
- assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- imeAppWindowIsAlwaysVisible(testApp, bugId = 141458352)
- }
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<Array<Any>> {
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = ImeAppAutoFocusHelper(instrumentation)
- layersTrace {
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- noUncoveredRegions(rotation)
- navBarLayerRotatesAndScales(rotation)
- statusBarLayerRotatesScales(rotation)
- imeLayerBecomesInvisible(bugId = 141458352)
- imeAppLayerIsAlwaysVisible(testApp, bugId = 141458352)
+ return FlickerTestRunnerFactory(instrumentation)
+ .buildTest { configuration ->
+ withTag { buildTestTag("imeToAppAutoOpen", testApp, configuration) }
+ repeat { configuration.repetitions }
+ setup {
+ eachRun {
+ device.wakeUpAndGoToHomeScreen()
+ this.setRotation(configuration.startRotation)
+ testApp.open()
+ testApp.openIME(device)
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ transitions {
+ device.pressBack()
+ device.waitForIdle()
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ imeAppWindowIsAlwaysVisible(testApp, bugId = 141458352)
+ }
+
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(configuration.startRotation)
+ navBarLayerRotatesAndScales(configuration.startRotation)
+ statusBarLayerRotatesScales(configuration.startRotation)
+ imeLayerBecomesInvisible(bugId = 141458352)
+ imeAppLayerIsAlwaysVisible(testApp, bugId = 141458352)
+ }
+ }
}
- }
}
}
-}
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index c1ba21a..7647802 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -19,19 +19,24 @@
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.dsl.flicker
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
-import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.helpers.buildTestTag
+import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -45,53 +50,63 @@
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class CloseImeAutoOpenWindowToHomeTest(
- rotationName: String,
- rotation: Int
-) : CloseImeWindowToHomeTest(rotationName, rotation) {
- override val testApp: ImeAppHelper
- get() = ImeAppAutoFocusHelper(instrumentation)
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
- @Test
- override fun test() {
- flicker(instrumentation) {
- withTag { buildTestTag("imeToHomeAutoOpen", testApp, rotation) }
- repeat { 1 }
- setup {
- eachRun {
- device.wakeUpAndGoToHomeScreen()
- this.setRotation(rotation)
- testApp.open()
- testApp.openIME(device)
- }
- }
- teardown {
- eachRun {
- testApp.exit()
- this.setRotation(Surface.ROTATION_0)
- }
- }
- transitions {
- device.pressHome()
- device.waitForIdle()
- }
- assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- imeWindowBecomesInvisible(bugId = 141458352)
- imeAppWindowBecomesInvisible(testApp, bugId = 157449248)
- }
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<Array<Any>> {
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = ImeAppAutoFocusHelper(instrumentation)
- layersTrace {
- navBarLayerIsAlwaysVisible(bugId = 140855415)
- statusBarLayerIsAlwaysVisible(bugId = 140855415)
- noUncoveredRegions(rotation, Surface.ROTATION_0, allStates = false)
- navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0, bugId = 140855415)
- statusBarLayerRotatesScales(rotation, Surface.ROTATION_0)
- imeLayerBecomesInvisible(bugId = 141458352)
- imeAppLayerBecomesInvisible(testApp, bugId = 153739621)
+ return FlickerTestRunnerFactory(instrumentation)
+ .buildTest { configuration ->
+ withTestName {
+ buildTestTag("imeToHomeAutoOpen", testApp, configuration)
+ }
+ repeat { configuration.repetitions }
+ setup {
+ eachRun {
+ device.wakeUpAndGoToHomeScreen()
+ this.setRotation(configuration.startRotation)
+ testApp.open()
+ testApp.openIME(device)
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ transitions {
+ device.pressHome()
+ device.waitForIdle()
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ imeWindowBecomesInvisible(bugId = 141458352)
+ imeAppWindowBecomesInvisible(testApp, bugId = 157449248)
+ }
+
+ layersTrace {
+ navBarLayerIsAlwaysVisible(bugId = 140855415)
+ statusBarLayerIsAlwaysVisible(bugId = 140855415)
+ noUncoveredRegions(configuration.startRotation, Surface.ROTATION_0,
+ allStates = false)
+ navBarLayerRotatesAndScales(configuration.startRotation,
+ Surface.ROTATION_0, bugId = 140855415)
+ statusBarLayerRotatesScales(configuration.startRotation,
+ Surface.ROTATION_0)
+ imeLayerBecomesInvisible(bugId = 141458352)
+ imeAppLayerBecomesInvisible(testApp, bugId = 153739621)
+ }
+ }
}
- }
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index 2c00722..136cf86 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -19,19 +19,24 @@
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.NonRotationTestBase
-import com.android.server.wm.flicker.dsl.flicker
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.helpers.buildTestTag
+import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -44,52 +49,57 @@
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CloseImeWindowToAppTest(
- rotationName: String,
- rotation: Int
-) : NonRotationTestBase(rotationName, rotation) {
- open val testApp = ImeAppHelper(instrumentation)
+class CloseImeWindowToAppTest(
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
- @Test
- open fun test() {
- flicker(instrumentation) {
- withTag { buildTestTag("imeToApp", testApp, rotation) }
- repeat { 1 }
- setup {
- eachRun {
- device.wakeUpAndGoToHomeScreen()
- this.setRotation(rotation)
- testApp.open()
- testApp.openIME(device)
- }
- }
- teardown {
- eachRun {
- testApp.exit()
- this.setRotation(Surface.ROTATION_0)
- }
- }
- transitions {
- device.pressBack()
- device.waitForIdle()
- }
- assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- imeAppWindowIsAlwaysVisible(testApp)
- }
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<Array<Any>> {
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = ImeAppHelper(instrumentation)
+ return FlickerTestRunnerFactory(instrumentation)
+ .buildTest { configuration ->
+ withTestName { buildTestTag("imeToApp", testApp, configuration) }
+ repeat { configuration.repetitions }
+ setup {
+ eachRun {
+ device.wakeUpAndGoToHomeScreen()
+ this.setRotation(configuration.startRotation)
+ testApp.open()
+ testApp.openIME(device)
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ transitions {
+ device.pressBack()
+ device.waitForIdle()
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ imeAppWindowIsAlwaysVisible(testApp)
+ }
- layersTrace {
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- noUncoveredRegions(rotation)
- navBarLayerRotatesAndScales(rotation)
- statusBarLayerRotatesScales(rotation)
- imeLayerBecomesInvisible(enabled = false)
- imeAppLayerIsAlwaysVisible(testApp)
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(configuration.startRotation)
+ navBarLayerRotatesAndScales(configuration.startRotation)
+ statusBarLayerRotatesScales(configuration.startRotation)
+ imeLayerBecomesInvisible(enabled = false)
+ imeAppLayerIsAlwaysVisible(testApp)
+ }
+ }
}
- }
}
}
}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index 4697adc..6cfb282 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -19,21 +19,26 @@
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.NonRotationTestBase
-import com.android.server.wm.flicker.dsl.flicker
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.openQuickstep
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
+import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -45,61 +50,69 @@
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CloseImeWindowToHomeTest(
- rotationName: String,
- rotation: Int
-) : NonRotationTestBase(rotationName, rotation) {
- open val testApp = ImeAppHelper(instrumentation)
+class CloseImeWindowToHomeTest(
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
- @Test
- open fun test() {
- flicker(instrumentation) {
- withTag { buildTestTag("imeToHome", testApp, rotation) }
- repeat { 1 }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- this.setRotation(rotation)
- testApp.open()
- }
- eachRun {
- device.openQuickstep()
- device.reopenAppFromOverview()
- this.setRotation(rotation)
- testApp.openIME(device)
- }
- }
- transitions {
- device.pressHome()
- device.waitForIdle()
- }
- teardown {
- eachRun {
- device.pressHome()
- }
- test {
- testApp.exit()
- this.setRotation(Surface.ROTATION_0)
- }
- }
- assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- imeWindowBecomesInvisible()
- imeAppWindowBecomesInvisible(testApp)
- }
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<Array<Any>> {
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = ImeAppHelper(instrumentation)
+ return FlickerTestRunnerFactory(instrumentation)
+ .buildTest { configuration ->
+ withTestName { buildTestTag("imeToHome", testApp, configuration) }
+ repeat { configuration.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ this.setRotation(configuration.startRotation)
+ testApp.open()
+ }
+ eachRun {
+ device.openQuickstep()
+ device.reopenAppFromOverview()
+ this.setRotation(configuration.startRotation)
+ testApp.openIME(device)
+ }
+ }
+ transitions {
+ device.pressHome()
+ device.waitForIdle()
+ }
+ teardown {
+ eachRun {
+ device.pressHome()
+ }
+ test {
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ imeWindowBecomesInvisible()
+ imeAppWindowBecomesInvisible(testApp)
+ }
- layersTrace {
- navBarLayerIsAlwaysVisible(bugId = 140855415)
- statusBarLayerIsAlwaysVisible(bugId = 140855415)
- noUncoveredRegions(rotation, Surface.ROTATION_0, allStates = false)
- navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0, bugId = 140855415)
- statusBarLayerRotatesScales(rotation, Surface.ROTATION_0)
- imeLayerBecomesInvisible(bugId = 153739621)
- imeAppLayerBecomesInvisible(testApp, bugId = 153739621)
+ layersTrace {
+ navBarLayerIsAlwaysVisible(bugId = 140855415)
+ statusBarLayerIsAlwaysVisible(bugId = 140855415)
+ noUncoveredRegions(configuration.startRotation,
+ Surface.ROTATION_0, allStates = false)
+ navBarLayerRotatesAndScales(configuration.startRotation,
+ Surface.ROTATION_0, bugId = 140855415)
+ statusBarLayerRotatesScales(configuration.startRotation,
+ Surface.ROTATION_0)
+ imeLayerBecomesInvisible(bugId = 153739621)
+ imeAppLayerBecomesInvisible(testApp, bugId = 153739621)
+ }
+ }
}
- }
}
}
}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ImeAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/ImeAssertions.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index 2caa8f3..5767a94 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -19,19 +19,24 @@
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.NonRotationTestBase
-import com.android.server.wm.flicker.dsl.flicker
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.helpers.buildTestTag
+import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -45,62 +50,65 @@
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenImeWindowTest(
- rotationName: String,
- rotation: Int
-) : NonRotationTestBase(rotationName, rotation) {
- @Test
- fun test() {
- val testApp = ImeAppHelper(instrumentation)
-
- flicker(instrumentation) {
- withTag { buildTestTag("openIme", testApp, rotation) }
- repeat { 1 }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- this.setRotation(rotation)
- testApp.open()
- }
- }
- transitions {
- testApp.openIME(device)
- }
- teardown {
- eachRun {
- testApp.closeIME(device)
- }
- test {
- testApp.exit()
- this.setRotation(Surface.ROTATION_0)
- }
- }
- assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
-
- all("imeWindowBecomesVisible") {
- this.skipUntilFirstAssertion()
- .hidesNonAppWindow(IME_WINDOW_TITLE)
- .then()
- .showsNonAppWindow(IME_WINDOW_TITLE)
- }
- }
-
- layersTrace {
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- noUncoveredRegions(rotation)
- navBarLayerRotatesAndScales(rotation)
- statusBarLayerRotatesScales(rotation)
-
- imeLayerBecomesVisible()
- }
- }
- }
- }
-
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
companion object {
private const val IME_WINDOW_TITLE = "InputMethod"
+
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<Array<Any>> {
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = ImeAppHelper(instrumentation)
+
+ return FlickerTestRunnerFactory(instrumentation)
+ .buildTest { configuration ->
+ withTestName { buildTestTag("openIme", testApp, configuration) }
+ repeat { configuration.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ this.setRotation(configuration.startRotation)
+ testApp.open()
+ }
+ }
+ transitions {
+ testApp.openIME(device)
+ }
+ teardown {
+ eachRun {
+ testApp.closeIME(device)
+ }
+ test {
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+
+ all("imeWindowBecomesVisible") {
+ this.skipUntilFirstAssertion()
+ .hidesNonAppWindow(IME_WINDOW_TITLE)
+ .then()
+ .showsNonAppWindow(IME_WINDOW_TITLE)
+ }
+ }
+
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(configuration.startRotation)
+ navBarLayerRotatesAndScales(configuration.startRotation)
+ statusBarLayerRotatesScales(configuration.startRotation)
+
+ imeLayerBecomesVisible()
+ }
+ }
+ }
+ }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
new file mode 100644
index 0000000..7e857f3
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 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.wm.flicker.launch
+
+import android.platform.helpers.IAppHelper
+import com.android.server.wm.flicker.dsl.LayersAssertion
+import com.android.server.wm.flicker.dsl.WmAssertion
+
+fun WmAssertion.wallpaperWindowBecomesInvisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("wallpaperWindowBecomesInvisible", enabled, bugId) {
+ this.showsBelowAppWindow("Wallpaper")
+ .then()
+ .hidesBelowAppWindow("Wallpaper")
+ }
+}
+
+fun WmAssertion.appWindowReplacesLauncherAsTopWindow(
+ testApp: IAppHelper,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("appWindowReplacesLauncherAsTopWindow", enabled, bugId) {
+ this.showsAppWindowOnTop("Launcher")
+ .then()
+ .showsAppWindowOnTop("Snapshot", testApp.getPackage())
+ }
+}
+
+fun LayersAssertion.wallpaperLayerBecomesInvisible(
+ testApp: IAppHelper,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("wallpaperLayerBecomesInvisible", enabled, bugId) {
+ this.showsLayer("Wallpaper")
+ .then()
+ .replaceVisibleLayer("Wallpaper", testApp.getPackage())
+ }
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 2c9c8ba..1081414 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -19,18 +19,26 @@
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.dsl.flicker
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.focusChanges
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.helpers.buildTestTag
+import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -44,53 +52,64 @@
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenAppColdTest(
- rotationName: String,
- rotation: Int
-) : OpenAppTestBase(rotationName, rotation) {
- @Test
- fun test() {
- flicker(instrumentation) {
- withTag { buildTestTag("openAppCold", testApp, rotation) }
- repeat { 1 }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- }
- eachRun {
- this.setRotation(rotation)
- }
- }
- transitions {
- testApp.open()
- }
- teardown {
- eachRun {
- testApp.exit()
- this.setRotation(Surface.ROTATION_0)
- }
- }
- assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- appWindowReplacesLauncherAsTopWindow()
- wallpaperWindowBecomesInvisible()
- }
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<Array<Any>> {
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = StandardAppHelper(instrumentation,
+ "com.android.server.wm.flicker.testapp", "SimpleApp")
+ return FlickerTestRunnerFactory(instrumentation)
+ .buildTest { configuration ->
+ withTag { buildTestTag("openAppCold", testApp, configuration) }
+ repeat { configuration.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ }
+ eachRun {
+ this.setRotation(configuration.startRotation)
+ }
+ }
+ transitions {
+ testApp.open()
+ }
+ teardown {
+ eachRun {
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ appWindowReplacesLauncherAsTopWindow(testApp)
+ wallpaperWindowBecomesInvisible()
+ }
- layersTrace {
- // During testing the launcher is always in portrait mode
- noUncoveredRegions(Surface.ROTATION_0, rotation, bugId = 141361128)
- navBarLayerRotatesAndScales(Surface.ROTATION_0, rotation)
- statusBarLayerRotatesScales(Surface.ROTATION_0, rotation)
- navBarLayerIsAlwaysVisible(enabled = rotation == Surface.ROTATION_0)
- statusBarLayerIsAlwaysVisible(enabled = false)
- wallpaperLayerBecomesInvisible()
- }
+ layersTrace {
+ // During testing the launcher is always in portrait mode
+ noUncoveredRegions(Surface.ROTATION_0, configuration.endRotation,
+ bugId = 141361128)
+ navBarLayerRotatesAndScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ statusBarLayerRotatesScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ navBarLayerIsAlwaysVisible(
+ enabled = configuration.endRotation == Surface.ROTATION_0)
+ statusBarLayerIsAlwaysVisible(enabled = false)
+ wallpaperLayerBecomesInvisible(testApp)
+ }
- eventLog {
- focusChanges("NexusLauncherActivity", testApp.`package`)
+ eventLog {
+ focusChanges("NexusLauncherActivity", testApp.`package`)
+ }
+ }
}
- }
}
}
}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTestBase.kt
deleted file mode 100644
index 98e05d5..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTestBase.kt
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2020 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.wm.flicker.launch
-
-import com.android.server.wm.flicker.NonRotationTestBase
-import com.android.server.wm.flicker.helpers.StandardAppHelper
-import com.android.server.wm.flicker.dsl.LayersAssertion
-import com.android.server.wm.flicker.dsl.WmAssertion
-
-abstract class OpenAppTestBase(
- rotationName: String,
- rotation: Int
-) : NonRotationTestBase(rotationName, rotation) {
- protected val testApp = StandardAppHelper(instrumentation,
- "com.android.server.wm.flicker.testapp", "SimpleApp")
-
- protected fun WmAssertion.wallpaperWindowBecomesInvisible(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
- ) {
- all("wallpaperWindowBecomesInvisible", enabled, bugId) {
- this.showsBelowAppWindow("Wallpaper")
- .then()
- .hidesBelowAppWindow("Wallpaper")
- }
- }
-
- protected fun WmAssertion.appWindowReplacesLauncherAsTopWindow(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
- ) {
- all("appWindowReplacesLauncherAsTopWindow", enabled, bugId) {
- this.showsAppWindowOnTop("Launcher")
- .then()
- .showsAppWindowOnTop("Snapshot", testApp.getPackage())
- }
- }
-
- protected fun LayersAssertion.wallpaperLayerBecomesInvisible(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
- ) {
- all("appWindowReplacesLauncherAsTopWindow", enabled, bugId) {
- this.showsLayer("Wallpaper")
- .then()
- .replaceVisibleLayer("Wallpaper", testApp.getPackage())
- }
- }
-}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index acd141a..2061994 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -16,21 +16,29 @@
package com.android.server.wm.flicker.launch
+import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.helpers.StandardAppHelper
-import com.android.server.wm.flicker.dsl.flicker
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.focusChanges
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.helpers.buildTestTag
+import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -39,64 +47,73 @@
* Test warm launch app.
* To run this test: `atest FlickerTests:OpenAppWarmTest`
*/
+@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenAppWarmTest(
- rotationName: String,
- rotation: Int
-) : OpenAppTestBase(rotationName, rotation) {
- @Test
- fun test() {
- val testApp = StandardAppHelper(instrumentation,
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<Array<Any>> {
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = StandardAppHelper(instrumentation,
"com.android.server.wm.flicker.testapp", "SimpleApp")
+ return FlickerTestRunnerFactory(instrumentation)
+ .buildTest { configuration ->
+ withTag { buildTestTag("openAppWarm", testApp, configuration) }
+ repeat { configuration.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ testApp.open()
+ }
+ eachRun {
+ device.pressHome()
+ this.setRotation(configuration.startRotation)
+ }
+ }
+ transitions {
+ testApp.open()
+ }
+ teardown {
+ eachRun {
+ this.setRotation(Surface.ROTATION_0)
+ }
+ test {
+ testApp.exit()
+ }
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ appWindowReplacesLauncherAsTopWindow(testApp)
+ wallpaperWindowBecomesInvisible(enabled = false)
+ }
- flicker(instrumentation) {
- withTag { buildTestTag("openAppWarm", testApp, rotation) }
- repeat { 1 }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- testApp.open()
- }
- eachRun {
- device.pressHome()
- this.setRotation(rotation)
- }
- }
- transitions {
- testApp.open()
- }
- teardown {
- eachRun {
- this.setRotation(Surface.ROTATION_0)
- }
- test {
- testApp.exit()
- }
- }
- assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- appWindowReplacesLauncherAsTopWindow()
- wallpaperWindowBecomesInvisible(enabled = false)
- }
+ layersTrace {
+ // During testing the launcher is always in portrait mode
+ noUncoveredRegions(Surface.ROTATION_0, configuration.endRotation,
+ bugId = 141361128)
+ navBarLayerRotatesAndScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ statusBarLayerRotatesScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ navBarLayerIsAlwaysVisible(
+ enabled = configuration.endRotation == Surface.ROTATION_0)
+ statusBarLayerIsAlwaysVisible(enabled = false)
+ wallpaperLayerBecomesInvisible(testApp)
+ }
- layersTrace {
- // During testing the launcher is always in portrait mode
- noUncoveredRegions(Surface.ROTATION_0, rotation, bugId = 141361128)
- navBarLayerRotatesAndScales(Surface.ROTATION_0, rotation)
- statusBarLayerRotatesScales(Surface.ROTATION_0, rotation)
- navBarLayerIsAlwaysVisible(enabled = rotation == Surface.ROTATION_0)
- statusBarLayerIsAlwaysVisible(enabled = false)
- wallpaperLayerBecomesInvisible()
+ eventLog {
+ focusChanges("NexusLauncherActivity", testApp.`package`)
+ }
+ }
}
-
- eventLog {
- focusChanges("NexusLauncherActivity", testApp.`package`)
- }
- }
}
}
}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/CommonAssertions.kt
similarity index 63%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipTestBase.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/pip/CommonAssertions.kt
index 691db7fb..6bc9dcb 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipTestBase.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/CommonAssertions.kt
@@ -16,16 +16,4 @@
package com.android.server.wm.flicker.pip
-import com.android.server.wm.flicker.NonRotationTestBase
-import com.android.server.wm.flicker.helpers.PipAppHelper
-
-abstract class PipTestBase(
- rotationName: String,
- rotation: Int
-) : NonRotationTestBase(rotationName, rotation) {
- protected val testApp = PipAppHelper(instrumentation)
-
- companion object {
- const val sPipWindowTitle = "PipMenuActivity"
- }
-}
\ No newline at end of file
+internal const val PIP_WINDOW_TITLE = "PipMenuActivity"
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt
index 9cfc033..89539fd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt
@@ -16,23 +16,31 @@
package com.android.server.wm.flicker.pip
+import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.dsl.flicker
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.helpers.PipAppHelper
+import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.closePipWindow
import com.android.server.wm.flicker.helpers.expandPipWindow
import com.android.server.wm.flicker.helpers.hasPipWindow
+import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -41,81 +49,85 @@
* Test Pip launch.
* To run this test: `atest FlickerTests:PipToAppTest`
*/
+@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 152738416)
class EnterPipTest(
- rotationName: String,
- rotation: Int
-) : PipTestBase(rotationName, rotation) {
- @Test
- fun test() {
- flicker(instrumentation) {
- withTag { buildTestTag("enterPip", testApp, rotation) }
- repeat { 1 }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- }
- eachRun {
- device.pressHome()
- testApp.open()
- this.setRotation(rotation)
- }
- }
- teardown {
- eachRun {
- if (device.hasPipWindow()) {
- device.closePipWindow()
- }
- testApp.exit()
- this.setRotation(Surface.ROTATION_0)
- }
- test {
- if (device.hasPipWindow()) {
- device.closePipWindow()
- }
- }
- }
- transitions {
- testApp.clickEnterPipButton(device)
- device.expandPipWindow()
- }
- assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- all("pipWindowBecomesVisible") {
- this.showsAppWindow(testApp.`package`)
- .then()
- .showsAppWindow(sPipWindowTitle)
- }
- }
-
- layersTrace {
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- noUncoveredRegions(rotation, Surface.ROTATION_0, allStates = false)
- navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0)
- statusBarLayerRotatesScales(rotation, Surface.ROTATION_0)
-
- all("pipLayerBecomesVisible") {
- this.showsLayer(testApp.launcherName)
- .then()
- .showsLayer(sPipWindowTitle)
- }
- }
- }
- }
- }
-
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val supportedRotations = intArrayOf(Surface.ROTATION_0)
- return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
+ fun getParams(): List<Array<Any>> {
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = PipAppHelper(instrumentation)
+ return FlickerTestRunnerFactory(instrumentation, listOf(Surface.ROTATION_0))
+ .buildTest { configuration ->
+ withTestName { buildTestTag("enterPip", testApp, configuration) }
+ repeat { configuration.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ }
+ eachRun {
+ device.pressHome()
+ testApp.open()
+ this.setRotation(configuration.startRotation)
+ }
+ }
+ teardown {
+ eachRun {
+ if (device.hasPipWindow()) {
+ device.closePipWindow()
+ }
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ test {
+ if (device.hasPipWindow()) {
+ device.closePipWindow()
+ }
+ }
+ }
+ transitions {
+ testApp.clickEnterPipButton(device)
+ device.expandPipWindow()
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+
+ all("pipWindowBecomesVisible") {
+ this.showsAppWindow(testApp.`package`)
+ .then()
+ .showsAppWindow(PIP_WINDOW_TITLE)
+ }
+ }
+
+ layersTrace {
+ navBarLayerIsAlwaysVisible(bugId = 140855415)
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(configuration.startRotation, Surface.ROTATION_0,
+ enabled = false)
+ navBarLayerRotatesAndScales(configuration.startRotation,
+ Surface.ROTATION_0, bugId = 140855415)
+ statusBarLayerRotatesScales(configuration.startRotation,
+ Surface.ROTATION_0)
+ }
+
+ layersTrace {
+ all("pipLayerBecomesVisible") {
+ this.showsLayer(testApp.launcherName)
+ .then()
+ .showsLayer(PIP_WINDOW_TITLE)
+ }
+ }
+ }
+ }
}
}
}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
index deccc90..ac54a0a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
@@ -19,21 +19,28 @@
import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.dsl.flicker
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
import com.android.server.wm.flicker.focusChanges
+import com.android.server.wm.flicker.helpers.PipAppHelper
+import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.closePipWindow
import com.android.server.wm.flicker.helpers.expandPipWindow
import com.android.server.wm.flicker.helpers.hasPipWindow
+import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -47,73 +54,82 @@
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 152738416)
class PipToAppTest(
- rotationName: String,
- rotation: Int
-) : PipTestBase(rotationName, rotation) {
- @Test
- fun test() {
- flicker(instrumentation) {
- withTag { buildTestTag("exitPipModeToApp", testApp, rotation) }
- repeat { 1 }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- device.pressHome()
- testApp.open()
- }
- eachRun {
- this.setRotation(rotation)
- testApp.clickEnterPipButton(device)
- device.hasPipWindow()
- }
- }
- teardown {
- eachRun {
- this.setRotation(Surface.ROTATION_0)
- }
- test {
- if (device.hasPipWindow()) {
- device.closePipWindow()
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<Array<Any>> {
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = PipAppHelper(instrumentation)
+ return FlickerTestRunnerFactory(instrumentation, listOf(Surface.ROTATION_0))
+ .buildTest { configuration ->
+ withTestName { buildTestTag("exitPipModeToApp", testApp, configuration) }
+ repeat { configuration.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ device.pressHome()
+ testApp.open()
+ }
+ eachRun {
+ this.setRotation(configuration.startRotation)
+ testApp.clickEnterPipButton(device)
+ device.hasPipWindow()
+ }
}
- testApp.exit()
- }
- }
- transitions {
- device.expandPipWindow()
- device.waitForIdle()
- }
- assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
+ teardown {
+ eachRun {
+ this.setRotation(Surface.ROTATION_0)
+ }
+ test {
+ if (device.hasPipWindow()) {
+ device.closePipWindow()
+ }
+ testApp.exit()
+ }
+ }
+ transitions {
+ device.expandPipWindow()
+ device.waitForIdle()
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
- all("appReplacesPipWindow") {
- this.showsAppWindow(sPipWindowTitle)
- .then()
- .showsAppWindowOnTop(testApp.launcherName)
+ all("appReplacesPipWindow") {
+ this.showsAppWindow(PIP_WINDOW_TITLE)
+ .then()
+ .showsAppWindowOnTop(testApp.launcherName)
+ }
+ }
+
+ layersTrace {
+ navBarLayerIsAlwaysVisible(bugId = 140855415)
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(configuration.startRotation, Surface.ROTATION_0,
+ enabled = false)
+ navBarLayerRotatesAndScales(configuration.startRotation,
+ Surface.ROTATION_0, bugId = 140855415)
+ statusBarLayerRotatesScales(configuration.startRotation,
+ Surface.ROTATION_0)
+
+ all("appReplacesPipLayer") {
+ this.showsLayer(PIP_WINDOW_TITLE)
+ .then()
+ .showsLayer(testApp.launcherName)
+ }
+ }
+
+ eventLog {
+ focusChanges(
+ "NexusLauncherActivity", testApp.launcherName,
+ "NexusLauncherActivity", bugId = 151179149)
+ }
}
}
-
- layersTrace {
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- noUncoveredRegions(rotation)
- navBarLayerRotatesAndScales(rotation)
- statusBarLayerRotatesScales(rotation)
-
- all("appReplacesPipLayer") {
- this.showsLayer(sPipWindowTitle)
- .then()
- .showsLayer(testApp.launcherName)
- }
- }
-
- eventLog {
- focusChanges(
- "NexusLauncherActivity", testApp.launcherName, "NexusLauncherActivity",
- bugId = 151179149)
- }
- }
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt
index f40869c..f14a27d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt
@@ -19,20 +19,27 @@
import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.dsl.flicker
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
import com.android.server.wm.flicker.focusChanges
+import com.android.server.wm.flicker.helpers.PipAppHelper
+import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.closePipWindow
import com.android.server.wm.flicker.helpers.hasPipWindow
+import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -46,83 +53,83 @@
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 152738416)
class PipToHomeTest(
- rotationName: String,
- rotation: Int
-) : PipTestBase(rotationName, rotation) {
- @Test
- fun test() {
- flicker(instrumentation) {
- withTag { buildTestTag("exitPipModeToApp", testApp, rotation) }
- repeat { 1 }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- device.pressHome()
- }
- eachRun {
- testApp.open()
- this.setRotation(rotation)
- testApp.clickEnterPipButton(device)
- device.hasPipWindow()
- }
- }
- teardown {
- eachRun {
- this.setRotation(Surface.ROTATION_0)
- if (device.hasPipWindow()) {
- device.closePipWindow()
- }
- }
- test {
- if (device.hasPipWindow()) {
- device.closePipWindow()
- }
- testApp.exit()
- }
- }
- transitions {
- testApp.closePipWindow(device)
- }
- assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
-
- all("pipWindowBecomesInvisible") {
- this.showsAppWindow(sPipWindowTitle)
- .then()
- .hidesAppWindow(sPipWindowTitle)
- }
- }
-
- layersTrace {
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- // The final state is the launcher, so always in portrait mode
- noUncoveredRegions(rotation, Surface.ROTATION_0, allStates = false)
- navBarLayerRotatesAndScales(rotation)
- statusBarLayerRotatesScales(rotation)
-
- all("pipLayerBecomesInvisible") {
- this.showsLayer(sPipWindowTitle)
- .then()
- .hidesLayer(sPipWindowTitle)
- }
- }
-
- eventLog {
- focusChanges(testApp.launcherName, "NexusLauncherActivity", bugId = 151179149)
- }
- }
- }
- }
-
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val supportedRotations = intArrayOf(Surface.ROTATION_0)
- return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
+ fun getParams(): List<Array<Any>> {
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = PipAppHelper(instrumentation)
+ return FlickerTestRunnerFactory(instrumentation, listOf(Surface.ROTATION_0))
+ .buildTest { configuration ->
+ withTestName { buildTestTag("exitPipModeToApp", testApp, configuration) }
+ repeat { configuration.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ device.pressHome()
+ }
+ eachRun {
+ testApp.open()
+ this.setRotation(configuration.startRotation)
+ testApp.clickEnterPipButton(device)
+ device.hasPipWindow()
+ }
+ }
+ teardown {
+ eachRun {
+ this.setRotation(Surface.ROTATION_0)
+ if (device.hasPipWindow()) {
+ device.closePipWindow()
+ }
+ }
+ test {
+ if (device.hasPipWindow()) {
+ device.closePipWindow()
+ }
+ testApp.exit()
+ }
+ }
+ transitions {
+ testApp.closePipWindow(device)
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+
+ all("pipWindowBecomesInvisible") {
+ this.showsAppWindow(PIP_WINDOW_TITLE)
+ .then()
+ .hidesAppWindow(PIP_WINDOW_TITLE)
+ }
+ }
+
+ layersTrace {
+ navBarLayerIsAlwaysVisible(bugId = 140855415)
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(configuration.startRotation, Surface.ROTATION_0,
+ enabled = false)
+ navBarLayerRotatesAndScales(configuration.startRotation,
+ Surface.ROTATION_0, bugId = 140855415)
+ statusBarLayerRotatesScales(configuration.startRotation,
+ Surface.ROTATION_0)
+
+ all("pipLayerBecomesInvisible") {
+ this.showsLayer(PIP_WINDOW_TITLE)
+ .then()
+ .hidesLayer(PIP_WINDOW_TITLE)
+ }
+ }
+
+ eventLog {
+ focusChanges(testApp.launcherName, "NexusLauncherActivity",
+ bugId = 151179149)
+ }
+ }
+ }
}
}
}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 99218c2..24ca311 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -16,24 +16,30 @@
package com.android.server.wm.flicker.rotation
+import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
import android.view.Surface
-import com.android.server.wm.flicker.NonRotationTestBase.Companion.SCREENSHOT_LAYER
-import com.android.server.wm.flicker.RotationTestBase
-import com.android.server.wm.flicker.helpers.StandardAppHelper
-import com.android.server.wm.flicker.dsl.flicker
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.focusDoesNotChange
+import com.android.server.wm.flicker.helpers.StandardAppHelper
import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -42,84 +48,95 @@
* Cycle through supported app rotations.
* To run this test: `atest FlickerTest:ChangeAppRotationTest`
*/
+@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class ChangeAppRotationTest(
- beginRotationName: String,
- endRotationName: String,
- beginRotation: Int,
- endRotation: Int
-) : RotationTestBase(beginRotationName, endRotationName, beginRotation, endRotation) {
- @Test
- fun test() {
- val testApp = StandardAppHelper(instrumentation,
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
+ companion object {
+ private const val SCREENSHOT_LAYER = "RotationLayer"
+
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> {
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = StandardAppHelper(instrumentation,
"com.android.server.wm.flicker.testapp", "SimpleApp")
-
- flicker(instrumentation) {
- withTag {
- buildTestTag("changeAppRotation", testApp, beginRotation, endRotation)
- }
- repeat { 1 }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- testApp.open()
- }
- eachRun {
- this.setRotation(beginRotation)
- }
- }
- teardown {
- eachRun {
- this.setRotation(Surface.ROTATION_0)
- }
- test {
- testApp.exit()
- }
- }
- transitions {
- this.setRotation(endRotation)
- }
- assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- }
-
- layersTrace {
- navBarLayerIsAlwaysVisible(bugId = 140855415)
- statusBarLayerIsAlwaysVisible(bugId = 140855415)
- noUncoveredRegions(beginRotation, endRotation, allStates = false)
- navBarLayerRotatesAndScales(beginRotation, endRotation)
- statusBarLayerRotatesScales(beginRotation, endRotation)
- }
-
- layersTrace {
- val startingPos = WindowUtils.getDisplayBounds(beginRotation)
- val endingPos = WindowUtils.getDisplayBounds(endRotation)
-
- start("appLayerRotates_StartingPos") {
- this.hasVisibleRegion(testApp.getPackage(), startingPos)
+ return FlickerTestRunnerFactory(instrumentation)
+ .buildRotationTest { configuration ->
+ withTestName {
+ buildTestTag(
+ "changeAppRotation", testApp, configuration)
}
-
- end("appLayerRotates_EndingPos") {
- this.hasVisibleRegion(testApp.getPackage(), endingPos)
+ repeat { configuration.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ testApp.open()
+ }
+ eachRun {
+ this.setRotation(configuration.startRotation)
+ }
}
+ teardown {
+ eachRun {
+ this.setRotation(Surface.ROTATION_0)
+ }
+ test {
+ testApp.exit()
+ }
+ }
+ transitions {
+ this.setRotation(configuration.endRotation)
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ }
- all("screenshotLayerBecomesInvisible") {
- this.showsLayer(testApp.getPackage())
- .then()
- .showsLayer(SCREENSHOT_LAYER)
- .then()
+ layersTrace {
+ navBarLayerIsAlwaysVisible(bugId = 140855415)
+ statusBarLayerIsAlwaysVisible(bugId = 140855415)
+ noUncoveredRegions(configuration.startRotation,
+ configuration.endRotation, allStates = false)
+ navBarLayerRotatesAndScales(configuration.startRotation,
+ configuration.endRotation)
+ statusBarLayerRotatesScales(configuration.startRotation,
+ configuration.endRotation)
+ }
+
+ layersTrace {
+ val startingPos = WindowUtils.getDisplayBounds(
+ configuration.startRotation)
+ val endingPos = WindowUtils.getDisplayBounds(
+ configuration.endRotation)
+
+ start("appLayerRotates_StartingPos") {
+ this.hasVisibleRegion(testApp.getPackage(), startingPos)
+ }
+
+ end("appLayerRotates_EndingPos") {
+ this.hasVisibleRegion(testApp.getPackage(), endingPos)
+ }
+
+ all("screenshotLayerBecomesInvisible") {
+ this.showsLayer(testApp.getPackage())
+ .then()
+ .showsLayer(SCREENSHOT_LAYER)
+ .then()
showsLayer(testApp.getPackage())
+ }
+ }
+
+ eventLog {
+ focusDoesNotChange(bugId = 151179149)
+ }
}
}
-
- eventLog {
- focusDoesNotChange(bugId = 151179149)
- }
- }
}
}
}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index 33a823d..8ad6c46 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -16,29 +16,36 @@
package com.android.server.wm.flicker.rotation
+import android.content.ComponentName
import android.content.Intent
-import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
+import android.os.Bundle
+import android.platform.test.annotations.Presubmit
import android.view.Surface
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
-import com.android.server.wm.flicker.RotationTestBase
-import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.focusDoesNotChange
import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.buildTestTag
+import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.stopPackage
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.testapp.ActivityOptions
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -47,150 +54,142 @@
* Cycle through supported app rotations using seamless rotations.
* To run this test: `atest FlickerTests:SeamlessAppRotationTest`
*/
+@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 147659548)
class SeamlessAppRotationTest(
- testId: String,
- private val intent: Intent,
- beginRotationName: String,
- endRotationName: String,
- beginRotation: Int,
- endRotation: Int
-) : RotationTestBase(beginRotationName, endRotationName, beginRotation, endRotation) {
- @Test
- fun test() {
- var intentId = ""
- if (intent.extras?.getBoolean(ActivityOptions.EXTRA_STARVE_UI_THREAD) == true) {
- intentId = "BUSY_UI_THREAD"
- }
-
- flicker(instrumentation) {
- withTag {
- "changeAppRotation_" + intentId + "_" +
- Surface.rotationToString(beginRotation) + "_" +
- Surface.rotationToString(endRotation)
- }
- repeat { 1 }
- setup {
- eachRun {
- device.wakeUpAndGoToHomeScreen()
- instrumentation.targetContext.startActivity(intent)
- device.wait(Until.hasObject(By.pkg(intent.component?.packageName)
- .depth(0)), APP_LAUNCH_TIMEOUT)
- this.setRotation(beginRotation)
- }
- }
- teardown {
- eachRun {
- stopPackage(
- instrumentation.targetContext,
- intent.component?.packageName
- ?: error("Unable to determine package name for intent"))
- this.setRotation(Surface.ROTATION_0)
- }
- }
- transitions {
- this.setRotation(endRotation)
- }
- assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible(bugId = 140855415)
- statusBarWindowIsAlwaysVisible(bugId = 140855415)
- }
-
- layersTrace {
- navBarLayerIsAlwaysVisible(bugId = 140855415)
- statusBarLayerIsAlwaysVisible(bugId = 140855415)
- noUncoveredRegions(beginRotation, endRotation, allStates = true)
- navBarLayerRotatesAndScales(beginRotation, endRotation)
- statusBarLayerRotatesScales(beginRotation, endRotation, enabled = false)
- }
-
- layersTrace {
- all("appLayerRotates"/*, bugId = 147659548*/) {
- val startingPos = WindowUtils.getDisplayBounds(beginRotation)
- val endingPos = WindowUtils.getDisplayBounds(endRotation)
-
- if (startingPos == endingPos) {
- this.hasVisibleRegion(
- intent.component?.packageName ?: "",
- startingPos)
- } else {
- this.hasVisibleRegion(intent.component?.packageName ?: "", startingPos)
- .then()
- .hasVisibleRegion(intent.component?.packageName
- ?: "", endingPos)
- }
- }
-
- all("noUncoveredRegions"/*, bugId = 147659548*/) {
- val startingBounds = WindowUtils.getDisplayBounds(beginRotation)
- val endingBounds = WindowUtils.getDisplayBounds(endRotation)
- if (startingBounds == endingBounds) {
- this.coversAtLeastRegion(startingBounds)
- } else {
- this.coversAtLeastRegion(startingBounds)
- .then()
- .coversAtLeastRegion(endingBounds)
- }
- }
- }
-
- eventLog {
- focusDoesNotChange(bugId = 151179149)
- }
- }
- }
- }
-
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
companion object {
private const val APP_LAUNCH_TIMEOUT: Long = 10000
- // launch test activity that supports seamless rotation with a busy UI thread to miss frames
- // when the app is asked to redraw
+ private val Bundle.intent: Intent?
+ get() = this.getParcelable(Intent::class.java.simpleName)
+
+ private val Bundle.intentPackageName: String
+ get() = this.intent?.component?.packageName ?: ""
+
+ private val Bundle.intentId get() = if (this.intent?.getBooleanExtra(
+ ActivityOptions.EXTRA_STARVE_UI_THREAD, false) == true) {
+ "BUSY_UI_THREAD"
+ } else {
+ ""
+ }
+
+ private fun Bundle.createConfig(starveUiThread: Boolean): Bundle {
+ val config = this.deepCopy()
+ val intent = Intent()
+ intent.addCategory(Intent.CATEGORY_LAUNCHER)
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ intent.component = ComponentName("com.android.server.wm.flicker.testapp",
+ "com.android.server.wm.flicker.testapp.SeamlessRotationActivity")
+
+ intent.putExtra(ActivityOptions.EXTRA_STARVE_UI_THREAD, starveUiThread)
+
+ config.putParcelable(Intent::class.java.simpleName, intent)
+ return config
+ }
+
+ @JvmStatic
+ private fun FlickerTestRunnerFactory.getConfigurations(): List<Bundle> {
+ return this.getConfigRotationTests().flatMap {
+ val defaultRun = it.createConfig(starveUiThread = false)
+ val busyUiRun = it.createConfig(starveUiThread = true)
+ listOf(defaultRun, busyUiRun)
+ }
+ }
+
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<Array<Any>> {
- val supportedRotations = intArrayOf(Surface.ROTATION_0, Surface.ROTATION_90)
- val params = mutableListOf<Array<Any>>()
- val testIntents = mutableListOf<Intent>()
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val factory = FlickerTestRunnerFactory(instrumentation)
+ val configurations = factory.getConfigurations()
+ return factory.buildRotationTest(configurations) { configuration ->
+ withTestName {
+ buildTestTag("seamlessRotation_" + configuration.intentId,
+ app = null, configuration = configuration)
+ }
+ repeat { configuration.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ instrumentation.targetContext.startActivity(configuration.intent)
+ val searchQuery = By.pkg(configuration.intent?.component?.packageName)
+ .depth(0)
+ device.wait(Until.hasObject(searchQuery), APP_LAUNCH_TIMEOUT)
+ }
+ eachRun {
+ this.setRotation(configuration.startRotation)
+ }
+ }
+ teardown {
+ test {
+ this.setRotation(Surface.ROTATION_0)
+ stopPackage(
+ instrumentation.targetContext,
+ configuration.intent?.component?.packageName
+ ?: error("Unable to determine package name for intent"))
+ }
+ }
+ transitions {
+ this.setRotation(configuration.endRotation)
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible(bugId = 140855415)
+ statusBarWindowIsAlwaysVisible(bugId = 140855415)
+ }
- // launch test activity that supports seamless rotation
- var intent = Intent(Intent.ACTION_MAIN)
- intent.component = ActivityOptions.SEAMLESS_ACTIVITY_COMPONENT_NAME
- intent.flags = FLAG_ACTIVITY_NEW_TASK
- testIntents.add(intent)
+ layersTrace {
+ navBarLayerIsAlwaysVisible(bugId = 140855415)
+ statusBarLayerIsAlwaysVisible(bugId = 140855415)
+ noUncoveredRegions(configuration.startRotation,
+ configuration.endRotation, allStates = false
+ /*, bugId = 147659548*/)
+ navBarLayerRotatesAndScales(configuration.startRotation,
+ configuration.endRotation)
+ statusBarLayerRotatesScales(configuration.startRotation,
+ configuration.endRotation, enabled = false)
+ }
- // launch test activity that supports seamless rotation with a busy UI thread to miss frames
- // when the app is asked to redraw
- intent = Intent(intent)
- intent.putExtra(ActivityOptions.EXTRA_STARVE_UI_THREAD, true)
- intent.flags = FLAG_ACTIVITY_NEW_TASK
- testIntents.add(intent)
- for (testIntent in testIntents) {
- for (begin in supportedRotations) {
- for (end in supportedRotations) {
- if (begin != end) {
- var testId: String = Surface.rotationToString(begin) +
- "_" + Surface.rotationToString(end)
- if (testIntent.extras?.getBoolean(
- ActivityOptions.EXTRA_STARVE_UI_THREAD) == true) {
- testId += "_" + "BUSY_UI_THREAD"
+ layersTrace {
+ val startingBounds = WindowUtils
+ .getDisplayBounds(configuration.startRotation)
+ val endingBounds = WindowUtils
+ .getDisplayBounds(configuration.endRotation)
+
+ all("appLayerRotates"/*, bugId = 147659548*/) {
+ if (startingBounds == endingBounds) {
+ this.hasVisibleRegion(
+ configuration.intentPackageName, startingBounds)
+ } else {
+ this.hasVisibleRegion(configuration.intentPackageName,
+ startingBounds)
+ .then()
+ .hasVisibleRegion(configuration.intentPackageName,
+ endingBounds)
}
- params.add(arrayOf(
- testId,
- testIntent,
- Surface.rotationToString(begin),
- Surface.rotationToString(end),
- begin,
- end))
}
+
+ all("noUncoveredRegions"/*, bugId = 147659548*/) {
+ if (startingBounds == endingBounds) {
+ this.coversAtLeastRegion(startingBounds)
+ } else {
+ this.coversAtLeastRegion(startingBounds)
+ .then()
+ .coversAtLeastRegion(endingBounds)
+ }
+ }
+ }
+
+ eventLog {
+ focusDoesNotChange(bugId = 151179149)
}
}
}
- return params
}
}
}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
index 3b5e669..ae9fcf9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
@@ -16,25 +16,32 @@
package com.android.server.wm.flicker.splitscreen
-import android.view.Surface
+import android.platform.test.annotations.Presubmit
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.NonRotationTestBase
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.StandardAppHelper
-import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.focusChanges
+import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.exitSplitScreen
import com.android.server.wm.flicker.helpers.isInSplitScreen
import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -43,78 +50,79 @@
* Test open app to split screen.
* To run this test: `atest FlickerTests:OpenAppToSplitScreenTest`
*/
+@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 161435597)
class OpenAppToSplitScreenTest(
- rotationName: String,
- rotation: Int
-) : NonRotationTestBase(rotationName, rotation) {
- @Test
- fun test() {
- val testApp = StandardAppHelper(instrumentation,
- "com.android.server.wm.flicker.testapp", "SimpleApp")
-
- flicker(instrumentation) {
- withTag { buildTestTag("appToSplitScreen", testApp, rotation) }
- repeat { 1 }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- }
- eachRun {
- testApp.open()
- this.setRotation(rotation)
- }
- }
- teardown {
- eachRun {
- if (device.isInSplitScreen()) {
- device.exitSplitScreen()
- }
- }
- test {
- testApp.exit()
- }
- }
- transitions {
- device.launchSplitScreen()
- }
- assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- }
-
- layersTrace {
- navBarLayerIsAlwaysVisible(bugId = 140855415)
- statusBarLayerIsAlwaysVisible()
- noUncoveredRegions(rotation, enabled = false)
- navBarLayerRotatesAndScales(rotation, bugId = 140855415)
- statusBarLayerRotatesScales(rotation)
-
- all("dividerLayerBecomesVisible") {
- this.hidesLayer(DOCKED_STACK_DIVIDER)
- .then()
- .showsLayer(DOCKED_STACK_DIVIDER)
- }
- }
-
- eventLog {
- focusChanges(testApp.`package`,
- "recents_animation_input_consumer", "NexusLauncherActivity",
- bugId = 151179149)
- }
- }
- }
- }
-
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<Array<Any>> {
- val supportedRotations = intArrayOf(Surface.ROTATION_0)
- return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = StandardAppHelper(instrumentation,
+ "com.android.server.wm.flicker.testapp", "SimpleApp")
+
+ return FlickerTestRunnerFactory(instrumentation)
+ .buildTest { configuration ->
+ withTestName {
+ buildTestTag("appToSplitScreen", testApp, configuration)
+ }
+ repeat { configuration.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ }
+ eachRun {
+ testApp.open()
+ this.setRotation(configuration.endRotation)
+ }
+ }
+ teardown {
+ eachRun {
+ if (device.isInSplitScreen()) {
+ device.exitSplitScreen()
+ }
+ }
+ test {
+ testApp.exit()
+ }
+ }
+ transitions {
+ device.launchSplitScreen()
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ }
+
+ layersTrace {
+ navBarLayerIsAlwaysVisible(bugId = 140855415)
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(configuration.endRotation, enabled = false)
+ navBarLayerRotatesAndScales(configuration.endRotation,
+ bugId = 140855415)
+ statusBarLayerRotatesScales(configuration.endRotation)
+
+ all("dividerLayerBecomesVisible") {
+ this.hidesLayer(DOCKED_STACK_DIVIDER)
+ .then()
+ .showsLayer(DOCKED_STACK_DIVIDER)
+ }
+ }
+
+ eventLog {
+ focusChanges(testApp.`package`,
+ "recents_animation_input_consumer", "NexusLauncherActivity",
+ bugId = 151179149)
+ }
+ }
+ }
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
index abf41a1..4b9f024 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
@@ -19,32 +19,39 @@
import android.graphics.Region
import android.util.Rational
import android.view.Surface
-import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.By
-import com.android.server.wm.flicker.FlickerTestBase
+import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.StandardAppHelper
-import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.focusDoesNotChange
import com.android.server.wm.flicker.helpers.ImeAppHelper
import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.exitSplitScreen
import com.android.server.wm.flicker.helpers.isInSplitScreen
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.resizeSplitScreen
+import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
/**
* Test split screen resizing window transitions.
@@ -53,138 +60,149 @@
* Currently it runs only in 0 degrees because of b/156100803
*/
@RequiresDevice
-@RunWith(AndroidJUnit4::class)
+@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 159096424)
-class ResizeSplitScreenTest : FlickerTestBase() {
- @Test
- fun test() {
- val testAppTop = StandardAppHelper(instrumentation,
- "com.android.server.wm.flicker.testapp", "SimpleApp")
- val testAppBottom = ImeAppHelper(instrumentation)
-
- flicker(instrumentation) {
- withTag {
- val description = (startRatio.toString().replace("/", "-") + "_to_" +
- stopRatio.toString().replace("/", "-"))
- buildTestTag("resizeSplitScreen", testAppTop, rotation,
- rotation, testAppBottom, description)
- }
- repeat { 1 }
- setup {
- eachRun {
- device.wakeUpAndGoToHomeScreen()
- this.setRotation(rotation)
- this.launcherStrategy.clearRecentAppsFromOverview()
- testAppBottom.open()
- device.pressHome()
- testAppTop.open()
- device.waitForIdle()
- device.launchSplitScreen()
- val snapshot = device.findObject(By.res(device.launcherPackageName, "snapshot"))
- snapshot.click()
- testAppBottom.openIME(device)
- device.pressBack()
- device.resizeSplitScreen(startRatio)
- }
- }
- teardown {
- eachRun {
- device.exitSplitScreen()
- device.pressHome()
- testAppTop.exit()
- testAppBottom.exit()
- }
- test {
- if (device.isInSplitScreen()) {
- device.exitSplitScreen()
- }
- }
- }
- transitions {
- device.resizeSplitScreen(stopRatio)
- }
- assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
-
- all("topAppWindowIsAlwaysVisible", bugId = 156223549) {
- this.showsAppWindow(sSimpleActivity)
- }
-
- all("bottomAppWindowIsAlwaysVisible", bugId = 156223549) {
- this.showsAppWindow(sImeActivity)
- }
- }
-
- layersTrace {
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- noUncoveredRegions(rotation)
- navBarLayerRotatesAndScales(rotation)
- statusBarLayerRotatesScales(rotation)
-
- all("topAppLayerIsAlwaysVisible") {
- this.showsLayer(sSimpleActivity)
- }
-
- all("bottomAppLayerIsAlwaysVisible") {
- this.showsLayer(sImeActivity)
- }
-
- all("dividerLayerIsAlwaysVisible") {
- this.showsLayer(DOCKED_STACK_DIVIDER)
- }
-
- start("appsStartingBounds", enabled = false) {
- val displayBounds = WindowUtils.displayBounds
- val entry = this.trace.entries.firstOrNull()
- ?: throw IllegalStateException("Trace is empty")
- val dividerBounds = entry.getVisibleBounds(DOCKED_STACK_DIVIDER).bounds
-
- val topAppBounds = Region(0, 0, dividerBounds.right,
- dividerBounds.top + WindowUtils.dockedStackDividerInset)
- val bottomAppBounds = Region(0,
- dividerBounds.bottom - WindowUtils.dockedStackDividerInset,
- displayBounds.right,
- displayBounds.bottom - WindowUtils.navigationBarHeight)
- this.hasVisibleRegion("SimpleActivity", topAppBounds)
- .and()
- .hasVisibleRegion("ImeActivity", bottomAppBounds)
- }
-
- end("appsEndingBounds", enabled = false) {
- val displayBounds = WindowUtils.displayBounds
- val entry = this.trace.entries.lastOrNull()
- ?: throw IllegalStateException("Trace is empty")
- val dividerBounds = entry.getVisibleBounds(DOCKED_STACK_DIVIDER).bounds
-
- val topAppBounds = Region(0, 0, dividerBounds.right,
- dividerBounds.top + WindowUtils.dockedStackDividerInset)
- val bottomAppBounds = Region(0,
- dividerBounds.bottom - WindowUtils.dockedStackDividerInset,
- displayBounds.right,
- displayBounds.bottom - WindowUtils.navigationBarHeight)
-
- this.hasVisibleRegion(sSimpleActivity, topAppBounds)
- .and()
- .hasVisibleRegion(sImeActivity, bottomAppBounds)
- }
- }
-
- eventLog {
- focusDoesNotChange()
- }
- }
- }
- }
-
+class ResizeSplitScreenTest(
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
companion object {
private const val sSimpleActivity = "SimpleActivity"
private const val sImeActivity = "ImeActivity"
- private val rotation = Surface.ROTATION_0
private val startRatio = Rational(1, 3)
private val stopRatio = Rational(2, 3)
+
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> {
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testAppTop = StandardAppHelper(instrumentation,
+ "com.android.server.wm.flicker.testapp", "SimpleApp")
+ val testAppBottom = ImeAppHelper(instrumentation)
+
+ return FlickerTestRunnerFactory(instrumentation, listOf(Surface.ROTATION_0))
+ .buildTest { configuration ->
+ withTestName {
+ val description = (startRatio.toString().replace("/", "-") + "_to_" +
+ stopRatio.toString().replace("/", "-"))
+ buildTestTag("resizeSplitScreen", testAppTop.launcherName,
+ configuration.startRotation, configuration.endRotation,
+ testAppBottom.launcherName, description)
+ }
+ repeat { configuration.repetitions }
+ setup {
+ eachRun {
+ device.wakeUpAndGoToHomeScreen()
+ this.setRotation(configuration.startRotation)
+ this.launcherStrategy.clearRecentAppsFromOverview()
+ testAppBottom.open()
+ device.pressHome()
+ testAppTop.open()
+ device.waitForIdle()
+ device.launchSplitScreen()
+ val snapshot =
+ device.findObject(By.res(device.launcherPackageName, "snapshot"))
+ snapshot.click()
+ testAppBottom.openIME(device)
+ device.pressBack()
+ device.resizeSplitScreen(startRatio)
+ }
+ }
+ teardown {
+ eachRun {
+ if (device.isInSplitScreen()) {
+ device.exitSplitScreen()
+ }
+ device.pressHome()
+ testAppTop.exit()
+ testAppBottom.exit()
+ }
+ test {
+ if (device.isInSplitScreen()) {
+ device.exitSplitScreen()
+ }
+ }
+ }
+ transitions {
+ device.resizeSplitScreen(stopRatio)
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+
+ all("topAppWindowIsAlwaysVisible", bugId = 156223549) {
+ this.showsAppWindow(sSimpleActivity)
+ }
+
+ all("bottomAppWindowIsAlwaysVisible", bugId = 156223549) {
+ this.showsAppWindow(sImeActivity)
+ }
+ }
+
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(configuration.endRotation)
+ navBarLayerRotatesAndScales(configuration.endRotation)
+ statusBarLayerRotatesScales(configuration.endRotation)
+
+ all("topAppLayerIsAlwaysVisible") {
+ this.showsLayer(sSimpleActivity)
+ }
+
+ all("bottomAppLayerIsAlwaysVisible") {
+ this.showsLayer(sImeActivity)
+ }
+
+ all("dividerLayerIsAlwaysVisible") {
+ this.showsLayer(DOCKED_STACK_DIVIDER)
+ }
+
+ start("appsStartingBounds", enabled = false) {
+ val displayBounds = WindowUtils.displayBounds
+ val entry = this.trace.entries.firstOrNull()
+ ?: throw IllegalStateException("Trace is empty")
+ val dividerBounds =
+ entry.getVisibleBounds(DOCKED_STACK_DIVIDER).bounds
+
+ val topAppBounds = Region(0, 0, dividerBounds.right,
+ dividerBounds.top + WindowUtils.dockedStackDividerInset)
+ val bottomAppBounds = Region(0,
+ dividerBounds.bottom - WindowUtils.dockedStackDividerInset,
+ displayBounds.right,
+ displayBounds.bottom - WindowUtils.navigationBarHeight)
+ this.hasVisibleRegion("SimpleActivity", topAppBounds)
+ .and()
+ .hasVisibleRegion("ImeActivity", bottomAppBounds)
+ }
+
+ end("appsEndingBounds", enabled = false) {
+ val displayBounds = WindowUtils.displayBounds
+ val entry = this.trace.entries.lastOrNull()
+ ?: throw IllegalStateException("Trace is empty")
+ val dividerBounds =
+ entry.getVisibleBounds(DOCKED_STACK_DIVIDER).bounds
+
+ val topAppBounds = Region(0, 0, dividerBounds.right,
+ dividerBounds.top + WindowUtils.dockedStackDividerInset)
+ val bottomAppBounds = Region(0,
+ dividerBounds.bottom - WindowUtils.dockedStackDividerInset,
+ displayBounds.right,
+ displayBounds.bottom - WindowUtils.navigationBarHeight)
+
+ this.hasVisibleRegion(sSimpleActivity, topAppBounds)
+ .and()
+ .hasVisibleRegion(sImeActivity, bottomAppBounds)
+ }
+ }
+
+ eventLog {
+ focusDoesNotChange()
+ }
+ }
+ }
+ }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
index 7447bda..f966a66 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
@@ -19,23 +19,29 @@
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.NonRotationTestBase
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
import com.android.server.wm.flicker.helpers.StandardAppHelper
-import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.focusDoesNotChange
+import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.exitSplitScreen
import com.android.server.wm.flicker.helpers.isInSplitScreen
import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -49,82 +55,80 @@
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class SplitScreenToLauncherTest(
- rotationName: String,
- rotation: Int
-) : NonRotationTestBase(rotationName, rotation) {
- @Test
- fun test() {
- val testApp = StandardAppHelper(instrumentation,
- "com.android.server.wm.flicker.testapp", "SimpleApp")
-
- flicker(instrumentation) {
- withTag { buildTestTag("splitScreenToLauncher", testApp, rotation) }
- repeat { 1 }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- }
- eachRun {
- testApp.open()
- this.setRotation(rotation)
- device.launchSplitScreen()
- device.waitForIdle()
- }
- }
- teardown {
- eachRun {
- testApp.exit()
- }
- test {
- if (device.isInSplitScreen()) {
- device.exitSplitScreen()
- }
- }
- }
- transitions {
- device.exitSplitScreen()
- }
- assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- }
-
- layersTrace {
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- noUncoveredRegions(rotation)
- navBarLayerRotatesAndScales(rotation)
- statusBarLayerRotatesScales(rotation)
-
- // b/161435597 causes the test not to work on 90 degrees
- all("dividerLayerBecomesInvisible") {
- this.showsLayer(DOCKED_STACK_DIVIDER)
- .then()
- .hidesLayer(DOCKED_STACK_DIVIDER)
- }
-
- all("appLayerBecomesInvisible") {
- this.showsLayer(testApp.getPackage())
- .then()
- .hidesLayer(testApp.getPackage())
- }
- }
-
- eventLog {
- focusDoesNotChange(bugId = 151179149)
- }
- }
- }
- }
-
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<Array<Any>> {
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = StandardAppHelper(instrumentation,
+ "com.android.server.wm.flicker.testapp", "SimpleApp")
+
// b/161435597 causes the test not to work on 90 degrees
- val supportedRotations = intArrayOf(Surface.ROTATION_0)
- return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
+ return FlickerTestRunnerFactory(instrumentation, listOf(Surface.ROTATION_0))
+ .buildTest { configuration ->
+ withTestName {
+ buildTestTag("splitScreenToLauncher", testApp, configuration)
+ }
+ repeat { configuration.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ }
+ eachRun {
+ testApp.open()
+ this.setRotation(configuration.endRotation)
+ device.launchSplitScreen()
+ device.waitForIdle()
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit()
+ }
+ test {
+ if (device.isInSplitScreen()) {
+ device.exitSplitScreen()
+ }
+ }
+ }
+ transitions {
+ device.exitSplitScreen()
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ }
+
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(configuration.endRotation)
+ navBarLayerRotatesAndScales(configuration.endRotation)
+ statusBarLayerRotatesScales(configuration.endRotation)
+
+ // b/161435597 causes the test not to work on 90 degrees
+ all("dividerLayerBecomesInvisible") {
+ this.showsLayer(DOCKED_STACK_DIVIDER)
+ .then()
+ .hidesLayer(DOCKED_STACK_DIVIDER)
+ }
+
+ all("appLayerBecomesInvisible") {
+ this.showsLayer(testApp.getPackage())
+ .then()
+ .hidesLayer(testApp.getPackage())
+ }
+ }
+
+ eventLog {
+ focusDoesNotChange(bugId = 151179149)
+ }
+ }
+ }
}
}
}
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 226d2d5..bf7a6ff 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -18,6 +18,8 @@
import static com.android.tests.rollback.host.WatchdogEventLogger.watchdogEventOccurred;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -25,6 +27,7 @@
import static org.junit.Assume.assumeTrue;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.ddmlib.Log;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.IFileEntry;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -51,6 +54,7 @@
*/
@RunWith(DeviceJUnit4ClassRunner.class)
public class StagedRollbackTest extends BaseHostJUnit4Test {
+ private static final String TAG = "StagedRollbackTest";
private static final int NATIVE_CRASHES_THRESHOLD = 5;
/**
@@ -124,12 +128,14 @@
}
if (found) {
- if (!getDevice().isAdbRoot()) {
+ try {
getDevice().enableAdbRoot();
- }
- getDevice().remountSystemWritable();
- for (String file : files) {
- getDevice().executeShellCommand("rm -rf " + file);
+ getDevice().remountSystemWritable();
+ for (String file : files) {
+ getDevice().executeShellCommand("rm -rf " + file);
+ }
+ } finally {
+ getDevice().disableAdbRoot();
}
getDevice().reboot();
}
@@ -272,6 +278,8 @@
List<String> after = getSnapshotDirectories("/data/misc_ce/0/rollback");
// Only check directories newly created during the test
after.removeAll(before);
+ // There should be only one /data/misc_ce/0/rollback/<rollbackId> created during test
+ assertThat(after).hasSize(1);
after.forEach(dir -> assertDirectoryIsEmpty(dir));
}
@@ -328,8 +336,8 @@
String oldFilePath1 = apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + "/" + TEST_FILENAME_1;
String oldFilePath2 =
apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + TEST_SUBDIR + TEST_FILENAME_2;
- assertTrue(getDevice().pushString(TEST_STRING_1, oldFilePath1));
- assertTrue(getDevice().pushString(TEST_STRING_2, oldFilePath2));
+ pushString(TEST_STRING_1, oldFilePath1);
+ pushString(TEST_STRING_2, oldFilePath2);
// Install new version of the APEX with rollback enabled
runPhase("testRollbackApexDataDirectories_Phase1");
@@ -341,8 +349,8 @@
String newFilePath3 = apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + "/" + TEST_FILENAME_3;
String newFilePath4 =
apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + TEST_SUBDIR + TEST_FILENAME_4;
- assertTrue(getDevice().pushString(TEST_STRING_3, newFilePath3));
- assertTrue(getDevice().pushString(TEST_STRING_4, newFilePath4));
+ pushString(TEST_STRING_3, newFilePath3);
+ pushString(TEST_STRING_4, newFilePath4);
// Roll back the APEX
runPhase("testRollbackApexDataDirectories_Phase2");
@@ -358,6 +366,8 @@
List<String> after = getSnapshotDirectories("/data/misc/apexrollback");
// Only check directories newly created during the test
after.removeAll(before);
+ // There should be only one /data/misc/apexrollback/<rollbackId> created during test
+ assertThat(after).hasSize(1);
after.forEach(dir -> assertDirectoryIsEmpty(dir));
}
@@ -374,8 +384,8 @@
APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_1;
String oldFilePath2 =
apexDataDirDeUser(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_2;
- assertTrue(getDevice().pushString(TEST_STRING_1, oldFilePath1));
- assertTrue(getDevice().pushString(TEST_STRING_2, oldFilePath2));
+ pushString(TEST_STRING_1, oldFilePath1);
+ pushString(TEST_STRING_2, oldFilePath2);
// Install new version of the APEX with rollback enabled
runPhase("testRollbackApexDataDirectories_Phase1");
@@ -388,8 +398,8 @@
apexDataDirDeUser(APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_3;
String newFilePath4 =
apexDataDirDeUser(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_4;
- assertTrue(getDevice().pushString(TEST_STRING_3, newFilePath3));
- assertTrue(getDevice().pushString(TEST_STRING_4, newFilePath4));
+ pushString(TEST_STRING_3, newFilePath3);
+ pushString(TEST_STRING_4, newFilePath4);
// Roll back the APEX
runPhase("testRollbackApexDataDirectories_Phase2");
@@ -405,6 +415,8 @@
List<String> after = getSnapshotDirectories("/data/misc_de/0/apexrollback");
// Only check directories newly created during the test
after.removeAll(before);
+ // There should be only one /data/misc_de/0/apexrollback/<rollbackId> created during test
+ assertThat(after).hasSize(1);
after.forEach(dir -> assertDirectoryIsEmpty(dir));
}
@@ -420,8 +432,8 @@
String oldFilePath1 = apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_1;
String oldFilePath2 =
apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_2;
- assertTrue(getDevice().pushString(TEST_STRING_1, oldFilePath1));
- assertTrue(getDevice().pushString(TEST_STRING_2, oldFilePath2));
+ pushString(TEST_STRING_1, oldFilePath1);
+ pushString(TEST_STRING_2, oldFilePath2);
// Install new version of the APEX with rollback enabled
runPhase("testRollbackApexDataDirectories_Phase1");
@@ -433,8 +445,8 @@
String newFilePath3 = apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_3;
String newFilePath4 =
apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_4;
- assertTrue(getDevice().pushString(TEST_STRING_3, newFilePath3));
- assertTrue(getDevice().pushString(TEST_STRING_4, newFilePath4));
+ pushString(TEST_STRING_3, newFilePath3);
+ pushString(TEST_STRING_4, newFilePath4);
// Roll back the APEX
runPhase("testRollbackApexDataDirectories_Phase2");
@@ -450,6 +462,8 @@
List<String> after = getSnapshotDirectories("/data/misc_ce/0/apexrollback");
// Only check directories newly created during the test
after.removeAll(before);
+ // There should be only one /data/misc_ce/0/apexrollback/<rollbackId> created during test
+ assertThat(after).hasSize(1);
after.forEach(dir -> assertDirectoryIsEmpty(dir));
}
@@ -464,8 +478,8 @@
// Push files to apk data directory
String oldFilePath1 = apkDataDirDe(TESTAPP_A, 0) + "/" + TEST_FILENAME_1;
String oldFilePath2 = apkDataDirDe(TESTAPP_A, 0) + TEST_SUBDIR + TEST_FILENAME_2;
- assertTrue(getDevice().pushString(TEST_STRING_1, oldFilePath1));
- assertTrue(getDevice().pushString(TEST_STRING_2, oldFilePath2));
+ pushString(TEST_STRING_1, oldFilePath1);
+ pushString(TEST_STRING_2, oldFilePath2);
// Install version 2 of TESTAPP_A with rollback enabled
runPhase("testRollbackApkDataDirectories_Phase2");
@@ -476,8 +490,8 @@
getDevice().deleteFile(oldFilePath2);
String newFilePath3 = apkDataDirDe(TESTAPP_A, 0) + "/" + TEST_FILENAME_3;
String newFilePath4 = apkDataDirDe(TESTAPP_A, 0) + TEST_SUBDIR + TEST_FILENAME_4;
- assertTrue(getDevice().pushString(TEST_STRING_3, newFilePath3));
- assertTrue(getDevice().pushString(TEST_STRING_4, newFilePath4));
+ pushString(TEST_STRING_3, newFilePath3);
+ pushString(TEST_STRING_4, newFilePath4);
// Roll back the APK
runPhase("testRollbackApkDataDirectories_Phase3");
@@ -499,8 +513,8 @@
String oldFilePath1 = apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_1;
String oldFilePath2 =
apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_2;
- assertTrue(getDevice().pushString(TEST_STRING_1, oldFilePath1));
- assertTrue(getDevice().pushString(TEST_STRING_2, oldFilePath2));
+ pushString(TEST_STRING_1, oldFilePath1);
+ pushString(TEST_STRING_2, oldFilePath2);
// Install new version of the APEX with rollback enabled
runPhase("testRollbackApexDataDirectories_Phase1");
@@ -509,6 +523,8 @@
List<String> after = getSnapshotDirectories("/data/misc_ce/0/apexrollback");
// Only check directories newly created during the test
after.removeAll(before);
+ // There should be only one /data/misc_ce/0/apexrollback/<rollbackId> created during test
+ assertThat(after).hasSize(1);
// Expire all rollbacks and check CE snapshot directories are deleted
runPhase("testCleanUp");
for (String dir : after) {
@@ -520,11 +536,13 @@
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild());
final String fileName = APK_IN_APEX_TESTAPEX_NAME + "_v1.apex";
final File apex = buildHelper.getTestFile(fileName);
- if (!getDevice().isAdbRoot()) {
+ try {
getDevice().enableAdbRoot();
+ getDevice().remountSystemWritable();
+ assertTrue(getDevice().pushFile(apex, "/system/apex/" + fileName));
+ } finally {
+ getDevice().disableAdbRoot();
}
- getDevice().remountSystemWritable();
- assertTrue(getDevice().pushFile(apex, "/system/apex/" + fileName));
getDevice().reboot();
}
@@ -544,16 +562,18 @@
return String.format("/data/user_de/%d/%s", userId, apexName);
}
- private List<String> getSnapshotDirectories(String baseDir) {
- try {
- return getDevice().getFileEntry(baseDir).getChildren(false)
- .stream().filter(entry -> entry.getName().matches("\\d+(-prerestore)?"))
- .map(entry -> entry.getFullPath())
- .collect(Collectors.toList());
- } catch (Exception e) {
- // Return an empty list if any error
+ private List<String> getSnapshotDirectories(String baseDir) throws Exception {
+ IFileEntry f = getDevice().getFileEntry(baseDir);
+ if (f == null) {
+ Log.d(TAG, "baseDir doesn't exist: " + baseDir);
return Collections.EMPTY_LIST;
}
+ List<String> list = f.getChildren(false)
+ .stream().filter(entry -> entry.getName().matches("\\d+(-prerestore)?"))
+ .map(entry -> entry.getFullPath())
+ .collect(Collectors.toList());
+ Log.d(TAG, "getSnapshotDirectories=" + list);
+ return list;
}
private void assertDirectoryIsEmpty(String path) {
@@ -600,4 +620,13 @@
return false;
}
}
+
+ private void pushString(String contents, String deviceFilePath) throws Exception {
+ try {
+ getDevice().enableAdbRoot();
+ assertThat(getDevice().pushString(contents, deviceFilePath)).isTrue();
+ } finally {
+ getDevice().disableAdbRoot();
+ }
+ }
}
diff --git a/tests/net/TEST_MAPPING b/tests/net/TEST_MAPPING
index 005cbe9..89fc6ea 100644
--- a/tests/net/TEST_MAPPING
+++ b/tests/net/TEST_MAPPING
@@ -8,5 +8,10 @@
{
"name": "FrameworksNetDeflakeTest"
}
+ ],
+ "imports": [
+ {
+ "path": "cts/tests/tests/net"
+ }
]
}
\ No newline at end of file
diff --git a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
index 8f09377..6d2c7dc 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -150,7 +151,7 @@
}
private void assertRatTypeChangedForSub(String subscriberId, int ratType) {
- assertEquals(mMonitor.getRatTypeForSubscriberId(subscriberId), ratType);
+ assertEquals(ratType, mMonitor.getRatTypeForSubscriberId(subscriberId));
final ArgumentCaptor<Integer> typeCaptor = ArgumentCaptor.forClass(Integer.class);
// Verify callback with the subscriberId and the RAT type should be as expected.
// It will fail if get a callback with an unexpected RAT type.
@@ -302,26 +303,84 @@
reset(mDelegate);
// Set IMSI to null again to simulate somehow IMSI is not available, such as
- // modem crash. Verify service should not unregister listener.
+ // modem crash. Verify service should unregister listener.
updateSubscriberIdForTestSub(TEST_SUBID1, null);
- verify(mTelephonyManager, never()).listen(any(), anyInt());
- assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
+ verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor.getValue()),
+ eq(PhoneStateListener.LISTEN_NONE));
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
reset(mDelegate);
+ clearInvocations(mTelephonyManager);
- // Set RAT type of sim1 to LTE. Verify RAT type of sim1 is still changed even if the IMSI
- // is not available. The monitor keeps the listener even if the IMSI disappears because
- // the IMSI can never change for any given subId, therefore even if the IMSI is updated
- // to null, the monitor should continue accepting updates of the RAT type. However,
- // telephony is never actually supposed to do this, if the IMSI disappears there should
- // not be updates, but it's still the right thing to do theoretically.
- setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
+ // Simulate somehow IMSI is back. Verify service will register with
+ // another listener and fire callback accordingly.
+ final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor2 =
+ ArgumentCaptor.forClass(RatTypeListener.class);
+ updateSubscriberIdForTestSub(TEST_SUBID1, TEST_IMSI1);
+ verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor2.capture(),
+ eq(PhoneStateListener.LISTEN_SERVICE_STATE));
+ assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ reset(mDelegate);
+ clearInvocations(mTelephonyManager);
+
+ // Set RAT type of sim1 to LTE. Verify RAT type of sim1 still works.
+ setRatTypeForSub(ratTypeListenerCaptor2.getAllValues(), TEST_SUBID1,
TelephonyManager.NETWORK_TYPE_LTE);
assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_LTE);
reset(mDelegate);
mMonitor.stop();
+ verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor2.getValue()),
+ eq(PhoneStateListener.LISTEN_NONE));
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ }
+
+ /**
+ * Verify that when IMSI suddenly changed for a given subId, the service will register a new
+ * listener and unregister the old one, and report changes on updated IMSI. This is for modem
+ * feature that may be enabled for certain carrier, which changes to use a different IMSI while
+ * roaming on certain networks for multi-IMSI SIM cards, but the subId stays the same.
+ */
+ @Test
+ public void testSubscriberIdChanged() {
+ mMonitor.start();
+ // Insert sim1, verify RAT type is NETWORK_TYPE_UNKNOWN, and never get any callback
+ // before changing RAT type.
+ addTestSub(TEST_SUBID1, TEST_IMSI1);
+ final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor =
+ ArgumentCaptor.forClass(RatTypeListener.class);
+ verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor.capture(),
+ eq(PhoneStateListener.LISTEN_SERVICE_STATE));
+ assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+
+ // Set RAT type of sim1 to UMTS.
+ // Verify RAT type of sim1 changes accordingly.
+ setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
+ TelephonyManager.NETWORK_TYPE_UMTS);
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
+ reset(mDelegate);
+ clearInvocations(mTelephonyManager);
+
+ // Simulate IMSI of sim1 changed to IMSI2. Verify the service will register with
+ // another listener and remove the old one. The RAT type of new IMSI stays at
+ // NETWORK_TYPE_UNKNOWN until received initial callback from telephony.
+ final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor2 =
+ ArgumentCaptor.forClass(RatTypeListener.class);
+ updateSubscriberIdForTestSub(TEST_SUBID1, TEST_IMSI2);
+ verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor2.capture(),
+ eq(PhoneStateListener.LISTEN_SERVICE_STATE));
verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor.getValue()),
eq(PhoneStateListener.LISTEN_NONE));
assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ assertRatTypeNotChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ reset(mDelegate);
+
+ // Set RAT type of sim1 to UMTS for new listener to simulate the initial callback received
+ // from telephony after registration. Verify RAT type of sim1 changes with IMSI2
+ // accordingly.
+ setRatTypeForSub(ratTypeListenerCaptor2.getAllValues(), TEST_SUBID1,
+ TelephonyManager.NETWORK_TYPE_UMTS);
+ assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ assertRatTypeChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_UMTS);
+ reset(mDelegate);
}
}
diff --git a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
index 7d7d2ba..7877ea1 100644
--- a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
@@ -87,12 +87,12 @@
}
SoftApConfiguration unparceled = parcelUnparcel(original);
- assertThat(unparceled).isNotSameAs(original);
+ assertThat(unparceled).isNotSameInstanceAs(original);
assertThat(unparceled).isEqualTo(original);
assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
- assertThat(copy).isNotSameAs(original);
+ assertThat(copy).isNotSameInstanceAs(original);
assertThat(copy).isEqualTo(original);
assertThat(copy.hashCode()).isEqualTo(original.hashCode());
}
@@ -111,12 +111,12 @@
assertThat(original.getMaxNumberOfClients()).isEqualTo(0);
SoftApConfiguration unparceled = parcelUnparcel(original);
- assertThat(unparceled).isNotSameAs(original);
+ assertThat(unparceled).isNotSameInstanceAs(original);
assertThat(unparceled).isEqualTo(original);
assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
- assertThat(copy).isNotSameAs(original);
+ assertThat(copy).isNotSameInstanceAs(original);
assertThat(copy).isEqualTo(original);
assertThat(copy.hashCode()).isEqualTo(original.hashCode());
}
@@ -159,12 +159,12 @@
}
SoftApConfiguration unparceled = parcelUnparcel(original);
- assertThat(unparceled).isNotSameAs(original);
+ assertThat(unparceled).isNotSameInstanceAs(original);
assertThat(unparceled).isEqualTo(original);
assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
- assertThat(copy).isNotSameAs(original);
+ assertThat(copy).isNotSameInstanceAs(original);
assertThat(copy).isEqualTo(original);
assertThat(copy.hashCode()).isEqualTo(original.hashCode());
}
@@ -185,12 +185,12 @@
SoftApConfiguration unparceled = parcelUnparcel(original);
- assertThat(unparceled).isNotSameAs(original);
+ assertThat(unparceled).isNotSameInstanceAs(original);
assertThat(unparceled).isEqualTo(original);
assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
- assertThat(copy).isNotSameAs(original);
+ assertThat(copy).isNotSameInstanceAs(original);
assertThat(copy).isEqualTo(original);
assertThat(copy.hashCode()).isEqualTo(original.hashCode());
}
@@ -212,12 +212,12 @@
SoftApConfiguration unparceled = parcelUnparcel(original);
- assertThat(unparceled).isNotSameAs(original);
+ assertThat(unparceled).isNotSameInstanceAs(original);
assertThat(unparceled).isEqualTo(original);
assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
- assertThat(copy).isNotSameAs(original);
+ assertThat(copy).isNotSameInstanceAs(original);
assertThat(copy).isEqualTo(original);
assertThat(copy.hashCode()).isEqualTo(original.hashCode());
}